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.

753 lines
20 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. Module Name:
  4. qryprint.c
  5. Abstract:
  6. This module contains functions called by the spoller to determine if a
  7. particular job can be print to a given printer
  8. Development History:
  9. 07-Dec-1993 Tue 00:48:24 created
  10. [Environment:]
  11. GDI Device Driver - Plotter.
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define DBG_PLOTFILENAME DbgQryPrint
  16. extern HMODULE hPlotUIModule;
  17. #define DBG_DEVQPRINT 0x00000001
  18. #define DBG_FORMDATA 0x00000002
  19. DEFINE_DBGVAR(0);
  20. #define USER_PAPER (DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PAPERSIZE)
  21. #define MAX_ERROR_CHARS 512
  22. UINT
  23. cdecl
  24. DQPsprintf(
  25. HINSTANCE hInst,
  26. LPWSTR pwBuf,
  27. DWORD cchBuf,
  28. LPDWORD pcchNeeded,
  29. LPWSTR pwszFormat,
  30. ...
  31. )
  32. /*++
  33. Routine Description:
  34. This fucntion output the debug informat to the debugger
  35. Arguments:
  36. hInst - handle to the driver's instance (hModule)
  37. pwBuf - Pointer to the WCHAR buffer for the output
  38. cchBuf - Count of characters pointed by the pwBuf, this includs
  39. the NULL terminator
  40. pcchBuf - pointer to the a DWORD to received total characteers needed
  41. for pwBuf (includes null terminator). If this pointer is
  42. NULL then no data is returned.
  43. pwszFormat - pointer to WCHAR format string, the introduce character is
  44. '%' and it may followed by a format character of following
  45. %c = a WCHAR
  46. %s = Insert a unicode string.
  47. %d = convert to long integer
  48. %u = convert to DWORD
  49. %x = Convert to lower case hex, 10 = a
  50. %X = Convert to upper case hex, 10 = A
  51. %! = Load the resource ID unicode string
  52. ... - variable data, each one must be pushed as a 32-bit data
  53. Return Value:
  54. Count of total characters put into the pwBuf. (not includes the null
  55. terminator).
  56. Development History:
  57. 08-Feb-1996 Thu 00:53:36 created
  58. --*/
  59. {
  60. #define MAX_CUR_TEXT_CHARS 256
  61. va_list vaList;
  62. LPWSTR pwStrData;
  63. LPWSTR pwEndBuf;
  64. LPWSTR pwBufOrg;
  65. WCHAR c;
  66. WCHAR CurText[MAX_CUR_TEXT_CHARS];
  67. DWORD cchNeeded, cchSize;
  68. UINT i;
  69. static const LPWSTR pNumFmt[] = { L"%lX", L"%lx", L"%lu", L"%ld" };
  70. HRESULT hr;
  71. va_start(vaList, pwszFormat);
  72. //
  73. // pwEndBuf = the last character, cchNeeded is start with one since it
  74. // includes a null terminator
  75. //
  76. if (pwBufOrg = pwBuf) {
  77. pwEndBuf = (pwBuf + cchBuf - 1);
  78. } else {
  79. pwEndBuf = pwBuf;
  80. }
  81. cchNeeded = 1;
  82. while (c = *pwszFormat++) {
  83. pwStrData = NULL;
  84. cchSize = 0;
  85. i = 1;
  86. if (c == L'%') {
  87. pwStrData = CurText;
  88. cchSize = CCHOF(CurText);
  89. i = 0;
  90. switch (c = *pwszFormat++) {
  91. case L's':
  92. pwStrData = (LPWSTR)va_arg(vaList, LPWSTR);
  93. cchSize = wcslen(pwStrData) + 1;
  94. break;
  95. case L'd': // Index = 3
  96. ++i;
  97. case L'u': // Index = 2
  98. ++i;
  99. case L'x': // Index = 1
  100. ++i;
  101. case L'X': // Index = 0;
  102. hr = StringCchPrintfW(pwStrData, cchSize, pNumFmt[i], (DWORD)va_arg(vaList, DWORD));
  103. i = 0;
  104. break;
  105. case '!':
  106. //
  107. // %! = load the string from resource ID
  108. //
  109. //
  110. // The LoadString will append a NULL too
  111. //
  112. if (!LoadString(hInst,
  113. (UINT)va_arg(vaList, UINT),
  114. pwStrData,
  115. MAX_CUR_TEXT_CHARS)) {
  116. // If we can't read the string, put and empty string here.
  117. pwStrData[0] = L'\0';
  118. }
  119. break;
  120. case L'c':
  121. c = (WCHAR)va_arg(vaList, WCHAR);
  122. //
  123. // Fall through
  124. //
  125. default:
  126. pwStrData = NULL;
  127. i = 1;
  128. break;
  129. }
  130. }
  131. if (!i) {
  132. if (pwStrData) {
  133. i = lstrlen(pwStrData);
  134. } else {
  135. c = L' ';
  136. i = 0;
  137. }
  138. }
  139. cchNeeded += i;
  140. if (pwBuf < pwEndBuf) {
  141. if (pwStrData) {
  142. lstrcpyn(pwBuf, pwStrData, (int)(pwEndBuf - pwBuf + 1));
  143. pwBuf += lstrlen(pwBuf);
  144. } else {
  145. *pwBuf++ = c;
  146. }
  147. } else if (!pcchNeeded) {
  148. break;
  149. }
  150. }
  151. if (pwEndBuf) {
  152. *pwEndBuf = L'\0';
  153. }
  154. if (pcchNeeded) {
  155. *pcchNeeded = cchNeeded;
  156. }
  157. va_end(vaList);
  158. return((UINT)(pwBuf - pwBufOrg));
  159. #undef MAX_CUR_TEXT_CHARS
  160. }
  161. BOOL
  162. DevQueryPrintEx(
  163. PDEVQUERYPRINT_INFO pDQPInfo
  164. )
  165. /*++
  166. Routine Description:
  167. This routine determines whether or not the driver can print the job
  168. described by pDevMode on the printer described by hPrinter
  169. Arguments:
  170. pDQPInfo - Pointer to DEVQUERYPRINT_INFO data structure
  171. typedef struct _DEVQUERYPRINT_INFO {
  172. WORD cbSize; // size of this structure in bytes
  173. WORD Level; // Level of this info, 1 for this version
  174. HANDLE hPrinter; // handle to the printer for the query
  175. DEVMODE *pDevMode; // pointer to the DEVMODE for this job.
  176. LPTSTR pszErrorStr; // pointer to the error string buffer.
  177. WORD cchErrorStr; // count characters of pszErrorStr passed.
  178. WORD cchNeeded; // count characters of pszErrorStr needed.
  179. } DEVQUERYPRINT_INFO, *PDEVQUERYPRINT_INFO;
  180. cbSize - size of this structure
  181. Level - This must be one (1) for this version of structure
  182. hPrinter - Identifies the printer on which the job is to be printed.
  183. pDevMode - Points to the DEVMODE structure that describes the print
  184. job that is to be determined as printable or
  185. non-printable by hPrinter. The driver should always
  186. validate the DEVMODE structure whenever it is passed in.
  187. pszErrorStr - This is the pointer to a null terminated unicode string
  188. which to stored the reason for non-printable job. If the
  189. job is printable then it return TRUE. If the job
  190. is non-printable then it return FALSE, and a null
  191. terminated unicode string pointed by the pszErrorStr for
  192. the reason by this job is not printable. The size of
  193. this buffer in characters is specified by the cchErrorStr.
  194. cchErrorStr - Specified the size of pszErrorStr in characters (includs
  195. null terminator) when calling this function. If an error
  196. string is returned due to the non-printable job (returned
  197. FALSE), the driver will set ccchNeeded to the total
  198. characters (includes null terminator) required for the
  199. pszErrorStr, in this case the driver must always
  200. truncate the error string to fit into the pwErrorStr
  201. (only if it is not NULL) passed up to the cchErrorStr
  202. characters passed.
  203. cchNeeded - When driver returned FALSE, it specified total characters
  204. required for the pszErrorStr. If cchNeeded returned
  205. from the driver is larger then the cchErrorStr then it
  206. indicate the passed pszErrorStr is too small to hold the
  207. full error string, in this case the driver must always
  208. truncate the error string to fit into the pszErrorStr
  209. passed up to the cchErrorStr size.
  210. Return Value:
  211. BOOLEAN - TRUE - The job is printable and should not be hold.
  212. FALSE - The job is not printable and cchNeeded in the
  213. DEVQUERYPRINT_INFO data structure specified total
  214. characters required for the pszErrorStr. If returned
  215. cchNeeded is greater then cchErrorStr passed then it
  216. indicated that pszErrorStr is too small for storing the
  217. error string, in this case the driver must always
  218. truncate the error string to fit into the pszErrorStr
  219. passed, up to the cchErrorStr characters.
  220. *Note*
  221. The driver should have some predefined generic resource error strings
  222. for some possible known errors. such as memroy allocation error, data
  223. file not found, invalid devmode,... for returning non devmode related
  224. errors. The caller can pre-allocated larger buffer (such as 256
  225. wchars) for storing the error string rather than calling this function
  226. twice.
  227. Development History:
  228. 07-Feb-1996 Wed 20:37:31 created
  229. --*/
  230. {
  231. PPRINTERINFO pPI = NULL;
  232. LONG ErrorResID = 0;
  233. static WCHAR wFormat1[] = L"<%s> %!";
  234. //
  235. // if it passed a NULL DEVMODE then we just honor it to said can print
  236. //
  237. pDQPInfo->cchNeeded = 0;
  238. ErrorResID = IDS_FORM_NOT_AVAI;
  239. if (!pDQPInfo->pDevMode) {
  240. PLOTWARN(("DevQueryPrint: No DEVMODE passed, CANNOT PRINT"));
  241. ErrorResID = IDS_INVALID_DATA;
  242. } else if (!(pPI = MapPrinter(pDQPInfo->hPrinter,
  243. (PPLOTDEVMODE)pDQPInfo->pDevMode,
  244. (LPDWORD)&ErrorResID,
  245. MPF_DEVICEDATA))) {
  246. //
  247. // The MapPrinter will allocate memory, set default devmode, reading
  248. // and validating the GPC then update from current pritner registry,
  249. //
  250. PLOTRIP(("DevQueryPrint: MapPrinter() failed"));
  251. } else if (pPI->dmErrBits & (USER_PAPER | DM_FORMNAME)) {
  252. //
  253. // We encounter some errors, and the form has been set to default
  254. //
  255. PLOTWARN(("DevQueryPrint: CAN'T PRINT, dmErrBits=%08lx (PAPER/FORM)",
  256. pPI->dmErrBits));
  257. } else if ((pPI->PlotDM.dm.dmFields & DM_FORMNAME) &&
  258. (wcscmp(pPI->CurPaper.Name, pPI->PlotDM.dm.dmFormName) == 0)) {
  259. //
  260. // We can print this form now
  261. //
  262. ErrorResID = 0;
  263. PLOTDBG(DBG_DEVQPRINT, ("DevQueryPrint: Match FormName=%s",
  264. pPI->PlotDM.dm.dmFormName));
  265. } else if ((!pPI->CurPaper.Size.cy) ||
  266. (((pPI->PlotDM.dm.dmFields & USER_PAPER) == USER_PAPER) &&
  267. (pPI->PlotDM.dm.dmPaperSize == DMPAPER_USER)) ||
  268. (pPI->PPData.Flags & PPF_SMALLER_FORM)) {
  269. LONG lTmp;
  270. SIZEL szl;
  271. BOOL VarLenPaper;
  272. //
  273. // 1. If we have ROLL PAPER Installed OR
  274. // 2. User Defined Paper Size
  275. // 3. User said OK to print smaller form then installed one
  276. //
  277. // THEN we want to see if it can fit into the device installed form
  278. //
  279. szl.cx = DMTOSPL(pPI->PlotDM.dm.dmPaperWidth);
  280. szl.cy = DMTOSPL(pPI->PlotDM.dm.dmPaperLength);
  281. if (VarLenPaper = (BOOL)!pPI->CurPaper.Size.cy) {
  282. pPI->CurPaper.Size.cy = pPI->pPlotGPC->DeviceSize.cy;
  283. }
  284. PLOTDBG(DBG_DEVQPRINT,
  285. ("DevQueryPrint: CurPaper=%ldx%ld, Req=%ldx%ld, VarLen=%ld",
  286. pPI->CurPaper.Size.cx, pPI->CurPaper.Size.cy,
  287. szl.cx, szl.cy, VarLenPaper));
  288. //
  289. // One of Following conditions met in that sequence then we can print
  290. // the form on loaded paper
  291. //
  292. // 1. Same size (PORTRAIT or LANDSCAPE)
  293. // 2. Larger Size (PORTRAIT or LANDSCAPE) AND
  294. // Not a variable length paper AND
  295. // PPF_SAMLLER_FORM flag set
  296. //
  297. if ((pPI->CurPaper.Size.cx < szl.cx) ||
  298. (pPI->CurPaper.Size.cy < szl.cy)) {
  299. //
  300. // Swap this so we can do one easier comparsion later
  301. //
  302. SWAP(szl.cx, szl.cy, lTmp);
  303. }
  304. if ((pPI->CurPaper.Size.cx >= szl.cx) &&
  305. (pPI->CurPaper.Size.cy >= szl.cy)) {
  306. if ((!VarLenPaper) &&
  307. (!(pPI->PPData.Flags & PPF_SMALLER_FORM)) &&
  308. ((pPI->CurPaper.Size.cx > szl.cx) ||
  309. (pPI->CurPaper.Size.cy > szl.cy))) {
  310. PLOTDBG(DBG_DEVQPRINT,
  311. ("DevQueryPrint: CAN'T PRINT: user DO NOT want print on larger paper"));
  312. } else {
  313. PLOTDBG(DBG_DEVQPRINT,
  314. ("DevQueryPrint: Paper Size FITS in DEVICE, %ld x %ld",
  315. szl.cx, szl.cy));
  316. ErrorResID = 0;
  317. }
  318. } else {
  319. DQPsprintf((HINSTANCE)hPlotUIModule,
  320. pDQPInfo->pszErrorStr,
  321. pDQPInfo->cchErrorStr,
  322. &(pDQPInfo->cchNeeded),
  323. wFormat1,
  324. pPI->PlotDM.dm.dmFormName,
  325. IDS_FORM_TOO_BIG);
  326. PLOTDBG(DBG_DEVQPRINT,
  327. ("DevQueryPrint: CAN'T PRINT: Form Size too small"));
  328. }
  329. }
  330. if (pPI)
  331. {
  332. PLOTDBG(DBG_DEVQPRINT, ("DevQueryPrint: %s PRINT %s",
  333. (ErrorResID) ? "CAN'T" : "OK to", pPI->PlotDM.dm.dmFormName));
  334. }
  335. if ((!pDQPInfo->cchNeeded) && (ErrorResID)) {
  336. switch (ErrorResID) {
  337. case IDS_FORM_NOT_AVAI:
  338. if (pPI)
  339. {
  340. DQPsprintf((HINSTANCE)hPlotUIModule,
  341. pDQPInfo->pszErrorStr,
  342. pDQPInfo->cchErrorStr,
  343. &(pDQPInfo->cchNeeded),
  344. wFormat1,
  345. pPI->PlotDM.dm.dmFormName,
  346. IDS_FORM_NOT_AVAI);
  347. }
  348. break;
  349. default:
  350. DQPsprintf((HINSTANCE)hPlotUIModule,
  351. pDQPInfo->pszErrorStr,
  352. pDQPInfo->cchErrorStr,
  353. &(pDQPInfo->cchNeeded),
  354. L"%!",
  355. ErrorResID);
  356. break;
  357. }
  358. }
  359. //
  360. // Unget the printer GPC mapping if we got one
  361. //
  362. if (pPI) {
  363. UnMapPrinter(pPI);
  364. }
  365. return((!ErrorResID) && (!pDQPInfo->cchNeeded));
  366. }
  367. #if 0
  368. BOOL
  369. WINAPI
  370. DevQueryPrint(
  371. HANDLE hPrinter,
  372. DEVMODE *pDM,
  373. DWORD *pdwErrIDS
  374. )
  375. /*++
  376. Routine Description:
  377. This routine determines whether or not the driver can print the job
  378. described by pDevMode on the printer described by hPrinter. If if can, it
  379. puts zero into pdwErrIDS. If it cannot, it puts the resource id of the
  380. string describing why it could not.
  381. Arguments:
  382. hPrinter - Handle to the printer to be checked
  383. pDM - Point to the DEVMODE passed in
  384. pdwErrIDS - Point the the DWORD to received resource string ID number for
  385. the error.
  386. Return Value:
  387. This routine returns TRUE for success, FALSE for failure.
  388. when it return TRUE, the *pdwErrIDS determine if it can print or not, if
  389. *pdwErrIDS == 0, then it can print else it contains the string ID for the
  390. reason why it can not print.
  391. Development History:
  392. 07-Dec-1993 Tue 00:50:32 created
  393. 14-Jun-1994 Tue 22:43:36 updated
  394. Make installed RollPaper always print if the size is reasonable
  395. --*/
  396. {
  397. PPRINTERINFO pPI = NULL;
  398. //
  399. // if it passed a NULL DEVMODE then we just honor it to said can print
  400. //
  401. if (!pDM) {
  402. PLOTWARN(("DevQueryPrint: No DEVMODE passed, CANNOT PRINT"));
  403. *pdwErrIDS = IDS_INV_DMSIZE;
  404. return(TRUE);
  405. }
  406. if (!(pPI = MapPrinter(hPrinter,
  407. (PPLOTDEVMODE)pDM,
  408. pdwErrIDS,
  409. MPF_DEVICEDATA))) {
  410. //
  411. // The MapPrinter will allocate memory, set default devmode, reading
  412. // and validating the GPC then update from current pritner registry,
  413. //
  414. PLOTRIP(("DevQueryPrint: MapPrinter() failed"));
  415. return(TRUE);
  416. }
  417. //
  418. // Assume this error
  419. //
  420. *pdwErrIDS = IDS_FORM_NOT_AVAI;
  421. if (pPI->dmErrBits & (USER_PAPER | DM_FORMNAME)) {
  422. //
  423. // We encounter some errors, and the form has been set to default
  424. //
  425. PLOTWARN(("DevQueryPrint: CAN'T PRINT, dmErrBits=%08lx (PAPER/FORM)",
  426. pPI->dmErrBits));
  427. } else if ((pPI->PlotDM.dm.dmFields & DM_FORMNAME) &&
  428. (wcscmp(pPI->CurPaper.Name, pPI->PlotDM.dm.dmFormName) == 0)) {
  429. //
  430. // We can print this form now
  431. //
  432. *pdwErrIDS = 0;
  433. PLOTDBG(DBG_DEVQPRINT, ("DevQueryPrint: Match FormName=%s",
  434. pPI->PlotDM.dm.dmFormName));
  435. } else if ((!pPI->CurPaper.Size.cy) ||
  436. (((pPI->PlotDM.dm.dmFields & USER_PAPER) == USER_PAPER) &&
  437. (pPI->PlotDM.dm.dmPaperSize == DMPAPER_USER)) ||
  438. (pPI->PPData.Flags & PPF_SMALLER_FORM)) {
  439. LONG lTmp;
  440. SIZEL szl;
  441. BOOL VarLenPaper;
  442. //
  443. // 1. If we have ROLL PAPER Installed OR
  444. // 2. User Defined Paper Size
  445. // 3. User said OK to print smaller form then installed one
  446. //
  447. // THEN we want to see if it can fit into the device installed form
  448. //
  449. szl.cx = DMTOSPL(pPI->PlotDM.dm.dmPaperWidth);
  450. szl.cy = DMTOSPL(pPI->PlotDM.dm.dmPaperLength);
  451. if (VarLenPaper = (BOOL)!pPI->CurPaper.Size.cy) {
  452. pPI->CurPaper.Size.cy = pPI->pPlotGPC->DeviceSize.cy;
  453. }
  454. PLOTDBG(DBG_DEVQPRINT,
  455. ("DevQueryPrint: CurPaper=%ldx%ld, Req=%ldx%ld, VarLen=%ld",
  456. pPI->CurPaper.Size.cx, pPI->CurPaper.Size.cy,
  457. szl.cx, szl.cy, VarLenPaper));
  458. //
  459. // One of Following conditions met in that sequence then we can print
  460. // the form on loaded paper
  461. //
  462. // 1. Same size (PORTRAIT or LANDSCAPE)
  463. // 2. Larger Size (PORTRAIT or LANDSCAPE) AND
  464. // Not a variable length paper AND
  465. // PPF_SAMLLER_FORM flag set
  466. //
  467. if ((pPI->CurPaper.Size.cx < szl.cx) ||
  468. (pPI->CurPaper.Size.cy < szl.cy)) {
  469. //
  470. // Swap this so we can do one easier comparsion later
  471. //
  472. SWAP(szl.cx, szl.cy, lTmp);
  473. }
  474. if ((pPI->CurPaper.Size.cx >= szl.cx) &&
  475. (pPI->CurPaper.Size.cy >= szl.cy)) {
  476. if ((!VarLenPaper) &&
  477. (!(pPI->PPData.Flags & PPF_SMALLER_FORM)) &&
  478. ((pPI->CurPaper.Size.cx > szl.cx) ||
  479. (pPI->CurPaper.Size.cy > szl.cy))) {
  480. PLOTDBG(DBG_DEVQPRINT,
  481. ("DevQueryPrint: CAN'T PRINT: user DO NOT want print on larger paper"));
  482. } else {
  483. PLOTDBG(DBG_DEVQPRINT,
  484. ("DevQueryPrint: Paper Size FITS in DEVICE, %ld x %ld",
  485. szl.cx, szl.cy));
  486. *pdwErrIDS = 0;
  487. }
  488. } else {
  489. PLOTDBG(DBG_DEVQPRINT,
  490. ("DevQueryPrint: CAN'T PRINT: Form Size too small"));
  491. }
  492. }
  493. PLOTDBG(DBG_DEVQPRINT, ("DevQueryPrint: %s PRINT %s",
  494. (*pdwErrIDS) ? "CAN'T" : "OK to", pPI->PlotDM.dm.dmFormName));
  495. //
  496. // Unget the printer GPC mapping if we got one
  497. //
  498. UnMapPrinter(pPI);
  499. return(TRUE);
  500. }
  501. #endif