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.

525 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. quryprnt.c
  5. Abstract:
  6. This file handles the DrvQueryPrintEx spooler API
  7. Environment:
  8. Win32 subsystem, DriverUI module, user mode
  9. Revision History:
  10. 02/13/97 -davidx-
  11. Implement OEM plugin support.
  12. 02/08/97 -davidx-
  13. Rewrote it to use common data management functions.
  14. 02/04/97 -davidx-
  15. Reorganize driver UI to separate ps and uni DLLs.
  16. 07/17/96 -amandan-
  17. Created it.
  18. --*/
  19. #include "precomp.h"
  20. //
  21. // Forward declaration of local functions
  22. //
  23. BOOL BFormatDQPMessage(PDEVQUERYPRINT_INFO, INT, ...);
  24. BOOL BQueryPrintDevmode(PDEVQUERYPRINT_INFO, PCOMMONINFO);
  25. BOOL BQueryPrintForm(PDEVQUERYPRINT_INFO, PCOMMONINFO);
  26. BOOL
  27. DevQueryPrintEx(
  28. PDEVQUERYPRINT_INFO pDQPInfo
  29. )
  30. /*++
  31. Routine Description:
  32. This function checks whether the job can be printed with
  33. DEVMODE passed in. This function will use the following
  34. criterias to determine whether the job is printable:
  35. - get basic printer information
  36. - verify input devmode
  37. - verify resolution is supported
  38. - verify there is no conflicts between printer feature selections
  39. - verify form-to-tray assignment
  40. Arguments:
  41. pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
  42. Return Value:
  43. TRUE if the job can be printed with the given DEVMODE, otherwise FALSE
  44. --*/
  45. {
  46. PCOMMONINFO pci;
  47. BOOL bResult;
  48. if (pDQPInfo == NULL || pDQPInfo->hPrinter == NULL)
  49. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_PARAM);
  50. if (pDQPInfo->pDevMode == NULL)
  51. return TRUE;
  52. if ((pci = PLoadCommonInfo(pDQPInfo->hPrinter, NULL, 0)) == NULL)
  53. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_COMMONINFO);
  54. bResult = BQueryPrintDevmode(pDQPInfo, pci) &&
  55. BQueryPrintForm(pDQPInfo, pci);
  56. if (bResult)
  57. {
  58. PFN_OEMDevQueryPrintEx pfnOEMDevQueryPrintEx;
  59. //
  60. // call OEMDevQueryPrintEx entrypoint for each plugin,
  61. // or until one of them returns FALSE.
  62. //
  63. FOREACH_OEMPLUGIN_LOOP(pci)
  64. if (HAS_COM_INTERFACE(pOemEntry))
  65. {
  66. HRESULT hr;
  67. hr = HComOEMDevQueryPrintEx(pOemEntry,
  68. &pci->oemuiobj,
  69. pDQPInfo,
  70. pci->pdm,
  71. pOemEntry->pOEMDM);
  72. if (hr == E_NOTIMPL)
  73. continue;
  74. if (!(bResult = SUCCEEDED(hr)))
  75. break;
  76. }
  77. else
  78. {
  79. if ((pfnOEMDevQueryPrintEx = GET_OEM_ENTRYPOINT(pOemEntry, OEMDevQueryPrintEx)) &&
  80. !pfnOEMDevQueryPrintEx(&pci->oemuiobj, pDQPInfo, pci->pdm, pOemEntry->pOEMDM))
  81. {
  82. ERR(("OEMDevQueryPrintEx failed for '%ws': %d\n",
  83. CURRENT_OEM_MODULE_NAME(pOemEntry),
  84. GetLastError()));
  85. bResult = FALSE;
  86. break;
  87. }
  88. }
  89. END_OEMPLUGIN_LOOP
  90. }
  91. VFreeCommonInfo(pci);
  92. return bResult;
  93. }
  94. BOOL
  95. BFormatDQPMessage(
  96. PDEVQUERYPRINT_INFO pDQPInfo,
  97. INT iMsgResId,
  98. ...
  99. )
  100. /*++
  101. Routine Description:
  102. Format DevQueryPrintEx error message
  103. Arguments:
  104. pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
  105. iMsgResId - Error message format specifier (string resource ID)
  106. Return Value:
  107. FALSE
  108. --*/
  109. #define MAX_FORMAT_STRING 256
  110. #define MAX_DQP_MESSAGE 512
  111. {
  112. TCHAR awchFormat[MAX_FORMAT_STRING];
  113. TCHAR awchMessage[MAX_DQP_MESSAGE];
  114. INT iLength = 0;
  115. va_list arglist;
  116. //
  117. // Load the format specifier string resource
  118. // and use swprintf to format the error message
  119. //
  120. va_start(arglist, iMsgResId);
  121. if (! LoadString(ghInstance, iMsgResId, awchFormat, MAX_FORMAT_STRING))
  122. awchFormat[0] = NUL;
  123. if (SUCCEEDED(StringCchVPrintfW(awchMessage,
  124. CCHOF(awchMessage),
  125. awchFormat,
  126. arglist)))
  127. {
  128. iLength = wcslen(awchMessage);
  129. }
  130. if (iLength <= 0)
  131. {
  132. StringCchCopyW(awchMessage, CCHOF(awchMessage), L"Error");
  133. iLength = wcslen(awchMessage);
  134. }
  135. va_end(arglist);
  136. //
  137. // Copy the error message string to DQPInfo
  138. //
  139. iLength += 1;
  140. pDQPInfo->cchNeeded = iLength;
  141. if (iLength > (INT) pDQPInfo->cchErrorStr)
  142. iLength = pDQPInfo->cchErrorStr;
  143. if (pDQPInfo->pszErrorStr && iLength)
  144. CopyString(pDQPInfo->pszErrorStr, awchMessage, iLength);
  145. return FALSE;
  146. }
  147. BOOL
  148. BQueryPrintDevmode(
  149. PDEVQUERYPRINT_INFO pDQPInfo,
  150. PCOMMONINFO pci
  151. )
  152. /*++
  153. Routine Description:
  154. Validate devmode information
  155. Arguments:
  156. pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
  157. pci - Points to basic printer info
  158. Return Value:
  159. TRUE if successful, FALSE if the job should be held
  160. --*/
  161. {
  162. INT iRealizedRes, iResX, iResY;
  163. PFEATURE pFeature;
  164. DWORD dwFeatureIndex, dwOptionIndexOld, dwOptionIndexNew;
  165. BOOL bUpdateFormField;
  166. //
  167. // Validate input devmode
  168. // Get printer-sticky properties
  169. // Merge doc- and printer-sticky printer feature selections
  170. // Fix up combined options array with public devmode info
  171. //
  172. if (! BFillCommonInfoDevmode(pci, NULL, pDQPInfo->pDevMode))
  173. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_DEVMODE);
  174. if (! BFillCommonInfoPrinterData(pci))
  175. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_PRINTERDATA);
  176. if (! BCombineCommonInfoOptionsArray(pci))
  177. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_MEMORY);
  178. VFixOptionsArrayWithDevmode(pci);
  179. //
  180. // Remember the paper size option parser picked to support the devmode form
  181. //
  182. if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL)
  183. {
  184. ASSERT(FALSE);
  185. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_DEVMODE);
  186. }
  187. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pci->pUIInfo, pFeature);
  188. dwOptionIndexOld = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  189. if (! ResolveUIConflicts(
  190. pci->pRawData,
  191. pci->pCombinedOptions,
  192. MAX_COMBINED_OPTIONS,
  193. MODE_DOCANDPRINTER_STICKY|DONT_RESOLVE_CONFLICT))
  194. {
  195. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_OPTSELECT);
  196. }
  197. dwOptionIndexNew = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  198. bUpdateFormField = FALSE;
  199. if (dwOptionIndexNew != dwOptionIndexOld)
  200. {
  201. //
  202. // Constraint resolving has changed page size selection, so we need
  203. // to update devmode's form fields.
  204. //
  205. bUpdateFormField = TRUE;
  206. }
  207. else
  208. {
  209. FORM_INFO_1 *pForm = NULL;
  210. //
  211. // Unless the form requested by devmode is not supported on the printer,
  212. // we still want to show the original form name in upcoming doc-setting UI.
  213. // For example, if input devmode requested "Legal", parser maps it to option
  214. // "OEM Legal", but both "Legal" and "OEM Legal" will be shown as supported
  215. // forms on the printer, then we should still show "Legal" instead of "OEM Legal"
  216. // in UI's PageSize list. However, if input devmode requestd "8.5 x 12", which
  217. // won't be shown as a supportd form and it's mapped to "OEM Legal", then we should
  218. // show "OEM Legal".
  219. //
  220. //
  221. // pdm->dmFormName won't have a valid form name for custom page size (see
  222. // BValidateDevmodeFormFields()). VOptionsToDevmodeFields() knows to handle that.
  223. //
  224. if ((pci->pdm->dmFields & DM_FORMNAME) &&
  225. (pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1)) &&
  226. !BFormSupportedOnPrinter(pci, pForm, &dwOptionIndexNew))
  227. {
  228. bUpdateFormField = TRUE;
  229. }
  230. MemFree(pForm);
  231. }
  232. VOptionsToDevmodeFields(pci, bUpdateFormField);
  233. if (! BUpdateUIInfo(pci))
  234. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_COMMONINFO);
  235. //
  236. // Check if the requested resolution is supported
  237. //
  238. iRealizedRes = max(pci->pdm->dmPrintQuality, pci->pdm->dmYResolution);
  239. iResX = iResY = 0;
  240. //
  241. // Kludze, there are some cases where apps set dmPrintQuality/dmYResolution
  242. // to be one of the DMRES values. We skip the checking for resolution
  243. // since Unidrv/Pscript will map them to one of the valid resolution options
  244. // at print time
  245. //
  246. if (pDQPInfo->pDevMode->dmFields & DM_PRINTQUALITY)
  247. {
  248. iResX = pDQPInfo->pDevMode->dmPrintQuality;
  249. if (iResX <= DMRES_DRAFT)
  250. return TRUE;
  251. }
  252. if (pDQPInfo->pDevMode->dmFields & DM_YRESOLUTION)
  253. {
  254. iResY = pDQPInfo->pDevMode->dmYResolution;
  255. if (iResY <= DMRES_DRAFT)
  256. return TRUE;
  257. }
  258. if (max(iResX, iResY) != iRealizedRes)
  259. return BFormatDQPMessage(pDQPInfo, IDS_DQPERR_RESOLUTION);
  260. return TRUE;
  261. }
  262. BOOL
  263. BQueryPrintForm(
  264. PDEVQUERYPRINT_INFO pDQPInfo,
  265. PCOMMONINFO pci
  266. )
  267. /*++
  268. Routine Description:
  269. Check if the requested form and/or tray is available
  270. Arguments:
  271. pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
  272. pci - Points to basic printer info
  273. Return Value:
  274. TRUE if successful, FALSE if the job should be held
  275. --*/
  276. {
  277. PUIINFO pUIInfo;
  278. PFEATURE pFeature;
  279. PPAGESIZE pPageSize;
  280. PWSTR pwstrTrayName;
  281. FORM_TRAY_TABLE pFormTrayTable;
  282. FINDFORMTRAY FindData;
  283. WCHAR awchTrayName[CCHBINNAME];
  284. DWORD dwFeatureIndex, dwOptionIndex;
  285. BOOL bResult = FALSE;
  286. //
  287. // Skip it if form name is not specified
  288. //
  289. if ((pci->pdm->dmFields & DM_FORMNAME) == 0 ||
  290. pci->pdm->dmFormName[0] == NUL)
  291. {
  292. return TRUE;
  293. }
  294. pUIInfo = pci->pUIInfo;
  295. if ((pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE)) == NULL)
  296. {
  297. ASSERT(FALSE);
  298. return TRUE;
  299. }
  300. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
  301. dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  302. if ((pPageSize = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) == NULL)
  303. {
  304. ASSERT(FALSE);
  305. return TRUE;
  306. }
  307. //
  308. // For custom page size option, we have left the devmode form fields unchanged.
  309. // See function VOptionToDevmodeFields().
  310. //
  311. //
  312. // We've only shown user forms supported by custom page size in Form-to-Tray table.
  313. //
  314. if (pPageSize->dwPaperSizeID == DMPAPER_USER ||
  315. pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
  316. {
  317. FORM_INFO_1 *pForm;
  318. //
  319. // We already verified the dmFormName field at the beginning.
  320. //
  321. if (pForm = MyGetForm(pci->hPrinter, pci->pdm->dmFormName, 1))
  322. {
  323. //
  324. // Built-in and printer forms supported by custom page size option won't show
  325. // up in either PageSize list or Form-to-Tray assignment table. So we only
  326. // continue to check the From-to-Tray assignment table for user forms supported
  327. // by custom page size option. See function BFormSupportedOnPrinter().
  328. //
  329. if (pForm->Flags != FORM_USER)
  330. {
  331. MemFree(pForm);
  332. return TRUE;
  333. }
  334. MemFree(pForm);
  335. }
  336. }
  337. //
  338. // Get the specified tray name, if any
  339. //
  340. pwstrTrayName = NULL;
  341. if (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_INPUTSLOT))
  342. {
  343. PINPUTSLOT pInputSlot;
  344. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
  345. dwOptionIndex = pci->pCombinedOptions[dwFeatureIndex].ubCurOptIndex;
  346. if ((pInputSlot = PGetIndexedOption(pUIInfo, pFeature, dwOptionIndex)) &&
  347. (pInputSlot->dwPaperSourceID != DMBIN_FORMSOURCE) &&
  348. LOAD_STRING_OPTION_NAME(pci, pInputSlot, awchTrayName, CCHBINNAME))
  349. {
  350. pwstrTrayName = awchTrayName;
  351. }
  352. }
  353. //
  354. // Find out if the requested form/tray pair is
  355. // listed in the form-to-tray assignment table.
  356. //
  357. if (pFormTrayTable = PGetFormTrayTable(pci->hPrinter, NULL))
  358. {
  359. RESET_FINDFORMTRAY(pFormTrayTable, &FindData);
  360. bResult = BSearchFormTrayTable(pFormTrayTable,
  361. pwstrTrayName,
  362. pci->pdm->dmFormName,
  363. &FindData);
  364. MemFree(pFormTrayTable);
  365. }
  366. if (! bResult)
  367. {
  368. if (pwstrTrayName != NULL)
  369. {
  370. return BFormatDQPMessage(pDQPInfo,
  371. IDS_DQPERR_FORMTRAY,
  372. pci->pdm->dmFormName,
  373. pwstrTrayName);
  374. }
  375. else
  376. {
  377. return BFormatDQPMessage(pDQPInfo,
  378. IDS_DQPERR_FORMTRAY_ANY,
  379. pci->pdm->dmFormName);
  380. }
  381. }
  382. return TRUE;
  383. }