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.

2286 lines
60 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. oemutil.c
  5. Abstract:
  6. Library functions to implement OEM plugin architecture
  7. Environment:
  8. Windows NT printer driver
  9. Revision History:
  10. 04/17/97 -davidx-
  11. Provide OEM plugins access to driver private settings.
  12. 01/24/97 -davidx-
  13. Add function for loading DLLs and get entrypoint addresses.
  14. 01/21/97 -davidx-
  15. Created it.
  16. --*/
  17. #define DEFINE_OEMPROC_NAMES
  18. #include "lib.h"
  19. #ifndef KERNEL_MODE
  20. #include <winddiui.h>
  21. #endif
  22. #include <printoem.h>
  23. #include "oemutil.h"
  24. //
  25. // Macros used to loop through each OEM plugin
  26. //
  27. #define FOREACH_OEMPLUGIN_LOOP(pOemPlugins) \
  28. { \
  29. DWORD _oemCount = (pOemPlugins)->dwCount; \
  30. POEM_PLUGIN_ENTRY pOemEntry = (pOemPlugins)->aPlugins; \
  31. for ( ; _oemCount--; pOemEntry++) \
  32. {
  33. #define END_OEMPLUGIN_LOOP \
  34. } \
  35. }
  36. BOOL
  37. BExpandOemFilename(
  38. PTSTR *ppDest,
  39. LPCTSTR pSrc,
  40. LPCTSTR pDir
  41. )
  42. /*++
  43. Routine Description:
  44. Expand an OEM plugin filename to a fully qualified pathname
  45. Arguments:
  46. ppDest - Returns a pointer to fully qualified OEM filename
  47. pSrc - Specifies OEM filename without any directory prefix
  48. pDir - Specifies printer driver directory
  49. Return Value:
  50. TRUE if successful, FALSE if there is an error
  51. --*/
  52. {
  53. INT iSrcLen, iDirLen;
  54. PTSTR pDest;
  55. *ppDest = NULL;
  56. if (pSrc != NULL && pDir != NULL)
  57. {
  58. iSrcLen = _tcslen(pSrc);
  59. iDirLen = _tcslen(pDir);
  60. if ((pDest = MemAlloc((iSrcLen + iDirLen + 1) * sizeof(TCHAR))) == NULL)
  61. {
  62. ERR(("Memory allocation failed\n"));
  63. return FALSE;
  64. }
  65. CopyMemory(pDest, pDir, iDirLen * sizeof(TCHAR));
  66. CopyMemory(pDest+iDirLen, pSrc, (iSrcLen+1) * sizeof(TCHAR));
  67. *ppDest = pDest;
  68. }
  69. return TRUE;
  70. }
  71. POEM_PLUGINS
  72. PGetOemPluginInfo(
  73. HANDLE hPrinter,
  74. LPCTSTR pctstrDriverPath,
  75. PDRIVER_INFO_3 pDriverInfo3
  76. )
  77. /*++
  78. Routine Description:
  79. Get information about OEM plugins for a printer
  80. Arguments:
  81. hPrinter - Handle to a printer
  82. pctstrDriverPath - Points to the full pathname of driver DLL
  83. Return Value:
  84. Pointer to OEM plugin information for the printer
  85. NULL if there is an error
  86. Note:
  87. If there is no OEM plugin associated with the printer,
  88. an OEM_PLUGINS structure is still returned but
  89. its dwCount field will be zero.
  90. Notice the difference between user-mode and kernel-mode implementations.
  91. In user-mode, we're only interested in OEMConfigFileN and OEMHelpFileN.
  92. In kernel-mode, we're only interested in OEMDriverFileN.
  93. --*/
  94. {
  95. LPCTSTR driverfiles[MAX_OEM_PLUGINS];
  96. LPCTSTR configfiles[MAX_OEM_PLUGINS];
  97. LPCTSTR helpfiles[MAX_OEM_PLUGINS];
  98. POEM_PLUGINS pOemPlugins;
  99. PTSTR ptstrIniData = NULL;
  100. PTSTR pTemp = NULL;
  101. DWORD dwCount = 0;
  102. //
  103. // Retrieve the data from model-specific printer INI file
  104. //
  105. //
  106. // Fixing RC1 bug #423567
  107. //
  108. #if 0
  109. if (hPrinter)
  110. ptstrIniData = PtstrGetPrinterDataMultiSZPair(hPrinter, REGVAL_INIDATA, NULL);
  111. #endif
  112. //
  113. // In the following 2 cases, we need to parse the INI file:
  114. //
  115. // 1. hPrinter is NULL;
  116. //
  117. // 2. When NT5 Unidrv/PScript5 client connecting to NT4 RASDD/PScript server,
  118. // the server printer's registry initially doesn't contain the REGVAL_INIDATA,
  119. // so we need to parse the INI file and write it into RASDD/PScript registry.
  120. //
  121. if (hPrinter == NULL || ptstrIniData == NULL)
  122. {
  123. if (BProcessPrinterIniFile(hPrinter, pDriverInfo3, &pTemp, 0))
  124. ptstrIniData = pTemp;
  125. else
  126. ptstrIniData = NULL;
  127. }
  128. if (ptstrIniData != NULL)
  129. {
  130. TCHAR atchDriverKey[20];
  131. TCHAR atchConfigKey[20];
  132. TCHAR atchHelpKey[20];
  133. PTSTR ptstrDriverKeyDigit;
  134. PTSTR ptstrConfigKeyDigit;
  135. PTSTR ptstrHelpKeyDigit;
  136. ZeroMemory((PVOID) driverfiles, sizeof(driverfiles));
  137. ZeroMemory((PVOID) configfiles, sizeof(configfiles));
  138. ZeroMemory((PVOID) helpfiles, sizeof(helpfiles));
  139. StringCchCopyW(atchDriverKey, CCHOF(atchDriverKey), TEXT("OEMDriverFile1"));
  140. StringCchCopyW(atchConfigKey, CCHOF(atchConfigKey), TEXT("OEMConfigFile1"));
  141. StringCchCopyW(atchHelpKey, CCHOF(atchHelpKey), TEXT("OEMHelpFile1"));
  142. ptstrDriverKeyDigit = &atchDriverKey[_tcslen(atchDriverKey) - 1];
  143. ptstrConfigKeyDigit = &atchConfigKey[_tcslen(atchConfigKey) - 1];
  144. ptstrHelpKeyDigit = &atchHelpKey[_tcslen(atchHelpKey) - 1];
  145. while (TRUE)
  146. {
  147. //
  148. // Find the files associated with the next OEM plugin.
  149. // Stop if there are no more OEM plugins left.
  150. //
  151. driverfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchDriverKey);
  152. configfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchConfigKey);
  153. helpfiles[dwCount] = PtstrSearchStringInMultiSZPair(ptstrIniData, atchHelpKey);
  154. if (!driverfiles[dwCount] && !configfiles[dwCount] && !helpfiles[dwCount])
  155. break;
  156. //
  157. // Check if there are too many OEM plugins
  158. //
  159. if (dwCount >= MAX_OEM_PLUGINS)
  160. {
  161. ERR(("Exceeded max number of OEM plugins allowed: %d\n", MAX_OEM_PLUGINS));
  162. break;
  163. }
  164. //
  165. // Move on to look for the next OEM plugin
  166. // We assume max number of plugins is less than 10
  167. //
  168. dwCount++;
  169. (*ptstrDriverKeyDigit)++;
  170. (*ptstrConfigKeyDigit)++;
  171. (*ptstrHelpKeyDigit)++;
  172. }
  173. }
  174. if ((pOemPlugins = MemAllocZ(offsetof(OEM_PLUGINS, aPlugins) +
  175. sizeof(OEM_PLUGIN_ENTRY) * dwCount)) == NULL)
  176. {
  177. ERR(("Memory allocation failed\n"));
  178. }
  179. else if (pOemPlugins->dwCount = dwCount)
  180. {
  181. PTSTR ptstrDriverDir;
  182. BOOL bResult = TRUE;
  183. VERBOSE(("Number of OEM plugins installed: %d\n", dwCount));
  184. dwCount = 0;
  185. if ((ptstrDriverDir = PtstrGetDriverDirectory(pctstrDriverPath)) == NULL)
  186. {
  187. ERR(("Couldn't get printer driver directory\n"));
  188. bResult = FALSE;
  189. }
  190. else
  191. {
  192. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  193. #ifdef KERNEL_MODE
  194. bResult = BExpandOemFilename(&pOemEntry->ptstrDriverFile,
  195. driverfiles[dwCount],
  196. ptstrDriverDir);
  197. #else
  198. bResult = BExpandOemFilename(&pOemEntry->ptstrConfigFile,
  199. configfiles[dwCount],
  200. ptstrDriverDir) &&
  201. BExpandOemFilename(&pOemEntry->ptstrHelpFile,
  202. helpfiles[dwCount],
  203. ptstrDriverDir);
  204. #endif
  205. if (! bResult)
  206. break;
  207. dwCount++;
  208. END_OEMPLUGIN_LOOP
  209. MemFree(ptstrDriverDir);
  210. }
  211. if (! bResult)
  212. {
  213. VFreeOemPluginInfo(pOemPlugins);
  214. pOemPlugins = NULL;
  215. }
  216. }
  217. MemFree(ptstrIniData);
  218. return pOemPlugins;
  219. }
  220. VOID
  221. VFreeSinglePluginEntry(
  222. POEM_PLUGIN_ENTRY pOemEntry
  223. )
  224. /*++
  225. Routine Description:
  226. Unload one plugin and dispose information about it
  227. Arguments:
  228. pOemEntry - Pointer to the single plugin entry information
  229. Return Value:
  230. NONE
  231. --*/
  232. {
  233. if (pOemEntry->hInstance)
  234. {
  235. //
  236. // Since we are calling plugin's DllInitialize(DLL_PROCESS_ATTACH)
  237. // no matter the plugin is using COM or non-COM interface, we must
  238. // do the same for DllInitialize(DLL_PROCESS_DETACH), so plugin will
  239. // get balanced DllInitialize calls.
  240. //
  241. if (HAS_COM_INTERFACE(pOemEntry))
  242. {
  243. ReleaseOemInterface(pOemEntry);
  244. #if defined(KERNEL_MODE) && defined(WINNT_40)
  245. //
  246. // This must be called after COM interface is released,
  247. // because the Release() interface function still needs
  248. // the kernel semaphore.
  249. //
  250. (void) BHandleOEMInitialize(pOemEntry, DLL_PROCESS_DETACH);
  251. #endif // KERNEL_MODE && WINNT_40
  252. //
  253. // FreeLibrary happens in Driver_CoFreeOEMLibrary
  254. //
  255. #if defined(KERNEL_MODE)
  256. if ( !(pOemEntry->dwFlags & OEMNOT_UNLOAD_PLUGIN) )
  257. #endif
  258. Driver_CoFreeOEMLibrary(pOemEntry->hInstance);
  259. }
  260. else
  261. {
  262. #if defined(KERNEL_MODE) && defined(WINNT_40)
  263. (void) BHandleOEMInitialize(pOemEntry, DLL_PROCESS_DETACH);
  264. #endif // KERNEL_MODE && WINNT_40
  265. #if defined(KERNEL_MODE)
  266. if ( !(pOemEntry->dwFlags & OEMNOT_UNLOAD_PLUGIN) )
  267. #endif
  268. FreeLibrary(pOemEntry->hInstance);
  269. }
  270. pOemEntry->hInstance = NULL;
  271. }
  272. //
  273. // BHandleOEMInitialize needs to use the kernel mode render plugin
  274. // DLL name, so we should free the names here.
  275. //
  276. MemFree(pOemEntry->ptstrDriverFile);
  277. MemFree(pOemEntry->ptstrConfigFile);
  278. MemFree(pOemEntry->ptstrHelpFile);
  279. pOemEntry->ptstrDriverFile = NULL;
  280. pOemEntry->ptstrConfigFile = NULL;
  281. pOemEntry->ptstrHelpFile = NULL;
  282. }
  283. VOID
  284. VFreeOemPluginInfo(
  285. POEM_PLUGINS pOemPlugins
  286. )
  287. /*++
  288. Routine Description:
  289. Dispose of information about OEM plugins
  290. Arguments:
  291. pOemPlugins - Pointer to OEM plugin information
  292. Return Value:
  293. NONE
  294. --*/
  295. {
  296. ASSERT(pOemPlugins != NULL);
  297. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  298. #if defined(KERNEL_MODE)
  299. //
  300. // If this is debug build, and if the appropriate registry flag
  301. // (DoNotUnloadPluginDLL) is set, then the OEM plugin driver
  302. // should not be unloaded.
  303. // One use of this is to find out memory leaks using umdh/dhcmp.
  304. // umdh.exe needs the plugin to be present in the memory to give a
  305. // good stack trace.
  306. //
  307. DWORD dwType = 0;
  308. DWORD ul = 0;
  309. DWORD dwNotUnloadPluginDLL = 0;
  310. PDEVOBJ pdevobj = (PDEVOBJ) (pOemPlugins->pdriverobj);
  311. if( pdevobj &&
  312. (GetPrinterData( pdevobj->hPrinter,
  313. L"DoNotUnloadPluginDLL",
  314. &dwType,
  315. (LPBYTE) &dwNotUnloadPluginDLL,
  316. sizeof( dwNotUnloadPluginDLL ),
  317. &ul ) == ERROR_SUCCESS) &&
  318. ul == sizeof( dwNotUnloadPluginDLL ) &&
  319. dwNotUnloadPluginDLL )
  320. {
  321. pOemEntry->dwFlags |= OEMNOT_UNLOAD_PLUGIN;
  322. }
  323. #endif
  324. VFreeSinglePluginEntry(pOemEntry);
  325. END_OEMPLUGIN_LOOP
  326. MemFree(pOemPlugins);
  327. }
  328. BOOL
  329. BLoadOEMPluginModules(
  330. POEM_PLUGINS pOemPlugins
  331. )
  332. /*++
  333. Routine Description:
  334. Load OEM plugins modules into memory
  335. Arguments:
  336. pOemPlugins - Points to OEM plugin info structure
  337. Return Value:
  338. TRUE if successful, FALSE if there is an error
  339. --*/
  340. {
  341. PFN_OEMGetInfo pfnOEMGetInfo;
  342. DWORD dwData, dwSize;
  343. DWORD dwCount, dwIndex;
  344. PTSTR ptstrDllName;
  345. //
  346. // Quick exit when no OEM plugin is installed
  347. //
  348. if (pOemPlugins->dwCount == 0)
  349. return TRUE;
  350. //
  351. // Load each OEM module in turn
  352. //
  353. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  354. //
  355. // Load driver or config DLL depending on whether
  356. // we're being called from kernel or user mode
  357. //
  358. if (ptstrDllName = CURRENT_OEM_MODULE_NAME(pOemEntry))
  359. {
  360. //
  361. // Return failure if there is an error when loading the OEM module
  362. // or if the OEM module doesn't export OEMGetInfo entrypoint
  363. //
  364. // Note: LoadLibraryEx is only available for UI mode and user-mode
  365. // rendering module
  366. //
  367. #if defined(KERNEL_MODE) && defined(WINNT_40)
  368. if (! (pOemEntry->hInstance = LoadLibrary(ptstrDllName)) )
  369. {
  370. ERR(("LoadLibrary failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  371. goto oemload_error;
  372. }
  373. //
  374. // Notice this is called no matter plugin uses COM or non-COM interface.
  375. //
  376. if (!BHandleOEMInitialize(pOemEntry, DLL_PROCESS_ATTACH))
  377. {
  378. ERR(("BHandleOEMInitialize failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  379. goto oemload_error;
  380. }
  381. #else // !KERNEL_MODE || !WINNT_40
  382. SetErrorMode(SEM_FAILCRITICALERRORS);
  383. if (! (pOemEntry->hInstance = LoadLibraryEx(ptstrDllName,
  384. NULL,
  385. LOAD_WITH_ALTERED_SEARCH_PATH)) )
  386. {
  387. ERR(("LoadLibrary failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  388. goto oemload_error;
  389. }
  390. #endif // KERNEL_MODE && WINNT_40
  391. //
  392. // If we can get an interface from OEM plugin, then OEM is using COM interface
  393. //
  394. if (BGetOemInterface(pOemEntry))
  395. {
  396. ASSERT(pOemEntry->pIntfOem != NULL);
  397. }
  398. else
  399. {
  400. //
  401. // Make sure to NULL the pointer to indicate no COM interface available.
  402. //
  403. pOemEntry->pIntfOem = NULL;
  404. }
  405. //
  406. // Call OEMGetInfo to verify interface version and
  407. // get OEM module's signature
  408. //
  409. if (HAS_COM_INTERFACE(pOemEntry))
  410. {
  411. if (!SUCCEEDED(HComOEMGetInfo(pOemEntry,
  412. OEMGI_GETSIGNATURE,
  413. &pOemEntry->dwSignature,
  414. sizeof(DWORD),
  415. &dwSize)) ||
  416. pOemEntry->dwSignature == 0)
  417. {
  418. ERR(("HComOEMGetInfo failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  419. goto oemload_error;
  420. }
  421. }
  422. else
  423. {
  424. if (!(pfnOEMGetInfo = GET_OEM_ENTRYPOINT(pOemEntry, OEMGetInfo)) ||
  425. !pfnOEMGetInfo(OEMGI_GETINTERFACEVERSION, &dwData, sizeof(DWORD), &dwSize) ||
  426. dwData != PRINTER_OEMINTF_VERSION ||
  427. !pfnOEMGetInfo(OEMGI_GETSIGNATURE, &pOemEntry->dwSignature, sizeof(DWORD), &dwSize) ||
  428. pOemEntry->dwSignature == 0)
  429. {
  430. ERR(("OEMGetInfo failed for OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  431. goto oemload_error;
  432. }
  433. }
  434. continue;
  435. oemload_error:
  436. ERR(("Failed to load OEM module '%ws': %d\n", ptstrDllName, GetLastError()));
  437. return FALSE;
  438. }
  439. END_OEMPLUGIN_LOOP
  440. //
  441. // Verify that no two OEM modules share the same signature
  442. //
  443. for (dwCount = 1; dwCount < pOemPlugins->dwCount; dwCount++)
  444. {
  445. POEM_PLUGIN_ENTRY pOemEntry;
  446. pOemEntry = &pOemPlugins->aPlugins[dwCount];
  447. if (pOemEntry->hInstance == NULL)
  448. continue;
  449. for (dwIndex=0; dwIndex < dwCount; dwIndex++)
  450. {
  451. //
  452. // If there is a signature conflict, unload the plugin
  453. // which appears later in the order.
  454. //
  455. if (pOemPlugins->aPlugins[dwIndex].dwSignature == pOemEntry->dwSignature)
  456. {
  457. ERR(("Duplicate signature for OEM plugins\n"));
  458. VFreeSinglePluginEntry(pOemEntry);
  459. pOemEntry->dwSignature = 0;
  460. break;
  461. }
  462. }
  463. }
  464. return TRUE;
  465. }
  466. OEMPROC
  467. PGetOemEntrypointAddress(
  468. POEM_PLUGIN_ENTRY pOemEntry,
  469. DWORD dwIndex
  470. )
  471. /*++
  472. Routine Description:
  473. Get the address for the specified OEM entrypoint
  474. Arguments:
  475. pOemEntry - Points to information about the OEM module
  476. dwIndex - OEM entrypoint index
  477. Return Value:
  478. Address of the specified OEM entrypoint
  479. NULL if the entrypoint is not found or if there is an error
  480. --*/
  481. {
  482. ASSERT(dwIndex < MAX_OEMENTRIES);
  483. BITSET(pOemEntry->aubProcFlags, dwIndex);
  484. if (pOemEntry->hInstance != NULL)
  485. {
  486. pOemEntry->oemprocs[dwIndex] = (OEMPROC)
  487. GetProcAddress(pOemEntry->hInstance, OEMProcNames[dwIndex]);
  488. #if 0
  489. if (pOemEntry->oemprocs[dwIndex] == NULL && GetLastError() != ERROR_PROC_NOT_FOUND)
  490. ERR(("Couldn't find proc %s: %d\n", OEMProcNames[dwIndex], GetLastError()));
  491. #endif
  492. }
  493. return pOemEntry->oemprocs[dwIndex];
  494. }
  495. POEM_PLUGIN_ENTRY
  496. PFindOemPluginWithSignature(
  497. POEM_PLUGINS pOemPlugins,
  498. DWORD dwSignature
  499. )
  500. /*++
  501. Routine Description:
  502. Find the OEM plugin entry having the specified signature
  503. Arguments:
  504. pOemPlugins - Specifies information about all loaded OEM plugins
  505. dwSignature - Specifies the signature in question
  506. Return Value:
  507. Pointer to the OEM plugin entry having the specified signature
  508. NULL if no such entry is found
  509. --*/
  510. {
  511. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  512. if (pOemEntry->hInstance == NULL)
  513. continue;
  514. if (pOemEntry->dwSignature == dwSignature)
  515. return pOemEntry;
  516. END_OEMPLUGIN_LOOP
  517. WARNING(("Cannot find OEM plugin whose signature is: 0x%x\n", dwSignature));
  518. return NULL;
  519. }
  520. BOOL
  521. BCalcTotalOEMDMSize(
  522. HANDLE hPrinter,
  523. POEM_PLUGINS pOemPlugins,
  524. PDWORD pdwOemDMSize
  525. )
  526. /*++
  527. Routine Description:
  528. Calculate the total private devmode size for all OEM plugins
  529. Arguments:
  530. hPrinter - Handle to the current printer
  531. pOemPlugins - Specifies information about all loaded OEM plugins
  532. pdwOemDMSize - Return the total private size for all OEM plugins
  533. Return Value:
  534. TRUE if successful, FALSE if there is an error
  535. --*/
  536. {
  537. DWORD dwSize;
  538. OEMDMPARAM OemDMParam;
  539. PFN_OEMDevMode pfnOEMDevMode;
  540. BOOL bOemCalled;
  541. HRESULT hr;
  542. //
  543. // Quick exit when no OEM plugin is installed
  544. //
  545. *pdwOemDMSize = dwSize = 0;
  546. if (pOemPlugins->dwCount == 0)
  547. return TRUE;
  548. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  549. if (pOemEntry->hInstance == NULL)
  550. continue;
  551. bOemCalled = FALSE;
  552. //
  553. // OEM private devmode size is saved in OEM_PLUGIN_ENTRY.dwOEMDMSize
  554. // if this is the very first call, we must call into OEM plugin's
  555. // OEMDevMode entrypoint to find out its private devmode size.
  556. //
  557. if (!(pOemEntry->dwFlags & OEMDEVMODE_CALLED))
  558. {
  559. pOemEntry->dwFlags |= OEMDEVMODE_CALLED;
  560. //
  561. // We reinitialize all field of OemDMParam inside
  562. // the loop in case an ill-behaving plugin touches
  563. // read-only fields.
  564. //
  565. ZeroMemory(&OemDMParam, sizeof(OemDMParam));
  566. OemDMParam.cbSize = sizeof(OemDMParam);
  567. OemDMParam.pdriverobj = pOemPlugins->pdriverobj;
  568. OemDMParam.hPrinter = hPrinter;
  569. OemDMParam.hModule = pOemEntry->hInstance;
  570. if (HAS_COM_INTERFACE(pOemEntry))
  571. {
  572. hr = HComOEMDevMode(pOemEntry, OEMDM_SIZE, &OemDMParam);
  573. if ((hr != E_NOTIMPL) && FAILED(hr))
  574. {
  575. ERR(("Cannot get OEM devmode size for '%ws': %d\n",
  576. CURRENT_OEM_MODULE_NAME(pOemEntry),
  577. GetLastError()));
  578. return FALSE;
  579. }
  580. if (SUCCEEDED(hr))
  581. bOemCalled = TRUE;
  582. }
  583. else
  584. {
  585. if (!BITTST((pOemEntry)->aubProcFlags, EP_OEMDevMode) &&
  586. (pfnOEMDevMode = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevMode)))
  587. {
  588. //
  589. // Query OEM plugin to find out the size of their
  590. // private devmode size.
  591. //
  592. if (! pfnOEMDevMode(OEMDM_SIZE, &OemDMParam))
  593. {
  594. ERR(("Cannot get OEM devmode size for '%ws': %d\n",
  595. CURRENT_OEM_MODULE_NAME(pOemEntry),
  596. GetLastError()));
  597. return FALSE;
  598. }
  599. bOemCalled = TRUE;
  600. }
  601. }
  602. if (bOemCalled)
  603. {
  604. //
  605. // Make sure the OEM private devmode size is at least
  606. // as big as OEM_DMEXTRAHEADER.
  607. //
  608. if (OemDMParam.cbBufSize > 0 &&
  609. OemDMParam.cbBufSize < sizeof(OEM_DMEXTRAHEADER))
  610. {
  611. ERR(("OEM devmode size for '%ws' is too small: %d\n",
  612. CURRENT_OEM_MODULE_NAME(pOemEntry),
  613. OemDMParam.cbBufSize));
  614. return FALSE;
  615. }
  616. pOemEntry->dwOEMDMSize = OemDMParam.cbBufSize;
  617. }
  618. }
  619. dwSize += pOemEntry->dwOEMDMSize;
  620. END_OEMPLUGIN_LOOP
  621. *pdwOemDMSize = dwSize;
  622. return TRUE;
  623. }
  624. BOOL
  625. BCallOEMDevMode(
  626. HANDLE hPrinter,
  627. PVOID pdriverobj,
  628. POEM_PLUGIN_ENTRY pOemEntry,
  629. DWORD fMode,
  630. PDEVMODE pPublicDMOut,
  631. PDEVMODE pPublicDMIn,
  632. POEM_DMEXTRAHEADER pOemDMOut,
  633. POEM_DMEXTRAHEADER pOemDMIn
  634. )
  635. /*++
  636. Routine Description:
  637. Helper function to invoke OEM plugin's OEMDevMode entrypoint
  638. Arguments:
  639. argument-name - description of argument
  640. Return Value:
  641. TRUE if successful, FALSE if there is an error
  642. --*/
  643. {
  644. OEMDMPARAM OemDMParam;
  645. PFN_OEMDevMode pfnOEMDevMode;
  646. HRESULT hr;
  647. if (!pOemEntry->hInstance || !pOemEntry->dwOEMDMSize)
  648. return TRUE;
  649. //
  650. // Call OEMDevMode to get OEM's default devmode
  651. //
  652. OemDMParam.cbSize = sizeof(OemDMParam);
  653. OemDMParam.pdriverobj = pdriverobj;
  654. OemDMParam.hPrinter = hPrinter;
  655. OemDMParam.hModule = pOemEntry->hInstance;
  656. OemDMParam.pPublicDMIn = pPublicDMIn;
  657. OemDMParam.pPublicDMOut = pPublicDMOut;
  658. OemDMParam.pOEMDMIn = pOemDMIn;
  659. OemDMParam.pOEMDMOut = pOemDMOut;
  660. OemDMParam.cbBufSize = pOemEntry->dwOEMDMSize;
  661. //
  662. // If OEM private devmode size is not 0, we should
  663. // have OEMDevMode entrypoint address already.
  664. //
  665. if (HAS_COM_INTERFACE(pOemEntry))
  666. {
  667. hr = HComOEMDevMode(pOemEntry, fMode, &OemDMParam);
  668. ASSERT(hr != E_NOTIMPL);
  669. if (FAILED(hr))
  670. {
  671. ERR(("OEMDevMode(%d) failed for '%ws': %d\n",
  672. fMode,
  673. CURRENT_OEM_MODULE_NAME(pOemEntry),
  674. GetLastError()));
  675. return FALSE;
  676. }
  677. }
  678. else
  679. {
  680. pfnOEMDevMode = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevMode);
  681. ASSERT(pfnOEMDevMode != NULL);
  682. if (! pfnOEMDevMode(fMode, &OemDMParam))
  683. {
  684. ERR(("OEMDevMode(%d) failed for '%ws': %d\n",
  685. fMode,
  686. CURRENT_OEM_MODULE_NAME(pOemEntry),
  687. GetLastError()));
  688. return FALSE;
  689. }
  690. }
  691. //
  692. // Perform simple sanity check on the output devmode
  693. // returned by the OEM plugin
  694. //
  695. if (pOemDMOut->dwSize != pOemEntry->dwOEMDMSize ||
  696. OemDMParam.cbBufSize != pOemEntry->dwOEMDMSize ||
  697. pOemDMOut->dwSignature != pOemEntry->dwSignature)
  698. {
  699. ERR(("Bad output data from OEMDevMode(%d) for '%ws'\n",
  700. fMode,
  701. CURRENT_OEM_MODULE_NAME(pOemEntry)));
  702. return FALSE;
  703. }
  704. return TRUE;
  705. }
  706. BOOL
  707. BInitOemPluginDefaultDevmode(
  708. IN HANDLE hPrinter,
  709. IN PDEVMODE pPublicDM,
  710. OUT POEM_DMEXTRAHEADER pOemDM,
  711. IN OUT POEM_PLUGINS pOemPlugins
  712. )
  713. /*++
  714. Routine Description:
  715. Initialize OEM plugin default devmodes
  716. Arguments:
  717. hPrinter - Handle to the current printer
  718. pPublicDM - Points to default public devmode information
  719. pOemDM - Points to output buffer for storing default OEM devmodes
  720. pOemPlugins - Information about OEM plugins
  721. Return Value:
  722. TRUE if successful, FALSE if there is an error
  723. Note:
  724. After this function successfully returns, OEM_PLUGIN_ENTRY.pOEMDM field
  725. for corresponding to each OEM plugin is updated with pointer to appropriate
  726. private OEM devmode.
  727. --*/
  728. {
  729. //
  730. // Quick exit when no OEM plugin is installed
  731. //
  732. if (pOemPlugins->dwCount == 0)
  733. return TRUE;
  734. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  735. if (pOemEntry->hInstance == NULL)
  736. continue;
  737. //
  738. // Call OEM plugin to get its default private devmode
  739. //
  740. if (! BCallOEMDevMode(hPrinter,
  741. pOemPlugins->pdriverobj,
  742. pOemEntry,
  743. OEMDM_DEFAULT,
  744. NULL,
  745. pPublicDM,
  746. pOemDM,
  747. NULL))
  748. {
  749. return FALSE;
  750. }
  751. //
  752. // Save a pointer to current OEM plugin's private devmode
  753. // and move on to the next OEM plugin
  754. //
  755. if (pOemEntry->dwOEMDMSize)
  756. {
  757. pOemEntry->pOEMDM = pOemDM;
  758. pOemDM = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDM + pOemEntry->dwOEMDMSize);
  759. }
  760. END_OEMPLUGIN_LOOP
  761. return TRUE;
  762. }
  763. BOOL
  764. BValidateAndMergeOemPluginDevmode(
  765. IN HANDLE hPrinter,
  766. OUT PDEVMODE pPublicDMOut,
  767. IN PDEVMODE pPublicDMIn,
  768. OUT POEM_DMEXTRAHEADER pOemDMOut,
  769. IN POEM_DMEXTRAHEADER pOemDMIn,
  770. IN OUT POEM_PLUGINS pOemPlugins
  771. )
  772. /*++
  773. Routine Description:
  774. Validate and merge OEM plugin private devmode fields
  775. Arguments:
  776. hPrinter - Handle to the current printer
  777. pPublicDMOut - Points to output public devmode
  778. pPublicDMIn - Points to input public devmode
  779. pOemDMOut - Points to output buffer for storing merged OEM devmodes
  780. pOemDMIn - Points to input OEM devmodes to be merged
  781. pOemPlugins - Information about OEM plugins
  782. Return Value:
  783. TRUE if successful, FALSE if there is an error
  784. Note:
  785. Both input and output public devmodes must be current version.
  786. Output public devmode be already validated when this function is called.
  787. pOemDMOut must be current version and validated as well.
  788. pOemDMIn must be current version but may not be valid.
  789. After this function successfully returns, OEM_PLUGIN_ENTRY.pOEMDM field
  790. for corresponding to each OEM plugin is updated with pointer to appropriate
  791. private OEM devmode.
  792. --*/
  793. {
  794. //
  795. // Quick exit when no OEM plugin is installed
  796. //
  797. if (pOemPlugins->dwCount == 0)
  798. return TRUE;
  799. FOREACH_OEMPLUGIN_LOOP(pOemPlugins)
  800. if (pOemEntry->hInstance == NULL)
  801. continue;
  802. //
  803. // Call OEM plugin to validate and merge its private devmode
  804. //
  805. if (! BCallOEMDevMode(hPrinter,
  806. pOemPlugins->pdriverobj,
  807. pOemEntry,
  808. OEMDM_MERGE,
  809. pPublicDMOut,
  810. pPublicDMIn,
  811. pOemDMOut,
  812. pOemDMIn))
  813. {
  814. return FALSE;
  815. }
  816. //
  817. //
  818. // Save a pointer to current OEM plugin's private devmode
  819. // and move on to the next OEM plugin
  820. //
  821. if (pOemEntry->dwOEMDMSize)
  822. {
  823. pOemEntry->pOEMDM = pOemDMOut;
  824. pOemDMOut = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMOut + pOemEntry->dwOEMDMSize);
  825. pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMIn + pOemEntry->dwOEMDMSize);
  826. }
  827. END_OEMPLUGIN_LOOP
  828. return TRUE;
  829. }
  830. /*++
  831. Routine Name:
  832. bIsValidPluginDevmodes
  833. Routine Description:
  834. This function scans through the OEM plugin devmodes block and
  835. verifies if every plugin devmode in that block is constructed correctly.
  836. Arguments:
  837. pOemDM - Points to OEM plugin devmodes block
  838. cbOemDMSize - Size in bytes of the OEM plugin devmodes block
  839. Return Value:
  840. TRUE if every plugin devmode in correctly constructed.
  841. FALSE otherwise.
  842. Last Error:
  843. N/A
  844. --*/
  845. BOOL
  846. bIsValidPluginDevmodes(
  847. IN POEM_DMEXTRAHEADER pOemDM,
  848. IN LONG cbOemDMSize
  849. )
  850. {
  851. OEM_DMEXTRAHEADER OemDMHeader;
  852. BOOL bValid = FALSE;
  853. ASSERT(pOemDM != NULL && cbOemDMSize != 0);
  854. //
  855. // Follow the chain of the OEM plugin devmodes, check each one's
  856. // OEM_DMEXTRAHEADER and verify the last OEM devmode ends at the
  857. // correct endpoint.
  858. //
  859. while (cbOemDMSize > 0)
  860. {
  861. //
  862. // Check if the remaining OEM private devmode is big enough
  863. //
  864. if (cbOemDMSize < sizeof(OEM_DMEXTRAHEADER))
  865. {
  866. WARNING(("OEM private devmode size too small.\n"));
  867. break;
  868. }
  869. //
  870. // Copy the memory since the pointer may not be properly aligned
  871. // if incoming devmode fields are corrupted.
  872. //
  873. CopyMemory(&OemDMHeader, pOemDM, sizeof(OEM_DMEXTRAHEADER));
  874. if (OemDMHeader.dwSize < sizeof(OEM_DMEXTRAHEADER) ||
  875. OemDMHeader.dwSize > (DWORD)cbOemDMSize)
  876. {
  877. WARNING(("Corrupted or truncated OEM private devmode\n"));
  878. break;
  879. }
  880. //
  881. // Move on to the next OEM plugin
  882. //
  883. cbOemDMSize -= OemDMHeader.dwSize;
  884. if (cbOemDMSize == 0)
  885. {
  886. bValid = TRUE;
  887. break;
  888. }
  889. pOemDM = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDM + OemDMHeader.dwSize);
  890. }
  891. return bValid;
  892. }
  893. BOOL
  894. BConvertOemPluginDevmode(
  895. IN HANDLE hPrinter,
  896. OUT PDEVMODE pPublicDMOut,
  897. IN PDEVMODE pPublicDMIn,
  898. OUT POEM_DMEXTRAHEADER pOemDMOut,
  899. IN POEM_DMEXTRAHEADER pOemDMIn,
  900. IN LONG cbOemDMInSize,
  901. IN POEM_PLUGINS pOemPlugins
  902. )
  903. /*++
  904. Routine Description:
  905. Convert OEM plugin default devmodes to current version
  906. Arguments:
  907. hPrinter - Handle to the current printer
  908. pPublicDMOut - Points to output public devmode
  909. pPublicDMIn - Points to input public devmode
  910. pOemDMOut - Points to output buffer for storing merged OEM devmodes
  911. pOemDMIn - Points to input OEM devmodes to be converted
  912. cbOemDMInSize - Size of input buffer, in bytes
  913. pOemPlugins - Information about OEM plugins
  914. Return Value:
  915. TRUE if successful, FALSE if there is an error
  916. Note:
  917. When this function is called, pOemDMOut must already contain
  918. valid current version private OEM devmode information.
  919. --*/
  920. {
  921. //
  922. // Quick exit when no OEM plugin is installed or no incoming OEM devmode
  923. //
  924. if (pOemPlugins->dwCount == 0 || cbOemDMInSize == 0)
  925. return TRUE;
  926. //
  927. // Sanity check on the incoming OEM private devmodes.
  928. //
  929. if (!bIsValidPluginDevmodes(pOemDMIn, cbOemDMInSize))
  930. {
  931. ERR(("Found wrong boundary. Incoming OEM private devmode data are ignored.\n"));
  932. return TRUE;
  933. }
  934. while (cbOemDMInSize > 0)
  935. {
  936. POEM_PLUGIN_ENTRY pOemEntry;
  937. OEM_DMEXTRAHEADER OemDMInHeader;
  938. //
  939. // Copy the memory since the pointer may not be properly aligned
  940. // if incoming devmode fields are corrupted.
  941. //
  942. CopyMemory(&OemDMInHeader, pOemDMIn, sizeof(OEM_DMEXTRAHEADER));
  943. //
  944. // Find the OEM plugin which owns the private devmode
  945. //
  946. pOemEntry = PFindOemPluginWithSignature(pOemPlugins, OemDMInHeader.dwSignature);
  947. if (pOemEntry != NULL)
  948. {
  949. POEM_DMEXTRAHEADER pOemDMCurrent;
  950. DWORD dwCount;
  951. //
  952. // Find the OEM plugin's location in the output OEM devmode buffer
  953. // This will always succeed because the output devmode must
  954. // contain valid current version OEM devmodes.
  955. //
  956. pOemDMCurrent = pOemDMOut;
  957. dwCount = pOemPlugins->dwCount;
  958. while (dwCount)
  959. {
  960. if (pOemEntry->dwSignature == pOemDMCurrent->dwSignature)
  961. break;
  962. dwCount--;
  963. pOemDMCurrent = (POEM_DMEXTRAHEADER)
  964. ((PBYTE) pOemDMCurrent + pOemDMCurrent->dwSize);
  965. }
  966. ASSERT(dwCount != 0);
  967. //
  968. // Call OEM plugin to convert its input devmode
  969. // to its current version devmode
  970. //
  971. if (! BCallOEMDevMode(hPrinter,
  972. pOemPlugins->pdriverobj,
  973. pOemEntry,
  974. OEMDM_CONVERT,
  975. pPublicDMOut,
  976. pPublicDMIn,
  977. pOemDMCurrent,
  978. pOemDMIn))
  979. {
  980. return FALSE;
  981. }
  982. }
  983. else
  984. WARNING(("No owner found for OEM devmode: 0x%x\n", pOemDMIn->dwSignature));
  985. //
  986. // Move on to the next OEM plugin
  987. //
  988. cbOemDMInSize -= OemDMInHeader.dwSize;
  989. pOemDMIn = (POEM_DMEXTRAHEADER) ((PBYTE) pOemDMIn + OemDMInHeader.dwSize);
  990. }
  991. return TRUE;
  992. }
  993. BOOL
  994. BGetPrinterDataSettingForOEM(
  995. IN PRINTERDATA *pPrinterData,
  996. IN DWORD dwIndex,
  997. OUT PVOID pOutput,
  998. IN DWORD cbSize,
  999. OUT PDWORD pcbNeeded
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Function called by OEM plugins to access driver settings in registry
  1004. Arguments:
  1005. pPrinterData - Points to the PRINTERDATA structure to be accessed
  1006. dwIndex - Predefined index specifying which field to access
  1007. pOutput - Points to output buffer
  1008. cbSize - Size of output buffer
  1009. pcbNeeded - Expected size of output buffer
  1010. Return Value:
  1011. TRUE if successful, FALSE if there is an error
  1012. --*/
  1013. #define MAPPRINTERDATAFIELD(index, field) \
  1014. { index, offsetof(PRINTERDATA, field), sizeof(pPrinterData->field) }
  1015. {
  1016. static const struct {
  1017. DWORD dwIndex;
  1018. DWORD dwOffset;
  1019. DWORD dwSize;
  1020. } aIndexMap[] = {
  1021. MAPPRINTERDATAFIELD(OEMGDS_PRINTFLAGS, dwFlags),
  1022. MAPPRINTERDATAFIELD(OEMGDS_FREEMEM, dwFreeMem),
  1023. MAPPRINTERDATAFIELD(OEMGDS_JOBTIMEOUT, dwJobTimeout),
  1024. MAPPRINTERDATAFIELD(OEMGDS_WAITTIMEOUT, dwWaitTimeout),
  1025. MAPPRINTERDATAFIELD(OEMGDS_PROTOCOL, wProtocol),
  1026. MAPPRINTERDATAFIELD(OEMGDS_MINOUTLINE, wMinoutlinePPEM),
  1027. MAPPRINTERDATAFIELD(OEMGDS_MAXBITMAP, wMaxbitmapPPEM),
  1028. { 0, 0, 0 }
  1029. };
  1030. INT i = 0;
  1031. while (aIndexMap[i].dwSize != 0)
  1032. {
  1033. if (aIndexMap[i].dwIndex == dwIndex)
  1034. {
  1035. *pcbNeeded = aIndexMap[i].dwSize;
  1036. if (cbSize < aIndexMap[i].dwSize || pOutput == NULL)
  1037. {
  1038. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1039. return FALSE;
  1040. }
  1041. CopyMemory(pOutput, (PBYTE) pPrinterData + aIndexMap[i].dwOffset, aIndexMap[i].dwSize);
  1042. return TRUE;
  1043. }
  1044. i++;
  1045. }
  1046. WARNING(("Unknown printer data index: %d\n", dwIndex));
  1047. SetLastError(ERROR_NOT_SUPPORTED);
  1048. return FALSE;
  1049. }
  1050. BOOL
  1051. BGetGenericOptionSettingForOEM(
  1052. IN PUIINFO pUIInfo,
  1053. IN POPTSELECT pOptionsArray,
  1054. IN PCSTR pstrFeatureName,
  1055. OUT PSTR pstrOutput,
  1056. IN DWORD cbSize,
  1057. OUT PDWORD pcbNeeded,
  1058. OUT PDWORD pdwOptionsReturned
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. Function called by OEM plugins to find out the currently selected
  1063. option(s) for the specified feature
  1064. Arguments:
  1065. pUIInfo - Points to UIINFO structure
  1066. pOptionsArray - Points to current option selection array
  1067. pstrFeatureName - Specifies the name of the interested feature
  1068. pOutput - Points to output buffer
  1069. cbSize - Size of output buffer
  1070. pcbNeeded - Expected size of output buffer
  1071. pdwOptionsReturned - Number of currently selected options
  1072. Return Value:
  1073. TRUE if successful, FALSE if there is an error
  1074. --*/
  1075. {
  1076. PFEATURE pFeature;
  1077. POPTION pOption;
  1078. PCSTR pstrOptionName;
  1079. DWORD dwFeatureIndex, dwNext, dwSize, dwCount;
  1080. ASSERT(pUIInfo && pOptionsArray && pstrFeatureName);
  1081. //
  1082. // Find the specified feature
  1083. //
  1084. pFeature = PGetNamedFeature(pUIInfo, pstrFeatureName, &dwFeatureIndex);
  1085. if (pFeature == NULL)
  1086. {
  1087. WARNING(("Unknown feature name: %s\n", pstrFeatureName));
  1088. SetLastError(ERROR_INVALID_PARAMETER);
  1089. return FALSE;
  1090. }
  1091. //
  1092. // Figure out how big the output buffer needs to be
  1093. //
  1094. dwCount = 0;
  1095. dwSize = 1;
  1096. dwNext = dwFeatureIndex;
  1097. do
  1098. {
  1099. pOption = PGetIndexedOption(pUIInfo, pFeature, pOptionsArray[dwNext].ubCurOptIndex);
  1100. if (pOption == NULL)
  1101. {
  1102. ERR(("Invalid option selection index: %d\n", dwNext));
  1103. goto first_do_next;
  1104. }
  1105. pstrOptionName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName);
  1106. ASSERT(pstrOptionName != NULL);
  1107. dwSize += strlen(pstrOptionName) + 1;
  1108. dwCount++;
  1109. first_do_next:
  1110. dwNext = pOptionsArray[dwNext].ubNext;
  1111. } while(dwNext != NULL_OPTSELECT) ;
  1112. *pdwOptionsReturned = dwCount;
  1113. *pcbNeeded = dwSize;
  1114. //
  1115. // If the output buffer is too small, return appropriate error code
  1116. //
  1117. if (cbSize < dwSize || pstrOutput == NULL)
  1118. {
  1119. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1120. return FALSE;
  1121. }
  1122. //
  1123. // Copy the selected option names
  1124. //
  1125. dwNext = dwFeatureIndex;
  1126. do
  1127. {
  1128. pOption = PGetIndexedOption(pUIInfo, pFeature, pOptionsArray[dwNext].ubCurOptIndex);
  1129. if (pOption == NULL)
  1130. {
  1131. ERR(("Invalid option selection index: %d\n", dwNext));
  1132. goto second_do_next;
  1133. }
  1134. pstrOptionName = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pOption->loKeywordName);
  1135. dwSize = strlen(pstrOptionName) + 1;
  1136. CopyMemory(pstrOutput, pstrOptionName, dwSize);
  1137. pstrOutput += dwSize;
  1138. second_do_next:
  1139. dwNext = pOptionsArray[dwNext].ubNext;
  1140. } while(dwNext != NULL_OPTSELECT) ;
  1141. //
  1142. // Don't forget the extra NUL character at the end
  1143. //
  1144. *pstrOutput = NUL;
  1145. return TRUE;
  1146. }
  1147. VOID
  1148. VPatchDevmodeSizeFields(
  1149. PDEVMODE pdm,
  1150. DWORD dwDriverDMSize,
  1151. DWORD dwOemDMSize
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. Patch various size fields in the devmode structure
  1156. Arguments:
  1157. pdm - Points to devmode structure to be patched
  1158. dwDriverDMSize - Size of driver private devmode
  1159. dwOemDMSize - Size of OEM plugin private devmodes
  1160. Return Value:
  1161. NONE
  1162. --*/
  1163. {
  1164. pdm->dmDriverExtra = (WORD) (dwDriverDMSize + dwOemDMSize);
  1165. if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
  1166. {
  1167. PPSDRVEXTRA pPsExtra = (PPSDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm);
  1168. pPsExtra->wSize = (WORD) dwDriverDMSize;
  1169. pPsExtra->wOEMExtra = (WORD) dwOemDMSize;
  1170. }
  1171. else
  1172. {
  1173. PUNIDRVEXTRA pUniExtra = (PUNIDRVEXTRA) GET_DRIVER_PRIVATE_DEVMODE(pdm);
  1174. pUniExtra->wSize = (WORD) dwDriverDMSize;
  1175. pUniExtra->wOEMExtra = (WORD) dwOemDMSize;
  1176. }
  1177. }
  1178. PDEVMODE
  1179. PGetDefaultDevmodeWithOemPlugins(
  1180. IN LPCTSTR ptstrPrinterName,
  1181. IN PUIINFO pUIInfo,
  1182. IN PRAWBINARYDATA pRawData,
  1183. IN BOOL bMetric,
  1184. IN OUT POEM_PLUGINS pOemPlugins,
  1185. IN HANDLE hPrinter
  1186. )
  1187. /*++
  1188. Routine Description:
  1189. Allocate memory and initialize it with default devmode information
  1190. This include public devmode, driver private devmode, as well as
  1191. private devmode for any OEM plugins.
  1192. Arguments:
  1193. ptstrPrinterName - Name of the current printer
  1194. pUIInfo - Points to a UIINFO structure
  1195. pRawData - Points to raw binary printer description data
  1196. bMetric - Whether the system is in metric country
  1197. pOemPlugins - Points to information about OEM plugins
  1198. hPrinter - Handle to the current printer
  1199. Return Value:
  1200. Pointer to a devmode structure (including driver private and
  1201. OEM plugin private devmodes) initialized to default settings;
  1202. NULL if there is an error
  1203. --*/
  1204. {
  1205. PDEVMODE pdm;
  1206. DWORD dwOemDMSize, dwSystemDMSize;
  1207. //
  1208. // Figure out the total devmode size and allocate memory:
  1209. // public fields
  1210. // driver private fields
  1211. // OEM plugin private fields, if any
  1212. //
  1213. dwSystemDMSize = sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra;
  1214. if (! BCalcTotalOEMDMSize(hPrinter, pOemPlugins, &dwOemDMSize) ||
  1215. ! (pdm = MemAllocZ(dwOemDMSize + dwSystemDMSize)))
  1216. {
  1217. return NULL;
  1218. }
  1219. //
  1220. // Call driver-specific function to initialize public and driver private fields
  1221. // Call OEM plugins to initialize their default devmode fields
  1222. //
  1223. if (! BInitDriverDefaultDevmode(pdm, ptstrPrinterName, pUIInfo, pRawData, bMetric) ||
  1224. ! BInitOemPluginDefaultDevmode(
  1225. hPrinter,
  1226. pdm,
  1227. (POEM_DMEXTRAHEADER) ((PBYTE) pdm + dwSystemDMSize),
  1228. pOemPlugins))
  1229. {
  1230. MemFree(pdm);
  1231. return NULL;
  1232. }
  1233. //
  1234. // Patch up various private devmode size fields
  1235. //
  1236. VPatchDevmodeSizeFields(pdm, gDriverDMInfo.dmDriverExtra, dwOemDMSize);
  1237. return pdm;
  1238. }
  1239. PDEVMODE
  1240. PConvertToCurrentVersionDevmodeWithOemPlugins(
  1241. IN HANDLE hPrinter,
  1242. IN PRAWBINARYDATA pRawData,
  1243. IN PDEVMODE pdmInput,
  1244. IN PDEVMODE pdmDefault,
  1245. IN POEM_PLUGINS pOemPlugins,
  1246. OUT PDWORD pdwOemDMSize
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. Convert input devmode to current version devmode.
  1251. Memory for the converted devmode is allocated by this function.
  1252. Arguments:
  1253. hPrinter - Handle to the current printer
  1254. pRawData - Points to raw binary printer description data
  1255. pdmInput - Pointer to the input devmode to be converted
  1256. pdmDefault - Points to a valid current version devmode
  1257. pOemPlugins - Information about OEM plugins
  1258. pdwOemDMSize - Returns the total size of all OEM plugin devmodes
  1259. Return Value:
  1260. Pointer to the converted devmode, NULL if there is an error
  1261. Note:
  1262. Core private devmode portion of returned devmode contains:
  1263. 1) if pdmInput is from unknown driver (including Rasdd):
  1264. core private devmode portion from pdmDefault
  1265. 2) if pdmInput is from our NT4 PScript/Win2K/XP/Longhorn+ drivers:
  1266. fixed-size core private devmode of pdmInput
  1267. --*/
  1268. {
  1269. DWORD dwOemDMSize;
  1270. WORD wCoreFixSize, wOEMExtra;
  1271. PDEVMODE pdm;
  1272. PVOID pDrvExtraIn, pOemDMOut, pOemDMIn;
  1273. BOOL bMSdm500In = FALSE, bMSdmPS4In = FALSE;
  1274. ASSERT(pdmInput != NULL);
  1275. //
  1276. // Allocate memory to hold converted devmode
  1277. //
  1278. if (! BCalcTotalOEMDMSize(hPrinter, pOemPlugins, &dwOemDMSize) ||
  1279. ! (pdm = MemAllocZ(dwOemDMSize + gDriverDMInfo.dmDriverExtra + sizeof(DEVMODE))))
  1280. {
  1281. return NULL;
  1282. }
  1283. //
  1284. // Copy public devmode fields
  1285. //
  1286. CopyMemory(pdm, pdmInput, min(sizeof(DEVMODE), pdmInput->dmSize));
  1287. pdm->dmSpecVersion = DM_SPECVERSION;
  1288. pdm->dmSize = sizeof(DEVMODE);
  1289. //
  1290. // Copy driver private devmode fields
  1291. //
  1292. pDrvExtraIn = GET_DRIVER_PRIVATE_DEVMODE(pdmInput);
  1293. wCoreFixSize = pdmInput->dmDriverExtra;
  1294. wOEMExtra = 0;
  1295. if (pdmInput->dmDriverVersion >= gDriverDMInfo.dmDriverVersion500 &&
  1296. wCoreFixSize >= gDriverDMInfo.dmDriverExtra500)
  1297. {
  1298. //
  1299. // Win2K/XP/Longhorn+ drivers must be allowed to enter this if-block
  1300. //
  1301. // (Note that in UNIDRVEXTRA500 we didn't have the last "dwEndingPad"
  1302. // field, since that field is only added in XP. And for PSDRIVER_VERSION_500
  1303. // we are using the Win2K's number 0x501.)
  1304. //
  1305. WORD wSize = wCoreFixSize;
  1306. if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
  1307. {
  1308. if (((PPSDRVEXTRA) pDrvExtraIn)->dwSignature == PSDEVMODE_SIGNATURE)
  1309. {
  1310. wSize = ((PPSDRVEXTRA) pDrvExtraIn)->wSize;
  1311. wOEMExtra = ((PPSDRVEXTRA) pDrvExtraIn)->wOEMExtra;
  1312. if ((wSize >= gDriverDMInfo.dmDriverExtra500) &&
  1313. ((wSize + wOEMExtra) <= pdmInput->dmDriverExtra))
  1314. {
  1315. //
  1316. // pdmInput is from our Win2K/XP/Longhorn+ PScript driver
  1317. //
  1318. bMSdm500In = TRUE;
  1319. }
  1320. }
  1321. }
  1322. else
  1323. {
  1324. if (((PUNIDRVEXTRA) pDrvExtraIn)->dwSignature == UNIDEVMODE_SIGNATURE)
  1325. {
  1326. wSize = ((PUNIDRVEXTRA) pDrvExtraIn)->wSize;
  1327. wOEMExtra = ((PUNIDRVEXTRA) pDrvExtraIn)->wOEMExtra;
  1328. if ((wSize >= gDriverDMInfo.dmDriverExtra500) &&
  1329. ((wSize + wOEMExtra) <= pdmInput->dmDriverExtra))
  1330. {
  1331. //
  1332. // pdmInput is from our Win2K/XP/Longhorn+ Unidrv driver
  1333. //
  1334. bMSdm500In = TRUE;
  1335. }
  1336. }
  1337. }
  1338. if (bMSdm500In && (wCoreFixSize > wSize))
  1339. wCoreFixSize = wSize;
  1340. }
  1341. else
  1342. {
  1343. if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
  1344. {
  1345. if (pdmInput->dmDriverVersion == PSDRIVER_VERSION_400 &&
  1346. wCoreFixSize == sizeof(PSDRVEXTRA400) &&
  1347. (((PSDRVEXTRA400 *) pDrvExtraIn)->dwSignature == PSDEVMODE_SIGNATURE))
  1348. {
  1349. //
  1350. // pdmInput is from our NT4 PScript driver
  1351. //
  1352. bMSdmPS4In = TRUE;
  1353. }
  1354. }
  1355. }
  1356. //
  1357. // Possible sources for pdmInput and their outcome at this point:
  1358. //
  1359. // 1. unknown driver (including NT4 Rasdd)
  1360. // bMSdm500In = FALSE, bMSdmPS4in = FALSE,
  1361. // wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
  1362. //
  1363. // 2. NT4 PScript driver
  1364. // bMSdm500In = FALSE, bMSdmPS4in = TRUE,
  1365. // wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
  1366. //
  1367. // 3. Win2K/XP driver without plugin
  1368. // bMSdm500In = TRUE, bMSdmPS4in = FALSE,
  1369. // wCoreFixSize = pdmInput->dmDriverExtra, wOEMExtra = 0
  1370. //
  1371. // 4. Win2K/XP driver with plugin
  1372. // bMSdm500In = TRUE, bMSdmPS4in = FALSE,
  1373. // wCoreFixSize = pdmInPriv->wSize < pdmInput->dmDriverExtra,
  1374. // wOEMExtra = pdmInPriv->wOEMExtra > 0
  1375. //
  1376. if (bMSdm500In || bMSdmPS4In)
  1377. {
  1378. CopyMemory(GET_DRIVER_PRIVATE_DEVMODE(pdm),
  1379. pDrvExtraIn,
  1380. min(gDriverDMInfo.dmDriverExtra, wCoreFixSize));
  1381. }
  1382. else
  1383. {
  1384. //
  1385. // pdmInput is from unknown driver, so copy our default private devmode.
  1386. // We don't want to copy unknown private devmode and then change all the
  1387. // size/version fields to have our current driver's values.
  1388. //
  1389. WARNING(("Input devmode is unknown, so ignore its private portion.\n"));
  1390. CopyMemory(GET_DRIVER_PRIVATE_DEVMODE(pdm),
  1391. GET_DRIVER_PRIVATE_DEVMODE(pdmDefault),
  1392. gDriverDMInfo.dmDriverExtra);
  1393. }
  1394. //
  1395. // Validate option array setting in the input devmode and correct
  1396. // any invalid option selections. This is needed since our future
  1397. // code assumes that the option array always have valid settings.
  1398. //
  1399. if (bMSdm500In)
  1400. {
  1401. PVOID pDrvExtraOut;
  1402. POPTSELECT pOptions;
  1403. //
  1404. // We are dealing with input devmode of Win2K/XP/Longhorn+ inbox drivers
  1405. //
  1406. pDrvExtraOut = GET_DRIVER_PRIVATE_DEVMODE(pdm);
  1407. if (gdwDriverDMSignature == PSDEVMODE_SIGNATURE)
  1408. {
  1409. pOptions = ((PPSDRVEXTRA) pDrvExtraOut)->aOptions;
  1410. }
  1411. else
  1412. {
  1413. pOptions = ((PUNIDRVEXTRA) pDrvExtraOut)->aOptions;
  1414. }
  1415. //
  1416. // validate input devmode option array and correct any invalid selections
  1417. //
  1418. ValidateDocOptions(pRawData,
  1419. pOptions,
  1420. MAX_PRINTER_OPTIONS);
  1421. }
  1422. pdm->dmDriverVersion = gDriverDMInfo.dmDriverVersion;
  1423. //
  1424. // CopyMemory above overwrote size fields in private devmode, need to restore them.
  1425. //
  1426. VPatchDevmodeSizeFields(pdm, gDriverDMInfo.dmDriverExtra, dwOemDMSize);
  1427. if (dwOemDMSize)
  1428. {
  1429. //
  1430. // Convert OEM plugin private devmodes.
  1431. // Start out with valid default settings.
  1432. //
  1433. pOemDMOut = (PBYTE) pdm + (sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra);
  1434. CopyMemory(pOemDMOut,
  1435. (PBYTE) pdmDefault + (sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra),
  1436. dwOemDMSize);
  1437. //
  1438. // Plugins are only supported by our Win2K and above drivers.
  1439. //
  1440. if (bMSdm500In && (wOEMExtra > 0) && (pdmInput->dmDriverExtra > wCoreFixSize))
  1441. {
  1442. pOemDMIn = (PBYTE) pdmInput + (pdmInput->dmSize + wCoreFixSize);
  1443. //
  1444. // We used to use "pdmInput->dmDriverExtra - wCoreFixSize" instead of "wOEMExtra"
  1445. // in this call, but that is under the assumption that everything after the core
  1446. // fixed fields are plugin devmodes. That assumption may not be true in Longhorn.
  1447. //
  1448. if (! BConvertOemPluginDevmode(
  1449. hPrinter,
  1450. pdm,
  1451. pdmInput,
  1452. pOemDMOut,
  1453. pOemDMIn,
  1454. (LONG)wOEMExtra,
  1455. pOemPlugins))
  1456. {
  1457. MemFree(pdm);
  1458. return NULL;
  1459. }
  1460. }
  1461. }
  1462. *pdwOemDMSize = dwOemDMSize;
  1463. return pdm;
  1464. }
  1465. BOOL
  1466. BValidateAndMergeDevmodeWithOemPlugins(
  1467. IN OUT PDEVMODE pdmOutput,
  1468. IN PUIINFO pUIInfo,
  1469. IN PRAWBINARYDATA pRawData,
  1470. IN PDEVMODE pdmInput,
  1471. IN OUT POEM_PLUGINS pOemPlugins,
  1472. IN HANDLE hPrinter
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Valicate input devmode and merge it into the output devmode.
  1477. This include public devmode, driver private devmode, as well as
  1478. private devmode for any OEM plugins.
  1479. Arguments:
  1480. pdmOutput - Points to the output devmode
  1481. pUIInfo - Points to a UIINFO structure
  1482. pRawData - Points to raw binary printer description data
  1483. pdmInput - Points to the input devmode
  1484. pOemPlugins - Points to information about OEM plugins
  1485. hPrinter - Handle to the current printer
  1486. Return Value:
  1487. TRUE if successful, FALSE otherwise
  1488. Note:
  1489. The output devmode must be a valid current version devmode
  1490. when this function is called.
  1491. --*/
  1492. {
  1493. PDEVMODE pdmConverted;
  1494. DWORD dwOemDMSize;
  1495. BOOL bResult;
  1496. if (pdmInput == NULL)
  1497. return TRUE;
  1498. //
  1499. // Otherwise, convert the input devmode to current version first
  1500. //
  1501. pdmConverted = PConvertToCurrentVersionDevmodeWithOemPlugins(
  1502. hPrinter,
  1503. pRawData,
  1504. pdmInput,
  1505. pdmOutput,
  1506. pOemPlugins,
  1507. &dwOemDMSize);
  1508. if ((pdmInput = pdmConverted) == NULL)
  1509. return FALSE;
  1510. //
  1511. // Validate and merge public and driver private devmode fields
  1512. //
  1513. bResult = BMergeDriverDevmode(pdmOutput, pUIInfo, pRawData, pdmInput);
  1514. //
  1515. // Validate and merge OEM plugin private devmode fields
  1516. //
  1517. if (bResult && dwOemDMSize)
  1518. {
  1519. DWORD dwSystemDMSize = sizeof(DEVMODE) + gDriverDMInfo.dmDriverExtra;
  1520. bResult = BValidateAndMergeOemPluginDevmode(
  1521. hPrinter,
  1522. pdmOutput,
  1523. pdmInput,
  1524. (POEM_DMEXTRAHEADER) ((PBYTE) pdmOutput + dwSystemDMSize),
  1525. (POEM_DMEXTRAHEADER) ((PBYTE) pdmInput + dwSystemDMSize),
  1526. pOemPlugins);
  1527. }
  1528. MemFree(pdmConverted);
  1529. return bResult;
  1530. }
  1531. #if defined(KERNEL_MODE) && defined(WINNT_40)
  1532. BOOL
  1533. BOEMPluginFirstLoad(
  1534. IN PTSTR ptstrDriverFile,
  1535. IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. Maintains ref count for the render plugin DLL and determines if it's
  1540. loaded for the first time.
  1541. Arguments:
  1542. ptstrDriverFile - OEM render plugin DLL name with fully qualified path
  1543. ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
  1544. Return Value:
  1545. TRUE: the render plugin DLL is loaded for the first time
  1546. FALSE: otherwise
  1547. --*/
  1548. {
  1549. POEM_PLUGIN_REFCOUNT pRefCount;
  1550. PTSTR ptstrPluginDllName;
  1551. INT iDllNameLen;
  1552. ASSERT(ptstrDriverFile && ppOEMPluginRefCount);
  1553. //
  1554. // Get the plugin DLL name without any path prefix
  1555. //
  1556. if ((ptstrPluginDllName = _tcsrchr(ptstrDriverFile, TEXT(PATH_SEPARATOR))) == NULL)
  1557. {
  1558. WARNING(("Plugin DLL path is not fully qualified: %ws\n", ptstrDriverFile));
  1559. ptstrPluginDllName = ptstrDriverFile;
  1560. }
  1561. else
  1562. {
  1563. ptstrPluginDllName++; // skip the last '\'
  1564. }
  1565. iDllNameLen = _tcslen(ptstrPluginDllName);
  1566. pRefCount = *ppOEMPluginRefCount;
  1567. //
  1568. // Search to see if the plugin DLL name is already in the ref count link list
  1569. //
  1570. while (pRefCount)
  1571. {
  1572. if (_tcsicmp(pRefCount->ptstrDriverFile, ptstrPluginDllName) == EQUAL_STRING)
  1573. {
  1574. break;
  1575. }
  1576. pRefCount = pRefCount->pNext;
  1577. }
  1578. if (pRefCount == NULL)
  1579. {
  1580. //
  1581. // A new plugin DLL is loaded. Add it to the ref count link list.
  1582. //
  1583. if ((pRefCount = MemAllocZ(sizeof(OEM_PLUGIN_REFCOUNT) + (iDllNameLen + 1)*sizeof(TCHAR))) == NULL)
  1584. {
  1585. ERR(("Memory allocation failed\n"));
  1586. return FALSE;
  1587. }
  1588. pRefCount->ptstrDriverFile = (PTSTR)((PBYTE)pRefCount + sizeof(OEM_PLUGIN_REFCOUNT));
  1589. pRefCount->dwRefCount = 1;
  1590. CopyMemory(pRefCount->ptstrDriverFile, ptstrPluginDllName, iDllNameLen * sizeof(TCHAR));
  1591. pRefCount->pNext = *ppOEMPluginRefCount;
  1592. *ppOEMPluginRefCount = pRefCount;
  1593. return TRUE;
  1594. }
  1595. else
  1596. {
  1597. //
  1598. // The plugin DLL name is already in the ref count link list, so just increase its ref count.
  1599. //
  1600. pRefCount->dwRefCount++;
  1601. return FALSE;
  1602. }
  1603. }
  1604. BOOL
  1605. BOEMPluginLastUnload(
  1606. IN PTSTR ptstrDriverFile,
  1607. IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. Maintains ref count for the render plugin DLL and determines if it's
  1612. unloaded by the last client.
  1613. Arguments:
  1614. ptstrDriverFile - OEM render plugin DLL name with fully qualified path
  1615. ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
  1616. Return Value:
  1617. TRUE: the render plugin DLL is unloaded by the last client
  1618. FALSE: otherwise
  1619. --*/
  1620. {
  1621. POEM_PLUGIN_REFCOUNT pRefCountPrev, pRefCount;
  1622. PTSTR ptstrPluginDllName;
  1623. ASSERT(ptstrDriverFile && ppOEMPluginRefCount);
  1624. //
  1625. // Get the plugin DLL name without any path prefix
  1626. //
  1627. if ((ptstrPluginDllName = _tcsrchr(ptstrDriverFile, TEXT(PATH_SEPARATOR))) == NULL)
  1628. {
  1629. WARNING(("Plugin DLL path is not fully qualified: %ws\n", ptstrDriverFile));
  1630. ptstrPluginDllName = ptstrDriverFile;
  1631. }
  1632. else
  1633. {
  1634. ptstrPluginDllName++; // skip the last '\'
  1635. }
  1636. pRefCountPrev = NULL;
  1637. pRefCount = *ppOEMPluginRefCount;
  1638. //
  1639. // Search to locate the plugin DLL entry in the ref count link list
  1640. //
  1641. while (pRefCount)
  1642. {
  1643. if (_tcsicmp(pRefCount->ptstrDriverFile, ptstrPluginDllName) == EQUAL_STRING)
  1644. {
  1645. break;
  1646. }
  1647. pRefCountPrev = pRefCount;
  1648. pRefCount = pRefCount->pNext;
  1649. }
  1650. if (pRefCount == NULL)
  1651. {
  1652. RIP(("Plugin DLL name is not in the ref count list: %ws\n", ptstrPluginDllName));
  1653. return FALSE;
  1654. }
  1655. if (--(pRefCount->dwRefCount) == 0)
  1656. {
  1657. //
  1658. // If the ref count decreases to 0, we need to remove the plugin DLL from the ref
  1659. // count link list.
  1660. //
  1661. if (pRefCountPrev == NULL)
  1662. {
  1663. *ppOEMPluginRefCount = pRefCount->pNext;
  1664. }
  1665. else
  1666. {
  1667. pRefCountPrev->pNext = pRefCount->pNext;
  1668. }
  1669. MemFree(pRefCount);
  1670. return TRUE;
  1671. }
  1672. return FALSE;
  1673. }
  1674. VOID
  1675. VFreePluginRefCountList(
  1676. IN OUT POEM_PLUGIN_REFCOUNT *ppOEMPluginRefCount
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. Free memory allocated in the ref count link list, and remove all the nodes in the list.
  1681. Finally the link list will be reset to empty.
  1682. Arguments:
  1683. ppOEMPluginRefCount - pointer to the pointer of OEM render plugin ref count link list
  1684. Return Value:
  1685. None
  1686. --*/
  1687. {
  1688. POEM_PLUGIN_REFCOUNT pRefCountRemove, pRefCount;
  1689. pRefCount = *ppOEMPluginRefCount;
  1690. while (pRefCount)
  1691. {
  1692. pRefCountRemove = pRefCount;
  1693. pRefCount = pRefCount->pNext;
  1694. MemFree(pRefCountRemove);
  1695. }
  1696. *ppOEMPluginRefCount = NULL;
  1697. }
  1698. #endif // KERNEL_MODE && WINNT_40