Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2827 lines
92 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright 2001 - 2003 Microsoft Corporation. All Rights Reserved.
  7. //
  8. // FILE: Features.cpp
  9. //
  10. //
  11. // PURPOSE: Implementation wrapper class for WinXP PS Driver Features and Options.
  12. //
  13. //
  14. //
  15. // PLATFORMS: Windows XP, Windows Server 2003
  16. //
  17. //
  18. #include "precomp.h"
  19. #include "debug.h"
  20. #include "oemui.h"
  21. #include "stringutils.h"
  22. #include "features.h"
  23. #include "resource.h"
  24. // StrSafe.h needs to be included last
  25. // to disallow bad string functions.
  26. #include <STRSAFE.H>
  27. ////////////////////////////////////////////////////////
  28. // Internal Defines and Macros
  29. ////////////////////////////////////////////////////////
  30. #define INITIAL_ENUM_FEATURES_SIZE 1024
  31. #define INITIAL_ENUM_OPTIONS_SIZE 64
  32. #define INITIAL_FEATURE_DISPLAY_NAME_SIZE 64
  33. #define INITIAL_OPTION_DISPLAY_NAME_SIZE 32
  34. #define INITIAL_GET_OPTION_SIZE 64
  35. #define INITIAL_GET_REASON_SIZE 1024
  36. #define DRIVER_FEATURE_PREFIX '%'
  37. #define IS_DRIVER_FEATURE(f) (DRIVER_FEATURE_PREFIX == (f)[0])
  38. // Flags that the uDisplayNameID should be returned as
  39. // MAKEINTRESOURCE() instead of loading the string resource.
  40. #define RETURN_INT_RESOURCE 1
  41. // Macros to test for conditions of KEYWORDMAP entry.
  42. #define IS_MAPPING_INT_RESOURCE(p) ((p)->dwFlags & RETURN_INT_RESOURCE)
  43. // TAG the identifies feature OPTITEM data stuct.
  44. #define FEATURE_OPTITEM_TAG 'FETR'
  45. ////////////////////////////////////////////////////////
  46. // Type Definitions
  47. ////////////////////////////////////////////////////////
  48. // Struct used to identify OPTITEM as
  49. // feature OPTITEM and to map back from
  50. // an OPTITEM to the feature.
  51. typedef struct _tagFeatureOptitemData
  52. {
  53. DWORD dwSize;
  54. DWORD dwTag;
  55. PCSTR pszFeatureKeyword;
  56. COptions *pOptions;
  57. } FEATUREOPTITEMDATA, *PFEATUREOPTITEMDATA;
  58. ////////////////////////////////////////////////////////
  59. // Internal Constants
  60. ////////////////////////////////////////////////////////
  61. static KEYWORDMAP gkmFeatureMap[] =
  62. {
  63. "%AddEuro", NULL, IDS_ADD_EURO, OEMCUIP_PRNPROP, 0,
  64. "%CtrlDAfter", NULL, IDS_CTRLD_AFTER, OEMCUIP_PRNPROP, 0,
  65. "%CtrlDBefore", NULL, IDS_CTRLD_BEFORE, OEMCUIP_PRNPROP, 0,
  66. //"%CustomPageSize", NULL, IDS_PSCRIPT_CUSTOMSIZE, OEMCUIP_DOCPROP, 0,
  67. "%GraphicsTrueGray", NULL, IDS_TRUE_GRAY_GRAPH, OEMCUIP_PRNPROP, 0,
  68. "%JobTimeout", NULL, IDS_JOBTIMEOUT, OEMCUIP_PRNPROP, 0,
  69. "%MaxFontSizeAsBitmap", NULL, IDS_PSMAXBITMAP, OEMCUIP_PRNPROP, 0,
  70. "%MetafileSpooling", NULL, IDS_METAFILE_SPOOLING, OEMCUIP_DOCPROP, 0,
  71. "%MinFontSizeAsOutline", NULL, IDS_PSMINOUTLINE, OEMCUIP_PRNPROP, 0,
  72. "%Mirroring", NULL, IDS_MIRROR, OEMCUIP_DOCPROP, 0,
  73. "%Negative", NULL, IDS_NEGATIVE_PRINT, OEMCUIP_DOCPROP, 0,
  74. "%Orientation", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ORIENTATION, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE,
  75. "%OutputFormat", NULL, IDS_PSOUTPUT_OPTION, OEMCUIP_DOCPROP, 0,
  76. "%OutputProtocol", NULL, IDS_PSPROTOCOL, OEMCUIP_PRNPROP, 0,
  77. "%OutputPSLevel", NULL, IDS_PSLEVEL, OEMCUIP_DOCPROP, 0,
  78. "%PageOrder", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PAGEORDER, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE,
  79. "%PagePerSheet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP, OEMCUIP_DOCPROP, RETURN_INT_RESOURCE,
  80. "%PSErrorHandler", NULL, IDS_PSERROR_HANDLER, OEMCUIP_DOCPROP, 0,
  81. "%PSMemory", NULL, IDS_POSTSCRIPT_VM, OEMCUIP_PRNPROP, 0,
  82. "%TextTrueGray", NULL, IDS_TRUE_GRAY_TEXT, OEMCUIP_PRNPROP, 0,
  83. "%TTDownloadFormat", NULL, IDS_PSTT_DLFORMAT, OEMCUIP_DOCPROP, 0,
  84. "%WaitTimeout", NULL, IDS_WAITTIMEOUT, OEMCUIP_PRNPROP, 0,
  85. };
  86. static const NUM_FEATURE_MAP = (sizeof(gkmFeatureMap)/sizeof(gkmFeatureMap[0]));
  87. static KEYWORDMAP gkmOptionMap[] =
  88. {
  89. "True", TEXT("COMPSTUI.DLL"), IDS_CPSUI_TRUE, 0, RETURN_INT_RESOURCE,
  90. "False", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FALSE, 0, RETURN_INT_RESOURCE,
  91. "Portrait", TEXT("COMPSTUI.DLL"), IDS_CPSUI_PORTRAIT, 0, RETURN_INT_RESOURCE,
  92. "Landscape", TEXT("COMPSTUI.DLL"), IDS_CPSUI_LANDSCAPE, 0, RETURN_INT_RESOURCE,
  93. "RotatedLandscape", TEXT("COMPSTUI.DLL"), IDS_CPSUI_ROT_LAND, 0, RETURN_INT_RESOURCE,
  94. "Speed", NULL, IDS_PSOPT_SPEED, 0, RETURN_INT_RESOURCE,
  95. "Portability", NULL, IDS_PSOPT_PORTABILITY, 0, 0,
  96. "EPS", NULL, IDS_PSOPT_EPS, 0, 0,
  97. "Archive", NULL, IDS_PSOPT_ARCHIVE, 0, 0,
  98. "ASCII", NULL, IDS_PSPROTOCOL_ASCII, 0, 0,
  99. "BCP", NULL, IDS_PSPROTOCOL_BCP, 0, 0,
  100. "TBCP", NULL, IDS_PSPROTOCOL_TBCP, 0, 0,
  101. "Binary", NULL, IDS_PSPROTOCOL_BINARY, 0, 0,
  102. "FrontToBack", TEXT("COMPSTUI.DLL"), IDS_CPSUI_FRONTTOBACK, 0, RETURN_INT_RESOURCE,
  103. "BackToFront", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BACKTOFRONT, 0, RETURN_INT_RESOURCE,
  104. "1", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NORMAL, 0, RETURN_INT_RESOURCE,
  105. "2", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_TWOUP, 0, RETURN_INT_RESOURCE,
  106. "4", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_FOURUP, 0, RETURN_INT_RESOURCE,
  107. "6", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXUP, 0, RETURN_INT_RESOURCE,
  108. "9", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_NINEUP, 0, RETURN_INT_RESOURCE,
  109. "16", TEXT("COMPSTUI.DLL"), IDS_CPSUI_NUP_SIXTEENUP, 0, RETURN_INT_RESOURCE,
  110. "Booklet", TEXT("COMPSTUI.DLL"), IDS_CPSUI_BOOKLET, 0, RETURN_INT_RESOURCE,
  111. "Automatic", NULL, IDS_TTDL_DEFAULT, 0, 0,
  112. "Outline", NULL, IDS_TTDL_TYPE1, 0, 0,
  113. "Bitmap", NULL, IDS_TTDL_TYPE3, 0, 0,
  114. "NativeTrueType", NULL, IDS_TTDL_TYPE42, 0, 0,
  115. };
  116. static const NUM_OPTION_MAP = (sizeof(gkmOptionMap)/sizeof(gkmOptionMap[0]));
  117. ////////////////////////////////////////////
  118. //
  119. // COptions Methods
  120. //
  121. //
  122. // Private Methods
  123. //
  124. // Initializes class data members.
  125. void COptions::Init()
  126. {
  127. m_wOptions = 0;
  128. m_cType = TVOT_COMBOBOX;
  129. m_pmszRaw = NULL;
  130. m_pszFeature = NULL;
  131. m_ppszOptions = NULL;
  132. m_ptRange.x = 0;
  133. m_ptRange.y = 0;
  134. m_dwSize = 0;
  135. m_pszUnits = NULL;
  136. m_hHeap = NULL;
  137. m_pInfo = NULL;
  138. }
  139. void COptions::Clear()
  140. {
  141. // Free memory associated with data members.
  142. if(NULL != m_pmszRaw) HeapFree(m_hHeap, 0, m_pmszRaw);
  143. if(NULL != m_ppszOptions) HeapFree(m_hHeap, 0, m_ppszOptions);
  144. if( (NULL != m_pszUnits) && !IS_INTRESOURCE(m_pszUnits)) HeapFree(m_hHeap, 0, m_pszUnits);
  145. // Free option info.
  146. FreeOptionInfo();
  147. // Initialize data members.
  148. Init();
  149. }
  150. // Frees memory associated with Option Info array.
  151. void COptions::FreeOptionInfo()
  152. {
  153. // Validate parameters.
  154. if( (NULL == m_hHeap)
  155. ||
  156. (NULL == m_pInfo)
  157. )
  158. {
  159. return;
  160. }
  161. // Free strings in the array.
  162. for(WORD wIndex = 0; wIndex < m_wOptions; ++wIndex)
  163. {
  164. PWSTR pszDisplay = m_pInfo[wIndex].pszDisplayName;
  165. if( (NULL != pszDisplay)
  166. &&
  167. !(IS_INTRESOURCE(pszDisplay))
  168. )
  169. {
  170. HeapFree(m_hHeap, 0, pszDisplay);
  171. }
  172. }
  173. // Free the array.
  174. HeapFree(m_hHeap, 0, m_pInfo);
  175. m_pInfo = NULL;
  176. }
  177. // Will do init for features that need special handling.
  178. HRESULT COptions::GetOptionsForSpecialFeatures(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  179. {
  180. HRESULT hrResult = E_NOTIMPL;
  181. // See if this is a special feature.
  182. // If it is, then call the special option init for the
  183. // feature.
  184. if(!lstrcmpA(m_pszFeature, "%CustomPageSize"))
  185. {
  186. // There is no option init for CustomPageSize.
  187. // The item itself must be handled specially.
  188. hrResult = S_OK;
  189. }
  190. else if( !lstrcmpA(m_pszFeature, "%JobTimeout")
  191. ||
  192. !lstrcmpA(m_pszFeature, "%WaitTimeout")
  193. )
  194. {
  195. // JobTimeout and WaitTimeout feature options are string representations
  196. // of an integer that represents number of seconds in the range 0 through
  197. // 2,147,483,647 (i.e. LONG_MAX). However, COMPSTUI limits us to
  198. // WORD size, which has range of 0 to 32,767 (i.e. SHRT_MAX).
  199. m_cType = TVOT_UDARROW;
  200. m_ptRange.x = 0;
  201. m_ptRange.y = SHRT_MAX;
  202. hrResult = GetOptionSelectionShort(Helper, poemuiobj);
  203. if(!SUCCEEDED(hrResult))
  204. {
  205. ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"),
  206. m_pszFeature,
  207. hrResult);
  208. goto Exit;
  209. }
  210. }
  211. else if( !lstrcmpA(m_pszFeature, "%MaxFontSizeAsBitmap")
  212. ||
  213. !lstrcmpA(m_pszFeature, "%MinFontSizeAsOutline")
  214. )
  215. {
  216. // MaxFontSizeAsBitmap, and MinFontSizeAsOutline feature options
  217. // are string representations of an integer that represents number
  218. // of pixels in the range 0 through 32,767 (i.e. SHRT_MAX).
  219. m_cType = TVOT_UDARROW;
  220. m_ptRange.x = 0;
  221. m_ptRange.y = SHRT_MAX;
  222. hrResult = GetOptionSelectionShort(Helper, poemuiobj);
  223. if(!SUCCEEDED(hrResult))
  224. {
  225. ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"),
  226. m_pszFeature,
  227. hrResult);
  228. goto Exit;
  229. }
  230. }
  231. else if( !lstrcmpA(m_pszFeature, "%PSMemory") )
  232. {
  233. DWORD dwType;
  234. DWORD dwLevel;
  235. DWORD dwNeeded;
  236. // PSMemory option is string representation of an integer
  237. // that represents number of seconds in the range 0
  238. // through 32,767 (i.e. SHRT_MAX).
  239. // However, the minimum is 172 KB for Level 1 and 249 KB for level 2
  240. m_cType = TVOT_UDARROW;
  241. m_ptRange.y = SHRT_MAX;
  242. hrResult = GetOptionSelectionShort(Helper, poemuiobj);
  243. if(!SUCCEEDED(hrResult))
  244. {
  245. ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"),
  246. m_pszFeature,
  247. hrResult);
  248. goto Exit;
  249. }
  250. // Get the global attribute for max language level.
  251. hrResult = Helper.GetGlobalAttribute(poemuiobj,
  252. 0,
  253. "LanguageLevel",
  254. &dwType,
  255. (PBYTE) &dwLevel,
  256. sizeof(dwLevel),
  257. &dwNeeded);
  258. if(!SUCCEEDED(hrResult))
  259. {
  260. ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get global attribute \"LanguageLevel\". (hrResult = 0x%x)\r\n"),
  261. hrResult);
  262. goto Exit;
  263. }
  264. // Set minimum range based on PS Max Language level.
  265. switch(dwLevel)
  266. {
  267. case 1:
  268. m_ptRange.x = 172;
  269. break;
  270. default:
  271. case 2:
  272. case 3:
  273. m_ptRange.x = 249;
  274. break;
  275. }
  276. // Get Units string.
  277. //GetStringResource(m_pszUnits
  278. }
  279. else if(!lstrcmpA(m_pszFeature, "%OutputPSLevel"))
  280. {
  281. hrResult = GetOptionsForOutputPSLevel(Helper, poemuiobj);
  282. if(!SUCCEEDED(hrResult))
  283. {
  284. ERR(ERRORTEXT("COptions::GetOptionsForSpecialFeatures() failed to get current selection for feature %hs. (hrResult = 0x%x)\r\n"),
  285. m_pszFeature,
  286. hrResult);
  287. goto Exit;
  288. }
  289. }
  290. Exit:
  291. return hrResult;
  292. }
  293. // Do init for PS Level options.
  294. HRESULT COptions::GetOptionsForOutputPSLevel(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  295. {
  296. WORD wCount = 0;
  297. DWORD dwLevel = 0;
  298. DWORD dwType = -1;
  299. DWORD dwNeeded = 0;
  300. HRESULT hrResult = E_NOTIMPL;
  301. // PS Level is integers from 1 to "LanguageLevel"
  302. // global atribute.
  303. m_cType = TVOT_COMBOBOX;
  304. // Get the global attribute for max language level.
  305. hrResult = Helper.GetGlobalAttribute(poemuiobj,
  306. 0,
  307. "LanguageLevel",
  308. &dwType,
  309. (PBYTE) &dwLevel,
  310. sizeof(dwLevel),
  311. &dwNeeded);
  312. if(!SUCCEEDED(hrResult))
  313. {
  314. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to get global attribute \"LanguageLevel\". (hrResult = 0x%x)\r\n"),
  315. hrResult);
  316. goto Exit;
  317. }
  318. //
  319. // Create Options for PS Level
  320. //
  321. // Set the number of options to the PS Level supported.
  322. m_wOptions = (WORD) dwLevel;
  323. // Allocate keyword list.
  324. // Allocate memory for pointer to keyword and the keyword itself, so that
  325. // the memory for the keyword strings will get de-allocated with the keyword list
  326. // on object destruction, just like regular features for which EnumOptions works.
  327. // User the size of a pointer (4 bytes on x86, and 8 on IA64) so that
  328. // it begining of the keyword strings will be DWORD or QUADWORD aligned
  329. // for x86 and IA64 respectively. Keyword strings aren't required to
  330. // be DWORD or QUADWORD aligned, but it is more optimal. Also, this gives
  331. // some additional space for the case of %OutputPSLevel keywords, which are
  332. // in the range of 1 through the max PostScript level supported, and only
  333. // require 2 CHARs (1 for the digit and one for the NULL terminator).
  334. m_ppszOptions = (PCSTR *) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * ( sizeof(PSTR) + sizeof(PCSTR *) ) );
  335. if(NULL == m_ppszOptions)
  336. {
  337. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate option keyword array for PS Level.\r\n"));
  338. hrResult = E_OUTOFMEMORY;
  339. goto Exit;
  340. }
  341. // Allocate option info array.
  342. m_pInfo = (POPTION_INFO) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * sizeof(OPTION_INFO));
  343. if(NULL == m_pInfo)
  344. {
  345. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate info array for PS Level.\r\n"));
  346. hrResult = E_OUTOFMEMORY;
  347. goto Exit;
  348. }
  349. // Init the option info.
  350. for(wCount = 0; wCount < m_wOptions; ++wCount)
  351. {
  352. // Init keyword.
  353. // The memory for both the keyword list and the keyword strings was allocated above.
  354. m_ppszOptions[wCount] = (PSTR)(m_ppszOptions + m_wOptions) + (sizeof(PSTR) * wCount);
  355. hrResult = StringCbPrintfA(const_cast<PSTR>(m_ppszOptions[wCount]), sizeof(PSTR), "%d", wCount + 1);
  356. if(FAILED(hrResult))
  357. {
  358. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to string representation of item %d.\r\n"),
  359. wCount + 1);
  360. goto Exit;
  361. }
  362. // Init option display name.
  363. m_pInfo[wCount].pszDisplayName = (PWSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, 2 * sizeof(WCHAR));
  364. if(NULL == m_pInfo[wCount].pszDisplayName)
  365. {
  366. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to allocate display string for Level %d.\r\n"),
  367. wCount);
  368. hrResult = E_OUTOFMEMORY;
  369. goto Exit;
  370. }
  371. // Init option display name.
  372. hrResult = StringCchPrintfW(m_pInfo[wCount].pszDisplayName, 2, TEXT("%d"), wCount + 1);
  373. if(FAILED(hrResult))
  374. {
  375. ERR(ERRORTEXT("COptions::GetOptionsForOutputPSLevel() failed to create display name for item %d.\r\n"),
  376. wCount + 1);
  377. goto Exit;
  378. }
  379. }
  380. //
  381. // Get Current Selection
  382. //
  383. hrResult = GetOptionSelectionIndex(Helper, poemuiobj);
  384. Exit:
  385. // Don't need to clean up memory allocation on error, since
  386. // all memory allocated are assigned to data members, which
  387. // will be cleaned up in the object destructor.
  388. return hrResult;
  389. }
  390. HRESULT COptions::GetOptionSelectionString(CUIHelper &Helper, POEMUIOBJ poemuiobj, PSTR *ppszSel)
  391. {
  392. PSTR pmszFeature = NULL;
  393. PSTR pmszBuf = NULL;
  394. WORD wCount = 0;
  395. PCSTR *ppszList = NULL;
  396. DWORD dwFeatureSize = 0;
  397. DWORD dwNeeded = 0;
  398. DWORD dwSize = INITIAL_GET_OPTION_SIZE;
  399. HRESULT hrResult = S_OK;
  400. //
  401. // Make single feature multi-sz.
  402. //
  403. // Allocate singe feature multi-sz buffer.
  404. dwFeatureSize = lstrlenA(m_pszFeature) + 2;
  405. pmszFeature = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, dwFeatureSize);
  406. if(NULL == pmszFeature)
  407. {
  408. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to allocate buffer for single feature multi-sz for feature %hs.\r\n"),
  409. m_pszFeature);
  410. hrResult = E_OUTOFMEMORY;
  411. goto Exit;
  412. }
  413. // Just need to do a regular string copy, since the buffer is already zero filled.
  414. hrResult = StringCbCopyA(pmszFeature, dwFeatureSize, m_pszFeature);
  415. if(FAILED(hrResult))
  416. {
  417. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to copy feature string %hs.\r\n"), m_pszFeature);
  418. }
  419. // Allocated initial buffer of reasonible size.
  420. pmszBuf = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, dwSize);
  421. if(NULL == pmszBuf)
  422. {
  423. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to allocate buffer to get current setting for feature %hs.\r\n"),
  424. m_pszFeature);
  425. hrResult = E_OUTOFMEMORY;
  426. goto Exit;
  427. }
  428. // Get current option selection.
  429. hrResult = Helper.GetOptions(poemuiobj,
  430. 0,
  431. pmszFeature,
  432. dwFeatureSize,
  433. pmszBuf,
  434. dwSize,
  435. &dwNeeded);
  436. if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded) )
  437. {
  438. PSTR pTemp = NULL;
  439. // INVARIANT: initial buffer not large enough.
  440. // Re-alloc buffer and try again.
  441. pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, pmszBuf, dwNeeded);
  442. if(NULL == pTemp)
  443. {
  444. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to re-allocate buffer to get current setting for feature %hs.\r\n"),
  445. m_pszFeature);
  446. hrResult = E_OUTOFMEMORY;
  447. goto Exit;
  448. }
  449. pmszBuf = pTemp;
  450. // Try to get current option selection again.
  451. hrResult = Helper.GetOptions(poemuiobj,
  452. 0,
  453. pmszFeature,
  454. dwFeatureSize,
  455. pmszBuf,
  456. dwNeeded,
  457. &dwNeeded);
  458. }
  459. if(!SUCCEEDED(hrResult))
  460. {
  461. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to get current setting for feature %hs. (hrResult = 0x%x)\r\n"),
  462. m_pszFeature,
  463. hrResult);
  464. goto Exit;
  465. }
  466. // NOTE: The return string from GetOptions() may return
  467. // contain no strings and not return a HRESULT error
  468. // when the feature isn't supported in the current document or
  469. // printer sticky mode.
  470. if('\0' == pmszBuf[0])
  471. {
  472. // Feature not supported for this sticky mode.
  473. goto Exit;
  474. }
  475. // Parse the results buffer to see what the current setting is.
  476. hrResult = MakeStrPtrList(m_hHeap, pmszBuf, &ppszList, &wCount);
  477. if(!SUCCEEDED(hrResult))
  478. {
  479. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to make string list for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"),
  480. m_pszFeature,
  481. hrResult);
  482. goto Exit;
  483. }
  484. // Check that we got 2 strings back.
  485. if(2 != wCount)
  486. {
  487. 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"),
  488. m_pszFeature,
  489. wCount);
  490. // Bail if we don't have at least 2 strings.
  491. if(2 > wCount)
  492. {
  493. goto Exit;
  494. }
  495. }
  496. // Return copy of just the GetOption() result.
  497. *ppszSel = MakeStringCopy(m_hHeap, ppszList[1]);
  498. if(NULL == *ppszSel)
  499. {
  500. ERR(ERRORTEXT("COptions::GetOptionSelectionString() failed to duplicate string GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"),
  501. m_pszFeature,
  502. hrResult);
  503. hrResult = E_OUTOFMEMORY;
  504. goto Exit;
  505. }
  506. Exit:
  507. // Free local buffers.
  508. if(NULL != pmszFeature) HeapFree(m_hHeap, 0, pmszFeature);
  509. if(NULL != pmszBuf) HeapFree(m_hHeap, 0, pmszBuf);
  510. if(NULL != ppszList) HeapFree(m_hHeap, 0, ppszList);
  511. return hrResult;
  512. }
  513. // Gets current Options selection for LONG value.
  514. HRESULT COptions::GetOptionSelectionLong(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  515. {
  516. PSTR pszSel = NULL;
  517. HRESULT hrResult = S_OK;
  518. // Get option selection string.
  519. hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel);
  520. if(!SUCCEEDED(hrResult))
  521. {
  522. ERR(ERRORTEXT("COptions::GetOptionSelectionLong() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"),
  523. m_pszFeature,
  524. hrResult);
  525. goto Exit;
  526. }
  527. // Convert string option to LONG and uses that as the selection.
  528. if(NULL != pszSel) m_Sel = atol(pszSel);
  529. Exit:
  530. // Free local buffers.
  531. if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
  532. return hrResult;
  533. }
  534. // Gets current Options selection for SHORT value.
  535. HRESULT COptions::GetOptionSelectionShort(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  536. {
  537. PSTR pszSel = NULL;
  538. HRESULT hrResult = S_OK;
  539. // Get option selection string.
  540. hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel);
  541. if(!SUCCEEDED(hrResult))
  542. {
  543. ERR(ERRORTEXT("COptions::GetOptionSelectionLong() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"),
  544. m_pszFeature,
  545. hrResult);
  546. goto Exit;
  547. }
  548. // Convert string option to LONG and uses that as the selection.
  549. if(NULL != pszSel) m_Sel = atoi(pszSel) & 0x00ffff;
  550. Exit:
  551. // Free local buffers.
  552. if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
  553. return hrResult;
  554. }
  555. // Gets current option selection for feature.
  556. HRESULT COptions::GetOptionSelectionIndex(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  557. {
  558. PSTR pszSel = NULL;
  559. HRESULT hrResult = S_OK;
  560. // Get option selection string.
  561. hrResult = GetOptionSelectionString(Helper, poemuiobj, &pszSel);
  562. if(!SUCCEEDED(hrResult))
  563. {
  564. ERR(ERRORTEXT("COptions::GetOptionSelectionIndex() failed to get string for GetOptions() return for feature %hs. (hrResult = 0x%x)\r\n"),
  565. m_pszFeature,
  566. hrResult);
  567. goto Exit;
  568. }
  569. // Find the matching option for the string returned from GetOption.
  570. m_Sel = FindOption(pszSel, m_wOptions - 1);
  571. Exit:
  572. // Free local buffers.
  573. if(NULL != pszSel) HeapFree(m_hHeap, 0, pszSel);
  574. return hrResult;
  575. }
  576. //
  577. // Public Methods
  578. //
  579. // Default constructor
  580. COptions::COptions()
  581. {
  582. Init();
  583. }
  584. // Destructor
  585. COptions::~COptions()
  586. {
  587. Clear();
  588. }
  589. // Get the option list for a feature
  590. HRESULT COptions::Acquire(HANDLE hHeap,
  591. CUIHelper &Helper,
  592. POEMUIOBJ poemuiobj,
  593. PCSTR pszFeature)
  594. {
  595. DWORD dwNeeded = 0;
  596. HRESULT hrResult = S_OK;
  597. VERBOSE(DLLTEXT("COptions::Acquire(0x%p, Helper, 0x%p, %hs) entered.\r\n"),
  598. hHeap,
  599. poemuiobj,
  600. pszFeature ? pszFeature : "NULL");
  601. // Don't retreive the Options again if we already got them.
  602. if( (0 < m_wOptions)
  603. &&
  604. (NULL != m_pszFeature)
  605. &&
  606. !lstrcmpA(m_pszFeature, pszFeature)
  607. )
  608. {
  609. VERBOSE(DLLTEXT("COptions::Acquire() already have options for feature %hs.\r\n"), m_pszFeature);
  610. VERBOSE(DLLTEXT("COptions::Acquire() returning with HRESULT of S_OK\r\n"));
  611. return S_OK;
  612. }
  613. // Save the heap handle for use later, such as freeing memory at destruction.
  614. m_hHeap = hHeap;
  615. // Store Keyword string.
  616. m_pszFeature = pszFeature;
  617. //
  618. // Enumerate Options.
  619. //
  620. // Some features require special handling for initializing their options.
  621. // EnumOpionts isn't implemented for these features.
  622. // Return of E_NOTIMPL indicates it isn't the feature doesn't
  623. // need special handling.
  624. hrResult = GetOptionsForSpecialFeatures(Helper, poemuiobj);
  625. if( SUCCEEDED(hrResult)
  626. ||
  627. (!SUCCEEDED(hrResult) && (E_NOTIMPL != hrResult) )
  628. )
  629. {
  630. // We either dealt with the special feature or incounter an error
  631. // trying to deal with the special feature.
  632. goto Exit;
  633. }
  634. // To try to cut down on having to call EnumOptions more than once,
  635. // pre-allocate a buffer of reasonable size.
  636. m_dwSize = INITIAL_ENUM_OPTIONS_SIZE;
  637. m_pmszRaw = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_dwSize);
  638. if(NULL == m_pmszRaw)
  639. {
  640. ERR(ERRORTEXT("COptions::Acquire() alloc for options for feature %hs failed.\r\n"), m_pszFeature);
  641. hrResult = E_OUTOFMEMORY;
  642. goto Exit;
  643. }
  644. // Try to get options list with initial buffer.
  645. hrResult = Helper.EnumOptions(poemuiobj, 0, m_pszFeature, m_pmszRaw, m_dwSize, &dwNeeded);
  646. if( (E_OUTOFMEMORY == hrResult) && (m_dwSize < dwNeeded))
  647. {
  648. PSTR pTemp;
  649. // INVARIANT: options list multi-sz wasn't large enough.
  650. // Re-allocate the buffer and try again.
  651. pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_pmszRaw, dwNeeded);
  652. if(NULL == pTemp)
  653. {
  654. ERR(ERRORTEXT("COptions::Acquire() re-alloc for options list for feature %hs failed.\r\n"), m_pszFeature);
  655. hrResult = E_OUTOFMEMORY;
  656. goto Exit;
  657. }
  658. m_pmszRaw = pTemp;
  659. m_dwSize = dwNeeded;
  660. // Try again to get the options list.
  661. hrResult = Helper.EnumOptions(poemuiobj, 0, m_pszFeature, m_pmszRaw, m_dwSize, &dwNeeded);
  662. if(!SUCCEEDED(hrResult))
  663. {
  664. ERR(ERRORTEXT("COptions::Acquire() failed to EnumOptions() for feature %hs after re-allocating buffer.\r\n"), m_pszFeature);
  665. goto Exit;
  666. }
  667. }
  668. // Make sure we got the option list.
  669. // Can't do anything more with out it.
  670. if(!SUCCEEDED(hrResult))
  671. {
  672. if(E_NOTIMPL != hrResult) ERR(ERRORTEXT("COptions::Acquire() failed to enumerate options for feature %hs. (hrResult = 0x%x)\r\n"), m_pszFeature, hrResult);
  673. goto Exit;
  674. }
  675. // INVARIANT: successfully got option keyword list.
  676. // Create array of string pointers to the Option names
  677. // in the multi-sz we got from EnumOptions().
  678. hrResult = MakeStrPtrList(m_hHeap, m_pmszRaw, &m_ppszOptions, &m_wOptions);
  679. if(!SUCCEEDED(hrResult))
  680. {
  681. ERR(ERRORTEXT("COptions::Acquire() failed to create pointer list to options. (hrResult = 0x%x)\r\n"), hrResult);
  682. goto Exit;
  683. }
  684. //
  685. // Build Option Information
  686. //
  687. // Allocate array to hold feature info
  688. m_pInfo = (POPTION_INFO) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_wOptions * sizeof(OPTION_INFO));
  689. if(NULL == m_pInfo)
  690. {
  691. ERR(ERRORTEXT("COptions::Acquire() failed to alloc feature info array.\r\n"));
  692. hrResult = E_OUTOFMEMORY;
  693. goto Exit;
  694. }
  695. // For each option, build or get useful information, such as display name.
  696. for(WORD wIndex = 0; wIndex < m_wOptions; ++wIndex)
  697. {
  698. POPTION_INFO pCurrent = m_pInfo + wIndex;
  699. // Get or build a keyword mapping entry
  700. // that maps from keyword to usefully where to get info, such as
  701. // display name, icon, option type, for keywords that may not be
  702. // able to get info for from Helper.
  703. pCurrent->pMapping = FindKeywordMapping(gkmOptionMap, NUM_OPTION_MAP, m_ppszOptions[wIndex]);
  704. // Get display names for each of the Options.
  705. // The function implements a heuristic for detemining the display name,
  706. // since can't get the display name from the UI Helper for all Options.
  707. hrResult = DetermineOptionDisplayName(m_hHeap,
  708. Helper,
  709. poemuiobj,
  710. m_pszFeature,
  711. m_ppszOptions[wIndex],
  712. pCurrent->pMapping,
  713. &pCurrent->pszDisplayName);
  714. if(!SUCCEEDED(hrResult))
  715. {
  716. ERR(ERRORTEXT("COptions::Acquire() failed to get display name for %hs of feature %hs. (hrResult = 0x%x)\r\n"),
  717. m_ppszOptions[wIndex],
  718. m_pszFeature,
  719. hrResult);
  720. goto Exit;
  721. }
  722. }
  723. //
  724. // Get current option selection.
  725. //
  726. hrResult = GetOptionSelectionIndex(Helper, poemuiobj);
  727. Exit:
  728. // Clean up if weren't successful.
  729. if(!SUCCEEDED(hrResult))
  730. {
  731. Clear();
  732. }
  733. VERBOSE(DLLTEXT("COptions::Acquire() returning with HRESULT of 0x%x\r\n"), hrResult);
  734. return hrResult;
  735. }
  736. // Return nth options keyword.
  737. PCSTR COptions::GetKeyword(WORD wIndex) const
  738. {
  739. // Validate parameters.
  740. if( (wIndex >= m_wOptions)
  741. ||
  742. (NULL == m_ppszOptions)
  743. )
  744. {
  745. return NULL;
  746. }
  747. return m_ppszOptions[wIndex];
  748. }
  749. // Return nth options display name.
  750. PCWSTR COptions::GetName(WORD wIndex) const
  751. {
  752. // Validate parameters.
  753. if( (wIndex >= m_wOptions)
  754. ||
  755. (NULL == m_pInfo)
  756. )
  757. {
  758. ERR(ERRORTEXT("COptions::GetName() invalid parameters.\r\n"));
  759. return NULL;
  760. }
  761. if(NULL == m_pInfo[wIndex].pszDisplayName) ERR(ERRORTEXT("COptions::GetName() returning NULL option display name.\r\n"));
  762. return m_pInfo[wIndex].pszDisplayName;
  763. }
  764. // Find option with matching keyword string.
  765. WORD COptions::FindOption(PCSTR pszOption, WORD wDefault) const
  766. {
  767. BOOL bFound = FALSE;
  768. WORD wMatch = wDefault;
  769. // Validate parameters.
  770. if( (NULL == pszOption)
  771. ||
  772. (NULL == m_ppszOptions)
  773. )
  774. {
  775. return wDefault;
  776. }
  777. // Walk the option keyword looking for a match.
  778. for(WORD wIndex = 0; !bFound && (wIndex < m_wOptions); ++wIndex)
  779. {
  780. bFound = !lstrcmpA(pszOption, m_ppszOptions[wIndex]);
  781. if(bFound)
  782. {
  783. wMatch = wIndex;
  784. }
  785. }
  786. return wMatch;
  787. }
  788. // Initializes OptItem with options for a feature.
  789. HRESULT COptions::InitOptItem(HANDLE hHeap, POPTITEM pOptItem)
  790. {
  791. WORD wParams = 0;
  792. WORD wOptions = 0;
  793. HRESULT hrResult = S_OK;
  794. // Set option selection.
  795. pOptItem->pSel = m_pSel;
  796. // Get count of number of options.
  797. // NOTE: Some feature options have no counts.
  798. wOptions = GetCount();
  799. // Different OPTTYPE types require different number of OPTPARAMs.
  800. switch(m_cType)
  801. {
  802. // For up down arrow control, the OPTPARAMs need is 2.
  803. case TVOT_UDARROW:
  804. wParams = 2;
  805. break;
  806. // For combobox, the OPTPARAMs needed is on per options.
  807. case TVOT_COMBOBOX:
  808. wParams = wOptions;
  809. break;
  810. // The default is the option count.
  811. default:
  812. WARNING(DLLTEXT("COptions::InitOptItem() OPTTYPE type %d num of OPTPARAMs not handled. Default to option count of %d.\r\n"),
  813. m_cType,
  814. wOptions);
  815. wParams = wOptions;
  816. break;
  817. }
  818. // Only do OPTTYPEs if we have non-Zero number of OPTPARAMs.
  819. // Every OPTTYPE has at leas one OPTPARAM.
  820. if(0 < wParams)
  821. {
  822. // Allocate memory for feature options.
  823. pOptItem->pOptType = CreateOptType(hHeap, wParams);
  824. if(NULL == pOptItem->pOptType)
  825. {
  826. ERR(ERRORTEXT("COptions::InitOptItem() failed to allocate OPTTYPEs for OPTITEM %hs.\r\n"),
  827. m_pszFeature);
  828. hrResult = E_OUTOFMEMORY;
  829. goto Exit;
  830. }
  831. // Set OPTTYPE.
  832. pOptItem->pOptType->Type = m_cType;
  833. // Different OPTTYPE types require different initialization.
  834. switch(m_cType)
  835. {
  836. // For up down arrow control, OPTPARAM[0] is used by the contrl.
  837. // pOptParam[0]->pData is the Units description string.
  838. // pOptParam[1].IconID is the min limit.
  839. // pOptParam[1].lParam is the max limit.
  840. case TVOT_UDARROW:
  841. assert(2 == wParams);
  842. pOptItem->pOptType->pOptParam[0].pData = m_pszUnits;
  843. pOptItem->pOptType->pOptParam[1].IconID = m_ptRange.x;
  844. pOptItem->pOptType->pOptParam[1].lParam = m_ptRange.y;
  845. break;
  846. // For combobox, the pOptParam[n].pData is the display name of the option.
  847. case TVOT_COMBOBOX:
  848. for(WORD wIndex = 0; wIndex < wParams; ++wIndex)
  849. {
  850. pOptItem->pOptType->pOptParam[wIndex].pData = const_cast<PWSTR>(GetName(wIndex));
  851. }
  852. break;
  853. default:
  854. ERR(ERRORTEXT("COptions::InitOptItem() OPTTYPE type %d OPTTYPE init not handled.\r\n"),
  855. m_cType);
  856. break;
  857. }
  858. }
  859. Exit:
  860. return hrResult;
  861. }
  862. // Refresh option selection.
  863. HRESULT COptions::RefreshSelection(CUIHelper &Helper, POEMUIOBJ poemuiobj)
  864. {
  865. HRESULT hrResult = S_OK;
  866. // Method for getting option selection is based
  867. // on OPTTYPE type.
  868. switch(m_cType)
  869. {
  870. case TVOT_UDARROW:
  871. hrResult = GetOptionSelectionShort(Helper, poemuiobj);
  872. break;
  873. case TVOT_COMBOBOX:
  874. hrResult = GetOptionSelectionIndex(Helper, poemuiobj);
  875. break;
  876. default:
  877. ERR(ERRORTEXT("COptions::RefreshSelection() not handled for type %d OPTTYPE.\r\n"),
  878. m_cType);
  879. break;
  880. }
  881. return hrResult;
  882. }
  883. ////////////////////////////////////////////
  884. //
  885. // CFeatures Methods
  886. //
  887. //
  888. // Private Methods
  889. //
  890. // Initializes class
  891. void CFeatures::Init()
  892. {
  893. // Initialize data members.
  894. m_wFeatures = 0;
  895. m_wDocFeatures = 0;
  896. m_wPrintFeatures = 0;
  897. m_pmszRaw = NULL;
  898. m_ppszKeywords = NULL;
  899. m_dwSize = 0;
  900. m_hHeap = NULL;
  901. m_pInfo = NULL;
  902. }
  903. // Cleans up class and re-initialize it.
  904. void CFeatures::Clear()
  905. {
  906. // Free memory associated with data members.
  907. if(NULL != m_pmszRaw) HeapFree(m_hHeap, 0, m_pmszRaw);
  908. if(NULL != m_ppszKeywords) HeapFree(m_hHeap, 0, m_ppszKeywords);
  909. // Free feature info
  910. FreeFeatureInfo();
  911. // Re-initialize
  912. Init();
  913. }
  914. // Free feature info
  915. void CFeatures::FreeFeatureInfo()
  916. {
  917. // Validate parameters.
  918. if( (NULL == m_hHeap)
  919. ||
  920. (NULL == m_pInfo)
  921. )
  922. {
  923. return;
  924. }
  925. // Free memory associated with feature info.
  926. for(WORD wIndex = 0; wIndex < m_wFeatures; ++wIndex)
  927. {
  928. PWSTR pszDisplay = m_pInfo[wIndex].pszDisplayName;
  929. // Free display name.
  930. if( (NULL != pszDisplay)
  931. &&
  932. !IS_INTRESOURCE(pszDisplay)
  933. )
  934. {
  935. HeapFree(m_hHeap, 0, pszDisplay);
  936. }
  937. }
  938. // Free feature info array.
  939. // Feature Info array allocated with new so
  940. // that each of the constructors for COptions
  941. // in fhte Feature Info array will be called.
  942. delete[] m_pInfo;
  943. }
  944. // Turns index for mode to modeless index, which
  945. // is the real index to the feature.
  946. WORD CFeatures::GetModelessIndex(WORD wIndex, DWORD dwMode) const
  947. {
  948. WORD wCount = 0;
  949. switch(dwMode)
  950. {
  951. // Number of features, all modes
  952. case 0:
  953. wCount = wIndex;
  954. break;
  955. // Find the nth feature that matches the mode
  956. case OEMCUIP_DOCPROP:
  957. case OEMCUIP_PRNPROP:
  958. // Walk the feature list looking for nth feature
  959. // with matching mode.
  960. for(wCount = 0; wCount < m_wFeatures; ++wCount)
  961. {
  962. // Count down to the feature we want.
  963. // Only count down for matching modes.
  964. if(dwMode == m_pInfo[wCount].dwMode)
  965. {
  966. if(0 == wIndex)
  967. {
  968. break;
  969. }
  970. else
  971. {
  972. --wIndex;
  973. }
  974. }
  975. }
  976. break;
  977. }
  978. return wCount;
  979. }
  980. //
  981. // Public Methods
  982. //
  983. // Default constructor
  984. CFeatures::CFeatures()
  985. {
  986. Init();
  987. }
  988. // Destructor
  989. CFeatures::~CFeatures()
  990. {
  991. // Clean up class.
  992. Clear();
  993. }
  994. // Gets Core Driver Features, if not already retrieved.
  995. HRESULT CFeatures::Acquire(HANDLE hHeap,
  996. CUIHelper &Helper,
  997. POEMUIOBJ poemuiobj
  998. )
  999. {
  1000. WORD wIndex = 0;
  1001. DWORD dwNeeded = 0;
  1002. HRESULT hrResult = S_OK;
  1003. VERBOSE(DLLTEXT("CFeatures::Acquire(0x%p, Helper, 0x%p) entered.\r\n"),
  1004. hHeap,
  1005. poemuiobj);
  1006. // Don't retreive the Features again if we already got them.
  1007. if(0 < m_wFeatures)
  1008. {
  1009. VERBOSE(DLLTEXT("CFeatures::Acquire() features already enumerated.\r\n"));
  1010. VERBOSE(DLLTEXT("CFeatures::Acquire() returning S_OK.\r\n"));
  1011. return S_OK;
  1012. }
  1013. // Save the heap handle for use later, such as freeing memory at destruction.
  1014. m_hHeap = hHeap;
  1015. //
  1016. // Enumerate features.
  1017. //
  1018. // To try to cut down on having to call EnumFeatures more than once,
  1019. // pre-allocate a buffer of reasonable size.
  1020. m_dwSize = INITIAL_ENUM_FEATURES_SIZE;
  1021. m_pmszRaw = (PSTR) HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_dwSize);
  1022. if(NULL == m_pmszRaw)
  1023. {
  1024. ERR(ERRORTEXT("CFeatures::Acquire() alloc for feature list failed.\r\n"));
  1025. hrResult = E_OUTOFMEMORY;
  1026. goto Exit;
  1027. }
  1028. // Try to get feature list with initial buffer.
  1029. hrResult = Helper.EnumFeatures(poemuiobj, 0, m_pmszRaw, m_dwSize, &dwNeeded);
  1030. if( (E_OUTOFMEMORY == hrResult) && (m_dwSize < dwNeeded))
  1031. {
  1032. PSTR pTemp;
  1033. // INVARIANT: feature list multi-sz wasn't large enough.
  1034. // Re-allocate the buffer and try again.
  1035. pTemp = (PSTR) HeapReAlloc(m_hHeap, HEAP_ZERO_MEMORY, m_pmszRaw, dwNeeded);
  1036. if(NULL == pTemp)
  1037. {
  1038. ERR(ERRORTEXT("CFeatures::Acquire() re-alloc for feature list failed.\r\n"));
  1039. hrResult = E_OUTOFMEMORY;
  1040. goto Exit;
  1041. }
  1042. m_pmszRaw = pTemp;
  1043. m_dwSize = dwNeeded;
  1044. // Try again to get the feature list.
  1045. hrResult = Helper.EnumFeatures(poemuiobj, 0, m_pmszRaw, m_dwSize, &dwNeeded);
  1046. if(!SUCCEEDED(hrResult))
  1047. {
  1048. ERR(ERRORTEXT("CFeatures::Acquire() failed to EnumFeatures() after re-allocating buffer.\r\n"));
  1049. goto Exit;
  1050. }
  1051. }
  1052. // Make sure we got the feature list.
  1053. // Can't do anything more with out it.
  1054. if(!SUCCEEDED(hrResult))
  1055. {
  1056. ERR(ERRORTEXT("CFeatures::Acquire() failed to enumerate features. (hrResult = 0x%x)\r\n"), hrResult);
  1057. goto Exit;
  1058. }
  1059. // INVARIANT: successfully got feature keyword list.
  1060. // Create array of string pointers to the feature keywords
  1061. // in the multi-sz we got from EnumFreatures().
  1062. hrResult = MakeStrPtrList(m_hHeap, m_pmszRaw, &m_ppszKeywords, &m_wFeatures);
  1063. if(!SUCCEEDED(hrResult))
  1064. {
  1065. ERR(ERRORTEXT("CFeatures::Acquire() failed to create pointer list to keywords. (hrResult = 0x%x)\r\n"), hrResult);
  1066. goto Exit;
  1067. }
  1068. //
  1069. // Build Feature Information
  1070. //
  1071. // Allocate array to hold feature info
  1072. // Use new for allocation so class
  1073. // constructors/destructors get called.
  1074. m_pInfo = new FEATURE_INFO[m_wFeatures];
  1075. if(NULL == m_pInfo)
  1076. {
  1077. ERR(ERRORTEXT("CFeatures::Acquire() failed to alloc feature info array.\r\n"));
  1078. hrResult = E_OUTOFMEMORY;
  1079. goto Exit;
  1080. }
  1081. // For each feature, build/get feature info....
  1082. for(wIndex = 0; wIndex < m_wFeatures; ++wIndex)
  1083. {
  1084. PFEATURE_INFO pCurrent = m_pInfo + wIndex;
  1085. // Get or build a keyword mapping entry
  1086. // that maps from keyword to usefully where to get info, such as
  1087. // display name, icon, option type, for keywords that may not be
  1088. // able to get info for from Helper.
  1089. pCurrent->pMapping = FindKeywordMapping(gkmFeatureMap, NUM_FEATURE_MAP, m_ppszKeywords[wIndex]);
  1090. // Get display names for each of the featurs.
  1091. // The function implements a heuristic for detemining the display name,
  1092. // since can't get the display name from the UI Helper for all features.
  1093. hrResult = DetermineFeatureDisplayName(m_hHeap,
  1094. Helper,
  1095. poemuiobj,
  1096. m_ppszKeywords[wIndex],
  1097. pCurrent->pMapping,
  1098. &pCurrent->pszDisplayName);
  1099. if(!SUCCEEDED(hrResult))
  1100. {
  1101. ERR(ERRORTEXT("CFeatures::Acquire() failed to get display name for feature %hs. (hrResult = 0x%x)\r\n"),
  1102. m_ppszKeywords[wIndex],
  1103. hrResult);
  1104. goto Exit;
  1105. }
  1106. // Get options for each feature.
  1107. // NOTE: some features don't have options; the HRESULT will be E_NOTIMPL for these.
  1108. hrResult = pCurrent->Options.Acquire(hHeap,
  1109. Helper,
  1110. poemuiobj,
  1111. m_ppszKeywords[wIndex]);
  1112. if(!SUCCEEDED(hrResult) && (E_NOTIMPL != hrResult))
  1113. {
  1114. ERR(ERRORTEXT("CFeatures::Acquire() failed to get options for feature %hs. (hrResult = 0x%x)\r\n"),
  1115. m_ppszKeywords[wIndex],
  1116. hrResult);
  1117. goto Exit;
  1118. }
  1119. // Determine if feature is Printer or Document sticky.
  1120. hrResult = DetermineStickiness(Helper,
  1121. poemuiobj,
  1122. m_ppszKeywords[wIndex],
  1123. pCurrent->pMapping,
  1124. &pCurrent->dwMode);
  1125. // Don't propagate error if failure from unhandled driver feature.
  1126. if( !SUCCEEDED(hrResult)
  1127. &&
  1128. !IS_DRIVER_FEATURE(m_ppszKeywords[wIndex])
  1129. )
  1130. {
  1131. ERR(ERRORTEXT("CFeatures::Acquire() failed to determine stickiness for feature %hs. (hrResult = 0x%x)\r\n"),
  1132. m_ppszKeywords[wIndex],
  1133. hrResult);
  1134. goto Exit;
  1135. }
  1136. // Keep track of mode counts.
  1137. switch(pCurrent->dwMode)
  1138. {
  1139. case OEMCUIP_DOCPROP:
  1140. ++m_wDocFeatures;
  1141. break;
  1142. case OEMCUIP_PRNPROP:
  1143. ++m_wPrintFeatures;
  1144. break;
  1145. default:
  1146. ERR(ERRORTEXT("CFeatures::Acquire() unknown stickiness for feature %hs.\r\n"),
  1147. m_ppszKeywords[wIndex]);
  1148. break;
  1149. }
  1150. }
  1151. // INVARIANT: successfully build feature list.
  1152. // Make sure that we always return success if we reach this point.
  1153. hrResult = S_OK;
  1154. Exit:
  1155. // Clean up if weren't successful.
  1156. if(!SUCCEEDED(hrResult))
  1157. {
  1158. Clear();
  1159. }
  1160. VERBOSE(DLLTEXT("CFeatures::Acquire() returning HRESULT of 0x%x.\r\n"), hrResult);
  1161. return hrResult;
  1162. }
  1163. // Returns number of features contained in class instance.
  1164. WORD CFeatures::GetCount(DWORD dwMode) const
  1165. {
  1166. WORD wCount = 0;
  1167. switch(dwMode)
  1168. {
  1169. // Number of features, all modes
  1170. case 0:
  1171. wCount = m_wFeatures;
  1172. break;
  1173. case OEMCUIP_DOCPROP:
  1174. wCount = m_wDocFeatures;
  1175. break;
  1176. case OEMCUIP_PRNPROP:
  1177. wCount = m_wPrintFeatures;
  1178. break;
  1179. }
  1180. VERBOSE(DLLTEXT("CFeatures::GetCount() returning %d\r\n"), wCount);
  1181. return wCount;
  1182. }
  1183. // Returns nth feature's keyword
  1184. PCSTR CFeatures::GetKeyword(WORD wIndex, DWORD dwMode) const
  1185. {
  1186. // Validate parameters.
  1187. if( (wIndex >= GetCount(dwMode))
  1188. ||
  1189. (NULL == m_ppszKeywords)
  1190. )
  1191. {
  1192. return NULL;
  1193. }
  1194. // Get internal index.
  1195. wIndex = GetModelessIndex(wIndex, dwMode);
  1196. // Return keyword
  1197. return m_ppszKeywords[wIndex];
  1198. }
  1199. // Return nth feature's Display Name.
  1200. PCWSTR CFeatures::GetName(WORD wIndex, DWORD dwMode) const
  1201. {
  1202. // Validate parameters.
  1203. if( (wIndex >= GetCount(dwMode))
  1204. ||
  1205. (NULL == m_pInfo)
  1206. )
  1207. {
  1208. return NULL;
  1209. }
  1210. // Get internal index.
  1211. wIndex = GetModelessIndex(wIndex, dwMode);
  1212. // Return display name.
  1213. return m_pInfo[wIndex].pszDisplayName;
  1214. }
  1215. // Returns pointer to option class for nth feature.
  1216. COptions* CFeatures::GetOptions(WORD wIndex, DWORD dwMode) const
  1217. {
  1218. // Validate parameters.
  1219. if( (wIndex >= GetCount(dwMode))
  1220. ||
  1221. (NULL == m_pInfo)
  1222. )
  1223. {
  1224. return NULL;
  1225. }
  1226. // Get internal index.
  1227. wIndex = GetModelessIndex(wIndex, dwMode);
  1228. // Return options pointer.
  1229. return &m_pInfo[wIndex].Options;
  1230. }
  1231. // Formats OPTITEM for specied feature.
  1232. HRESULT CFeatures::InitOptItem(HANDLE hHeap, POPTITEM pOptItem, WORD wIndex, DWORD dwMode)
  1233. {
  1234. COptions *pOptions = NULL;
  1235. HRESULT hrResult = S_OK;
  1236. PFEATUREOPTITEMDATA pData = NULL;
  1237. // Validate parameters.
  1238. if( (wIndex >= GetCount(dwMode))
  1239. ||
  1240. (NULL == m_pInfo)
  1241. ||
  1242. (NULL == pOptItem)
  1243. )
  1244. {
  1245. return E_INVALIDARG;
  1246. }
  1247. // Map mode index to internal index.
  1248. wIndex = GetModelessIndex(wIndex, dwMode);
  1249. // Get name of feature.
  1250. pOptItem->pName = const_cast<PWSTR>(GetName(wIndex));
  1251. // Add feature OPTITEM data to OPTITEM to facilitate saving
  1252. // selection changes.
  1253. pData = (PFEATUREOPTITEMDATA) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(FEATUREOPTITEMDATA));
  1254. if(NULL == pData)
  1255. {
  1256. ERR(ERRORTEXT("CFeatures::InitOptItem() failed to allocated memory for feature OPTITEM data."));
  1257. hrResult = E_OUTOFMEMORY;
  1258. goto Exit;
  1259. }
  1260. pData->dwSize = sizeof(FEATUREOPTITEMDATA);
  1261. pData->dwTag = FEATURE_OPTITEM_TAG;
  1262. pData->pszFeatureKeyword = GetKeyword(wIndex);
  1263. pData->pOptions = GetOptions(wIndex);
  1264. pOptItem->UserData = (ULONG_PTR) pData;
  1265. // Get pointer to options for this feature.
  1266. // NOTE: some features do not have option list for various reasons.
  1267. pOptions = GetOptions(wIndex);
  1268. if(NULL != pOptions)
  1269. {
  1270. // Initialize COption parts of the OPTITEM
  1271. hrResult = pOptions->InitOptItem(hHeap, pOptItem);
  1272. }
  1273. Exit:
  1274. Dump(pOptItem);
  1275. return hrResult;
  1276. }
  1277. //////////////////////////////////////////////////
  1278. //
  1279. // Regular functions not part of class
  1280. //
  1281. //////////////////////////////////////////////////
  1282. // Maps feature keywords to display names for the features.
  1283. HRESULT DetermineFeatureDisplayName(HANDLE hHeap,
  1284. CUIHelper &Helper,
  1285. POEMUIOBJ poemuiobj,
  1286. PCSTR pszKeyword,
  1287. const PKEYWORDMAP pMapping,
  1288. PWSTR *ppszDisplayName)
  1289. {
  1290. DWORD dwDataType = -1;
  1291. DWORD dwSize = INITIAL_FEATURE_DISPLAY_NAME_SIZE;
  1292. DWORD dwNeeded = 0;
  1293. HRESULT hrResult = S_OK;
  1294. // Validate parameters.
  1295. if( (NULL == hHeap)
  1296. ||
  1297. (NULL == pszKeyword)
  1298. ||
  1299. (NULL == ppszDisplayName)
  1300. )
  1301. {
  1302. ERR(ERRORTEXT("DetermineFeatureDisplayName() invalid arguement.\r\n"));
  1303. hrResult = E_INVALIDARG;
  1304. goto Exit;
  1305. }
  1306. //
  1307. // Call the Helper function.
  1308. //
  1309. // Helper will return Display Names for PPD Features, but
  1310. // not for Driver Synthisized features (i.e. features prefixed with %).
  1311. // Do it for Driver Synthisized features, just in case the helper
  1312. // interface changes to support it.
  1313. // Pre-allocate a buffer of reasonable size to try
  1314. // to one have to call GetFeatureAttribute() once.
  1315. *ppszDisplayName = (PWSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize);
  1316. if(NULL == *ppszDisplayName)
  1317. {
  1318. ERR(ERRORTEXT("DetermineFeatureDisplayName() alloc for feature display name failed.\r\n"));
  1319. hrResult = E_OUTOFMEMORY;
  1320. goto Exit;
  1321. }
  1322. // Try to get diplay name for feature from Helper.
  1323. hrResult = Helper.GetFeatureAttribute(poemuiobj,
  1324. 0,
  1325. pszKeyword,
  1326. "DisplayName",
  1327. &dwDataType,
  1328. (PBYTE) *ppszDisplayName,
  1329. dwSize,
  1330. &dwNeeded);
  1331. if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded))
  1332. {
  1333. PWSTR pTemp;
  1334. // INVARIANT: initial buffer wasn't large enough.
  1335. // Re-alloc buffer and try again.
  1336. pTemp = (PWSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, *ppszDisplayName, dwNeeded);
  1337. if(NULL == pTemp)
  1338. {
  1339. ERR(ERRORTEXT("DetermineFeatureDisplayName() re-alloc for feature display name failed.\r\n"));
  1340. hrResult = E_OUTOFMEMORY;
  1341. goto Exit;
  1342. }
  1343. *ppszDisplayName = pTemp;
  1344. // Try to get the display name from Helper, again.
  1345. hrResult = Helper.GetFeatureAttribute(poemuiobj,
  1346. 0,
  1347. pszKeyword,
  1348. "DisplayName",
  1349. &dwDataType,
  1350. (PBYTE) *ppszDisplayName,
  1351. dwNeeded,
  1352. &dwNeeded);
  1353. }
  1354. if(SUCCEEDED(hrResult))
  1355. {
  1356. // INVARIANT: Successfully got display name from Helper for feature.
  1357. // Don't need to do anything more.
  1358. // Check the data type, it should be kADT_UNICODE.
  1359. if(kADT_UNICODE != dwDataType) WARNING(DLLTEXT("DetermineFeatureDisplayName() feature attribute type not kADT_UNICODE. (dwDataType = %d)\r\n"), dwDataType);
  1360. goto Exit;
  1361. }
  1362. // INVARIANT: Did not get the display name from the Helper.
  1363. // Free memory allocated for call to Helper.
  1364. if(NULL != *ppszDisplayName)
  1365. {
  1366. HeapFree(hHeap, 0, *ppszDisplayName);
  1367. *ppszDisplayName = NULL;
  1368. }
  1369. // Try alternative methods for getting the display name other
  1370. // than from the Helper function.
  1371. // If we have a mapping entry, then try to get resource string
  1372. // for the display name.
  1373. // Otherwise, covert the keyword to UNICODE and use that.
  1374. if(NULL != pMapping)
  1375. {
  1376. //
  1377. // Try mapping the keyword to resource string.
  1378. //
  1379. hrResult = GetDisplayNameFromMapping(hHeap, pMapping, ppszDisplayName);
  1380. }
  1381. else
  1382. {
  1383. //
  1384. // Convert the keyword to UNICODE and use that.
  1385. //
  1386. // Convert ANSI keyword to Unicode string for display name.
  1387. // Need to remove the % for Driver Synthisized features.
  1388. // For debug version, add marker that shows that the display name was faked.
  1389. PCSTR pConvert = IS_DRIVER_FEATURE(pszKeyword) ? pszKeyword + 1 : pszKeyword;
  1390. #if DBG
  1391. CHAR szTemp[256];
  1392. if(FAILED(StringCbPrintfA(szTemp, sizeof(szTemp), "%s (Keyword)", pConvert)))
  1393. {
  1394. ERR(ERRORTEXT("DetermineFeatureDisplayName() StringCbPrintfA() called failed.\r\n"));
  1395. }
  1396. pConvert = szTemp;
  1397. #endif
  1398. *ppszDisplayName = MakeUnicodeString(hHeap, pConvert);
  1399. if(NULL == *ppszDisplayName)
  1400. {
  1401. ERR(ERRORTEXT("DetermineFeatureDisplayName() alloc for feature display name failed.\r\n"));
  1402. hrResult = E_OUTOFMEMORY;
  1403. goto Exit;
  1404. }
  1405. // Return success even though we faked a display name.
  1406. hrResult = S_OK;
  1407. }
  1408. Exit:
  1409. // If failed, then return no string.
  1410. if(!SUCCEEDED(hrResult))
  1411. {
  1412. if(NULL != *ppszDisplayName)
  1413. {
  1414. HeapFree(hHeap, 0, *ppszDisplayName);
  1415. *ppszDisplayName = NULL;
  1416. }
  1417. }
  1418. return hrResult;
  1419. }
  1420. // Maps option keywords to display names for the option.
  1421. HRESULT DetermineOptionDisplayName(HANDLE hHeap,
  1422. CUIHelper &Helper,
  1423. POEMUIOBJ poemuiobj,
  1424. PCSTR pszFeature,
  1425. PCSTR pszOption,
  1426. const PKEYWORDMAP pMapping,
  1427. PWSTR *ppszDisplayName)
  1428. {
  1429. DWORD dwDataType = -1;
  1430. DWORD dwSize = INITIAL_OPTION_DISPLAY_NAME_SIZE;
  1431. DWORD dwNeeded = 0;
  1432. HRESULT hrResult = S_OK;
  1433. // Validate parameters.
  1434. if( (NULL == hHeap)
  1435. ||
  1436. (NULL == pszFeature)
  1437. ||
  1438. (NULL == pszOption)
  1439. ||
  1440. (NULL == ppszDisplayName)
  1441. )
  1442. {
  1443. ERR(ERRORTEXT("DetermineOptionDisplayName() invalid arguement.\r\n"));
  1444. hrResult = E_INVALIDARG;
  1445. goto Exit;
  1446. }
  1447. //
  1448. // Call the Helper function.
  1449. //
  1450. // Helper will return Display Names for PPD Feature Options, but
  1451. // not for Driver Synthisized features options (i.e. features prefixed with %).
  1452. // Do it for all options, just in case the helper interface changes to support it.
  1453. // Pre-allocate a buffer of reasonable size to try
  1454. // to one have to call GetOptionAttribute() once.
  1455. *ppszDisplayName = (PWSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize);
  1456. if(NULL == *ppszDisplayName)
  1457. {
  1458. ERR(ERRORTEXT("DetermineOptionDisplayName() alloc for feature display name failed.\r\n"));
  1459. hrResult = E_OUTOFMEMORY;
  1460. goto Exit;
  1461. }
  1462. // Try to get diplay name for feature from Helper.
  1463. hrResult = Helper.GetOptionAttribute(poemuiobj,
  1464. 0,
  1465. pszFeature,
  1466. pszOption,
  1467. "DisplayName",
  1468. &dwDataType,
  1469. (PBYTE) *ppszDisplayName,
  1470. dwSize,
  1471. &dwNeeded);
  1472. if( (E_OUTOFMEMORY == hrResult) && (dwSize < dwNeeded))
  1473. {
  1474. PWSTR pTemp;
  1475. // INVARIANT: initial buffer wasn't large enough.
  1476. // Re-alloc buffer and try again.
  1477. pTemp = (PWSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, *ppszDisplayName, dwNeeded);
  1478. if(NULL == pTemp)
  1479. {
  1480. ERR(ERRORTEXT("GetOptionAttribute() re-alloc for feature display name failed.\r\n"));
  1481. hrResult = E_OUTOFMEMORY;
  1482. goto Exit;
  1483. }
  1484. *ppszDisplayName = pTemp;
  1485. // Try to get the display name from Helper, again.
  1486. hrResult = Helper.GetOptionAttribute(poemuiobj,
  1487. 0,
  1488. pszFeature,
  1489. pszOption,
  1490. "DisplayName",
  1491. &dwDataType,
  1492. (PBYTE) *ppszDisplayName,
  1493. dwNeeded,
  1494. &dwNeeded);
  1495. }
  1496. if(SUCCEEDED(hrResult))
  1497. {
  1498. // INVARIANT: Successfully got display name from Helper for feature.
  1499. // Don't need to do anything more.
  1500. // Check the data type, it should be kADT_UNICODE.
  1501. if(kADT_UNICODE != dwDataType) WARNING(DLLTEXT("DetermineOptionDisplayName() feature attribute type not kADT_UNICODE. (dwDataType = %d)\r\n"), dwDataType);
  1502. goto Exit;
  1503. }
  1504. // INVARIANT: Did not get the display name from the Helper.
  1505. // Free memory allocated for call to Helper.
  1506. if(NULL != *ppszDisplayName)
  1507. {
  1508. HeapFree(hHeap, 0, *ppszDisplayName);
  1509. *ppszDisplayName = NULL;
  1510. }
  1511. // Try alternative methods for getting the display name other
  1512. // than from the Helper function.
  1513. // If we have a mapping entry, then try to get resource string
  1514. // for the display name.
  1515. // Otherwise, covert the keyword to UNICODE and use that.
  1516. if(NULL != pMapping)
  1517. {
  1518. //
  1519. // Try mapping the keyword to resource string.
  1520. //
  1521. hrResult = GetDisplayNameFromMapping(hHeap, pMapping, ppszDisplayName);
  1522. }
  1523. else
  1524. {
  1525. //
  1526. // Convert the keyword to UNICODE and use that.
  1527. //
  1528. // Convert ANSI keyword to Unicode string for display name.
  1529. // For debug version, add marker that shows that the display name was faked.
  1530. PCSTR pConvert = pszOption;
  1531. #if DBG
  1532. CHAR szTemp[256];
  1533. if(FAILED(StringCbPrintfA(szTemp, sizeof(szTemp), "%s (Keyword)", pConvert)))
  1534. {
  1535. ERR(ERRORTEXT("DetermineOptionDisplayName() StringCbPrintfA() called failed.\r\n"));
  1536. }
  1537. pConvert = szTemp;
  1538. #endif
  1539. *ppszDisplayName = MakeUnicodeString(hHeap, pConvert);
  1540. if(NULL == *ppszDisplayName)
  1541. {
  1542. ERR(ERRORTEXT("DetermineOptionDisplayName() alloc for feature display name failed.\r\n"));
  1543. hrResult = E_OUTOFMEMORY;
  1544. goto Exit;
  1545. }
  1546. // Return success even though we faked a display name.
  1547. hrResult = S_OK;
  1548. }
  1549. Exit:
  1550. // If failed, then return no string.
  1551. if(!SUCCEEDED(hrResult))
  1552. {
  1553. if(NULL != *ppszDisplayName)
  1554. {
  1555. HeapFree(hHeap, 0, *ppszDisplayName);
  1556. *ppszDisplayName = NULL;
  1557. }
  1558. }
  1559. return hrResult;
  1560. }
  1561. // Determines sticky mode for the feature.
  1562. HRESULT DetermineStickiness(CUIHelper &Helper,
  1563. POEMUIOBJ poemuiobj,
  1564. PCSTR pszKeyword,
  1565. const PKEYWORDMAP pMapping,
  1566. PDWORD pdwMode)
  1567. {
  1568. CHAR szGroupType[32] = {0};
  1569. DWORD dwType = 0;
  1570. DWORD dwNeeded = 0;
  1571. HRESULT hrResult = S_OK;
  1572. // Use mapping to see what stickiness of the feature is.
  1573. if(NULL != pMapping)
  1574. {
  1575. *pdwMode = pMapping->dwMode;
  1576. goto Exit;
  1577. }
  1578. // By default make feature Document sticky, if we don't have mapping.
  1579. *pdwMode = OEMCUIP_DOCPROP;
  1580. // Try to use Helper to determine stickiness.
  1581. hrResult = Helper.GetFeatureAttribute(poemuiobj,
  1582. 0,
  1583. pszKeyword,
  1584. "OpenGroupType",
  1585. &dwType,
  1586. (PBYTE) szGroupType,
  1587. sizeof(szGroupType),
  1588. &dwNeeded);
  1589. if(SUCCEEDED(hrResult))
  1590. {
  1591. // INVARIANT: found out if feature is an installable option.
  1592. // Installable options are the only PPD features
  1593. // that are Printer sticky.
  1594. if(!lstrcmpA(szGroupType, "InstallableOptions"))
  1595. {
  1596. *pdwMode = OEMCUIP_PRNPROP;
  1597. }
  1598. goto Exit;
  1599. }
  1600. Exit:
  1601. return hrResult;
  1602. }
  1603. // Find the mapping entry from the keyword.
  1604. PKEYWORDMAP FindKeywordMapping(PKEYWORDMAP pKeywordMap, WORD wMapSize, PCSTR pszKeyword)
  1605. {
  1606. BOOL bFound = FALSE;
  1607. PKEYWORDMAP pMapping = NULL;
  1608. // Walk mapping array for matching keyword.
  1609. for(WORD wIndex = 0; !bFound && (wIndex < wMapSize); ++wIndex)
  1610. {
  1611. bFound = !lstrcmpA(pszKeyword, pKeywordMap[wIndex].pszKeyword);
  1612. if(bFound)
  1613. {
  1614. pMapping = pKeywordMap + wIndex;
  1615. }
  1616. }
  1617. return pMapping;
  1618. }
  1619. // Get display name from mapping entry.
  1620. HRESULT GetDisplayNameFromMapping(HANDLE hHeap, PKEYWORDMAP pMapping, PWSTR *ppszDisplayName)
  1621. {
  1622. HMODULE hModule = NULL;
  1623. HRESULT hrResult = S_OK;
  1624. // Validate parameters.
  1625. if( (NULL == hHeap)
  1626. ||
  1627. (NULL == pMapping)
  1628. ||
  1629. (NULL == ppszDisplayName)
  1630. )
  1631. {
  1632. hrResult = E_INVALIDARG;
  1633. goto Exit;
  1634. }
  1635. // Check for simple case of returning INT resource.
  1636. if( (NULL == pMapping->pwszModule)
  1637. ||
  1638. IS_MAPPING_INT_RESOURCE(pMapping)
  1639. )
  1640. {
  1641. // Just need to do MAKEINTRESOURCE on the resource ID and return.
  1642. *ppszDisplayName = MAKEINTRESOURCE(pMapping->uDisplayNameID);
  1643. goto Exit;
  1644. }
  1645. // We only need to get the module if we aren't loading the resource from
  1646. // this module (i.e. if module name isn't NULL).
  1647. // Also, as an optimization, we assume that the module has already been loaded,
  1648. // since the only cases currently are this module, driver ui, and Compstui.dll.
  1649. hModule = GetModuleHandle(pMapping->pwszModule);
  1650. if(NULL == hModule)
  1651. {
  1652. DWORD dwError = GetLastError();
  1653. ERR(ERRORTEXT("GetDisplayNameFromMapping() for failed to load module %s. (Error %d)\r\n"),
  1654. pMapping->pwszModule,
  1655. dwError);
  1656. hrResult = HRESULT_FROM_WIN32(dwError);
  1657. goto Exit;
  1658. }
  1659. // INVARIANT: have handle to module to load resource from or the
  1660. // resource is being loaded from this module.
  1661. // Get the string resouce.
  1662. hrResult = GetStringResource(hHeap, hModule, pMapping->uDisplayNameID, ppszDisplayName);
  1663. if(!SUCCEEDED(hrResult))
  1664. {
  1665. ERR(ERRORTEXT("GetDisplayNameFromMapping() failed to load string. (hrResult = 0x%x)\r\n"),
  1666. hrResult);
  1667. goto Exit;
  1668. }
  1669. Exit:
  1670. return hrResult;
  1671. }
  1672. // Test if an OPTITEM is an OPTITEM for a feature.
  1673. // Macro for testing if OPTITEM is feature OPTITEM
  1674. BOOL IsFeatureOptitem(POPTITEM pOptItem)
  1675. {
  1676. BOOL bRet = FALSE;
  1677. PFEATUREOPTITEMDATA pData = NULL;
  1678. // Make sure pointers are NULL.
  1679. if( (NULL == pOptItem)
  1680. ||
  1681. (NULL == pOptItem->UserData)
  1682. )
  1683. {
  1684. // INVARIANT: can't be feature OPTITEM, since one of
  1685. // the necessary pointer are NULL.
  1686. return FALSE;
  1687. }
  1688. // For convienience, assign to pointer to feature OPTITEM data.
  1689. pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
  1690. // Check size and tag.
  1691. bRet = (sizeof(FEATUREOPTITEMDATA) == pData->dwSize)
  1692. &&
  1693. (FEATURE_OPTITEM_TAG == pData->dwTag);
  1694. return bRet;
  1695. }
  1696. // Walks array of OPTITEMs saving each feature OPTITEM
  1697. // that has changed.
  1698. HRESULT SaveFeatureOptItems(HANDLE hHeap,
  1699. CUIHelper *pHelper,
  1700. POEMUIOBJ poemuiobj,
  1701. HWND hWnd,
  1702. POPTITEM pOptItem,
  1703. WORD wItems)
  1704. {
  1705. PSTR pmszPairs = NULL;
  1706. WORD wPairs = 0;
  1707. WORD wConflicts = 0;
  1708. WORD wReasons = 0;
  1709. DWORD dwSize = 0;
  1710. DWORD dwResult = 0;
  1711. PCSTR *ppszReasons = NULL;
  1712. PWSTR pszConfilictFeature = NULL;
  1713. PWSTR pszConfilictOption = NULL;
  1714. PWSTR pszCaption = NULL;
  1715. PWSTR pszFormat = NULL;
  1716. PWSTR pszMessage = NULL;
  1717. HRESULT hrResult = S_OK;
  1718. // Validate parameters
  1719. if( (NULL == hHeap)
  1720. ||
  1721. (NULL == pHelper)
  1722. ||
  1723. (NULL == pOptItem)
  1724. )
  1725. {
  1726. ERR(ERRORTEXT("SaveFeatureOptItems() called with invalid parameters.\r\n"));
  1727. hrResult = E_INVALIDARG;
  1728. goto Exit;
  1729. }
  1730. // Get feature option pairs to save.
  1731. hrResult = GetChangedFeatureOptions(hHeap, pOptItem, wItems, &pmszPairs, &wPairs, &dwSize);
  1732. if(!SUCCEEDED(hrResult))
  1733. {
  1734. ERR(ERRORTEXT("SaveFeatureOptItems() failed to get changed feature option pairs. (hrResult = 0x%x)\r\n"),
  1735. hrResult);
  1736. goto Exit;
  1737. }
  1738. // Don't need to do anything more if no feature options changed.
  1739. if(0 == wPairs)
  1740. {
  1741. VERBOSE(DLLTEXT("SaveFeatureOptItems() no feature options that need to be set.\r\n"));
  1742. goto Exit;
  1743. }
  1744. // Set the change feature options.
  1745. // For the first SetOptions() call, don't have the
  1746. // core driver UI resolve conflicts, so we can
  1747. // prompt user for automatic resolution or let
  1748. // them do the conflict resolving.
  1749. hrResult = pHelper->SetOptions(poemuiobj,
  1750. SETOPTIONS_FLAG_KEEP_CONFLICT,
  1751. pmszPairs,
  1752. dwSize,
  1753. &dwResult);
  1754. if(!SUCCEEDED(hrResult))
  1755. {
  1756. ERR(ERRORTEXT("SaveFeatureOptItems() call to SetOptions() failed. (hrResult = 0x%x, dwResult = %d\r\n"),
  1757. hrResult,
  1758. dwResult);
  1759. goto Exit;
  1760. }
  1761. // Check to see if we were able to save changed feature options,
  1762. // or if there is a conflict that needs resolution.
  1763. if(SETOPTIONS_RESULT_CONFLICT_REMAINED == dwResult)
  1764. {
  1765. int nRet;
  1766. DWORD dwRet;
  1767. CONFLICT Conflict;
  1768. PKEYWORDMAP pMapping = NULL;
  1769. // INVARIANT: constraint conflict, options weren't saved.
  1770. // Get list of all features that have conflict.
  1771. hrResult = GetFirstConflictingFeature(hHeap,
  1772. pHelper,
  1773. poemuiobj,
  1774. pOptItem,
  1775. wItems,
  1776. &Conflict);
  1777. if(!SUCCEEDED(hrResult))
  1778. {
  1779. goto Exit;
  1780. }
  1781. // Create string pointer list in to multi-sz of first conflict.
  1782. hrResult = MakeStrPtrList(hHeap, Conflict.pmszReasons, &ppszReasons, &wReasons);
  1783. if(!SUCCEEDED(hrResult))
  1784. {
  1785. ERR(ERRORTEXT("SaveFeatureOptItems() failed to make string list for conflict reasons. (hrResult = 0x%x)\r\n"),
  1786. hrResult);
  1787. goto Exit;
  1788. }
  1789. //
  1790. // Get display versions of feature/option conflict reason.
  1791. //
  1792. // Get or build a keyword mapping entry
  1793. // that maps from keyword to usefully where to get info, such as
  1794. // display name, icon, option type, for keywords that may not be
  1795. // able to get info for from Helper.
  1796. pMapping = FindKeywordMapping(gkmFeatureMap, NUM_FEATURE_MAP, ppszReasons[0]);
  1797. // Get display names for each of the featurs.
  1798. // The function implements a heuristic for detemining the display name,
  1799. // since can't get the display name from the UI Helper for all features.
  1800. hrResult = DetermineFeatureDisplayName(hHeap,
  1801. *pHelper,
  1802. poemuiobj,
  1803. ppszReasons[0],
  1804. pMapping,
  1805. &pszConfilictFeature);
  1806. if(!SUCCEEDED(hrResult))
  1807. {
  1808. ERR(ERRORTEXT("SaveFeatureOptItems failed to get display name for feature %hs. (hrResult = 0x%x)\r\n"),
  1809. ppszReasons[0],
  1810. hrResult);
  1811. goto Exit;
  1812. }
  1813. // Get or build a keyword mapping entry
  1814. // that maps from keyword to usefully where to get info, such as
  1815. // display name, icon, option type, for keywords that may not be
  1816. // able to get info for from Helper.
  1817. pMapping = FindKeywordMapping(gkmOptionMap, NUM_OPTION_MAP, ppszReasons[1]);
  1818. // Get option display name.
  1819. hrResult = DetermineOptionDisplayName(hHeap,
  1820. *pHelper,
  1821. poemuiobj,
  1822. ppszReasons[0],
  1823. ppszReasons[1],
  1824. pMapping,
  1825. &pszConfilictOption);
  1826. if(!SUCCEEDED(hrResult))
  1827. {
  1828. ERR(ERRORTEXT("SaveFeatureOptItems() failed to get display name for %hs of feature %hs. (hrResult = 0x%x)\r\n"),
  1829. ppszReasons[1],
  1830. ppszReasons[0],
  1831. hrResult);
  1832. goto Exit;
  1833. }
  1834. //
  1835. // Prompt user about how to resolve conflict.
  1836. //
  1837. // Get caption name.
  1838. hrResult = GetStringResource(hHeap, ghInstance, IDS_NAME, &pszCaption);
  1839. if(!SUCCEEDED(hrResult))
  1840. {
  1841. ERR(ERRORTEXT("SaveFeatureOptItems() failed to get caption name. (hrResult = 0x%x)\r\n"),
  1842. hrResult);
  1843. goto Exit;
  1844. }
  1845. // Get message body format string.
  1846. hrResult = GetStringResource(hHeap, ghInstance, IDS_CONSTRAINT_CONFLICT, &pszFormat);
  1847. if(!SUCCEEDED(hrResult))
  1848. {
  1849. ERR(ERRORTEXT("SaveFeatureOptItems() failed to get constraint conflict format. (hrResult = 0x%x)\r\n"),
  1850. hrResult);
  1851. goto Exit;
  1852. }
  1853. // Get messsage body.
  1854. PVOID paArgs[4] = {pszConfilictFeature,
  1855. pszConfilictOption,
  1856. const_cast<PWSTR>(Conflict.pszFeature),
  1857. Conflict.pszOption
  1858. };
  1859. dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1860. pszFormat,
  1861. 0,
  1862. 0,
  1863. (PWSTR) &pszMessage,
  1864. 0,
  1865. (va_list *) paArgs);
  1866. if(0 == dwRet)
  1867. {
  1868. DWORD dwError = GetLastError();
  1869. ERR(ERRORTEXT("SaveFeatureOptItems() failed to FormatMessage() for constraint conflict of feature %hs option %hs. (Last Error %d)\r\n"),
  1870. Conflict.pszFeatureKeyword,
  1871. Conflict.pszOptionKeyword,
  1872. dwError);
  1873. hrResult = HRESULT_FROM_WIN32(dwError);
  1874. goto Exit;
  1875. }
  1876. // Display simple message box with prompt.
  1877. nRet = MessageBox(hWnd, pszMessage, pszCaption, MB_YESNO | MB_ICONWARNING);
  1878. // Check to see how user wants to resolve conflict.
  1879. if(IDYES == nRet)
  1880. {
  1881. // Let core driver resolve conflict resolution.
  1882. hrResult = pHelper->SetOptions(poemuiobj,
  1883. SETOPTIONS_FLAG_RESOLVE_CONFLICT,
  1884. pmszPairs,
  1885. dwSize,
  1886. &dwResult);
  1887. // Conflict resolution requires refreshing current option
  1888. // selection for each feature, since selection may have
  1889. // changed because of conflict resolution.
  1890. RefreshOptItemSelection(pHelper, poemuiobj, pOptItem, wItems);
  1891. }
  1892. // Return failure if there are still conflictts.
  1893. if(SETOPTIONS_RESULT_CONFLICT_REMAINED == dwResult)
  1894. {
  1895. hrResult = E_FAIL;
  1896. }
  1897. }
  1898. Exit:
  1899. // Clean up...
  1900. // cleanup heap allocs.
  1901. if(NULL != pmszPairs) HeapFree(hHeap, 0, pmszPairs);
  1902. if(NULL != ppszReasons) HeapFree(hHeap, 0, ppszReasons);
  1903. if(NULL != pszConfilictFeature) HeapFree(hHeap, 0, pszConfilictFeature);
  1904. if(NULL != pszConfilictOption) HeapFree(hHeap, 0, pszConfilictOption);
  1905. if(NULL != pszCaption) HeapFree(hHeap, 0, pszCaption);
  1906. if(NULL != pszFormat) HeapFree(hHeap, 0, pszFormat);
  1907. if(NULL != pszMessage) LocalFree(pszMessage);
  1908. return hrResult;
  1909. }
  1910. // Allocates buffer, if needed, and calls IPrintCoreUI2::WhyConsrained
  1911. // to get reason for constraint.
  1912. HRESULT GetWhyConstrained(HANDLE hHeap,
  1913. CUIHelper *pHelper,
  1914. POEMUIOBJ poemuiobj,
  1915. PCSTR pszFeature,
  1916. PCSTR pszOption,
  1917. PSTR *ppmszReason,
  1918. PDWORD pdwSize)
  1919. {
  1920. PSTR pmszReasonList = *ppmszReason;
  1921. DWORD dwNeeded = 0;
  1922. HRESULT hrResult = S_OK;
  1923. // If buffer wasn't passed in, then allocate one.
  1924. if( (NULL == pmszReasonList) || (0 == *pdwSize) )
  1925. {
  1926. // If no size or size is smaller than default, then change to default
  1927. // size. We want to try to only allocate and call once.
  1928. if(*pdwSize < INITIAL_GET_REASON_SIZE)
  1929. {
  1930. *pdwSize = INITIAL_GET_REASON_SIZE;
  1931. }
  1932. // Alloc initial buffer for reason constrained.
  1933. pmszReasonList = (PSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, *pdwSize);
  1934. if(NULL == pmszReasonList)
  1935. {
  1936. ERR(ERRORTEXT("GetWhyConstrained() failed to alloc buffer for constraint reasons for feature %hs and option %hs.\r\n"),
  1937. pszFeature,
  1938. pszOption);
  1939. hrResult = E_OUTOFMEMORY;
  1940. goto Exit;
  1941. }
  1942. }
  1943. // Get reason for constraint.
  1944. hrResult = pHelper->WhyConstrained(poemuiobj,
  1945. 0,
  1946. pszFeature,
  1947. pszOption,
  1948. pmszReasonList,
  1949. *pdwSize,
  1950. &dwNeeded);
  1951. if( (E_OUTOFMEMORY == hrResult)
  1952. &&
  1953. (*pdwSize < dwNeeded)
  1954. )
  1955. {
  1956. PSTR pTemp;
  1957. // INVARIANT: initial buffer not large enough.
  1958. // Re-alloc buffer to needed size.
  1959. pTemp = (PSTR) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pmszReasonList, dwNeeded);
  1960. if(NULL == pTemp)
  1961. {
  1962. ERR(ERRORTEXT("GetWhyConstrained() failed to re-allocate buffer for constraint reason for feature %hs and option %hs.\r\n"),
  1963. pszFeature,
  1964. pszOption);
  1965. hrResult = E_OUTOFMEMORY;
  1966. goto Exit;
  1967. }
  1968. pmszReasonList = pTemp;
  1969. *pdwSize = dwNeeded;
  1970. // Retry getting constaint reason.
  1971. hrResult = pHelper->WhyConstrained(poemuiobj,
  1972. 0,
  1973. pszFeature,
  1974. pszOption,
  1975. pmszReasonList,
  1976. *pdwSize,
  1977. &dwNeeded);
  1978. }
  1979. Exit:
  1980. // On error, do clean up.
  1981. if(!SUCCEEDED(hrResult))
  1982. {
  1983. // Free reason buffer.
  1984. if(NULL != pmszReasonList) HeapFree(hHeap, 0, pmszReasonList);
  1985. // Return NULL and zero size.
  1986. *ppmszReason = NULL;
  1987. *pdwSize = 0;
  1988. }
  1989. else
  1990. {
  1991. *ppmszReason = pmszReasonList;
  1992. }
  1993. return hrResult;
  1994. }
  1995. // Creates multi-sz list of feature option pairs that have changed.
  1996. HRESULT GetChangedFeatureOptions(HANDLE hHeap,
  1997. POPTITEM pOptItem,
  1998. WORD wItems,
  1999. PSTR *ppmszPairs,
  2000. PWORD pwPairs,
  2001. PDWORD pdwSize)
  2002. {
  2003. WORD wCount = 0;
  2004. WORD wChanged = 0;
  2005. WORD wPairs = 0;
  2006. PSTR pmszPairs = NULL;
  2007. DWORD dwNeeded = 2;
  2008. DWORD dwOffset = 0;
  2009. HRESULT hrResult = S_OK;
  2010. PFEATUREOPTITEMDATA pData = NULL;
  2011. // Walk OPTITEM array looking or changed options,
  2012. // and calculating size needed for multi-sz buffer.
  2013. for(wCount = 0; wCount < wItems; ++wCount)
  2014. {
  2015. PSTR pszOption = NULL;
  2016. // Just go to next item if this OPTITEM hasn't
  2017. // changed or isn't a feature OPTITEM.
  2018. if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags)
  2019. ||
  2020. !IsFeatureOptitem(pOptItem + wCount)
  2021. )
  2022. {
  2023. continue;
  2024. }
  2025. // For convienience, assign to pointer to feature OPTITEM data.
  2026. pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
  2027. // Increment options changed and size needed.
  2028. pszOption = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount);
  2029. if(NULL != pszOption)
  2030. {
  2031. ++wChanged;
  2032. dwNeeded += lstrlenA(pData->pszFeatureKeyword) + lstrlenA(pszOption) + 2;
  2033. // Need to free option keyword string copy
  2034. // allocated in GetOptionKeywordFromOptItem().
  2035. HeapFree(hHeap, 0, pszOption);
  2036. }
  2037. }
  2038. // Don't need to do anything more if no feature options changed.
  2039. if(0 == wChanged)
  2040. {
  2041. goto Exit;
  2042. }
  2043. // Allocate multi-sz buffer.
  2044. pmszPairs = (PSTR) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwNeeded);
  2045. if(NULL == pmszPairs)
  2046. {
  2047. ERR(ERRORTEXT("GetChangedFeatureOptions() failed to allocate multi-sz.\r\n"));
  2048. hrResult = E_OUTOFMEMORY;
  2049. goto Exit;
  2050. }
  2051. // Build mult-sz list of feature option pairs
  2052. // that changed.
  2053. for(wCount = 0, wPairs = 0; (wCount < wItems) && (wPairs < wChanged); ++wCount)
  2054. {
  2055. PSTR pszOption = NULL;
  2056. // Just go to next item if this OPTITEM hasn't
  2057. // changed or isn't a feature OPTITEM.
  2058. if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags)
  2059. ||
  2060. !IsFeatureOptitem(pOptItem + wCount)
  2061. )
  2062. {
  2063. continue;
  2064. }
  2065. // For convienience, assign to pointer to feature OPTITEM data.
  2066. pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
  2067. // Add feature option pair.
  2068. pszOption = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount);
  2069. if(NULL != pszOption)
  2070. {
  2071. if(dwOffset * sizeof(CHAR) < dwNeeded)
  2072. {
  2073. break;
  2074. }
  2075. hrResult = StringCbCopyA(pmszPairs + dwOffset, dwNeeded - (dwOffset * sizeof(CHAR)), pData->pszFeatureKeyword);
  2076. dwOffset += lstrlenA(pData->pszFeatureKeyword) + 1;
  2077. if(dwOffset * sizeof(CHAR) < dwNeeded)
  2078. {
  2079. break;
  2080. }
  2081. hrResult = StringCbCopyA(pmszPairs + dwOffset, dwNeeded - (dwOffset * sizeof(CHAR)), pszOption);
  2082. dwOffset += lstrlenA(pszOption) + 1;
  2083. // Keep track of number of pairs added, so
  2084. // we are able to exit loop as soon as
  2085. // we added all changed feature options.
  2086. ++wPairs;
  2087. // Need to free option keyword string copy
  2088. // allocated in GetOptionKeywordFromOptItem().
  2089. HeapFree(hHeap, 0, pszOption);
  2090. }
  2091. }
  2092. Exit:
  2093. if(SUCCEEDED(hrResult))
  2094. {
  2095. // INVARIANT: either successfully build mutli-sz of changed
  2096. // feature option pairs, or there are no feature
  2097. // that options changed.
  2098. // Return pairs and number of pairs.
  2099. *pwPairs = wPairs;
  2100. *pdwSize = dwNeeded;
  2101. *ppmszPairs = pmszPairs;
  2102. }
  2103. else
  2104. {
  2105. // INVARINAT: error.
  2106. // Clean up.
  2107. if(NULL == pmszPairs) HeapFree(hHeap, 0, pmszPairs);
  2108. // Return NULL and zero count.
  2109. *pwPairs = 0;
  2110. *pdwSize = 0;
  2111. *ppmszPairs = NULL;
  2112. }
  2113. return hrResult;
  2114. }
  2115. // Returns pointer to option keyword for a feature OPTITEM.
  2116. PSTR GetOptionKeywordFromOptItem(HANDLE hHeap, POPTITEM pOptItem)
  2117. {
  2118. char szNumber[16] = {0};
  2119. PSTR pszOption = NULL;
  2120. PFEATUREOPTITEMDATA pData = NULL;
  2121. // Validate parameter.
  2122. if(!IsFeatureOptitem(pOptItem))
  2123. {
  2124. ERR(ERRORTEXT("GetOptionKeywordFromOptItem() invalid parameter.\r\n"));
  2125. goto Exit;
  2126. }
  2127. // For convienience, assign to pointer to feature OPTITEM data.
  2128. pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
  2129. // Option selection is based on type of OPTTYPE.
  2130. switch(pOptItem->pOptType->Type)
  2131. {
  2132. // For up down arrow control, selection is just pOptItem->Sel
  2133. // converted to string.
  2134. case TVOT_UDARROW:
  2135. if(FAILED(StringCbPrintfA(szNumber, sizeof(szNumber)/sizeof(szNumber[0]), "%u", pOptItem->Sel)))
  2136. {
  2137. ERR(ERRORTEXT("GetOptionKeywordFromOptItem() failed to convert number to string.\r\n"));
  2138. }
  2139. szNumber[sizeof(szNumber)/sizeof(szNumber[0]) - 1] = '\0';
  2140. pszOption = MakeStringCopy(hHeap, szNumber);
  2141. break;
  2142. // For combobox, pOptItem->Sel is the index in to the
  2143. // option array.
  2144. case TVOT_COMBOBOX:
  2145. pszOption = MakeStringCopy(hHeap, pData->pOptions->GetKeyword((WORD)pOptItem->Sel));
  2146. break;
  2147. // The default is the option count.
  2148. default:
  2149. ERR(ERRORTEXT("GetOptionKeywordFromOptItem() OPTTYPE type %d num of OPTPARAMs not handled.\r\n"),
  2150. pOptItem->pOptType->Type);
  2151. goto Exit;
  2152. break;
  2153. }
  2154. Exit:
  2155. return pszOption;
  2156. }
  2157. // Returns pointer to option display name for a feature OPTITEM.
  2158. PWSTR GetOptionDisplayNameFromOptItem(HANDLE hHeap, POPTITEM pOptItem)
  2159. {
  2160. WCHAR szNumber[16] = {0};
  2161. PWSTR pszOption = NULL;
  2162. PFEATUREOPTITEMDATA pData = NULL;
  2163. // Validate parameter.
  2164. if(!IsFeatureOptitem(pOptItem))
  2165. {
  2166. ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() invalid parameter.\r\n"));
  2167. goto Exit;
  2168. }
  2169. // For convienience, assign to pointer to feature OPTITEM data.
  2170. pData = (PFEATUREOPTITEMDATA)(pOptItem->UserData);
  2171. // Option selection is based on type of OPTTYPE.
  2172. switch(pOptItem->pOptType->Type)
  2173. {
  2174. // For up down arrow control, selection is just pOptItem->Sel
  2175. // converted to string.
  2176. case TVOT_UDARROW:
  2177. if(FAILED(StringCbPrintfW(szNumber, sizeof(szNumber)/sizeof(szNumber[0]), L"%u", pOptItem->Sel)))
  2178. {
  2179. ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() failed to convert number to string.\r\n"));
  2180. }
  2181. szNumber[sizeof(szNumber)/sizeof(szNumber[0]) - 1] = L'\0';
  2182. pszOption = MakeStringCopy(hHeap, szNumber);
  2183. break;
  2184. // For combobox, pOptItem->Sel is the index in to the
  2185. // option array.
  2186. case TVOT_COMBOBOX:
  2187. pszOption = MakeStringCopy(hHeap, pOptItem->pOptType->pOptParam[pOptItem->Sel].pData);
  2188. break;
  2189. // The default is the option count.
  2190. default:
  2191. ERR(ERRORTEXT("GetOptionDisplayNameFromOptItem() OPTTYPE type %d num of OPTPARAMs not handled.\r\n"),
  2192. pOptItem->pOptType->Type);
  2193. goto Exit;
  2194. break;
  2195. }
  2196. Exit:
  2197. return pszOption;
  2198. }
  2199. // Refreshes option selection for each feature OPTITEM
  2200. HRESULT RefreshOptItemSelection(CUIHelper *pHelper,
  2201. POEMUIOBJ poemuiobj,
  2202. POPTITEM pOptItems,
  2203. WORD wItems)
  2204. {
  2205. HRESULT hrResult = S_OK;
  2206. PFEATUREOPTITEMDATA pData = NULL;
  2207. // Walk OPTITEM array refreshing feature OPTITEMs.
  2208. for(WORD wCount = 0; wCount < wItems; ++wCount)
  2209. {
  2210. // Just go to next item if this OPTITEM isn't a feature OPTITEM.
  2211. if(!IsFeatureOptitem(pOptItems + wCount))
  2212. {
  2213. continue;
  2214. }
  2215. // For convienience, assign to pointer to feature OPTITEM data.
  2216. pData = (PFEATUREOPTITEMDATA)(pOptItems[wCount].UserData);
  2217. // Refresh COption selection.
  2218. pData->pOptions->RefreshSelection(*pHelper, poemuiobj);
  2219. // Assign COption selection to OPTITEM selection.
  2220. pOptItems[wCount].pSel = pData->pOptions->GetSelection();
  2221. }
  2222. return hrResult;
  2223. }
  2224. // Creates array of conflict features.
  2225. HRESULT GetFirstConflictingFeature(HANDLE hHeap,
  2226. CUIHelper *pHelper,
  2227. POEMUIOBJ poemuiobj,
  2228. POPTITEM pOptItem,
  2229. WORD wItems,
  2230. PCONFLICT pConflict)
  2231. {
  2232. WORD wCount = 0;
  2233. HRESULT hrResult = S_OK;
  2234. PFEATUREOPTITEMDATA pData = NULL;
  2235. // Walk OPTITEM array looking or changed options that are in conflict.
  2236. for(wCount = 0; wCount < wItems; ++wCount)
  2237. {
  2238. // Just go to next item if this OPTITEM hasn't
  2239. // changed or isn't a feature OPTITEM.
  2240. if( !(OPTIF_CHANGEONCE & pOptItem[wCount].Flags)
  2241. ||
  2242. !IsFeatureOptitem(pOptItem + wCount)
  2243. )
  2244. {
  2245. continue;
  2246. }
  2247. // For convienience, assign to pointer to feature OPTITEM data.
  2248. pData = (PFEATUREOPTITEMDATA)(pOptItem[wCount].UserData);
  2249. // Init conflict record if this feature is in conflict.
  2250. pConflict->pszOptionKeyword = GetOptionKeywordFromOptItem(hHeap, pOptItem + wCount);
  2251. if(NULL != pConflict->pszOptionKeyword)
  2252. {
  2253. // Get reason for conflict
  2254. // If the feature isn't in conflict,
  2255. // then the pmszReasonList will start
  2256. // with NULL terminator.
  2257. hrResult = GetWhyConstrained(hHeap,
  2258. pHelper,
  2259. poemuiobj,
  2260. pData->pszFeatureKeyword,
  2261. pConflict->pszOptionKeyword,
  2262. &pConflict->pmszReasons,
  2263. &pConflict->dwReasonsSize);
  2264. if(!SUCCEEDED(hrResult))
  2265. {
  2266. // NOTE: driver features aren't supported by WhyConstrained.
  2267. if((E_INVALIDARG == hrResult) && IS_DRIVER_FEATURE(pData->pszFeatureKeyword))
  2268. {
  2269. // Need to reset the result in case it is the last
  2270. // feature OPTITEM.
  2271. hrResult = S_OK;
  2272. continue;
  2273. }
  2274. ERR(ERRORTEXT("GetConflictingFeatures() failed to get reason for feature %hs option %hs constraint. (hrResult = 0x%x)\r\n"),
  2275. pData->pszFeatureKeyword,
  2276. pConflict->pszOptionKeyword,
  2277. hrResult);
  2278. goto Exit;
  2279. }
  2280. // Record conflict if feature is in conflict.
  2281. if( (NULL != pConflict->pmszReasons)
  2282. &&
  2283. (pConflict->pmszReasons[0] != '\0')
  2284. )
  2285. {
  2286. // Save pointer to feature keyword.
  2287. pConflict->pszFeatureKeyword = pData->pszFeatureKeyword;
  2288. pConflict->pszFeature = pOptItem[wCount].pName;
  2289. pConflict->pszOption = GetOptionDisplayNameFromOptItem(hHeap, pOptItem + wCount);
  2290. // Found first conflict.
  2291. break;
  2292. }
  2293. }
  2294. }
  2295. Exit:
  2296. return hrResult;
  2297. }