summaryrefslogtreecommitdiff
path: root/print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp')
-rw-r--r--print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp1991
1 files changed, 1991 insertions, 0 deletions
diff --git a/print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp b/print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp
new file mode 100644
index 00000000..f2663bc0
--- /dev/null
+++ b/print/OEM Printer Customization Plug-in Samples/C++/uniuirep/src/Features.cpp
@@ -0,0 +1,1991 @@
+//+--------------------------------------------------------------------------
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright 1997 - 2005 Microsoft Corporation. All Rights Reserved.
+//
+// FILE: Features.cpp
+//
+// PURPOSE: Implements wrapper classes for managing the features &
+// options supported by the driver.
+//
+//--------------------------------------------------------------------------
+
+#include "precomp.h"
+
+// This indicates to Prefast that this is a usermode driver file.
+_Analysis_mode_(_Analysis_code_type_user_driver_);
+
+////////////////////////////////////////////////////////
+// Internal Defines and Macros
+////////////////////////////////////////////////////////
+
+//
+// TAG the identifies feature OPTITEM data stuct.
+//
+#define FEATURE_OPTITEM_TAG 'FETR'
+
+
+////////////////////////////////////////////////////////
+// Type Definitions
+////////////////////////////////////////////////////////
+//
+// Struct used to identify OPTITEM as feature OPTITEM and to map back
+// from an OPTITEM to the feature.
+//
+typedef struct _tagFeatureOptItemData
+{
+ DWORD dwSize;
+ DWORD dwTag;
+ PCSTR pszFeatureKeyword;
+ CFeature *pFeature;
+
+} FEATUREOPTITEMDATA, *PFEATUREOPTITEMDATA;
+
+//
+// Mapping of feature names to keywords
+//
+static CONST KEYWORDMAP gkmFeatureMap[] =
+{
+ {"RESDLL", NULL, IDS_RESDLL, OEMCUIP_PRNPROP},
+ {"InputBin", TEXT("COMPSTUI.DLL"), IDS_CPSUI_SOURCE, OEMCUIP_DOCPROP},
+ {"Orientation", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ORIENTATION, OEMCUIP_DOCPROP},
+ {"Resolution", TEXT("COMPSTUI.DLL"), IDS_CPSUI_RESOLUTION, OEMCUIP_DOCPROP},
+ {"GraphicsMode", NULL, IDS_GRAPHICS_MODE, OEMCUIP_DOCPROP},
+ {"PaperSize", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FORMNAME, OEMCUIP_DOCPROP},
+ {"MediaType", TEXT("COMPSTUI.DLL"), IDS_CPSUI_MEDIA, OEMCUIP_DOCPROP},
+ {"ColorMode", TEXT("COMPSTUI.DLL"), IDS_CPSUI_COLOR_APPERANCE, OEMCUIP_DOCPROP},
+ {"Halftone", TEXT("COMPSTUI.DLL"), IDS_CPSUI_HALFTONE, OEMCUIP_DOCPROP},
+ {"DuplexUnit", NULL, IDS_DUPLEX_UNIT, OEMCUIP_PRNPROP},
+ {"Duplex", TEXT("COMPSTUI.DLL"), IDS_CPSUI_DUPLEX, OEMCUIP_DOCPROP},
+ {"Memory", NULL, IDS_INSTALLED_MEMORY, OEMCUIP_PRNPROP},
+ {"OutputBin", TEXT("COMPSTUI.DLL"), IDS_CPSUI_OUTPUTBIN, OEMCUIP_DOCPROP},
+ {"PageProtect", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PAGEPROTECT, OEMCUIP_PRNPROP},
+ {"%PagePerSheet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP, OEMCUIP_DOCPROP},
+ {"%PageOrder", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PAGEORDER, OEMCUIP_DOCPROP},
+ {"%PagesPerSheetOrdering", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_DIRECTION, OEMCUIP_DOCPROP},
+ {"%PagesPerSheetBorder", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_BORDER, OEMCUIP_DOCPROP},
+ {"%TextAsGraphics", NULL, IDS_TEXT_ASGRX, OEMCUIP_DOCPROP},
+ {"%MetafileSpooling", NULL, IDS_METAFILE_SPOOLING, OEMCUIP_DOCPROP}
+};
+
+//
+// Number of elements in the feature map table.
+//
+static const NUM_FEATURE_MAP = (sizeof(gkmFeatureMap)/sizeof(gkmFeatureMap[0]));
+
+//
+// Mapping of option names to resources. A more complete driver would parse
+// this mapping from the GDL file, rather than use hard-coded mappings.
+//
+static CONST KEYWORDMAP gkmOptionMap[] =
+{
+ {"ON", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ON, 0},
+ {"OFF", TEXT("COMPSTUI.DLL"), IDS_CPSUI_OFF, 0},
+ {"NONE", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NONE, 0},
+ {"None", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NONE, 0},
+ {"True", TEXT("COMPSTUI.DLL"), IDS_CPSUI_TRUE, 0},
+ {"False", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FALSE, 0,},
+ {"PORTRAIT", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PORTRAIT, 0},
+ {"LANDSCAPE", TEXT("COMPSTUI.DLL"), IDS_CPSUI_LANDSCAPE, 0},
+ {"LANDSCAPE_CC90", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ROT_LAND, 0},
+ {"FORMSOURCE", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FORMSOURCE, 0},
+ {"UPPER", TEXT("COMPSTUI.DLL"), IDS_CPSUI_UPPER_TRAY, 0},
+ {"AUTO", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PRINTFLDSETTING, 0},
+ {"Auto", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PRINTFLDSETTING, 0},
+ {"PLAIN", TEXT("COMPSTUI.DLL"), IDS_CPSUI_STANDARD, 0},
+ {"TRANSPARENCY", TEXT("COMPSTUI.DLL"), IDS_CPSUI_TRANSPARENCY, 0},
+ {"HORIZONTAL", TEXT("COMPSTUI.DLL"), IDS_CPSUI_HORIZONTAL, 0},
+ {"VERTICAL", TEXT("COMPSTUI.DLL"), IDS_CPSUI_VERTICAL, 0},
+ {"FrontToBack", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FRONTTOBACK, 0},
+ {"BackToFront", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BACKTOFRONT, 0},
+ {"1", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NORMAL, 0},
+ {"2", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_TWOUP, 0},
+ {"4", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_FOURUP, 0},
+ {"6", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXUP, 0},
+ {"9", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NINEUP, 0},
+ {"16", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXTEENUP, 0},
+ {"Booklet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BOOKLET, 0},
+ {"RightThenDown", TEXT("COMPSTUI.DLL"), IDS_CPSUI_RIGHT_THEN_DOWN, 0},
+ {"DownThenRight", TEXT("COMPSTUI.DLL"), IDS_CPSUI_DOWN_THEN_RIGHT, 0},
+ {"LeftThenDown", TEXT("COMPSTUI.DLL"), IDS_CPSUI_LEFT_THEN_DOWN, 0},
+ {"DownThenLeft", TEXT("COMPSTUI.DLL"), IDS_CPSUI_DOWN_THEN_LEFT, 0},
+ {"UniresDLL", NULL, IDS_UNIRESDLL, 0},
+ {"600dpi", NULL, IDS_RESOLUTION_600_DPI, 0},
+ {"300dpi", NULL, IDS_RESOLUTION_300_DPI, 0},
+ {"150dpi", NULL, IDS_RESOLUTION_150_DPI, 0},
+ {"RASTERMODE", NULL, IDS_RASTERMODE, 0},
+ {"HPGL2MODE", NULL, IDS_HPGL2MODE, 0},
+ {"LETTER", NULL, IDS_PAPERSIZE_LETTER, 0},
+ {"LEGAL", NULL, IDS_PAPERSIZE_LEGAL, 0},
+ {"EXECUTIVE", NULL, IDS_PAPERSIZE_EXECUTIVE, 0},
+ {"A4", NULL, IDS_PAPERSIZE_A4, 0},
+ {"B5", NULL, IDS_PAPERSIZE_B5, 0},
+ {"Mono", NULL, IDS_COLORMODE_MONO, 0},
+ {"Color", TEXT("COMPSTUI.DLL"), IDS_CPSUI_COLOR_APPERANCE, 0},
+ {"24bpp", NULL, IDS_COLORMODE_24BPP, 0},
+ {"8bpp", NULL, IDS_COLORMODE_8BPP, 0},
+ {"HT_PATSIZE_AUTO", NULL, IDS_HALFTONE_AUTO, 0},
+ {"HT_PATSIZE_SUPERCELL_M", NULL, IDS_HALFTONE_SUPERCELL_M, 0},
+ {"HT_PATSIZE_6x6_M", NULL, IDS_HALFTONE_6x6_M, 0},
+ {"HT_PATSIZE_8x8_M", NULL, IDS_HALFTONE_8x8_M, 0},
+ {"Option1", NULL, IDS_OUTBIN_DEFAULT, 0},
+ {"Option14", NULL, IDS_OUTBIN_STACKER, 0},
+ {"EnvTray", NULL, IDS_UIREP_ENVTRAY, 0},
+ {"Automatic", NULL, IDS_TTDL_DEFAULT, 0},
+ {"Outline", NULL, IDS_TTDL_TYPE1, 0},
+ {"Bitmap", NULL, IDS_TTDL_TYPE3, 0},
+ {"NativeTrueType", NULL, IDS_TTDL_TYPE42, 0},
+ {"16384KB", NULL, IDS_MEMORY_STD, 0},
+ {"32768KB", NULL, IDS_MEMORY_UPGRADE, 0}
+};
+
+//
+// Number of elements in the option map table.
+//
+static const NUM_OPTION_MAP = (sizeof(gkmOptionMap)/sizeof(gkmOptionMap[0]));
+
+//
+// Fall-back mapping for any feature or option that doesn't
+// have a pre-defined display name.
+//
+KEYWORDMAP gDefaultMapping = {"", NULL, IDS_MISSINGNAME, OEMCUIP_DOCPROP};
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// COption::Acquire
+//
+// Synopsis:
+// Load the option information as described in the mapping.
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+COption::Acquire(
+ HANDLE hHeap,
+ PCKEYWORDMAP pMapping
+ )
+{
+ m_pMapping = pMapping;
+ m_hHeap = hHeap;
+
+ return GetDisplayNameFromMapping(hHeap, m_pMapping, &m_pszDisplayName);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeaturePairs::ClearPair(
+//
+// Synopsis:
+// Remove a feature-option pair entry from the set of feature / option
+// pairs.
+//
+//
+//----------------------------------------------------------------------------
+VOID
+CFeaturePairs::ClearPair(
+ size_t iIndex
+ // Index of the feature-option pair to be removed.
+ )
+{
+ if (m_pData[iIndex].pszFeature)
+ {
+ free((VOID*)m_pData[iIndex].pszFeature);
+ m_pData[iIndex].pszFeature = NULL;
+ }
+
+ if (m_pData[iIndex].pszOption)
+ {
+ free((VOID*)m_pData[iIndex].pszOption);
+ m_pData[iIndex].pszOption = NULL;
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeaturePairs Constructor
+//
+// Synopsis:
+// Create a feature-pairs object containing cElements entries, and
+// initialize them all to NULL.
+//
+//
+//----------------------------------------------------------------------------
+CFeaturePairs::CFeaturePairs(
+ size_t cElements
+ // number of elements to remove.
+ )
+{
+ m_pData = NULL;
+ size_t cbFeatureOptions = 0;
+ m_cElements = 0;
+
+ if (SUCCEEDED(SizeTMult(cElements, sizeof(PRINT_FEATURE_OPTION), &cbFeatureOptions)))
+ {
+ m_pData = new PRINT_FEATURE_OPTION[cElements];
+
+ if (m_pData)
+ {
+ m_cElements = cElements;
+ memset(m_pData, 0, cbFeatureOptions);
+ }
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeaturePairs destructor
+//
+// Synopsis:
+// Release any memory used by this object
+//
+//
+//----------------------------------------------------------------------------
+CFeaturePairs::~CFeaturePairs()
+{
+ if (m_pData)
+ {
+ for (size_t iPair = 0; iPair < m_cElements; iPair++)
+ {
+ ClearPair(iPair);
+ }
+
+ delete m_pData;
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeaturePairs::SetPair
+//
+// Synopsis:
+// Set the pair at the specified index to the specified value. Each
+// pair represents a feature and a currently selected option for that
+// feature.
+//
+// Returns:
+// S_OK
+// E_OUTOFMEMORY
+// E_INVALIDARG if the index is out of of bounds.
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+CFeaturePairs::SetPair(
+ size_t iIndex,
+ // Index of the entry to set.
+ PCSTR pcszFeature,
+ // The name of the feature. This doesn't
+ // hold a pointer to the string passed in.
+ PCSTR pcszOption
+ // The name of the option. This doesn't
+ // hold a pointer to the string passed in.
+ )
+{
+
+ if (iIndex > m_cElements || !pcszFeature || !pcszOption)
+ {
+ return E_INVALIDARG;
+ }
+
+ //
+ // Deferred error result from failed constructor...
+ //
+ if (!m_pData)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ //
+ // Configure the data elements
+ //
+ m_pData[iIndex].pszFeature = new CHAR[strlen(pcszFeature)+1];
+ m_pData[iIndex].pszOption = new CHAR[strlen(pcszOption)+1];
+
+ if (m_pData[iIndex].pszFeature && m_pData[iIndex].pszOption)
+ {
+ memcpy((PSTR)m_pData[iIndex].pszFeature, pcszFeature, (strlen(pcszFeature)+1));
+ memcpy((PSTR)m_pData[iIndex].pszOption, pcszOption, (strlen(pcszOption)+1));
+ return S_OK;
+ }
+ else
+ {
+ return E_OUTOFMEMORY;
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::Clear
+//
+// Synopsis:
+// Reset the option collection information to it's state before otions
+// were acquired.
+//
+//
+//----------------------------------------------------------------------------
+
+VOID
+CFeature::Clear()
+{
+ if (m_pOptions != NULL)
+ {
+ delete [] m_pOptions;
+ m_pOptions = NULL;
+ }
+
+ if (m_pszDisplayName != NULL && !IS_INTRESOURCE(m_pszDisplayName))
+ {
+ HeapFree(m_hHeap, 0, m_pszDisplayName);
+ }
+
+ m_dwOptions = 0;
+ m_Sel = 0;
+ m_pszFeature = NULL;
+ m_hHeap = NULL;
+ m_pOptions = NULL;
+ m_pMapping = &gDefaultMapping;
+ m_pszDisplayName = NULL;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature (constructor)
+//
+// Synopsis:
+// Initialize the option collection to a default state. Does
+// not acquire the options from the GPD / helper.
+//
+//
+//----------------------------------------------------------------------------
+CFeature::CFeature() :
+ m_dwOptions(0),
+ m_Sel(0),
+ m_pszFeature(NULL),
+ m_hHeap(NULL),
+ m_pOptions(NULL),
+ m_pMapping(&gDefaultMapping),
+ m_pszDisplayName(NULL)
+{
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature (destructor)
+//
+// Synopsis:
+// Clean up any memory we're holding.
+//
+//
+//----------------------------------------------------------------------------
+CFeature::~CFeature()
+{
+ Clear();
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::Acquire
+//
+// Synopsis:
+// Populate the options in the collection using the
+// supplied helper to acquire options for the specified
+// feature.
+//
+// Returns:
+// S_OK on success, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+CFeature::Acquire(
+ _In_ HANDLE hHeap,
+ // The heap to make allocations from
+ _In_ IPrintCoreHelper* pHelper,
+ // Pointer to the Unidrv supplied helper object
+ _In_ PCSTR pszFeature
+ // The name of the feature to read settings for.
+ )
+{
+ VERBOSE(DLLTEXT("CFeature::Acquire entry."));
+
+ HRESULT hrResult = S_OK;
+ PCSTR *ppszOptions = NULL;
+
+ //
+ // Don't retreive the Options again if we already got them.
+ //
+ if ((m_dwOptions > 0) &&
+ (m_pszFeature != NULL) &&
+ !lstrcmpA(m_pszFeature, pszFeature))
+ {
+ WARNING(DLLTEXT("CFeature::Acquire: Already have options for feature %hs. Returning S_OK.\r\n"), m_pszFeature);
+ return S_OK;
+ }
+
+ //
+ // Save the heap handle for use later, such as freeing memory at destruction.
+ //
+ m_hHeap = hHeap;
+
+ //
+ // Store Keyword string.
+ //
+ m_pszFeature = pszFeature;
+
+ //
+ // Get or build a keyword mapping entry that
+ // maps from keyword to info such as display name &
+ // whether the feature is a device setting or document
+ // setting.
+ //
+ m_pMapping = GetKeywordMapping(gkmFeatureMap, NUM_FEATURE_MAP, pszFeature);
+
+ //
+ // Get the display name for this feature
+ //
+ hrResult = GetDisplayNameFromMapping(hHeap, m_pMapping, &m_pszDisplayName);
+
+ if (!SUCCEEDED(hrResult))
+ {
+ ERR(ERRORTEXT("CFeature::Acquire: Failed to get display name for feature %hs with error code 0x%x!\r\n"),
+ pszFeature,
+ hrResult);
+ goto Exit;
+ }
+
+ //
+ // Enumerate Options.
+ //
+ hrResult = pHelper->EnumOptions(m_pszFeature,
+ &ppszOptions,
+ &m_dwOptions
+ );
+
+ //
+ // Make sure we got the option list.
+ // Can't do anything more with out it.
+ //
+ if (!SUCCEEDED(hrResult))
+ {
+ ERR(ERRORTEXT("CFeature::Acquire: Failed to enumerate options for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
+ goto Exit;
+ }
+
+ //
+ // Build COption
+ //
+ m_pOptions = new COption[m_dwOptions];
+
+ if (m_pOptions == NULL)
+ {
+ ERR(ERRORTEXT("COption::Acquire: Failed to allocate memory for option info array!\r\n"));
+ hrResult = E_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ //
+ // For each option, build and/or get useful info like display name etc.
+ //
+ for (DWORD dwIndex = 0; dwIndex < m_dwOptions; dwIndex++)
+ {
+ PCKEYWORDMAP pMapping =
+ GetKeywordMapping(gkmOptionMap, NUM_OPTION_MAP, ppszOptions[dwIndex]);
+
+ //
+ // Get or build a keyword mapping entry that
+ // maps from keyword to info such as display name,
+ // icon, option type etc. which we can't get from
+ // the helper interface
+ //
+ hrResult = m_pOptions[dwIndex].Acquire(m_hHeap,
+ pMapping);
+
+ if (!SUCCEEDED(hrResult))
+ {
+ ERR(ERRORTEXT("CFeature::Acquire: Failed to load information for option %hs of feature %hs with error code 0x%x!\r\n"),
+ ppszOptions[dwIndex],
+ m_pszFeature,
+ hrResult);
+ goto Exit;
+ }
+ }
+
+ //
+ // Get current option selection.
+ //
+ if(SUCCEEDED(hrResult) && m_dwOptions > 0)
+ {
+ hrResult = RefreshSelection(pHelper);
+ }
+
+Exit:
+
+ //
+ // Cleanup if weren't successful
+ //
+ if (!SUCCEEDED(hrResult))
+ {
+ Clear();
+ }
+
+ return hrResult;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::GetOption
+//
+// Synopsis:
+// Get a reference to the description of the option at the specified index.
+//
+// Returns:
+// A pointer to the requested option if available, otherwise NULL.
+//
+//
+//----------------------------------------------------------------------------
+CONST COption *
+CFeature::GetOption(
+ DWORD dwIndex
+ // Index of the option for which the display name is requested.
+ ) const
+{
+ VERBOSE(DLLTEXT("CFeature::GetOption entry."));
+
+ if ((dwIndex >= m_dwOptions) || (m_pOptions == NULL))
+ {
+ ERR(ERRORTEXT("CFeature::GetOption: Invalid parameters!\r\n"));
+ return NULL;
+ }
+
+ return &(m_pOptions[dwIndex]);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::FindOption
+//
+// Synopsis:
+// Find the index of the option with the specified keyword. If no such
+// option exists, this routine returns the specified result instead.
+//
+//
+//----------------------------------------------------------------------------
+_Success_(return != FALSE) BOOL
+CFeature::FindOption(
+ _In_ PCSTR pszOption,
+ // The name of the option to look for
+ _Out_ DWORD *pdwOption
+ // The index of the default option to use if the name isn't found
+ ) const
+{
+ VERBOSE(DLLTEXT("CFeature::FindOption entry."));
+
+ BOOL bFound = FALSE;
+
+ //
+ // Validate parameters
+ //
+ if (pszOption == NULL ||
+ pdwOption == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // Walk the option keyword looking for a match.
+ //
+ for(DWORD dwIndex = 0; !bFound && (dwIndex < m_dwOptions); dwIndex++)
+ {
+ bFound = !lstrcmpA(pszOption, m_pOptions[dwIndex].GetKeyword());
+
+ if(bFound)
+ {
+ *pdwOption = dwIndex;
+ }
+ }
+
+ return bFound;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::InitOptItem
+//
+// Synopsis:
+// Configure the provided OPTITEM with the options in this collection.
+//
+// Returns:
+//
+// Notes:
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+CFeature::InitOptItem(
+ _In_ HANDLE hHeap,
+ // The heap to allocate memory from.
+ _Inout_ POPTITEM pOptItem
+ // The optitem struct being initialized.
+ )
+{
+ VERBOSE(DLLTEXT("CFeature::InitOptItem entry."));
+
+ HRESULT hrResult = S_OK;
+
+ //
+ // Add feature OPTITEM data to OPTITEM to facilitate saving
+ // selection changes
+ //
+ PFEATUREOPTITEMDATA pData =
+ (PFEATUREOPTITEMDATA)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(FEATUREOPTITEMDATA));
+
+ if (pData == NULL)
+ {
+ ERR(ERRORTEXT("CFeatureCollection::InitOptItem: Failed to allocated memory for feature OPTITEM data."));
+ hrResult = E_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ //
+ // Configure the callback data structure
+ //
+ pData->dwSize = sizeof(FEATUREOPTITEMDATA);
+ pData->dwTag = FEATURE_OPTITEM_TAG;
+ pData->pszFeatureKeyword = this->GetKeyword();
+ pData->pFeature = this;
+
+ //
+ // Configure the optitem
+ //
+ pOptItem->UserData = (ULONG_PTR)pData;
+ pOptItem->pName = const_cast<PWSTR>(this->GetDisplayName());
+ pOptItem->Sel = m_Sel;
+
+ //
+ // If there's only 1 option, mark the feature as disabled.
+ //
+ if (GetCount() > 1)
+ {
+ pOptItem->Flags = 0;
+ }
+ else
+ {
+ pOptItem->Flags |= OPTIF_DISABLED;
+ }
+
+ //
+ // Only create options if there are options defined
+ // for this feature.
+ //
+ if (GetCount() > 0)
+ {
+ //
+ // Allocate memory for feature options.
+ //
+ pOptItem->pOptType = CreateOptType(hHeap, (WORD)GetCount());
+
+ if (pOptItem->pOptType == NULL)
+ {
+ ERR(ERRORTEXT("CFeature::InitOptItem: Failed to allocate OPTTYPEs for OPTITEM %hs!\r\n"),
+ this->GetKeyword());
+ hrResult = E_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ //
+ // Set OPTTYPE type & display string for each OPTPARAM in the ot
+ //
+ pOptItem->pOptType->Type = TVOT_COMBOBOX;
+
+ for (DWORD dwIndex = 0; dwIndex < GetCount(); dwIndex++)
+ {
+ pOptItem->pOptType->pOptParam[dwIndex].pData = const_cast<PWSTR>(this->GetOption(dwIndex)->GetDisplayName());
+ }
+ }
+
+Exit:
+
+ return hrResult;
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeature::RefreshSelection
+//
+// Synopsis:
+// Synchronize the currently selected option with the option
+// that Unidrvui recognizes as being selected.
+//
+// Returns:
+// S_OK on success, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+CFeature::RefreshSelection(
+ _In_ IPrintCoreHelper *pHelper
+ // Pointer to the Unidrv supplied helper object
+ )
+{
+ VERBOSE(DLLTEXT("CFeature::RefreshSelection entry."));
+
+ PCSTR pszSel = NULL;
+ HRESULT hrResult = S_OK;
+
+ //
+ // Get current option selection.
+ //
+ hrResult = pHelper->GetOption(NULL, 0, m_pszFeature, &pszSel);
+
+ if(SUCCEEDED(hrResult))
+ {
+ if (!FindOption(pszSel, &m_Sel))
+ {
+ //
+ // The option name should always match something in the option
+ // array. If for some reason that's not the case, default
+ // back to option 0.
+ //
+ WARNING(ERRORTEXT("CFeature::RefreshSelection: Failed to find selected option!\r\n"));
+ m_Sel = 0;
+ }
+ }
+ else if(hrResult == E_FAIL)
+ {
+ //
+ // GetOption fails with E_FAIL when trying to read document-
+ // sticky options if the printer preferences is being shown.
+ // Hide the error & default the selection. The feature won't
+ // be shown in the UI.
+ //
+ m_Sel = 0;
+ hrResult = S_OK;
+ }
+
+ return hrResult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection::Clear
+//
+// Synopsis:
+// Release any memory associated with this feature collection and reset
+// values to defaults.
+//
+//
+//----------------------------------------------------------------------------
+VOID
+CFeatureCollection::Clear()
+{
+ //
+ // feature info array allocated with new so
+ // that each of the constructors for CFeature
+ // will be called.
+ //
+ if (m_pFeatures)
+ {
+ delete [] m_pFeatures;
+ }
+
+ //
+ // Re-initialize
+ //
+ m_dwFeatures = 0;
+ m_dwDocFeatures = 0;
+ m_dwPrintFeatures = 0;
+ m_hHeap = NULL;
+ m_pFeatures = NULL;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection::GetModelessIndex
+//
+// Synopsis:
+// Get the absolute index of the feature, assuming the index provided is
+// for the specified mode. This if there are three features,
+//
+// DocFeature1
+// DocFeature2
+// PrinterFeature1
+//
+// If this routine is called with index 0, and mode OEMCUIP_PRNPROP,
+// it will return the absolute index of the first printer-sticky feature,
+// which in this case would be 2 (remember, the first index is 0).
+//
+//
+//----------------------------------------------------------------------------
+DWORD
+CFeatureCollection::GetModelessIndex(
+ DWORD dwIndex,
+ // The index relative to the specified mode.
+ DWORD dwMode
+ // The mode for which the index applies. See synopsis above for
+ // a more detailed explanation of mode.
+ ) const
+{
+ DWORD dwCount = 0;
+
+ switch(dwMode)
+ {
+ //
+ // Number of features, all modes
+ //
+ case 0:
+ dwCount = dwIndex;
+ break;
+
+ case OEMCUIP_DOCPROP:
+ case OEMCUIP_PRNPROP:
+ //
+ // Walk the feature list looking for the nth feature
+ // with matching mode
+ //
+ for (dwCount = 0; dwCount < m_dwFeatures; dwCount++)
+ {
+ //
+ // Count down to the feature we want
+ // Only countdown for matching modes
+ //
+ if (dwMode == m_pFeatures[dwCount].GetMode())
+ {
+ if (dwIndex == 0)
+ {
+ break;
+ }
+ else
+ {
+ --dwIndex;
+ }
+ }
+ }
+ break;
+ }
+
+ return dwCount;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection (constructor)
+//
+// Synopsis:
+//
+//
+//----------------------------------------------------------------------------
+CFeatureCollection::CFeatureCollection() :
+ m_dwFeatures(0),
+ m_dwDocFeatures(0),
+ m_dwPrintFeatures(0),
+ m_hHeap(NULL),
+ m_pFeatures(NULL)
+{
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection (destructor)
+//
+// Synopsis:
+// Release all resources held by this object
+//
+//
+//----------------------------------------------------------------------------
+CFeatureCollection::~CFeatureCollection()
+{
+ //
+ // Clean up class.
+ //
+ Clear();
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection::Acquire
+//
+// Synopsis:
+// Load all of the features supported by unidrv as well as those specified
+// in the GPD using the provided helper object
+//
+// Returns:
+// S_OK on success else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+CFeatureCollection::Acquire(
+ HANDLE hHeap,
+ // The heap from which any allocations should be made
+ IPrintCoreHelper *pHelper
+ // The helper object that provides access to the core driver features.
+ )
+{
+ VERBOSE(DLLTEXT("CFeatureCollection::Acquire entry."));
+
+ HRESULT hrResult = S_OK;
+
+ PCSTR *ppszKeywords = NULL;
+ // String list that points to each feature keyword
+
+ //
+ // Don't retreive the Features again if we already got them.
+ //
+ if (m_dwFeatures > 0)
+ {
+ WARNING(DLLTEXT("CFeatureCollection::Acquire: Features have already been enumerated. Returning S_OK.\r\n"));
+ return S_OK;
+ }
+
+ // Save the heap handle for use later, such as freeing memory at destruction.
+ m_hHeap = hHeap;
+
+ // Enumerate features.
+ hrResult = pHelper->EnumFeatures(&ppszKeywords, &m_dwFeatures);
+
+ if (FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("CFeatureCollection::Acquire() failed to enumerate features. (hrResult = 0x%x)\r\n"), hrResult);
+ }
+ else
+ {
+ //
+ // Build Feature information
+ //
+ m_pFeatures = new CFeature[m_dwFeatures];
+
+ if (m_pFeatures == NULL)
+ {
+ ERR(ERRORTEXT("CFeatureCollection::Acquire: Failed to allocate feature info array!\r\n"));
+ hrResult = E_OUTOFMEMORY;
+ }
+
+ //
+ // For each feature, build/get feature info
+ //
+ for (DWORD dwIndex = 0; SUCCEEDED(hrResult) && dwIndex < m_dwFeatures ; dwIndex++)
+ {
+ //
+ // Get options for each feature
+ // Note: Some features don't have options, the HRESULT will be E_NOTIMPL for these
+ //
+ hrResult = m_pFeatures[dwIndex].Acquire(hHeap,
+ pHelper,
+ ppszKeywords[dwIndex]);
+
+ if (!SUCCEEDED(hrResult) && (hrResult != E_NOTIMPL))
+ {
+ ERR(ERRORTEXT("CFeatureCollection::Acquire: Failed to get options for feature %hs with error code 0x%x!\r\n"),
+ ppszKeywords[dwIndex],
+ hrResult);
+ }
+
+ //
+ // Keep track of mode counts
+ //
+ if (SUCCEEDED(hrResult))
+ {
+ switch(m_pFeatures[dwIndex].GetMode())
+ {
+ case OEMCUIP_DOCPROP:
+ ++m_dwDocFeatures;
+ break;
+
+ case OEMCUIP_PRNPROP:
+ ++m_dwPrintFeatures;
+ break;
+
+ default:
+ ERR(ERRORTEXT("CFeatureCollection::Acquire: Unknown stickiness for feature %hs!\r\n"),
+ ppszKeywords[dwIndex]);
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Clean up if we weren't successful
+ //
+ if (FAILED(hrResult))
+ {
+ Clear();
+ }
+
+ return hrResult;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection::GetCount
+//
+// Synopsis:
+// Get the number of features in the collection.
+//
+//
+//----------------------------------------------------------------------------
+DWORD
+CFeatureCollection::GetCount(
+ DWORD dwMode
+ // Should this routine count the doc-sticky features, printer sticky
+ // features, or both?
+ ) CONST
+{
+ DWORD dwCount = 0;
+
+ switch(dwMode)
+ {
+ case 0:
+ dwCount = m_dwFeatures;
+ break;
+
+ case OEMCUIP_DOCPROP:
+ dwCount = m_dwDocFeatures;
+ break;
+
+ case OEMCUIP_PRNPROP:
+ dwCount = m_dwPrintFeatures;
+ break;
+ }
+
+ return dwCount;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CFeatureCollection::GetFeature
+//
+// Synopsis:
+// Get the options for the feature at the specified index.
+//
+//
+//----------------------------------------------------------------------------
+CFeature*
+CFeatureCollection::GetFeature(
+ DWORD dwIndex,
+ // The index of the feature to look up.
+ DWORD dwMode
+ // The mode associated with the feature index.
+ ) const
+{
+ //
+ // Validate parameters
+ //
+ if ((dwIndex >= GetCount(dwMode)) || (m_pFeatures == NULL))
+ {
+ return NULL;
+ }
+
+ //
+ // Get internal index
+ //
+ dwIndex = GetModelessIndex(dwIndex, dwMode);
+
+ //
+ // Return options pointer
+ //
+ return &(m_pFeatures[dwIndex]);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::GetDisplayNameFromMapping
+//
+// Synopsis:
+// Load the string resource associated with the specified mapping entry.
+//
+// Returns:
+// S_OK on success, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+GetDisplayNameFromMapping(
+ _In_ HANDLE hHeap,
+ // The heap to perform allocations from
+ _In_ PCKEYWORDMAP pMapping,
+ // The mapping element for the element. Could be a feature or option.
+ _Out_ PWSTR *ppszDisplayName
+ // The location where this routine supplies the display name to the
+ // caller.
+ )
+{
+ HMODULE hModule = NULL;
+ HRESULT hrResult = S_OK;
+
+ VERBOSE(DLLTEXT("GetDisplayNameFromMapping entry."));
+
+ if ((hHeap == NULL) || (pMapping == NULL) || (ppszDisplayName == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ //
+ // Check for simple case of returning INT resource
+ //
+ if (pMapping->pwszModule == NULL)
+ {
+ //
+ // Just need to do MAKEINTRESOURCE on the resource ID and return
+ //
+ *ppszDisplayName = MAKEINTRESOURCE(pMapping->uDisplayNameID);
+ }
+ else
+ {
+ //
+ // We need to get the module name if we aren't loading the
+ // resource from this module (pwszModule != NULL). As an
+ // optimization, we assume that the module has already been loaded,
+ // since the only cases currently are this module, driver ui and compstui.dll.
+ //
+ hModule = GetModuleHandle(pMapping->pwszModule);
+
+ if (hModule == NULL)
+ {
+ DWORD dwError = GetLastError();
+
+ ERR(ERRORTEXT("GetDisplayNameFromMapping: Failed to load module %s with error code %d!\r\n"),
+ pMapping->pwszModule,
+ dwError);
+
+ hrResult = HRESULT_FROM_WIN32(dwError);
+
+ //
+ // In case last error wasn't set correctly, force it to an error value.
+ //
+ if (SUCCEEDED(hrResult))
+ {
+ hrResult = E_FAIL;
+ }
+ }
+
+ //
+ // Get the string resource
+ //
+ if (SUCCEEDED(hrResult))
+ {
+ hrResult = GetStringResource(hHeap, hModule, pMapping->uDisplayNameID, ppszDisplayName);
+ if (FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("GetDisplayNameFromMapping: Failed to load string with error code 0x%x!\r\n"), hrResult);
+ }
+ }
+ }
+
+ return hrResult;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::GetKeywordMapping
+//
+// Synopsis:
+// Find the mapping in the provided table associated with the specified
+// keyword. This routine can be used to look up both feature & option
+// mappings.
+//
+// Returns:
+// The requested mapping on success, otherwise NULL.
+//
+//
+//----------------------------------------------------------------------------
+PCKEYWORDMAP
+GetKeywordMapping(
+ _In_reads_(dwMapSize) PCKEYWORDMAP pKeywordMap,
+ // The mapping table to search in
+ DWORD dwMapSize,
+ // Number of elements in the mapping table.
+ PCSTR pszKeyword
+ // Keyword to look for in the table.
+ )
+{
+ BOOL bFound = FALSE;
+ PCKEYWORDMAP pMapping = &gDefaultMapping;
+
+ if ((pKeywordMap != NULL) && (pszKeyword != NULL))
+ {
+ //
+ // Walk mapping array for matching keyword
+ //
+ for (DWORD dwIndex = 0; !bFound && (dwIndex < dwMapSize); dwIndex++)
+ {
+ bFound = !lstrcmpA(pszKeyword, pKeywordMap[dwIndex].pszKeyword);
+
+ if (bFound)
+ {
+ pMapping = pKeywordMap + dwIndex;
+ }
+ }
+ }
+
+ return pMapping;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::IsFeatureOptItem
+//
+// Synopsis:
+// Test if an OPTITEM is an OPTITEM for a feature.
+//
+// Returns:
+// TRUE if the OPTITEM represents a feature, else FALSE.
+//
+//
+//----------------------------------------------------------------------------
+BOOL
+IsFeatureOptItem(
+ POPTITEM pOptItem
+ // The otitem to check
+ )
+{
+ BOOL bRet = FALSE;
+ PFEATUREOPTITEMDATA pData = NULL;
+
+
+ // Make sure pointers are NULL.
+ if( (NULL == pOptItem)
+ ||
+ (NULL == pOptItem->UserData)
+ )
+ {
+ //
+ // INVARIANT: can't be feature OPTITEM, since one of
+ // the necessary pointer are NULL.
+ //
+
+ return FALSE;
+ }
+
+ // For convienience, assign to pointer to feature OPTITEM data.
+ pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
+
+ // Check size and tag.
+ bRet = (sizeof(FEATUREOPTITEMDATA) == pData->dwSize)
+ &&
+ (FEATURE_OPTITEM_TAG == pData->dwTag);
+
+ return bRet;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::SaveFeatureOptItems
+//
+// Synopsis:
+// Walks array of OPTITEMs saving each feature OPTITEM
+// that has changed.
+//
+// Returns:
+// S_OK on success, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+SaveFeatureOptItems(
+ HANDLE hHeap,
+ // The heap to perform allocations from
+ IPrintCoreHelper* pHelper,
+ // Pointer to the Unidrv supplied helper object
+ HWND hWnd,
+ // The current window object. Used as the parent of any model dialogs /
+ // message boxes displayed from this routine.
+ _In_reads_(dwItems) POPTITEM pOptItem,
+ // The option items to save
+ DWORD dwItems
+ // The number of optitems in the array
+ )
+{
+ VERBOSE(DLLTEXT("SaveFeatureOptItems entry."));
+
+ DWORD dwPairsWritten = 0;
+ DWORD dwResult = 0;
+ HRESULT hrResult = S_OK;
+ CFeaturePairs *pPairs = NULL;
+
+ //
+ // Validate parameters
+ //
+ if (!(hHeap && pHelper && pOptItem))
+ {
+ ERR(ERRORTEXT("SaveFeatureOptItems: Invalid arguments!\r\n"));
+ return E_INVALIDARG;
+ }
+
+ //
+ // Get feature option pairs to save
+ //
+ hrResult = GetChangedFeatureOptions(pOptItem, dwItems, &pPairs);
+
+ if(FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("SaveFeatureOptItems: Failed to get changed feature option pairs! (error code 0x%x)\r\n"),
+ hrResult);
+ }
+
+ //
+ // Only update options if something changed.
+ //
+ if (SUCCEEDED(hrResult) &&
+ pPairs &&
+ pPairs->GetElementCount() > 0)
+ {
+
+ //
+ // Set the change feature options.
+ // For the first SetOptions() call, don't have the
+ // core driver UI resolve conflicts, so we can
+ // prompt user for automatic resolution or let
+ // them do the conflict resolving.
+ //
+ hrResult = pHelper->SetOptions(NULL,
+ 0,
+ FALSE,
+ pPairs->GetData(),
+ (DWORD)pPairs->GetElementCount(),
+ &dwPairsWritten,
+ &dwResult);
+
+ if(FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("SaveFeatureOptItems: SetOptions failed with dwResult = %d! (hrResult = 0x%x)\r\n"),
+ dwResult,
+ hrResult);
+ }
+ else if(SETOPTIONS_RESULT_CONFLICT_REMAINED == dwResult)
+ {
+ //
+ // SetOptions succeeded, but there was a conflict in the selected
+ // options that was not resolved. Ask the user if they'd like the
+ // plug-in to resolve the conflict for them.
+ //
+ int nRet;
+ CONST PRINT_FEATURE_OPTION *pConflicts;
+ DWORD dwConflicts;
+ PWSTR pszMessage = NULL;
+
+ hrResult = GetStringResource(hHeap, ghInstance, IDS_CONSTRAINT_CONFLICT, &pszMessage);
+ if(FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("SaveFeatureOptItems: Failed to load conflict resource string (error code 0x%x)\r\n"),
+ hrResult);
+ }
+
+ //
+ // INVARIANT: constraint conflict, options weren't saved.
+ //
+ // Get list of all features that have conflict.
+ //
+ if (SUCCEEDED(hrResult))
+ {
+ hrResult = GetFirstConflictingFeature(pHelper,
+ pOptItem,
+ dwItems,
+ &pConflicts,
+ &dwConflicts);
+
+ if (SUCCEEDED(hrResult) && dwConflicts == 0)
+ {
+ hrResult = E_FAIL;
+ ERR(ERRORTEXT("SaveFeatureOptItems: Driver indicated conflict, but didn't provide conflicting options!\r\n"));
+ }
+
+ if(FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("GetFirstConflictingFeature failed!"));
+ }
+ }
+
+ if (SUCCEEDED(hrResult))
+ {
+ //
+ // Display simple message box with prompt
+ //
+ nRet = MessageBox(hWnd,
+ pszMessage,
+ L"UI Replacement Test",
+ MB_YESNO | MB_ICONWARNING);
+
+ //
+ // Check to see how user wants to resolve conflict
+ //
+ if(nRet == IDYES)
+ {
+ //
+ // Let core driver resolve conflict resolution
+ //
+ hrResult = pHelper->SetOptions(NULL,
+ 0,
+ TRUE,
+ pPairs->GetData(),
+ (DWORD)pPairs->GetElementCount(),
+ &dwPairsWritten,
+ &dwResult);
+
+ //
+ // Conflict resolution requires refreshing current option
+ // selection for each feature, since selection may have
+ // changed because of conflict resolution.
+ //
+ if (SUCCEEDED(hrResult))
+ {
+ RefreshOptItemSelection(pHelper, pOptItem, dwItems);
+ }
+ }
+
+ //
+ // Return failure if there are still conflicts
+ //
+ if(dwResult == SETOPTIONS_RESULT_CONFLICT_REMAINED)
+ {
+ ERR(ERRORTEXT("SaveFeatureOptItems: Conflicts still exist even after calling core driver to resolve them!"));
+ hrResult = E_FAIL;
+ }
+ }
+
+ if(pszMessage != NULL)
+ {
+ HeapFree(hHeap, 0, pszMessage);
+ }
+ }
+ }
+
+ //
+ // Clean up
+ //
+
+ if (pPairs)
+ {
+ delete pPairs;
+ }
+
+ return hrResult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// GetChangedFeatureOptions
+//
+// Synopsis:
+// Creates a collection of all of the features that have changed in the
+// provided collection of OPTITEMs
+//
+// Returns:
+// S_OK on success, else E_*.
+//
+// Notes:
+// if no settings have been changed, the routine may return S_OK
+// and *ppPairs == NULL.
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+GetChangedFeatureOptions(
+ _In_reads_(dwItems) POPTITEM pOptItem,
+ // The array of optitems to search through
+ DWORD dwItems,
+ // The number of optitems in the provided array
+ _Outptr_result_maybenull_ CFeaturePairs **ppPairs
+ // feature / option keyword pairs describing the options that
+ // have changed.
+ )
+{
+ VERBOSE(DLLTEXT("GetChangedFeatureOptions entry."));
+
+ DWORD dwCount = 0;
+ DWORD dwChanged = 0;
+ HRESULT hrResult = S_OK;
+ CFeaturePairs *pPairs;
+
+ *ppPairs = NULL;
+
+ //
+ // Walk OPTITEM array looking or changed options,
+ // and calculating size needed for multi-sz buffer.
+ //
+ for (dwCount = 0; dwCount < dwItems; dwCount++)
+ {
+ //
+ // Just go to next item if this OPTITEM hasn't
+ // changed or isn't a feature OPTITEM
+ //
+ if ((OPTIF_CHANGEONCE & pOptItem[dwCount].Flags) &&
+ IsFeatureOptItem(&(pOptItem[dwCount]))
+ )
+ {
+ ++dwChanged;
+ }
+ }
+
+ //
+ // Don't need to do anything more if no feature options changed.
+ //
+ if(dwChanged != 0)
+ {
+ pPairs = new CFeaturePairs(dwChanged);
+
+ if (pPairs == NULL ||
+ pPairs->GetElementCount() == 0
+ )
+ {
+ ERR(ERRORTEXT("GetChangedFeatureOptions: Failed to allocate feature-option array!\r\n"));
+ hrResult = E_OUTOFMEMORY;
+
+ if ( pPairs )
+ {
+ delete pPairs;
+ pPairs = NULL;
+ }
+
+ }
+
+ //
+ // Build array of feature option pairs that changed
+ //
+ for (dwCount = 0;
+ SUCCEEDED(hrResult) && (dwCount < dwItems) && dwChanged;
+ dwCount++)
+ {
+ //
+ // Just go to next item if this OPTITEM hasn't
+ // changed or isn't a feature OPTITEM
+ //
+ if((OPTIF_CHANGEONCE & pOptItem[dwCount].Flags) &&
+ IsFeatureOptItem(&(pOptItem[dwCount]))
+ )
+ {
+ //
+ // For convienience, assign to pointer to feature OPTITEM data
+ //
+ PFEATUREOPTITEMDATA pData = (PFEATUREOPTITEMDATA)(pOptItem[dwCount].UserData);
+
+ //
+ // Add feature option pair
+ //
+ PCSTR pszOption = GetOptionKeywordFromOptItem(&pOptItem[dwCount]);
+
+ if (pszOption != NULL)
+ {
+ --dwChanged;
+ hrResult = pPairs->SetPair(dwChanged, pData->pszFeatureKeyword, pszOption);
+ }
+ }
+ }
+
+ if(SUCCEEDED(hrResult))
+ {
+ *ppPairs = pPairs;
+ }
+ else if (pPairs)
+ {
+ delete pPairs;
+ }
+ }
+
+ return hrResult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::GetOptionKeywordFromOptItem
+//
+// Synopsis:
+// Returns pointer to option keyword for a feature OPTITEM
+//
+// Returns:
+// The requested string on success, otherwise NULL
+//
+//
+//----------------------------------------------------------------------------
+PCSTR
+GetOptionKeywordFromOptItem(
+ POPTITEM pOptItem
+ // The opt item from which the keyword shoudl be read
+ )
+{
+ VERBOSE(DLLTEXT("GetOptionKeywordFromOptItem entry."));
+
+ PCSTR pszOption = NULL;
+
+ //
+ // Validate parameters
+ //
+ if(!IsFeatureOptItem(pOptItem))
+ {
+ ERR(ERRORTEXT("GetOptionKeywordFromOptItem: Invalid parameter!\r\n"));
+ }
+ else if(pOptItem->pOptType->Type != TVOT_COMBOBOX)
+ {
+ ERR(ERRORTEXT("GetOptionKeywordFromOptItem: OPTTYPE type %d number of OPTPARAMS not handled!\r\n"),
+ pOptItem->pOptType->Type);
+ }
+ else
+ {
+ //
+ // Option selection is based on type of OPTTYPE
+ //
+ PFEATUREOPTITEMDATA pData = ((PFEATUREOPTITEMDATA)(pOptItem->UserData));
+ CONST COption *pOption = pData->pFeature->GetOption((DWORD)pOptItem->Sel);
+
+ if (pOption)
+ {
+ pszOption = pOption->GetKeyword();
+ }
+ else
+ {
+ ERR(ERRORTEXT("GetOptionKeywordFromOptItem: Invalid option index %d!\r\n"), (DWORD)pOptItem->Sel);
+ }
+ }
+
+ return pszOption;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::RefreshOptItemSelection
+//
+// Synopsis:
+// For each feature update the currently selected option with the value
+// that the core driver has selected. This is useful for updating the
+// UI after resolving constraints.
+//
+// Returns:
+// S_OK on success, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+RefreshOptItemSelection(
+ IPrintCoreHelper *pHelper,
+ // Pointer to the Unidrv supplied helper object
+ _In_reads_(dwItems) POPTITEM pOptItems,
+ // An array of options to update
+ DWORD dwItems
+ // The number of options in the provided array
+ )
+{
+ HRESULT hrResult = S_OK;
+ PFEATUREOPTITEMDATA pData = NULL;
+
+ //
+ // Walk OPTITEM array refreshing feature OPTITEMs
+ //
+ for (DWORD dwCount = 0; dwCount < dwItems; dwCount++)
+ {
+ //
+ // Just go to next item if this OPTITEM isn't a feature OPTITEM
+ //
+ if (!IsFeatureOptItem(pOptItems + dwCount))
+ {
+ continue;
+ }
+
+ //
+ // For convienience, assign to pointer to feature OPTITEM data
+ //
+ pData = (PFEATUREOPTITEMDATA)(pOptItems[dwCount].UserData);
+
+ //
+ // Refresh COption selection
+ //
+ pData->pFeature->RefreshSelection(pHelper);
+
+ //
+ // Assign COption selection to OPTITEM selection
+ //
+ pOptItems[dwCount].Sel = pData->pFeature->GetSelection();
+ }
+
+ return hrResult;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::GetFirstConflictingFeature
+//
+// Synopsis:
+// Finds the first features that it finds to be in conflict with one
+// another and supplies those features in the ppConstraints parameter
+//
+// Returns:
+// S_OK on success, else E_*. Note that this routine can succeed even
+// if no features are in conflict. In that case, *ppConstraints will
+// be NULL.
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+GetFirstConflictingFeature(
+ IPrintCoreHelper *pHelper,
+ // Pointer to the Unidrv supplied helper object
+ _In_reads_(dwItems) POPTITEM pOptItem,
+ // The array of options to look for a conflict in
+ DWORD dwItems,
+ // The number of options in the array
+ CONST PRINT_FEATURE_OPTION **ppConstraints,
+ // If any constraints are found, supplies pairs of
+ // feature / option keywords to the caller indicating
+ // which options cannot be used together.
+ DWORD *pdwConstraints
+ // The number of constrained options
+ )
+{
+ VERBOSE(DLLTEXT("GetFirstConflictingFeature entry."));
+
+ DWORD dwCount = 0;
+ HRESULT hrResult = S_OK;
+ PCSTR pszOptionKeyword = NULL;
+
+ *ppConstraints = NULL;
+
+ //
+ // Walk OPTITEM array looking for changed options that are in conflict
+ //
+ for (dwCount = 0; dwCount < dwItems; dwCount++)
+ {
+ //
+ // Just go to next item if this OPTITEM hasn't
+ // changed or isn't a feature OPTITEM
+ //
+ if(!(OPTIF_CHANGEONCE & pOptItem[dwCount].Flags) ||
+ !IsFeatureOptItem(&(pOptItem[dwCount]))
+ )
+ {
+ continue;
+ }
+
+ PFEATUREOPTITEMDATA pData = (PFEATUREOPTITEMDATA)(pOptItem[dwCount].UserData);
+
+ //
+ // Init conflict record if this feature is in conflict
+ //
+ pszOptionKeyword = GetOptionKeywordFromOptItem(&pOptItem[dwCount]);
+
+ if (pszOptionKeyword != NULL)
+ {
+ //
+ // Get reason for conflict
+ //
+ hrResult = pHelper->WhyConstrained(NULL,
+ 0,
+ pData->pszFeatureKeyword,
+ pszOptionKeyword,
+ ppConstraints,
+ pdwConstraints);
+
+ if (FAILED(hrResult))
+ {
+ ERR(ERRORTEXT("GetConflictingFeatures: Failed to get reason for feature %hs option %hs constraint! (hrResult = 0x%x)\r\n"),
+ pData->pszFeatureKeyword,
+ pszOptionKeyword,
+ hrResult);
+ break;
+ }
+
+ if (*pdwConstraints > 0)
+ {
+ break;
+ }
+ }
+ }
+
+ return hrResult;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// CreateOptType
+//
+// Synopsis:
+// Allocates and initializes OptType for OptItem & OPTPARAMs for the
+// options under that struct.
+//
+// Returns:
+// A newly allocated POPTYPE from the specified heap on success, else
+// NULL.
+//
+//
+//----------------------------------------------------------------------------
+POPTTYPE
+CreateOptType(
+ HANDLE hHeap,
+ // heap to allocate the type from.
+ WORD wOptParams
+ // The number of options available for this feature.
+ )
+{
+ VERBOSE(DLLTEXT("CreateOptType entry."));
+
+ POPTTYPE pOptType = NULL;
+ // out parameter containing the allocated type struct & array of options.
+
+ //
+ // Allocate memory from the heap for the OPTTYPE; the driver will take
+ // care of clean up.
+ //
+ pOptType = (POPTTYPE) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(OPTTYPE));
+
+ if(NULL != pOptType)
+ {
+ // Initialize OPTTYPE.
+ pOptType->cbSize = sizeof(OPTTYPE);
+ pOptType->Count = wOptParams;
+
+ // Allocate memory from the heap for the OPTPARAMs for the OPTTYPE.
+ pOptType->pOptParam = (POPTPARAM) HeapAlloc(hHeap,
+ HEAP_ZERO_MEMORY,
+ wOptParams * sizeof(OPTPARAM));
+
+ if(NULL != pOptType->pOptParam)
+ {
+ // Initialize the OPTPARAMs.
+ for(WORD wCount = 0; wCount < wOptParams; wCount++)
+ {
+ pOptType->pOptParam[wCount].cbSize = sizeof(OPTPARAM);
+ }
+ }
+ else
+ {
+ // Free allocated memory and return NULL.
+ ERR(ERRORTEXT("CreateOptType() failed to allocated memory for OPTPARAMs!\r\n"));
+ HeapFree(hHeap, 0, pOptType);
+ pOptType = NULL;
+ }
+ }
+ else
+ {
+ ERR(ERRORTEXT("CreateOptType() failed to allocated memory for OPTTYPE!\r\n"));
+ }
+
+ return pOptType;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Member:
+// ::GetStringResource
+//
+// Synopsis:
+// Load a string from the resource section of hte specied module.
+//
+// Returns:
+// S_OK on failure, else E_*
+//
+//
+//----------------------------------------------------------------------------
+HRESULT
+GetStringResource(
+ _In_ HANDLE hHeap,
+ // Heap to allocate space for the resource from.
+ _In_ HMODULE hModule,
+ // Module to load the resource from
+ UINT uResource,
+ // resource ID
+ _Out_ PWSTR *ppszString
+ // out pointer to string resource loaded.
+ )
+{
+ VERBOSE(DLLTEXT("GetStringResource entry."));
+
+ HRESULT hr = S_OK;
+
+ //
+ // Allocate buffer for string resource from heap;
+ // let the driver clean it up.
+ //
+ *ppszString = NULL;
+ *ppszString = (PTSTR) HeapAlloc(hHeap,
+ HEAP_ZERO_MEMORY,
+ MAX_PATH * sizeof(TCHAR));
+
+ if(NULL != *ppszString)
+ {
+ //
+ // Load string resource; resize after loading so
+ // as not to waste memory.
+ //
+ INT nResult = LoadString(hModule,
+ uResource,
+ *ppszString,
+ MAX_PATH);
+
+ if( nResult > 0)
+ {
+ PWSTR pszTemp = (PWSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, *ppszString, (nResult + 1) * sizeof(WCHAR));
+
+ if (NULL != pszTemp)
+ {
+ *ppszString = pszTemp;
+ }
+ else
+ {
+ //
+ // a realloc failure doesn't free the original string, so
+ // re-alloc failing in this case is not critical.
+ //
+ VERBOSE(ERRORTEXT("GetStringResource() HeapReAlloc() of string retrieved failed! (Last Error was %d)\r\n"), GetLastError());
+ }
+ }
+ else
+ {
+ ERR(ERRORTEXT("LoadString() returned %d! (Last Error was %d)\r\n"), nResult, GetLastError());
+ ERR(ERRORTEXT("GetStringResource() failed to load string resource %d!\r\n"), uResource);
+ HeapFree(hHeap, 0, *ppszString);
+ *ppszString = NULL;
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ ERR(ERRORTEXT("GetStringResource() failed to allocate string buffer!\r\n"));
+ hr = E_OUTOFMEMORY;
+ }
+
+ return hr;
+}
+