|
|
// 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 2001 - 2003 Microsoft Corporation. All Rights Reserved.
//
// FILE: Features.cpp
//
//
// PURPOSE: Implementation wrapper class for WinXP PS Driver Features and Options.
//
//
//
// PLATFORMS: Windows XP, Windows Server 2003
//
//
#include "precomp.h"
#include "debug.h"
#include "oemui.h"
#include "stringutils.h"
#include "features.h"
#include "resource.h"
// StrSafe.h needs to be included last
// to disallow bad string functions.
#include <STRSAFE.H>
////////////////////////////////////////////////////////
// Internal Defines and Macros
////////////////////////////////////////////////////////
#define INITIAL_ENUM_FEATURES_SIZE 1024
#define INITIAL_ENUM_OPTIONS_SIZE 64
#define INITIAL_FEATURE_DISPLAY_NAME_SIZE 64
#define INITIAL_OPTION_DISPLAY_NAME_SIZE 32
#define INITIAL_GET_OPTION_SIZE 64
#define INITIAL_GET_REASON_SIZE 1024
#define DRIVER_FEATURE_PREFIX '%'
#define IS_DRIVER_FEATURE(f) (DRIVER_FEATURE_PREFIX == (f)[0])
// Flags that the uDisplayNameID should be returned as
// MAKEINTRESOURCE() instead of loading the string resource.
#define RETURN_INT_RESOURCE 1
// Macros to test for conditions of KEYWORDMAP entry.
#define IS_MAPPING_INT_RESOURCE(p) ((p)->dwFlags & RETURN_INT_RESOURCE)
// 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; COptions *pOptions;
} FEATUREOPTITEMDATA, *PFEATUREOPTITEMDATA;
////////////////////////////////////////////////////////
// Internal Constants
////////////////////////////////////////////////////////
static KEYWORDMAP gkmFeatureMap[] = { "%AddEuro", NULL, IDS_ADD_EURO, OEMCUIP_PRNPROP, 0, "%CtrlDAfter", NULL, IDS_CTRLD_AFTER, OEMCUIP_PRNPROP, 0, "%CtrlDBefore", NULL, IDS_CTRLD_BEFORE, OEMCUIP_PRNPROP, 0, //"%CustomPageSize", NULL, IDS_PSCRIPT_CUSTOMSIZE, OEMCUIP_DOCPROP, 0,
"%GraphicsTrueGray", NULL, IDS_TRUE_GRAY_GRAPH, OEMCUIP_PRNPROP, 0, "%JobTimeout", NULL, IDS_JOBTIMEOUT, OEMCUIP_PRNPROP, 0, "%MaxFontSizeAsBitmap", NULL, IDS_PSMAXBITMAP, OEMCUIP_PRNPROP, 0, "%MetafileSpooling", NULL, IDS_METAFILE_SPOOLING, OEMCUIP_DOCPROP, 0, "%MinFontSizeAsOutline", NULL, IDS_PSMINOUTLINE, OEMCUIP_PRNPROP, 0, "%Mirroring", NULL, IDS_MIRROR, OEMCUIP_DOCPROP, 0, "%Negative", NULL, IDS_NEGATIVE_PRINT, OEMCUIP_DOCPROP, 0, "%Orientation", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ORIENTATION, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE, "%OutputFormat", NULL, IDS_PSOUTPUT_OPTION, OEMCUIP_DOCPROP, 0, "%OutputProtocol", NULL, IDS_PSPROTOCOL, OEMCUIP_PRNPROP, 0, "%OutputPSLevel", NULL, IDS_PSLEVEL, OEMCUIP_DOCPROP, 0, "%PageOrder", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PAGEORDER, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE, "%PagePerSheet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE, "%PSErrorHandler", NULL, IDS_PSERROR_HANDLER, OEMCUIP_DOCPROP, 0, "%PSMemory", NULL, IDS_POSTSCRIPT_VM, OEMCUIP_PRNPROP, 0, "%TextTrueGray", NULL, IDS_TRUE_GRAY_TEXT, OEMCUIP_PRNPROP, 0, "%TTDownloadFormat", NULL, IDS_PSTT_DLFORMAT, OEMCUIP_DOCPROP, 0, "%WaitTimeout", NULL, IDS_WAITTIMEOUT, OEMCUIP_PRNPROP, 0, }; static const NUM_FEATURE_MAP = (sizeof(gkmFeatureMap)/sizeof(gkmFeatureMap[0]));
static KEYWORDMAP gkmOptionMap[] = { "True", TEXT("COMPSTUI.DLL"), IDS_CPSUI_TRUE, 0, RETURN_INT_RESOURCE, "False", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FALSE, 0, RETURN_INT_RESOURCE, "Portrait", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PORTRAIT, 0, RETURN_INT_RESOURCE, "Landscape", TEXT("COMPSTUI.DLL"), IDS_CPSUI_LANDSCAPE, 0, RETURN_INT_RESOURCE, "RotatedLandscape", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ROT_LAND, 0, RETURN_INT_RESOURCE, "Speed", NULL, IDS_PSOPT_SPEED, 0, RETURN_INT_RESOURCE, "Portability", NULL, IDS_PSOPT_PORTABILITY, 0, 0, "EPS", NULL, IDS_PSOPT_EPS, 0, 0, "Archive", NULL, IDS_PSOPT_ARCHIVE, 0, 0, "ASCII", NULL, IDS_PSPROTOCOL_ASCII, 0, 0, "BCP", NULL, IDS_PSPROTOCOL_BCP, 0, 0, "TBCP", NULL, IDS_PSPROTOCOL_TBCP, 0, 0, "Binary", NULL, IDS_PSPROTOCOL_BINARY, 0, 0, "FrontToBack", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FRONTTOBACK, 0, RETURN_INT_RESOURCE, "BackToFront", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BACKTOFRONT, 0, RETURN_INT_RESOURCE, "1", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NORMAL, 0, RETURN_INT_RESOURCE, "2", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_TWOUP, 0, RETURN_INT_RESOURCE, "4", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_FOURUP, 0, RETURN_INT_RESOURCE, "6", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXUP, 0, RETURN_INT_RESOURCE, "9", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NINEUP, 0, RETURN_INT_RESOURCE, "16", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXTEENUP, 0, RETURN_INT_RESOURCE, "Booklet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BOOKLET, 0, RETURN_INT_RESOURCE, "Automatic", NULL, IDS_TTDL_DEFAULT, 0, 0, "Outline", NULL, IDS_TTDL_TYPE1, 0, 0, "Bitmap", NULL, IDS_TTDL_TYPE3, 0, 0, "NativeTrueType", NULL, IDS_TTDL_TYPE42, 0, 0, }; static const NUM_OPTION_MAP = (sizeof(gkmOptionMap)/sizeof(gkmOptionMap[0]));
////////////////////////////////////////////
//
// COptions Methods
//
//
// Private Methods
//
// Initializes class data members.
void COptions::Init() { m_wOptions = 0; m_cType = TVOT_COMBOBOX; m_pmszRaw = NULL; m_pszFeature = NULL; m_ppszOptions = NULL; m_ptRange.x = 0; m_ptRange.y = 0; m_dwSize = 0; m_pszUnits = NULL; m_hHeap = NULL; m_pInfo = NULL; }
void COptions::Clear() { // Free memory associated with data members.
if(NULL != m_pmszRaw) HeapFree(m_hHeap, 0, m_pmszRaw); if(NULL != m_ppszOptions) HeapFree(m_hHeap, 0, m_ppszOptions); if( (NULL != m_pszUnits) && !IS_INTRESOURCE(m_pszUnits)) HeapFree(m_hHeap, 0, m_pszUnits);
// Free option info.
FreeOptionInfo();
// Initialize data members.
Init(); }
// Frees memory associated with Option Info array.
void COptions::FreeOptionInfo() { // Validate parameters.
if( (NULL == m_hHeap) || (NULL == m_pInfo) ) { return; }
// Free strings in the array.
for(WORD wIndex = 0; wIndex < m_wOptions; ++wIndex) { PWSTR pszDisplay = m_pInfo[wIndex].pszDisplayName;
if( (NULL != pszDisplay) && !(IS_INTRESOURCE(pszDisplay)) ) { HeapFree(m_hHeap, 0, pszDisplay); } }
// Free the array.
HeapFree(m_hHeap, 0, m_pInfo); m_pInfo = NULL; }
// Will do init for features that need special handling.
HRESULT COptions::GetOptionsForSpecialFeatures(CUIHelper &Helper, POEMUIOBJ poemuiobj) { HRESULT hrResult = E_NOTIMPL;
// See if this is a special feature.
// If it is, then call the special option init for the
// feature.
if(!lstrcmpA(m_pszFeature, "%CustomPageSize")) { // There is no option init for CustomPageSize.
// The item itself must be handled specially.
hrResult = S_OK; } else if( !lstrcmpA(m_pszFeature, "%JobTimeout") || !lstrcmpA(m_pszFeature, "%WaitTimeout") ) { // JobTimeout and WaitTimeout feature options are string representations
// of an integer that represents number of seconds in the range 0 through
// 2,147,483,647 (i.e. LONG_MAX). However, COMPSTUI limits us to
// WORD size, which has range of 0 to 32,767 (i.e. SHRT_MAX).
m_cType = TVOT_UDARROW; m_ptRange.x = 0; m_ptRange.y = SHRT_MAX; hrResult = GetOptionSelectionShort(Helper, poemuiobj); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; } } else if( !lstrcmpA(m_pszFeature, "%MaxFontSizeAsBitmap") || !lstrcmpA(m_pszFeature, "%MinFontSizeAsOutline") ) { // MaxFontSizeAsBitmap, and MinFontSizeAsOutline feature options
// are string representations of an integer that represents number
// of pixels in the range 0 through 32,767 (i.e. SHRT_MAX).
m_cType = TVOT_UDARROW; m_ptRange.x = 0; m_ptRange.y = SHRT_MAX; hrResult = GetOptionSelectionShort(Helper, poemuiobj); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; } } else if( !lstrcmpA(m_pszFeature, "%PSMemory") ) { DWORD dwType; DWORD dwLevel; DWORD dwNeeded;
// PSMemory option is string representation of an integer
// that represents number of seconds in the range 0
// through 32,767 (i.e. SHRT_MAX).
// However, the minimum is 172 KB for Level 1 and 249 KB for level 2
m_cType = TVOT_UDARROW; m_ptRange.y = SHRT_MAX; hrResult = GetOptionSelectionShort(Helper, poemuiobj); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// Get the global attribute for max language level.
hrResult = Helper.GetGlobalAttribute(poemuiobj, 0, "LanguageLevel", &dwType, (PBYTE) &dwLevel, sizeof(dwLevel), &dwNeeded); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get global attribute \"LanguageLevel\". (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
// Set minimum range based on PS Max Language level.
switch(dwLevel) { case 1: m_ptRange.x = 172; break;
default: case 2: case 3: m_ptRange.x = 249; break; }
// Get Units string.
//GetStringResource(m_pszUnits
} else if(!lstrcmpA(m_pszFeature, "%OutputPSLevel")) { hrResult = GetOptionsForOutputPSLevel(Helper, poemuiobj); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; } }
Exit:
return hrResult; }
// Do init for PS Level options.
HRESULT COptions::GetOptionsForOutputPSLevel(CUIHelper &Helper, POEMUIOBJ poemuiobj) { WORD wCount = 0; DWORD dwLevel = 0; DWORD dwType = -1; DWORD dwNeeded = 0; HRESULT hrResult = E_NOTIMPL;
// PS Level is integers from 1 to "LanguageLevel"
// global atribute.
m_cType = TVOT_COMBOBOX;
// Get the global attribute for max language level.
hrResult = Helper.GetGlobalAttribute(poemuiobj, 0, "LanguageLevel", &dwType, (PBYTE) &dwLevel, sizeof(dwLevel), &dwNeeded); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to get global attribute \"LanguageLevel\". (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
//
// Create Options for PS Level
//
// Set the number of options to the PS Level supported.
m_wOptions = (WORD) dwLevel;
// Allocate keyword list.
// Allocate memory for pointer to keyword and the keyword itself, so that
// the memory for the keyword strings will get de-allocated with the keyword list
// on object destruction, just like regular features for which EnumOptions works.
// User the size of a pointer (4 bytes on x86, and 8 on IA64) so that
// it begining of the keyword strings will be DWORD or QUADWORD aligned
// for x86 and IA64 respectively. Keyword strings aren't required to
// be DWORD or QUADWORD aligned, but it is more optimal. Also, this gives
// some additional space for the case of %OutputPSLevel keywords, which are
// in the range of 1 through the max PostScript level supported, and only
// require 2 CHARs (1 for the digit and one for the NULL terminator).
m_ppszOptions = (PCSTR *) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * ( sizeof(PSTR) + sizeof(PCSTR *) ) ); if(NULL == m_ppszOptions) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate option keyword array for PS Level.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Allocate option info array.
m_pInfo = (POPTION_INFO) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * sizeof(OPTION_INFO)); if(NULL == m_pInfo) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate info array for PS Level.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Init the option info.
for(wCount = 0; wCount < m_wOptions; ++wCount) { // Init keyword.
// The memory for both the keyword list and the keyword strings was allocated above.
m_ppszOptions[wCount] = (PSTR)(m_ppszOptions + m_wOptions) + (sizeof(PSTR) * wCount); hrResult = StringCbPrintfA(const_cast<PSTR>(m_ppszOptions[wCount]), sizeof(PSTR), "%d", wCount + 1); if(FAILED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to string representation of item %d.\r\n"), wCount + 1);
goto Exit; }
// Init option display name.
m_pInfo[wCount].pszDisplayName = (PWSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, 2 * sizeof(WCHAR)); if(NULL == m_pInfo[wCount].pszDisplayName) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate display string for Level %d.\r\n"), wCount);
hrResult = E_OUTOFMEMORY; goto Exit; } // Init option display name.
hrResult = StringCchPrintfW(m_pInfo[wCount].pszDisplayName, 2, TEXT("%d"), wCount + 1); if(FAILED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to create display name for item %d.\r\n"), wCount + 1);
goto Exit; } }
//
// Get Current Selection
//
hrResult = GetOptionSelectionIndex(Helper, poemuiobj);
Exit:
// Don't need to clean up memory allocation on error, since
// all memory allocated are assigned to data members, which
// will be cleaned up in the object destructor.
return hrResult; }
HRESULT COptions::GetOptionSelectionString(CUIHelper &Helper, POEMUIOBJ poemuiobj, PSTR *ppszSel) { PSTR pmszFeature = NULL; PSTR pmszBuf = NULL; WORD wCount = 0; PCSTR *ppszList = NULL; DWORD dwFeatureSize = 0; DWORD dwNeeded = 0; DWORD dwSize = INITIAL_GET_OPTION_SIZE; HRESULT hrResult = S_OK;
//
// Make single feature multi-sz.
//
// Allocate singe feature multi-sz buffer.
dwFeatureSize = lstrlenA(m_pszFeature) + 2; pmszFeature = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, dwFeatureSize); if(NULL == pmszFeature) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to allocate buffer for single feature multi-sz for feature %hs.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; }
// Just need to do a regular string copy, since the buffer is already zero filled.
hrResult = StringCbCopyA(pmszFeature, dwFeatureSize, m_pszFeature); if(FAILED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to copy feature string %hs.\r\n"), m_pszFeature); }
// Allocated initial buffer of reasonible size.
pmszBuf = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, dwSize); if(NULL == pmszBuf) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to allocate buffer to get current setting for feature %hs.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; }
// Get current option selection.
hrResult = Helper.GetOptions(poemuiobj, 0, pmszFeature, dwFeatureSize, pmszBuf, dwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded) ) { PSTR pTemp = NULL;
// INVARIANT: initial buffer not large enough.
// Re-alloc buffer and try again.
pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, pmszBuf, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to re-allocate buffer to get current setting for feature %hs.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; } pmszBuf = pTemp;
// Try to get current option selection again.
hrResult = Helper.GetOptions(poemuiobj, 0, pmszFeature, dwFeatureSize, pmszBuf, dwNeeded, &dwNeeded); }
if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to get current setting for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// NOTE: The return string from GetOptions() may return
// contain no strings and not return a HRESULT error
// when the feature isn't supported in the current document or
// printer sticky mode.
if('\0' == pmszBuf[0]) { // Feature not supported for this sticky mode.
goto Exit; }
// Parse the results buffer to see what the current setting is.
hrResult = MakeStrPtrList(m_hHeap, pmszBuf, &ppszList, &wCount); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to make string list for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// Check that we got 2 strings back.
if(2 != wCount) { WARNING(DLLTEXT("COptions::GetOptionSelectionString() the GetOption() return string list for \r\n\tfeature %hs is not of size 2.\r\n\tNumber of string is %d\r\n"), m_pszFeature, wCount);
// Bail if we don't have at least 2 strings.
if(2 > wCount) { goto Exit; } }
// Return copy of just the GetOption() result.
*ppszSel = MakeStringCopy(m_hHeap, ppszList[1]); if(NULL == *ppszSel) { ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to duplicate string GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
hrResult = E_OUTOFMEMORY; goto Exit; }
Exit:
// Free local buffers.
if(NULL != pmszFeature) HeapFree(m_hHeap, 0, pmszFeature); if(NULL != pmszBuf) HeapFree(m_hHeap, 0, pmszBuf); if(NULL != ppszList) HeapFree(m_hHeap, 0, ppszList);
return hrResult; }
// Gets current Options selection for LONG value.
HRESULT COptions::GetOptionSelectionLong(CUIHelper &Helper, POEMUIOBJ poemuiobj) { PSTR pszSel = NULL; HRESULT hrResult = S_OK;
// Get option selection string.
hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionLong() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// Convert string option to LONG and uses that as the selection.
if(NULL != pszSel) m_Sel = atol(pszSel);
Exit:
// Free local buffers.
if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
return hrResult; }
// Gets current Options selection for SHORT value.
HRESULT COptions::GetOptionSelectionShort(CUIHelper &Helper, POEMUIOBJ poemuiobj) { PSTR pszSel = NULL; HRESULT hrResult = S_OK;
// Get option selection string.
hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionLong() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// Convert string option to LONG and uses that as the selection.
if(NULL != pszSel) m_Sel = atoi(pszSel) & 0x00ffff;
Exit:
// Free local buffers.
if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
return hrResult; }
// Gets current option selection for feature.
HRESULT COptions::GetOptionSelectionIndex(CUIHelper &Helper, POEMUIOBJ poemuiobj) { PSTR pszSel = NULL; HRESULT hrResult = S_OK;
// Get option selection string.
hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::GetOptionSelectionIndex() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// Find the matching option for the string returned from GetOption.
m_Sel = FindOption(pszSel, m_wOptions - 1);
Exit:
// Free local buffers.
if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
return hrResult; }
//
// Public Methods
//
// Default constructor
COptions::COptions() { Init(); }
// Destructor
COptions::~COptions() { Clear(); }
// Get the option list for a feature
HRESULT COptions::Acquire(HANDLE hHeap, CUIHelper &Helper, POEMUIOBJ poemuiobj, PCSTR pszFeature) { DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
VERBOSE(DLLTEXT("COptions::Acquire(0x%p, Helper, 0x%p, %hs) entered.\r\n"), hHeap, poemuiobj, pszFeature ? pszFeature : "NULL");
// Don't retreive the Options again if we already got them.
if( (0 < m_wOptions) && (NULL != m_pszFeature) && !lstrcmpA(m_pszFeature, pszFeature) ) { VERBOSE(DLLTEXT("COptions::Acquire() already have options for feature %hs.\r\n"), m_pszFeature); VERBOSE(DLLTEXT("COptions::Acquire() returning with HRESULT of S_OK\r\n"));
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;
//
// Enumerate Options.
//
// Some features require special handling for initializing their options.
// EnumOpionts isn't implemented for these features.
// Return of E_NOTIMPL indicates it isn't the feature doesn't
// need special handling.
hrResult = GetOptionsForSpecialFeatures(Helper, poemuiobj); if( SUCCEEDED(hrResult) || (!SUCCEEDED(hrResult) && (E_NOTIMPL != hrResult) ) ) { // We either dealt with the special feature or incounter an error
// trying to deal with the special feature.
goto Exit; }
// To try to cut down on having to call EnumOptions more than once,
// pre-allocate a buffer of reasonable size.
m_dwSize = INITIAL_ENUM_OPTIONS_SIZE; m_pmszRaw = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_dwSize); if(NULL == m_pmszRaw) { ERR(ERRORTEXT("COptions::Acquire() alloc for options for feature %hs failed.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; }
// Try to get options list with initial buffer.
hrResult = Helper.EnumOptions(poemuiobj, 0, m_pszFeature, m_pmszRaw, m_dwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (m_dwSize < dwNeeded)) { PSTR pTemp;
// INVARIANT: options list multi-sz wasn't large enough.
// Re-allocate the buffer and try again.
pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_pmszRaw, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("COptions::Acquire() re-alloc for options list for feature %hs failed.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; } m_pmszRaw = pTemp; m_dwSize = dwNeeded;
// Try again to get the options list.
hrResult = Helper.EnumOptions(poemuiobj, 0, m_pszFeature, m_pmszRaw, m_dwSize, &dwNeeded); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::Acquire() failed to EnumOptions() for feature %hs after re-allocating buffer.\r\n"), m_pszFeature);
goto Exit; } }
// Make sure we got the option list.
// Can't do anything more with out it.
if(!SUCCEEDED(hrResult)) { if(E_NOTIMPL != hrResult) ERR(ERRORTEXT("COptions::Acquire() failed to enumerate options for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
goto Exit; }
// INVARIANT: successfully got option keyword list.
// Create array of string pointers to the Option names
// in the multi-sz we got from EnumOptions().
hrResult = MakeStrPtrList(m_hHeap, m_pmszRaw, &m_ppszOptions, &m_wOptions); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::Acquire() failed to create pointer list to options. (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
//
// Build Option Information
//
// Allocate array to hold feature info
m_pInfo = (POPTION_INFO) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * sizeof(OPTION_INFO)); if(NULL == m_pInfo) { ERR(ERRORTEXT("COptions::Acquire() failed to alloc feature info array.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// For each option, build or get useful information, such as display name.
for(WORD wIndex = 0; wIndex < m_wOptions; ++wIndex) { POPTION_INFO pCurrent = m_pInfo + wIndex;
// Get or build a keyword mapping entry
// that maps from keyword to usefully where to get info, such as
// display name, icon, option type, for keywords that may not be
// able to get info for from Helper.
pCurrent->pMapping = FindKeywordMapping(gkmOptionMap, NUM_OPTION_MAP, m_ppszOptions[wIndex]);
// Get display names for each of the Options.
// The function implements a heuristic for detemining the display name,
// since can't get the display name from the UI Helper for all Options.
hrResult = DetermineOptionDisplayName(m_hHeap, Helper, poemuiobj, m_pszFeature, m_ppszOptions[wIndex], pCurrent->pMapping, &pCurrent->pszDisplayName); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("COptions::Acquire() failed to get display name for %hs of feature %hs. (hrResult = 0x%x)\r\n"), m_ppszOptions[wIndex], m_pszFeature, hrResult);
goto Exit; } }
//
// Get current option selection.
//
hrResult = GetOptionSelectionIndex(Helper, poemuiobj);
Exit:
// Clean up if weren't successful.
if(!SUCCEEDED(hrResult)) { Clear(); }
VERBOSE(DLLTEXT("COptions::Acquire() returning with HRESULT of 0x%x\r\n"), hrResult);
return hrResult; }
// Return nth options keyword.
PCSTR COptions::GetKeyword(WORD wIndex) const { // Validate parameters.
if( (wIndex >= m_wOptions) || (NULL == m_ppszOptions) ) { return NULL; }
return m_ppszOptions[wIndex]; }
// Return nth options display name.
PCWSTR COptions::GetName(WORD wIndex) const { // Validate parameters.
if( (wIndex >= m_wOptions) || (NULL == m_pInfo) ) { ERR(ERRORTEXT("COptions::GetName() invalid parameters.\r\n"));
return NULL; }
if(NULL == m_pInfo[wIndex].pszDisplayName) ERR(ERRORTEXT("COptions::GetName() returning NULL option display name.\r\n"));
return m_pInfo[wIndex].pszDisplayName; }
// Find option with matching keyword string.
WORD COptions::FindOption(PCSTR pszOption, WORD wDefault) const { BOOL bFound = FALSE; WORD wMatch = wDefault;
// Validate parameters.
if( (NULL == pszOption) || (NULL == m_ppszOptions) ) { return wDefault; }
// Walk the option keyword looking for a match.
for(WORD wIndex = 0; !bFound && (wIndex < m_wOptions); ++wIndex) { bFound = !lstrcmpA(pszOption, m_ppszOptions[wIndex]); if(bFound) { wMatch = wIndex; } }
return wMatch; }
// Initializes OptItem with options for a feature.
HRESULT COptions::InitOptItem(HANDLE hHeap, POPTITEM pOptItem) { WORD wParams = 0; WORD wOptions = 0; HRESULT hrResult = S_OK;
// Set option selection.
pOptItem->pSel = m_pSel;
// Get count of number of options.
// NOTE: Some feature options have no counts.
wOptions = GetCount();
// Different OPTTYPE types require different number of OPTPARAMs.
switch(m_cType) { // For up down arrow control, the OPTPARAMs need is 2.
case TVOT_UDARROW: wParams = 2; break;
// For combobox, the OPTPARAMs needed is on per options.
case TVOT_COMBOBOX: wParams = wOptions; break;
// The default is the option count.
default: WARNING(DLLTEXT("COptions::InitOptItem() OPTTYPE type %d num of OPTPARAMs not handled. Default to option count of %d.\r\n"), m_cType, wOptions); wParams = wOptions; break; }
// Only do OPTTYPEs if we have non-Zero number of OPTPARAMs.
// Every OPTTYPE has at leas one OPTPARAM.
if(0 < wParams) { // Allocate memory for feature options.
pOptItem->pOptType = CreateOptType(hHeap, wParams); if(NULL == pOptItem->pOptType) { ERR(ERRORTEXT("COptions::InitOptItem() failed to allocate OPTTYPEs for OPTITEM %hs.\r\n"), m_pszFeature);
hrResult = E_OUTOFMEMORY; goto Exit; }
// Set OPTTYPE.
pOptItem->pOptType->Type = m_cType;
// Different OPTTYPE types require different initialization.
switch(m_cType) { // For up down arrow control, OPTPARAM[0] is used by the contrl.
// pOptParam[0]->pData is the Units description string.
// pOptParam[1].IconID is the min limit.
// pOptParam[1].lParam is the max limit.
case TVOT_UDARROW: assert(2 == wParams); pOptItem->pOptType->pOptParam[0].pData = m_pszUnits; pOptItem->pOptType->pOptParam[1].IconID = m_ptRange.x; pOptItem->pOptType->pOptParam[1].lParam = m_ptRange.y; break;
// For combobox, the pOptParam[n].pData is the display name of the option.
case TVOT_COMBOBOX: for(WORD wIndex = 0; wIndex < wParams; ++wIndex) { pOptItem->pOptType->pOptParam[wIndex].pData = const_cast<PWSTR>(GetName(wIndex)); } break;
default: ERR(ERRORTEXT("COptions::InitOptItem() OPTTYPE type %d OPTTYPE init not handled.\r\n"), m_cType); break; } }
Exit:
return hrResult; }
// Refresh option selection.
HRESULT COptions::RefreshSelection(CUIHelper &Helper, POEMUIOBJ poemuiobj) { HRESULT hrResult = S_OK;
// Method for getting option selection is based
// on OPTTYPE type.
switch(m_cType) {
case TVOT_UDARROW: hrResult = GetOptionSelectionShort(Helper, poemuiobj); break;
case TVOT_COMBOBOX: hrResult = GetOptionSelectionIndex(Helper, poemuiobj); break;
default: ERR(ERRORTEXT("COptions::RefreshSelection() not handled for type %d OPTTYPE.\r\n"), m_cType); break; }
return hrResult; }
////////////////////////////////////////////
//
// CFeatures Methods
//
//
// Private Methods
//
// Initializes class
void CFeatures::Init() { // Initialize data members.
m_wFeatures = 0; m_wDocFeatures = 0; m_wPrintFeatures = 0; m_pmszRaw = NULL; m_ppszKeywords = NULL; m_dwSize = 0; m_hHeap = NULL; m_pInfo = NULL; }
// Cleans up class and re-initialize it.
void CFeatures::Clear() { // Free memory associated with data members.
if(NULL != m_pmszRaw) HeapFree(m_hHeap, 0, m_pmszRaw); if(NULL != m_ppszKeywords) HeapFree(m_hHeap, 0, m_ppszKeywords);
// Free feature info
FreeFeatureInfo();
// Re-initialize
Init(); }
// Free feature info
void CFeatures::FreeFeatureInfo() { // Validate parameters.
if( (NULL == m_hHeap) || (NULL == m_pInfo) ) { return; }
// Free memory associated with feature info.
for(WORD wIndex = 0; wIndex < m_wFeatures; ++wIndex) { PWSTR pszDisplay = m_pInfo[wIndex].pszDisplayName;
// Free display name.
if( (NULL != pszDisplay) && !IS_INTRESOURCE(pszDisplay) ) { HeapFree(m_hHeap, 0, pszDisplay); } }
// Free feature info array.
// Feature Info array allocated with new so
// that each of the constructors for COptions
// in fhte Feature Info array will be called.
delete[] m_pInfo; }
// Turns index for mode to modeless index, which
// is the real index to the feature.
WORD CFeatures::GetModelessIndex(WORD wIndex, DWORD dwMode) const { WORD wCount = 0;
switch(dwMode) { // Number of features, all modes
case 0: wCount = wIndex; break;
// Find the nth feature that matches the mode
case OEMCUIP_DOCPROP: case OEMCUIP_PRNPROP: // Walk the feature list looking for nth feature
// with matching mode.
for(wCount = 0; wCount < m_wFeatures; ++wCount) { // Count down to the feature we want.
// Only count down for matching modes.
if(dwMode == m_pInfo[wCount].dwMode) { if(0 == wIndex) { break; } else { --wIndex; } } } break; }
return wCount; }
//
// Public Methods
//
// Default constructor
CFeatures::CFeatures() { Init(); }
// Destructor
CFeatures::~CFeatures() { // Clean up class.
Clear(); }
// Gets Core Driver Features, if not already retrieved.
HRESULT CFeatures::Acquire(HANDLE hHeap, CUIHelper &Helper, POEMUIOBJ poemuiobj ) { WORD wIndex = 0; DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
VERBOSE(DLLTEXT("CFeatures::Acquire(0x%p, Helper, 0x%p) entered.\r\n"), hHeap, poemuiobj);
// Don't retreive the Features again if we already got them.
if(0 < m_wFeatures) { VERBOSE(DLLTEXT("CFeatures::Acquire() features already enumerated.\r\n")); VERBOSE(DLLTEXT("CFeatures::Acquire() 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.
//
// To try to cut down on having to call EnumFeatures more than once,
// pre-allocate a buffer of reasonable size.
m_dwSize = INITIAL_ENUM_FEATURES_SIZE; m_pmszRaw = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_dwSize); if(NULL == m_pmszRaw) { ERR(ERRORTEXT("CFeatures::Acquire() alloc for feature list failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Try to get feature list with initial buffer.
hrResult = Helper.EnumFeatures(poemuiobj, 0, m_pmszRaw, m_dwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (m_dwSize < dwNeeded)) { PSTR pTemp;
// INVARIANT: feature list multi-sz wasn't large enough.
// Re-allocate the buffer and try again.
pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_pmszRaw, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("CFeatures::Acquire() re-alloc for feature list failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; } m_pmszRaw = pTemp; m_dwSize = dwNeeded;
// Try again to get the feature list.
hrResult = Helper.EnumFeatures(poemuiobj, 0, m_pmszRaw, m_dwSize, &dwNeeded); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("CFeatures::Acquire() failed to EnumFeatures() after re-allocating buffer.\r\n"));
goto Exit; } }
// Make sure we got the feature list.
// Can't do anything more with out it.
if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("CFeatures::Acquire() failed to enumerate features. (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
// INVARIANT: successfully got feature keyword list.
// Create array of string pointers to the feature keywords
// in the multi-sz we got from EnumFreatures().
hrResult = MakeStrPtrList(m_hHeap, m_pmszRaw, &m_ppszKeywords, &m_wFeatures); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("CFeatures::Acquire() failed to create pointer list to keywords. (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
//
// Build Feature Information
//
// Allocate array to hold feature info
// Use new for allocation so class
// constructors/destructors get called.
m_pInfo = new FEATURE_INFO[m_wFeatures]; if(NULL == m_pInfo) { ERR(ERRORTEXT("CFeatures::Acquire() failed to alloc feature info array.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// For each feature, build/get feature info....
for(wIndex = 0; wIndex < m_wFeatures; ++wIndex) { PFEATURE_INFO pCurrent = m_pInfo + wIndex;
// Get or build a keyword mapping entry
// that maps from keyword to usefully where to get info, such as
// display name, icon, option type, for keywords that may not be
// able to get info for from Helper.
pCurrent->pMapping = FindKeywordMapping(gkmFeatureMap, NUM_FEATURE_MAP, m_ppszKeywords[wIndex]);
// Get display names for each of the featurs.
// The function implements a heuristic for detemining the display name,
// since can't get the display name from the UI Helper for all features.
hrResult = DetermineFeatureDisplayName(m_hHeap, Helper, poemuiobj, m_ppszKeywords[wIndex], pCurrent->pMapping, &pCurrent->pszDisplayName); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("CFeatures::Acquire() failed to get display name for feature %hs. (hrResult = 0x%x)\r\n"), m_ppszKeywords[wIndex], hrResult);
goto Exit; }
// Get options for each feature.
// NOTE: some features don't have options; the HRESULT will be E_NOTIMPL for these.
hrResult = pCurrent->Options.Acquire(hHeap, Helper, poemuiobj, m_ppszKeywords[wIndex]); if(!SUCCEEDED(hrResult) && (E_NOTIMPL != hrResult)) { ERR(ERRORTEXT("CFeatures::Acquire() failed to get options for feature %hs. (hrResult = 0x%x)\r\n"), m_ppszKeywords[wIndex], hrResult);
goto Exit; }
// Determine if feature is Printer or Document sticky.
hrResult = DetermineStickiness(Helper, poemuiobj, m_ppszKeywords[wIndex], pCurrent->pMapping, &pCurrent->dwMode); // Don't propagate error if failure from unhandled driver feature.
if( !SUCCEEDED(hrResult) && !IS_DRIVER_FEATURE(m_ppszKeywords[wIndex]) ) { ERR(ERRORTEXT("CFeatures::Acquire() failed to determine stickiness for feature %hs. (hrResult = 0x%x)\r\n"), m_ppszKeywords[wIndex], hrResult);
goto Exit; }
// Keep track of mode counts.
switch(pCurrent->dwMode) { case OEMCUIP_DOCPROP: ++m_wDocFeatures; break;
case OEMCUIP_PRNPROP: ++m_wPrintFeatures; break;
default: ERR(ERRORTEXT("CFeatures::Acquire() unknown stickiness for feature %hs.\r\n"), m_ppszKeywords[wIndex]); break; }
}
// INVARIANT: successfully build feature list.
// Make sure that we always return success if we reach this point.
hrResult = S_OK;
Exit:
// Clean up if weren't successful.
if(!SUCCEEDED(hrResult)) { Clear(); }
VERBOSE(DLLTEXT("CFeatures::Acquire() returning HRESULT of 0x%x.\r\n"), hrResult);
return hrResult; }
// Returns number of features contained in class instance.
WORD CFeatures::GetCount(DWORD dwMode) const { WORD wCount = 0;
switch(dwMode) { // Number of features, all modes
case 0: wCount = m_wFeatures; break;
case OEMCUIP_DOCPROP: wCount = m_wDocFeatures; break;
case OEMCUIP_PRNPROP: wCount = m_wPrintFeatures; break;
}
VERBOSE(DLLTEXT("CFeatures::GetCount() returning %d\r\n"), wCount);
return wCount; }
// Returns nth feature's keyword
PCSTR CFeatures::GetKeyword(WORD wIndex, DWORD dwMode) const { // Validate parameters.
if( (wIndex >= GetCount(dwMode)) || (NULL == m_ppszKeywords) ) { return NULL; }
// Get internal index.
wIndex = GetModelessIndex(wIndex, dwMode);
// Return keyword
return m_ppszKeywords[wIndex]; }
// Return nth feature's Display Name.
PCWSTR CFeatures::GetName(WORD wIndex, DWORD dwMode) const { // Validate parameters.
if( (wIndex >= GetCount(dwMode)) || (NULL == m_pInfo) ) { return NULL; }
// Get internal index.
wIndex = GetModelessIndex(wIndex, dwMode);
// Return display name.
return m_pInfo[wIndex].pszDisplayName; }
// Returns pointer to option class for nth feature.
COptions* CFeatures::GetOptions(WORD wIndex, DWORD dwMode) const { // Validate parameters.
if( (wIndex >= GetCount(dwMode)) || (NULL == m_pInfo) ) { return NULL; }
// Get internal index.
wIndex = GetModelessIndex(wIndex, dwMode);
// Return options pointer.
return &m_pInfo[wIndex].Options; }
// Formats OPTITEM for specied feature.
HRESULT CFeatures::InitOptItem(HANDLE hHeap, POPTITEM pOptItem, WORD wIndex, DWORD dwMode) { COptions *pOptions = NULL; HRESULT hrResult = S_OK; PFEATUREOPTITEMDATA pData = NULL;
// Validate parameters.
if( (wIndex >= GetCount(dwMode)) || (NULL == m_pInfo) || (NULL == pOptItem) ) { return E_INVALIDARG; }
// Map mode index to internal index.
wIndex = GetModelessIndex(wIndex, dwMode);
// Get name of feature.
pOptItem->pName = const_cast<PWSTR>(GetName(wIndex));
// Add feature OPTITEM data to OPTITEM to facilitate saving
// selection changes.
pData = (PFEATUREOPTITEMDATA) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(FEATUREOPTITEMDATA)); if(NULL == pData) { ERR(ERRORTEXT("CFeatures::InitOptItem() failed to allocated memory for feature OPTITEM data."));
hrResult = E_OUTOFMEMORY; goto Exit; } pData->dwSize = sizeof(FEATUREOPTITEMDATA); pData->dwTag = FEATURE_OPTITEM_TAG; pData->pszFeatureKeyword = GetKeyword(wIndex); pData->pOptions = GetOptions(wIndex); pOptItem->UserData = (ULONG_PTR) pData;
// Get pointer to options for this feature.
// NOTE: some features do not have option list for various reasons.
pOptions = GetOptions(wIndex); if(NULL != pOptions) { // Initialize COption parts of the OPTITEM
hrResult = pOptions->InitOptItem(hHeap, pOptItem); }
Exit:
Dump(pOptItem);
return hrResult; }
//////////////////////////////////////////////////
//
// Regular functions not part of class
//
//////////////////////////////////////////////////
// Maps feature keywords to display names for the features.
HRESULT DetermineFeatureDisplayName(HANDLE hHeap, CUIHelper &Helper, POEMUIOBJ poemuiobj, PCSTR pszKeyword, const PKEYWORDMAP pMapping, PWSTR *ppszDisplayName) { DWORD dwDataType = -1; DWORD dwSize = INITIAL_FEATURE_DISPLAY_NAME_SIZE; DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
// Validate parameters.
if( (NULL == hHeap) || (NULL == pszKeyword) || (NULL == ppszDisplayName) ) { ERR(ERRORTEXT("DetermineFeatureDisplayName() invalid arguement.\r\n"));
hrResult = E_INVALIDARG; goto Exit; }
//
// Call the Helper function.
//
// Helper will return Display Names for PPD Features, but
// not for Driver Synthisized features (i.e. features prefixed with %).
// Do it for Driver Synthisized features, just in case the helper
// interface changes to support it.
// Pre-allocate a buffer of reasonable size to try
// to one have to call GetFeatureAttribute() once.
*ppszDisplayName = (PWSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize); if(NULL == *ppszDisplayName) { ERR(ERRORTEXT("DetermineFeatureDisplayName() alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Try to get diplay name for feature from Helper.
hrResult = Helper.GetFeatureAttribute(poemuiobj, 0, pszKeyword, "DisplayName", &dwDataType, (PBYTE) *ppszDisplayName, dwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded)) { PWSTR pTemp;
// INVARIANT: initial buffer wasn't large enough.
// Re-alloc buffer and try again.
pTemp = (PWSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, *ppszDisplayName, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("DetermineFeatureDisplayName() re-alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; } *ppszDisplayName = pTemp;
// Try to get the display name from Helper, again.
hrResult = Helper.GetFeatureAttribute(poemuiobj, 0, pszKeyword, "DisplayName", &dwDataType, (PBYTE) *ppszDisplayName, dwNeeded, &dwNeeded); }
if(SUCCEEDED(hrResult)) { // INVARIANT: Successfully got display name from Helper for feature.
// Don't need to do anything more.
// Check the data type, it should be kADT_UNICODE.
if(kADT_UNICODE != dwDataType) WARNING(DLLTEXT("DetermineFeatureDisplayName() feature attribute type not kADT_UNICODE. (dwDataType = %d)\r\n"), dwDataType);
goto Exit; }
// INVARIANT: Did not get the display name from the Helper.
// Free memory allocated for call to Helper.
if(NULL != *ppszDisplayName) { HeapFree(hHeap, 0, *ppszDisplayName); *ppszDisplayName = NULL; }
// Try alternative methods for getting the display name other
// than from the Helper function.
// If we have a mapping entry, then try to get resource string
// for the display name.
// Otherwise, covert the keyword to UNICODE and use that.
if(NULL != pMapping) { //
// Try mapping the keyword to resource string.
//
hrResult = GetDisplayNameFromMapping(hHeap, pMapping, ppszDisplayName); } else { //
// Convert the keyword to UNICODE and use that.
//
// Convert ANSI keyword to Unicode string for display name.
// Need to remove the % for Driver Synthisized features.
// For debug version, add marker that shows that the display name was faked.
PCSTR pConvert = IS_DRIVER_FEATURE(pszKeyword) ? pszKeyword + 1 : pszKeyword; #if DBG
CHAR szTemp[256]; if(FAILED(StringCbPrintfA(szTemp, sizeof(szTemp), "%s (Keyword)", pConvert))) { ERR(ERRORTEXT("DetermineFeatureDisplayName() StringCbPrintfA() called failed.\r\n")); } pConvert = szTemp; #endif
*ppszDisplayName = MakeUnicodeString(hHeap, pConvert); if(NULL == *ppszDisplayName) { ERR(ERRORTEXT("DetermineFeatureDisplayName() alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Return success even though we faked a display name.
hrResult = S_OK; }
Exit:
// If failed, then return no string.
if(!SUCCEEDED(hrResult)) { if(NULL != *ppszDisplayName) { HeapFree(hHeap, 0, *ppszDisplayName); *ppszDisplayName = NULL; } }
return hrResult; }
// Maps option keywords to display names for the option.
HRESULT DetermineOptionDisplayName(HANDLE hHeap, CUIHelper &Helper, POEMUIOBJ poemuiobj, PCSTR pszFeature, PCSTR pszOption, const PKEYWORDMAP pMapping, PWSTR *ppszDisplayName) { DWORD dwDataType = -1; DWORD dwSize = INITIAL_OPTION_DISPLAY_NAME_SIZE; DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
// Validate parameters.
if( (NULL == hHeap) || (NULL == pszFeature) || (NULL == pszOption) || (NULL == ppszDisplayName) ) { ERR(ERRORTEXT("DetermineOptionDisplayName() invalid arguement.\r\n"));
hrResult = E_INVALIDARG; goto Exit; }
//
// Call the Helper function.
//
// Helper will return Display Names for PPD Feature Options, but
// not for Driver Synthisized features options (i.e. features prefixed with %).
// Do it for all options, just in case the helper interface changes to support it.
// Pre-allocate a buffer of reasonable size to try
// to one have to call GetOptionAttribute() once.
*ppszDisplayName = (PWSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize); if(NULL == *ppszDisplayName) { ERR(ERRORTEXT("DetermineOptionDisplayName() alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Try to get diplay name for feature from Helper.
hrResult = Helper.GetOptionAttribute(poemuiobj, 0, pszFeature, pszOption, "DisplayName", &dwDataType, (PBYTE) *ppszDisplayName, dwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded)) { PWSTR pTemp;
// INVARIANT: initial buffer wasn't large enough.
// Re-alloc buffer and try again.
pTemp = (PWSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, *ppszDisplayName, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("GetOptionAttribute() re-alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; } *ppszDisplayName = pTemp;
// Try to get the display name from Helper, again.
hrResult = Helper.GetOptionAttribute(poemuiobj, 0, pszFeature, pszOption, "DisplayName", &dwDataType, (PBYTE) *ppszDisplayName, dwNeeded, &dwNeeded); }
if(SUCCEEDED(hrResult)) { // INVARIANT: Successfully got display name from Helper for feature.
// Don't need to do anything more.
// Check the data type, it should be kADT_UNICODE.
if(kADT_UNICODE != dwDataType) WARNING(DLLTEXT("DetermineOptionDisplayName() feature attribute type not kADT_UNICODE. (dwDataType = %d)\r\n"), dwDataType);
goto Exit; }
// INVARIANT: Did not get the display name from the Helper.
// Free memory allocated for call to Helper.
if(NULL != *ppszDisplayName) { HeapFree(hHeap, 0, *ppszDisplayName); *ppszDisplayName = NULL; }
// Try alternative methods for getting the display name other
// than from the Helper function.
// If we have a mapping entry, then try to get resource string
// for the display name.
// Otherwise, covert the keyword to UNICODE and use that.
if(NULL != pMapping) { //
// Try mapping the keyword to resource string.
//
hrResult = GetDisplayNameFromMapping(hHeap, pMapping, ppszDisplayName); } else { //
// Convert the keyword to UNICODE and use that.
//
// Convert ANSI keyword to Unicode string for display name.
// For debug version, add marker that shows that the display name was faked.
PCSTR pConvert = pszOption; #if DBG
CHAR szTemp[256]; if(FAILED(StringCbPrintfA(szTemp, sizeof(szTemp), "%s (Keyword)", pConvert))) { ERR(ERRORTEXT("DetermineOptionDisplayName() StringCbPrintfA() called failed.\r\n")); } pConvert = szTemp; #endif
*ppszDisplayName = MakeUnicodeString(hHeap, pConvert); if(NULL == *ppszDisplayName) { ERR(ERRORTEXT("DetermineOptionDisplayName() alloc for feature display name failed.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Return success even though we faked a display name.
hrResult = S_OK; }
Exit:
// If failed, then return no string.
if(!SUCCEEDED(hrResult)) { if(NULL != *ppszDisplayName) { HeapFree(hHeap, 0, *ppszDisplayName); *ppszDisplayName = NULL; } }
return hrResult; }
// Determines sticky mode for the feature.
HRESULT DetermineStickiness(CUIHelper &Helper, POEMUIOBJ poemuiobj, PCSTR pszKeyword, const PKEYWORDMAP pMapping, PDWORD pdwMode) { CHAR szGroupType[32] = {0}; DWORD dwType = 0; DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
// Use mapping to see what stickiness of the feature is.
if(NULL != pMapping) { *pdwMode = pMapping->dwMode; goto Exit; }
// By default make feature Document sticky, if we don't have mapping.
*pdwMode = OEMCUIP_DOCPROP;
// Try to use Helper to determine stickiness.
hrResult = Helper.GetFeatureAttribute(poemuiobj, 0, pszKeyword, "OpenGroupType", &dwType, (PBYTE) szGroupType, sizeof(szGroupType), &dwNeeded); if(SUCCEEDED(hrResult)) { // INVARIANT: found out if feature is an installable option.
// Installable options are the only PPD features
// that are Printer sticky.
if(!lstrcmpA(szGroupType, "InstallableOptions")) { *pdwMode = OEMCUIP_PRNPROP; } goto Exit; }
Exit:
return hrResult; }
// Find the mapping entry from the keyword.
PKEYWORDMAP FindKeywordMapping(PKEYWORDMAP pKeywordMap, WORD wMapSize, PCSTR pszKeyword) { BOOL bFound = FALSE; PKEYWORDMAP pMapping = NULL;
// Walk mapping array for matching keyword.
for(WORD wIndex = 0; !bFound && (wIndex < wMapSize); ++wIndex) { bFound = !lstrcmpA(pszKeyword, pKeywordMap[wIndex].pszKeyword); if(bFound) { pMapping = pKeywordMap + wIndex; } }
return pMapping; }
// Get display name from mapping entry.
HRESULT GetDisplayNameFromMapping(HANDLE hHeap, PKEYWORDMAP pMapping, PWSTR *ppszDisplayName) { HMODULE hModule = NULL; HRESULT hrResult = S_OK;
// Validate parameters.
if( (NULL == hHeap) || (NULL == pMapping) || (NULL == ppszDisplayName) ) { hrResult = E_INVALIDARG; goto Exit; }
// Check for simple case of returning INT resource.
if( (NULL == pMapping->pwszModule) || IS_MAPPING_INT_RESOURCE(pMapping) ) { // Just need to do MAKEINTRESOURCE on the resource ID and return.
*ppszDisplayName = MAKEINTRESOURCE(pMapping->uDisplayNameID); goto Exit; }
// We only need to get the module if we aren't loading the resource from
// this module (i.e. if module name isn't NULL).
// Also, 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(NULL == hModule) { DWORD dwError = GetLastError();
ERR(ERRORTEXT("GetDisplayNameFromMapping() for failed to load module %s. (Error %d)\r\n"), pMapping->pwszModule, dwError);
hrResult = HRESULT_FROM_WIN32(dwError); goto Exit; }
// INVARIANT: have handle to module to load resource from or the
// resource is being loaded from this module.
// Get the string resouce.
hrResult = GetStringResource(hHeap, hModule, pMapping->uDisplayNameID, ppszDisplayName); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("GetDisplayNameFromMapping() failed to load string. (hrResult = 0x%x)\r\n"), hrResult); goto Exit; }
Exit:
return hrResult; }
// Test if an OPTITEM is an OPTITEM for a feature.
// Macro for testing if OPTITEM is feature OPTITEM
BOOL IsFeatureOptitem(POPTITEM pOptItem) { 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; }
// Walks array of OPTITEMs saving each feature OPTITEM
// that has changed.
HRESULT SaveFeatureOptItems(HANDLE hHeap, CUIHelper *pHelper, POEMUIOBJ poemuiobj, HWND hWnd, POPTITEM pOptItem, WORD wItems) { PSTR pmszPairs = NULL; WORD wPairs = 0; WORD wConflicts = 0; WORD wReasons = 0; DWORD dwSize = 0; DWORD dwResult = 0; PCSTR *ppszReasons = NULL; PWSTR pszConfilictFeature = NULL; PWSTR pszConfilictOption = NULL; PWSTR pszCaption = NULL; PWSTR pszFormat = NULL; PWSTR pszMessage = NULL; HRESULT hrResult = S_OK;
// Validate parameters
if( (NULL == hHeap) || (NULL == pHelper) || (NULL == pOptItem) ) { ERR(ERRORTEXT("SaveFeatureOptItems() called with invalid parameters.\r\n"));
hrResult = E_INVALIDARG; goto Exit; }
// Get feature option pairs to save.
hrResult = GetChangedFeatureOptions(hHeap, pOptItem, wItems, &pmszPairs, &wPairs, &dwSize); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() failed to get changed feature option pairs. (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
// Don't need to do anything more if no feature options changed.
if(0 == wPairs) { VERBOSE(DLLTEXT("SaveFeatureOptItems() no feature options that need to be set.\r\n"));
goto Exit; }
// 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(poemuiobj, SETOPTIONS_FLAG_KEEP_CONFLICT, pmszPairs, dwSize, &dwResult); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() call to SetOptions() failed. (hrResult = 0x%x, dwResult = %d\r\n"), hrResult, dwResult);
goto Exit; }
// Check to see if we were able to save changed feature options,
// or if there is a conflict that needs resolution.
if(SETOPTIONS_RESULT_CONFLICT_REMAINED == dwResult) { int nRet; DWORD dwRet; CONFLICT Conflict; PKEYWORDMAP pMapping = NULL;
// INVARIANT: constraint conflict, options weren't saved.
// Get list of all features that have conflict.
hrResult = GetFirstConflictingFeature(hHeap, pHelper, poemuiobj, pOptItem, wItems, &Conflict); if(!SUCCEEDED(hrResult)) { goto Exit; }
// Create string pointer list in to multi-sz of first conflict.
hrResult = MakeStrPtrList(hHeap, Conflict.pmszReasons, &ppszReasons, &wReasons); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() failed to make string list for conflict reasons. (hrResult = 0x%x)\r\n"), hrResult);
goto Exit; }
//
// Get display versions of feature/option conflict reason.
//
// Get or build a keyword mapping entry
// that maps from keyword to usefully where to get info, such as
// display name, icon, option type, for keywords that may not be
// able to get info for from Helper.
pMapping = FindKeywordMapping(gkmFeatureMap, NUM_FEATURE_MAP, ppszReasons[0]);
// Get display names for each of the featurs.
// The function implements a heuristic for detemining the display name,
// since can't get the display name from the UI Helper for all features.
hrResult = DetermineFeatureDisplayName(hHeap, *pHelper, poemuiobj, ppszReasons[0], pMapping, &pszConfilictFeature); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems failed to get display name for feature %hs. (hrResult = 0x%x)\r\n"), ppszReasons[0], hrResult);
goto Exit; }
// Get or build a keyword mapping entry
// that maps from keyword to usefully where to get info, such as
// display name, icon, option type, for keywords that may not be
// able to get info for from Helper.
pMapping = FindKeywordMapping(gkmOptionMap, NUM_OPTION_MAP, ppszReasons[1]);
// Get option display name.
hrResult = DetermineOptionDisplayName(hHeap, *pHelper, poemuiobj, ppszReasons[0], ppszReasons[1], pMapping, &pszConfilictOption); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() failed to get display name for %hs of feature %hs. (hrResult = 0x%x)\r\n"), ppszReasons[1], ppszReasons[0], hrResult);
goto Exit; }
//
// Prompt user about how to resolve conflict.
//
// Get caption name.
hrResult = GetStringResource(hHeap, ghInstance, IDS_NAME, &pszCaption); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() failed to get caption name. (hrResult = 0x%x)\r\n"), hrResult); goto Exit; }
// Get message body format string.
hrResult = GetStringResource(hHeap, ghInstance, IDS_CONSTRAINT_CONFLICT, &pszFormat); if(!SUCCEEDED(hrResult)) { ERR(ERRORTEXT("SaveFeatureOptItems() failed to get constraint conflict format. (hrResult = 0x%x)\r\n"), hrResult); goto Exit; }
// Get messsage body.
PVOID paArgs[4] = {pszConfilictFeature, pszConfilictOption, const_cast<PWSTR>(Conflict.pszFeature), Conflict.pszOption }; dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, pszFormat, 0, 0, (PWSTR) &pszMessage, 0, (va_list *) paArgs); if(0 == dwRet) { DWORD dwError = GetLastError();
ERR(ERRORTEXT("SaveFeatureOptItems() failed to FormatMessage() for constraint conflict of feature %hs option %hs. (Last Error %d)\r\n"), Conflict.pszFeatureKeyword, Conflict.pszOptionKeyword, dwError);
hrResult = HRESULT_FROM_WIN32(dwError); goto Exit; }
// Display simple message box with prompt.
nRet = MessageBox(hWnd, pszMessage, pszCaption, MB_YESNO | MB_ICONWARNING);
// Check to see how user wants to resolve conflict.
if(IDYES == nRet) { // Let core driver resolve conflict resolution.
hrResult = pHelper->SetOptions(poemuiobj, SETOPTIONS_FLAG_RESOLVE_CONFLICT, pmszPairs, dwSize, &dwResult);
// Conflict resolution requires refreshing current option
// selection for each feature, since selection may have
// changed because of conflict resolution.
RefreshOptItemSelection(pHelper, poemuiobj, pOptItem, wItems); }
// Return failure if there are still conflictts.
if(SETOPTIONS_RESULT_CONFLICT_REMAINED == dwResult) { hrResult = E_FAIL; } }
Exit:
// Clean up...
// cleanup heap allocs.
if(NULL != pmszPairs) HeapFree(hHeap, 0, pmszPairs); if(NULL != ppszReasons) HeapFree(hHeap, 0, ppszReasons); if(NULL != pszConfilictFeature) HeapFree(hHeap, 0, pszConfilictFeature); if(NULL != pszConfilictOption) HeapFree(hHeap, 0, pszConfilictOption); if(NULL != pszCaption) HeapFree(hHeap, 0, pszCaption); if(NULL != pszFormat) HeapFree(hHeap, 0, pszFormat); if(NULL != pszMessage) LocalFree(pszMessage);
return hrResult; }
// Allocates buffer, if needed, and calls IPrintCoreUI2::WhyConsrained
// to get reason for constraint.
HRESULT GetWhyConstrained(HANDLE hHeap, CUIHelper *pHelper, POEMUIOBJ poemuiobj, PCSTR pszFeature, PCSTR pszOption, PSTR *ppmszReason, PDWORD pdwSize) { PSTR pmszReasonList = *ppmszReason; DWORD dwNeeded = 0; HRESULT hrResult = S_OK;
// If buffer wasn't passed in, then allocate one.
if( (NULL == pmszReasonList) || (0 == *pdwSize) ) { // If no size or size is smaller than default, then change to default
// size. We want to try to only allocate and call once.
if(*pdwSize < INITIAL_GET_REASON_SIZE) { *pdwSize = INITIAL_GET_REASON_SIZE; }
// Alloc initial buffer for reason constrained.
pmszReasonList = (PSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, *pdwSize); if(NULL == pmszReasonList) { ERR(ERRORTEXT("GetWhyConstrained() failed to alloc buffer for constraint reasons for feature %hs and option %hs.\r\n"), pszFeature, pszOption);
hrResult = E_OUTOFMEMORY; goto Exit; } }
// Get reason for constraint.
hrResult = pHelper->WhyConstrained(poemuiobj, 0, pszFeature, pszOption, pmszReasonList, *pdwSize, &dwNeeded); if( (E_OUTOFMEMORY == hrResult) && (*pdwSize < dwNeeded) ) { PSTR pTemp;
// INVARIANT: initial buffer not large enough.
// Re-alloc buffer to needed size.
pTemp = (PSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pmszReasonList, dwNeeded); if(NULL == pTemp) { ERR(ERRORTEXT("GetWhyConstrained() failed to re-allocate buffer for constraint reason for feature %hs and option %hs.\r\n"), pszFeature, pszOption);
hrResult = E_OUTOFMEMORY; goto Exit; } pmszReasonList = pTemp; *pdwSize = dwNeeded;
// Retry getting constaint reason.
hrResult = pHelper->WhyConstrained(poemuiobj, 0, pszFeature, pszOption, pmszReasonList, *pdwSize, &dwNeeded); }
Exit:
// On error, do clean up.
if(!SUCCEEDED(hrResult)) { // Free reason buffer.
if(NULL != pmszReasonList) HeapFree(hHeap, 0, pmszReasonList);
// Return NULL and zero size.
*ppmszReason = NULL; *pdwSize = 0; } else { *ppmszReason = pmszReasonList; }
return hrResult; }
// Creates multi-sz list of feature option pairs that have changed.
HRESULT GetChangedFeatureOptions(HANDLE hHeap, POPTITEM pOptItem, WORD wItems, PSTR *ppmszPairs, PWORD pwPairs, PDWORD pdwSize) { WORD wCount = 0; WORD wChanged = 0; WORD wPairs = 0; PSTR pmszPairs = NULL; DWORD dwNeeded = 2; DWORD dwOffset = 0; HRESULT hrResult = S_OK; PFEATUREOPTITEMDATA pData = NULL;
// Walk OPTITEM array looking or changed options,
// and calculating size needed for multi-sz buffer.
for(wCount = 0; wCount < wItems; ++wCount) { PSTR pszOption = NULL;
// Just go to next item if this OPTITEM hasn't
// changed or isn't a feature OPTITEM.
if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags) || !IsFeatureOptitem(pOptItem + wCount) ) { continue; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
// Increment options changed and size needed.
pszOption = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount); if(NULL != pszOption) { ++wChanged; dwNeeded += lstrlenA(pData->pszFeatureKeyword) + lstrlenA(pszOption) + 2;
// Need to free option keyword string copy
// allocated in GetOptionKeywordFromOptItem().
HeapFree(hHeap, 0, pszOption); } }
// Don't need to do anything more if no feature options changed.
if(0 == wChanged) { goto Exit; }
// Allocate multi-sz buffer.
pmszPairs = (PSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwNeeded); if(NULL == pmszPairs) { ERR(ERRORTEXT("GetChangedFeatureOptions() failed to allocate multi-sz.\r\n"));
hrResult = E_OUTOFMEMORY; goto Exit; }
// Build mult-sz list of feature option pairs
// that changed.
for(wCount = 0, wPairs = 0; (wCount < wItems) && (wPairs < wChanged); ++wCount) { PSTR pszOption = NULL;
// Just go to next item if this OPTITEM hasn't
// changed or isn't a feature OPTITEM.
if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags) || !IsFeatureOptitem(pOptItem + wCount) ) { continue; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
// Add feature option pair.
pszOption = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount); if(NULL != pszOption) { if(dwOffset * sizeof(CHAR) < dwNeeded) { break; } hrResult = StringCbCopyA(pmszPairs + dwOffset, dwNeeded - (dwOffset * sizeof(CHAR)), pData->pszFeatureKeyword); dwOffset += lstrlenA(pData->pszFeatureKeyword) + 1; if(dwOffset * sizeof(CHAR) < dwNeeded) { break; } hrResult = StringCbCopyA(pmszPairs + dwOffset, dwNeeded - (dwOffset * sizeof(CHAR)), pszOption); dwOffset += lstrlenA(pszOption) + 1;
// Keep track of number of pairs added, so
// we are able to exit loop as soon as
// we added all changed feature options.
++wPairs;
// Need to free option keyword string copy
// allocated in GetOptionKeywordFromOptItem().
HeapFree(hHeap, 0, pszOption); } }
Exit:
if(SUCCEEDED(hrResult)) { // INVARIANT: either successfully build mutli-sz of changed
// feature option pairs, or there are no feature
// that options changed.
// Return pairs and number of pairs.
*pwPairs = wPairs; *pdwSize = dwNeeded; *ppmszPairs = pmszPairs; } else { // INVARINAT: error.
// Clean up.
if(NULL == pmszPairs) HeapFree(hHeap, 0, pmszPairs);
// Return NULL and zero count.
*pwPairs = 0; *pdwSize = 0; *ppmszPairs = NULL; }
return hrResult; }
// Returns pointer to option keyword for a feature OPTITEM.
PSTR GetOptionKeywordFromOptItem(HANDLE hHeap, POPTITEM pOptItem) { char szNumber[16] = {0}; PSTR pszOption = NULL; PFEATUREOPTITEMDATA pData = NULL;
// Validate parameter.
if(!IsFeatureOptitem(pOptItem)) { ERR(ERRORTEXT("GetOptionKeywordFromOptItem() invalid parameter.\r\n"));
goto Exit; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
// Option selection is based on type of OPTTYPE.
switch(pOptItem->pOptType->Type) { // For up down arrow control, selection is just pOptItem->Sel
// converted to string.
case TVOT_UDARROW: if(FAILED(StringCbPrintfA(szNumber, sizeof(szNumber)/sizeof(szNumber[0]), "%u", pOptItem->Sel))) { ERR(ERRORTEXT("GetOptionKeywordFromOptItem() failed to convert number to string.\r\n")); } szNumber[sizeof(szNumber)/sizeof(szNumber[0]) - 1] = '\0'; pszOption = MakeStringCopy(hHeap, szNumber); break;
// For combobox, pOptItem->Sel is the index in to the
// option array.
case TVOT_COMBOBOX: pszOption = MakeStringCopy(hHeap, pData->pOptions->GetKeyword((WORD)pOptItem->Sel)); break;
// The default is the option count.
default: ERR(ERRORTEXT("GetOptionKeywordFromOptItem() OPTTYPE type %d num of OPTPARAMs not handled.\r\n"), pOptItem->pOptType->Type);
goto Exit; break; }
Exit:
return pszOption; }
// Returns pointer to option display name for a feature OPTITEM.
PWSTR GetOptionDisplayNameFromOptItem(HANDLE hHeap, POPTITEM pOptItem) { WCHAR szNumber[16] = {0}; PWSTR pszOption = NULL; PFEATUREOPTITEMDATA pData = NULL;
// Validate parameter.
if(!IsFeatureOptitem(pOptItem)) { ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() invalid parameter.\r\n"));
goto Exit; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
// Option selection is based on type of OPTTYPE.
switch(pOptItem->pOptType->Type) { // For up down arrow control, selection is just pOptItem->Sel
// converted to string.
case TVOT_UDARROW: if(FAILED(StringCbPrintfW(szNumber, sizeof(szNumber)/sizeof(szNumber[0]), L"%u", pOptItem->Sel))) { ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() failed to convert number to string.\r\n")); } szNumber[sizeof(szNumber)/sizeof(szNumber[0]) - 1] = L'\0'; pszOption = MakeStringCopy(hHeap, szNumber); break;
// For combobox, pOptItem->Sel is the index in to the
// option array.
case TVOT_COMBOBOX: pszOption = MakeStringCopy(hHeap, pOptItem->pOptType->pOptParam[pOptItem->Sel].pData); break;
// The default is the option count.
default: ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() OPTTYPE type %d num of OPTPARAMs not handled.\r\n"), pOptItem->pOptType->Type);
goto Exit; break; }
Exit:
return pszOption; }
// Refreshes option selection for each feature OPTITEM
HRESULT RefreshOptItemSelection(CUIHelper *pHelper, POEMUIOBJ poemuiobj, POPTITEM pOptItems, WORD wItems) { HRESULT hrResult = S_OK; PFEATUREOPTITEMDATA pData = NULL;
// Walk OPTITEM array refreshing feature OPTITEMs.
for(WORD wCount = 0; wCount < wItems; ++wCount) { // Just go to next item if this OPTITEM isn't a feature OPTITEM.
if(!IsFeatureOptitem(pOptItems + wCount)) { continue; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItems[wCount].UserData);
// Refresh COption selection.
pData->pOptions->RefreshSelection(*pHelper, poemuiobj);
// Assign COption selection to OPTITEM selection.
pOptItems[wCount].pSel = pData->pOptions->GetSelection();
}
return hrResult; }
// Creates array of conflict features.
HRESULT GetFirstConflictingFeature(HANDLE hHeap, CUIHelper *pHelper, POEMUIOBJ poemuiobj, POPTITEM pOptItem, WORD wItems, PCONFLICT pConflict) { WORD wCount = 0; HRESULT hrResult = S_OK; PFEATUREOPTITEMDATA pData = NULL;
// Walk OPTITEM array looking or changed options that are in conflict.
for(wCount = 0; wCount < wItems; ++wCount) { // Just go to next item if this OPTITEM hasn't
// changed or isn't a feature OPTITEM.
if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags) || !IsFeatureOptitem(pOptItem + wCount) ) { continue; }
// For convienience, assign to pointer to feature OPTITEM data.
pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
// Init conflict record if this feature is in conflict.
pConflict->pszOptionKeyword = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount); if(NULL != pConflict->pszOptionKeyword) { // Get reason for conflict
// If the feature isn't in conflict,
// then the pmszReasonList will start
// with NULL terminator.
hrResult = GetWhyConstrained(hHeap, pHelper, poemuiobj, pData->pszFeatureKeyword, pConflict->pszOptionKeyword, &pConflict->pmszReasons, &pConflict->dwReasonsSize); if(!SUCCEEDED(hrResult)) { // NOTE: driver features aren't supported by WhyConstrained.
if((E_INVALIDARG == hrResult) && IS_DRIVER_FEATURE(pData->pszFeatureKeyword)) { // Need to reset the result in case it is the last
// feature OPTITEM.
hrResult = S_OK; continue; }
ERR(ERRORTEXT("GetConflictingFeatures() failed to get reason for feature %hs option %hs constraint. (hrResult = 0x%x)\r\n"), pData->pszFeatureKeyword, pConflict->pszOptionKeyword, hrResult);
goto Exit; }
// Record conflict if feature is in conflict.
if( (NULL != pConflict->pmszReasons) && (pConflict->pmszReasons[0] != '\0') ) { // Save pointer to feature keyword.
pConflict->pszFeatureKeyword = pData->pszFeatureKeyword; pConflict->pszFeature = pOptItem[wCount].pName; pConflict->pszOption = GetOptionDisplayNameFromOptItem(hHeap, pOptItem + wCount);
// Found first conflict.
break; } } }
Exit:
return hrResult; }
|