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.

7581 lines
201 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. printnew.cpp
  5. Abstract:
  6. This module implements the Win32 property sheet print dialogs.
  7. Revision History:
  8. 11-04-97 JulieB Created.
  9. Feb-2000 LazarI major redesign (not to use printui anymore)
  10. Oct-2000 LazarI messages cleanup & redesign
  11. --*/
  12. // precompiled headers
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "cdids.h"
  16. #include "prnsetup.h"
  17. #include "printnew.h"
  18. #include "util.h"
  19. #ifndef ARRAYSIZE
  20. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  21. #endif // ARRAYSIZE
  22. inline static HRESULT CreateError()
  23. {
  24. DWORD dw = GetLastError();
  25. if (ERROR_SUCCESS == dw) return E_FAIL;
  26. return HRESULT_FROM_WIN32(dw);
  27. }
  28. //
  29. // Constant Declarations.
  30. //
  31. #define CDM_SELCHANGE (CDM_LAST + 102)
  32. #define CDM_PRINTNOTIFY (CDM_LAST + 103)
  33. #define CDM_NOPRINTERS (CDM_LAST + 104)
  34. #define CDM_INITDONE (CDM_LAST + 105)
  35. #define PRINTERS_ICOL_NAME 0
  36. #define PRINTERS_ICOL_QUEUESIZE 1
  37. #define PRINTERS_ICOL_STATUS 2
  38. #define PRINTERS_ICOL_COMMENT 3
  39. #define PRINTERS_ICOL_LOCATION 4
  40. #define PRINTERS_ICOL_MODEL 5
  41. #define SZ_PRINTUI TEXT("printui.dll")
  42. //
  43. // Default view mode value
  44. //
  45. #define VIEW_MODE_DEFAULT (UINT )(-1)
  46. //
  47. // Macro Definitions.
  48. //
  49. #define Print_HwndToBrowser(hwnd) ((CPrintBrowser *)GetWindowLongPtr(hwnd, DWLP_USER))
  50. #define Print_StoreBrowser(hwnd, pbrs) (SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pbrs))
  51. #define Print_IsInRange(id, idFirst, idLast) \
  52. ((UINT)((id) - idFirst) <= (UINT)(idLast - idFirst))
  53. //
  54. // Global Variables.
  55. //
  56. HWND g_hwndActivePrint = NULL;
  57. HACCEL g_haccPrint = NULL;
  58. HHOOK g_hHook = NULL;
  59. int g_nHookRef = -1;
  60. //
  61. // Extern Declarations.
  62. //
  63. extern HWND
  64. GetFocusedChild(
  65. HWND hwndDlg,
  66. HWND hwndFocus);
  67. extern void
  68. GetViewItemText(
  69. IShellFolder *psf,
  70. LPCITEMIDLIST pidl,
  71. LPTSTR pBuf,
  72. UINT cchBuf,
  73. DWORD dwFlags);
  74. // Frees up the PIDL using the shell allocator
  75. static void FreePIDL(LPITEMIDLIST pidl)
  76. {
  77. if (pidl)
  78. {
  79. LPMALLOC pShellMalloc;
  80. if (SUCCEEDED(SHGetMalloc(&pShellMalloc)))
  81. {
  82. pShellMalloc->Free(pidl);
  83. pShellMalloc->Release();
  84. }
  85. }
  86. }
  87. ////////////////////////////////////////////////////////////////////////////
  88. //
  89. // PrintDlgExA
  90. //
  91. // ANSI entry point for PrintDlgEx when this code is built UNICODE.
  92. //
  93. ////////////////////////////////////////////////////////////////////////////
  94. HRESULT WINAPI PrintDlgExA(
  95. LPPRINTDLGEXA pPDA)
  96. {
  97. PRINTINFOEX PI;
  98. HRESULT hResult;
  99. ZeroMemory(&PI, sizeof(PRINTINFOEX));
  100. hResult = ThunkPrintDlgEx(&PI, pPDA);
  101. if (SUCCEEDED(hResult))
  102. {
  103. ThunkPrintDlgExA2W(&PI);
  104. hResult = PrintDlgExX(&PI);
  105. ThunkPrintDlgExW2A(&PI);
  106. }
  107. FreeThunkPrintDlgEx(&PI);
  108. return (hResult);
  109. }
  110. ////////////////////////////////////////////////////////////////////////////
  111. //
  112. // PrintDlgEx
  113. //
  114. // The PrintDlgEx function displays a Print dialog that enables the
  115. // user to specify the properties of a particular print job.
  116. //
  117. ////////////////////////////////////////////////////////////////////////////
  118. HRESULT WINAPI PrintDlgEx(
  119. LPPRINTDLGEX pPD)
  120. {
  121. PRINTINFOEX PI;
  122. ZeroMemory(&PI, sizeof(PRINTINFOEX));
  123. PI.pPD = pPD;
  124. PI.ApiType = COMDLG_WIDE;
  125. return ( PrintDlgExX(&PI) );
  126. }
  127. ////////////////////////////////////////////////////////////////////////////
  128. //
  129. // PrintDlgExX
  130. //
  131. // Worker routine for the PrintDlgEx api.
  132. //
  133. ////////////////////////////////////////////////////////////////////////////
  134. HRESULT PrintDlgExX(
  135. PPRINTINFOEX pPI)
  136. {
  137. LPPRINTDLGEX pPD = pPI->pPD;
  138. BOOL hResult;
  139. DWORD dwFlags;
  140. DWORD nCopies;
  141. LPPRINTPAGERANGE pPageRanges;
  142. DWORD nFromPage, nToPage;
  143. UINT Ctr;
  144. BOOL bHooked = FALSE;
  145. //
  146. // Make sure the print dlg structure exists and that we're not being
  147. // called from a wow app.
  148. //
  149. if ((!pPD) || (IS16BITWOWAPP(pPD)))
  150. {
  151. pPI->dwExtendedError = CDERR_INITIALIZATION;
  152. return (E_INVALIDARG);
  153. }
  154. //
  155. // Make sure the size of the print dlg structure is valid.
  156. //
  157. if (pPD->lStructSize != sizeof(PRINTDLGEX))
  158. {
  159. pPI->dwExtendedError = CDERR_STRUCTSIZE;
  160. return (E_INVALIDARG);
  161. }
  162. //
  163. // Make sure the owner window exists and is valid.
  164. //
  165. if (!pPD->hwndOwner || !IsWindow(pPD->hwndOwner))
  166. {
  167. pPI->dwExtendedError = CDERR_DIALOGFAILURE;
  168. return (E_HANDLE);
  169. }
  170. //
  171. // Make sure only valid flags are passed into this routine.
  172. //
  173. if ((pPD->Flags & ~(PD_ALLPAGES |
  174. PD_SELECTION |
  175. PD_PAGENUMS |
  176. PD_NOSELECTION |
  177. PD_NOPAGENUMS |
  178. PD_COLLATE |
  179. PD_PRINTTOFILE |
  180. PD_NOWARNING |
  181. PD_RETURNDC |
  182. PD_RETURNIC |
  183. PD_RETURNDEFAULT |
  184. PD_ENABLEPRINTTEMPLATE |
  185. PD_ENABLEPRINTTEMPLATEHANDLE |
  186. PD_USEDEVMODECOPIESANDCOLLATE |
  187. PD_DISABLEPRINTTOFILE |
  188. PD_HIDEPRINTTOFILE |
  189. PD_CURRENTPAGE |
  190. PD_NOCURRENTPAGE |
  191. PD_EXCLUSIONFLAGS |
  192. PD_USELARGETEMPLATE |
  193. CD_WX86APP)) ||
  194. (pPD->Flags2 != 0) ||
  195. (pPD->ExclusionFlags & ~(PD_EXCL_COPIESANDCOLLATE)) ||
  196. (pPD->dwResultAction != 0))
  197. {
  198. pPI->dwExtendedError = PDERR_INITFAILURE;
  199. return (E_INVALIDARG);
  200. }
  201. //
  202. // Check the template settings as much as we can here.
  203. //
  204. if (pPD->Flags & PD_ENABLEPRINTTEMPLATEHANDLE)
  205. {
  206. if (!pPD->hInstance)
  207. {
  208. pPI->dwExtendedError = CDERR_NOHINSTANCE;
  209. return (E_HANDLE);
  210. }
  211. }
  212. else if (pPD->Flags & PD_ENABLEPRINTTEMPLATE)
  213. {
  214. if (!pPD->lpPrintTemplateName)
  215. {
  216. pPI->dwExtendedError = CDERR_NOTEMPLATE;
  217. return (E_POINTER);
  218. }
  219. if (!pPD->hInstance)
  220. {
  221. pPI->dwExtendedError = CDERR_NOHINSTANCE;
  222. return (E_HANDLE);
  223. }
  224. }
  225. else
  226. {
  227. if (pPD->lpPrintTemplateName || pPD->hInstance)
  228. {
  229. pPI->dwExtendedError = PDERR_INITFAILURE;
  230. return (E_INVALIDARG);
  231. }
  232. }
  233. //
  234. // Check the application property pages and the start page value.
  235. //
  236. if ((pPD->nPropertyPages && (pPD->lphPropertyPages == NULL)) ||
  237. ((pPD->nStartPage != START_PAGE_GENERAL) &&
  238. (pPD->nStartPage >= pPD->nPropertyPages)))
  239. {
  240. pPI->dwExtendedError = PDERR_INITFAILURE;
  241. return (E_INVALIDARG);
  242. }
  243. //
  244. // Check the page range boundaries if the PD_NOPAGENUMS flag is
  245. // not set.
  246. //
  247. if (!(pPD->Flags & PD_NOPAGENUMS))
  248. {
  249. if ((pPD->nMinPage > pPD->nMaxPage) ||
  250. (pPD->nPageRanges > pPD->nMaxPageRanges) ||
  251. (pPD->nMaxPageRanges == 0) ||
  252. ((pPD->nMaxPageRanges) && (!pPD->lpPageRanges)))
  253. {
  254. pPI->dwExtendedError = PDERR_INITFAILURE;
  255. return (E_INVALIDARG);
  256. }
  257. //
  258. // Check each of the given ranges.
  259. //
  260. pPageRanges = pPD->lpPageRanges;
  261. for (Ctr = 0; Ctr < pPD->nPageRanges; Ctr++)
  262. {
  263. //
  264. // Get the range.
  265. //
  266. nFromPage = pPageRanges[Ctr].nFromPage;
  267. nToPage = pPageRanges[Ctr].nToPage;
  268. //
  269. // Make sure the range is valid.
  270. //
  271. if ((nFromPage < pPD->nMinPage) || (nFromPage > pPD->nMaxPage) ||
  272. (nToPage < pPD->nMinPage) || (nToPage > pPD->nMaxPage))
  273. {
  274. pPI->dwExtendedError = PDERR_INITFAILURE;
  275. return (E_INVALIDARG);
  276. }
  277. }
  278. }
  279. //
  280. // Get the process version of the app for later use.
  281. //
  282. pPI->ProcessVersion = GetProcessVersion(0);
  283. //
  284. // Init hDC.
  285. //
  286. pPD->hDC = 0;
  287. //
  288. // Do minimal work when requesting a default printer.
  289. //
  290. if (pPD->Flags & PD_RETURNDEFAULT)
  291. {
  292. return (Print_ReturnDefault(pPI));
  293. }
  294. //
  295. // Load the necessary libraries.
  296. //
  297. if (!Print_LoadLibraries())
  298. {
  299. pPI->dwExtendedError = PDERR_LOADDRVFAILURE;
  300. hResult = CreateError();
  301. goto PrintDlgExX_DisplayWarning;
  302. }
  303. //
  304. // Load the necessary icons.
  305. //
  306. if (!Print_LoadIcons())
  307. {
  308. //
  309. // If the icons cannot be loaded, then fail.
  310. //
  311. pPI->dwExtendedError = PDERR_SETUPFAILURE;
  312. hResult = CreateError();
  313. goto PrintDlgExX_DisplayWarning;
  314. }
  315. //
  316. // Make sure the page ranges info is valid.
  317. //
  318. if ((!(pPD->Flags & PD_NOPAGENUMS)) &&
  319. ((pPD->nMinPage > pPD->nMaxPage) ||
  320. (pPD->nPageRanges > pPD->nMaxPageRanges) ||
  321. (pPD->nMaxPageRanges == 0) ||
  322. ((pPD->nMaxPageRanges) && (!(pPD->lpPageRanges)))))
  323. {
  324. pPI->dwExtendedError = PDERR_INITFAILURE;
  325. return (E_INVALIDARG);
  326. }
  327. //
  328. // Save the original information passed in by the app in case the
  329. // user hits cancel.
  330. //
  331. // Only the values that are modified at times other than during
  332. // PSN_APPLY need to be saved.
  333. //
  334. dwFlags = pPD->Flags;
  335. nCopies = pPD->nCopies;
  336. pPI->dwFlags = dwFlags;
  337. //
  338. // Set up the hook proc for input event messages.
  339. //
  340. if (InterlockedIncrement((LPLONG)&g_nHookRef) == 0)
  341. {
  342. g_hHook = SetWindowsHookEx( WH_MSGFILTER,
  343. Print_MessageHookProc,
  344. 0,
  345. GetCurrentThreadId() );
  346. if (g_hHook)
  347. {
  348. bHooked = TRUE;
  349. }
  350. else
  351. {
  352. --g_nHookRef;
  353. }
  354. }
  355. else
  356. {
  357. bHooked = TRUE;
  358. }
  359. //
  360. // Load the print folder accelerators.
  361. //
  362. if (!g_haccPrint)
  363. {
  364. g_haccPrint = LoadAccelerators( g_hinst,
  365. MAKEINTRESOURCE(IDA_PRINTFOLDER) );
  366. }
  367. //
  368. // Initialize the error codes to failure in case we die before we
  369. // actually bring up the property pages.
  370. //
  371. pPI->dwExtendedError = CDERR_INITIALIZATION;
  372. pPI->hResult = E_FAIL;
  373. pPI->hrOleInit = E_FAIL;
  374. //
  375. // Warning! Warning! Warning!
  376. //
  377. // We have to set g_tlsLangID before any call for CDLoadString
  378. //
  379. TlsSetValue(g_tlsLangID, (LPVOID) MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
  380. //
  381. // Bring up the dialog.
  382. //
  383. Print_InvokePropertySheets(pPI, pPD);
  384. hResult = pPI->hResult;
  385. //Ole Would have been initialized during the WM_INITDIALOG processing.
  386. // Uninitialize Ole Now
  387. SHOleUninitialize(pPI->hrOleInit);
  388. //
  389. // Unhook the input event messages.
  390. //
  391. if (bHooked)
  392. {
  393. //
  394. // Put this in a local so we don't need a critical section.
  395. //
  396. HHOOK hHook = g_hHook;
  397. if (InterlockedDecrement((LPLONG)&g_nHookRef) < 0)
  398. {
  399. UnhookWindowsHookEx(hHook);
  400. }
  401. }
  402. //
  403. // If the user hit cancel or if there was an error, restore the original
  404. // values passed in by the app.
  405. //
  406. // Only the values that are modified at times other than during
  407. // PSN_APPLY need to be restored here.
  408. //
  409. if ((pPI->FinalResult == 0) && (!pPI->fApply))
  410. {
  411. pPD->Flags = dwFlags;
  412. pPD->nCopies = nCopies;
  413. }
  414. //
  415. // See if we need to fill in the dwResultAction member field.
  416. //
  417. if (SUCCEEDED(hResult))
  418. {
  419. if (pPI->FinalResult != 0)
  420. {
  421. pPD->dwResultAction = PD_RESULT_PRINT;
  422. }
  423. else if (pPI->fApply)
  424. {
  425. pPD->dwResultAction = PD_RESULT_APPLY;
  426. }
  427. else
  428. {
  429. pPD->dwResultAction = PD_RESULT_CANCEL;
  430. }
  431. }
  432. //
  433. // Display any error messages.
  434. //
  435. PrintDlgExX_DisplayWarning:
  436. if ((!(dwFlags & PD_NOWARNING)) && FAILED(hResult) &&
  437. (pPI->ProcessVersion >= 0x40000))
  438. {
  439. TCHAR szWarning[SCRATCHBUF_SIZE];
  440. TCHAR szTitle[SCRATCHBUF_SIZE];
  441. int iszWarning;
  442. szTitle[0] = TEXT('\0');
  443. if (pPD->hwndOwner)
  444. {
  445. GetWindowText(pPD->hwndOwner, szTitle, ARRAYSIZE(szTitle));
  446. }
  447. if (!szTitle[0])
  448. {
  449. CDLoadString(g_hinst, iszWarningTitle, szTitle, ARRAYSIZE(szTitle));
  450. }
  451. switch (hResult)
  452. {
  453. case ( E_OUTOFMEMORY ) :
  454. {
  455. iszWarning = iszMemoryError;
  456. break;
  457. }
  458. default :
  459. {
  460. iszWarning = iszGeneralWarning;
  461. break;
  462. }
  463. }
  464. CDLoadString(g_hinst, iszWarning, szWarning, ARRAYSIZE(szWarning));
  465. MessageBeep(MB_ICONEXCLAMATION);
  466. MessageBox( pPD->hwndOwner,
  467. szWarning,
  468. szTitle,
  469. MB_ICONEXCLAMATION | MB_OK );
  470. }
  471. //
  472. // Return the result.
  473. //
  474. return (hResult);
  475. }
  476. ////////////////////////////////////////////////////////////////////////////
  477. //
  478. // Print_ReturnDefault
  479. //
  480. ////////////////////////////////////////////////////////////////////////////
  481. HRESULT Print_ReturnDefault(
  482. PPRINTINFOEX pPI)
  483. {
  484. LPPRINTDLGEX pPD = pPI->pPD;
  485. TCHAR szPrinterName[MAX_PRINTERNAME];
  486. LPDEVNAMES pDN;
  487. LPDEVMODE pDM;
  488. //
  489. // Initialize the error code to 0.
  490. //
  491. pPI->dwExtendedError = CDERR_GENERALCODES;
  492. //
  493. // Make sure the hDevMode and hDevNames fields are NULL.
  494. //
  495. if (pPD->hDevMode || pPD->hDevNames)
  496. {
  497. pPI->dwExtendedError = PDERR_RETDEFFAILURE;
  498. return (E_HANDLE);
  499. }
  500. //
  501. // Get the default printer name.
  502. //
  503. szPrinterName[0] = 0;
  504. PrintGetDefaultPrinterName(szPrinterName, ARRAYSIZE(szPrinterName));
  505. if (szPrinterName[0] == 0)
  506. {
  507. pPI->dwExtendedError = PDERR_NODEFAULTPRN;
  508. return (E_FAIL);
  509. }
  510. //
  511. // Allocate and fill in the DevNames structure.
  512. //
  513. if (!Print_SaveDevNames(szPrinterName, pPD))
  514. {
  515. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  516. return CreateError();
  517. }
  518. //
  519. // Allocate and fill in the DevMode structure.
  520. //
  521. pPD->hDevMode = Print_GetDevModeWrapper(szPrinterName);
  522. //
  523. // Get the device or information context, depending on which one
  524. // was requested (if any).
  525. //
  526. if ((pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames)))
  527. {
  528. if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode)))
  529. {
  530. PrintReturnICDC((LPPRINTDLG)pPD, pDN, pDM);
  531. GlobalUnlock(pPD->hDevMode);
  532. GlobalUnlock(pPD->hDevNames);
  533. return (S_OK);
  534. }
  535. else
  536. {
  537. GlobalUnlock(pPD->hDevNames);
  538. }
  539. }
  540. //
  541. // Make sure the pointers are NULL since we failed.
  542. //
  543. if (pPD->hDevNames)
  544. {
  545. GlobalFree(pPD->hDevNames);
  546. pPD->hDevNames = NULL;
  547. }
  548. if (pPD->hDevMode)
  549. {
  550. GlobalFree(pPD->hDevMode);
  551. pPD->hDevMode = NULL;
  552. }
  553. //
  554. // Return failure.
  555. //
  556. pPI->dwExtendedError = PDERR_NODEFAULTPRN;
  557. return (E_FAIL);
  558. }
  559. typedef BOOL (*PFN_bPrinterSetup)(
  560. HWND hwnd, // handle to parent window
  561. UINT uAction, // setup action
  562. UINT cchPrinterName, // size of pszPrinterName buffer in characters
  563. LPTSTR pszPrinterName, // in/out buffer for the printer name
  564. UINT *pcchPrinterName, // out buffer where we put the required number of characters
  565. LPCTSTR pszServerName // server name
  566. );
  567. typedef LONG (*PFN_DocumentPropertiesWrap)(
  568. HWND hwnd, // handle to parent window
  569. HANDLE hPrinter, // handle to printer object
  570. LPTSTR pDeviceName, // device name
  571. PDEVMODE pDevModeOutput, // modified device mode
  572. PDEVMODE pDevModeInput, // original device mode
  573. DWORD fMode, // mode options
  574. DWORD fExclusionFlags // exclusion flags
  575. );
  576. EXTERN_C CRITICAL_SECTION g_csLocal;
  577. static HINSTANCE hPrintUI = NULL;
  578. static PFN_bPrinterSetup g_pfnPrinterSetup = NULL;
  579. static PFN_DocumentPropertiesWrap g_pfnDocumentPropertiesWrap = NULL;
  580. ////////////////////////////////////////////////////////////////////////////
  581. //
  582. // Print_LoadLibraries
  583. //
  584. ////////////////////////////////////////////////////////////////////////////
  585. BOOL Print_LoadLibraries()
  586. {
  587. //
  588. // Make sure we hold the global CS while initializing
  589. // the global variables.
  590. //
  591. EnterCriticalSection(&g_csLocal);
  592. //
  593. // Load PrintUI.
  594. //
  595. if (!hPrintUI)
  596. {
  597. if ((hPrintUI = LoadLibrary(SZ_PRINTUI)))
  598. {
  599. //
  600. // Get the proc addresses of bPrinterSetup private API.
  601. //
  602. g_pfnPrinterSetup = (PFN_bPrinterSetup)GetProcAddress(hPrintUI, "bPrinterSetup");
  603. g_pfnDocumentPropertiesWrap = (PFN_DocumentPropertiesWrap)GetProcAddress(hPrintUI, "DocumentPropertiesWrap");
  604. if (NULL == g_pfnPrinterSetup || NULL == g_pfnDocumentPropertiesWrap)
  605. {
  606. // failed to get addresses of core printui APIs
  607. FreeLibrary(hPrintUI);
  608. hPrintUI = NULL;
  609. }
  610. }
  611. }
  612. //
  613. // Leave the global CS.
  614. //
  615. LeaveCriticalSection(&g_csLocal);
  616. //
  617. // Return the result.
  618. //
  619. return (hPrintUI != NULL);
  620. }
  621. ////////////////////////////////////////////////////////////////////////////
  622. //
  623. // Print_UnloadLibraries
  624. //
  625. ////////////////////////////////////////////////////////////////////////////
  626. VOID Print_UnloadLibraries()
  627. {
  628. if (hPrintUI)
  629. {
  630. FreeLibrary(hPrintUI);
  631. hPrintUI = NULL;
  632. }
  633. }
  634. ////////////////////////////////////////////////////////////////////////////
  635. //
  636. // Print_LoadIcons
  637. //
  638. ////////////////////////////////////////////////////////////////////////////
  639. BOOL Print_LoadIcons()
  640. {
  641. //
  642. // Load the collation images.
  643. //
  644. hIconCollate = LoadImage( g_hinst,
  645. MAKEINTRESOURCE(ICO_COLLATE),
  646. IMAGE_ICON,
  647. 0,
  648. 0,
  649. LR_SHARED);
  650. hIconNoCollate = LoadImage( g_hinst,
  651. MAKEINTRESOURCE(ICO_NO_COLLATE),
  652. IMAGE_ICON,
  653. 0,
  654. 0,
  655. LR_SHARED);
  656. //
  657. // Return TRUE only if all icons/images were loaded properly.
  658. //
  659. return (hIconCollate && hIconNoCollate);
  660. }
  661. ////////////////////////////////////////////////////////////////////////////
  662. //
  663. // Print_InvokePropertySheets
  664. //
  665. ////////////////////////////////////////////////////////////////////////////
  666. BOOL Print_InvokePropertySheets(
  667. PPRINTINFOEX pPI,
  668. LPPRINTDLGEX pPD)
  669. {
  670. BOOL bResult = FALSE;
  671. TCHAR pszTitle[MAX_PATH];
  672. TCHAR pszCaption[MAX_PATH];
  673. HANDLE hTemplate = NULL;
  674. HRSRC hRes;
  675. LANGID LangID;
  676. if (GET_BIDI_LOCALIZED_SYSTEM_LANGID(NULL)) {
  677. if (pPD->Flags & PD_ENABLEPRINTTEMPLATEHANDLE)
  678. {
  679. hTemplate = pPD->hInstance;
  680. }
  681. else
  682. {
  683. if (pPD->Flags & PD_ENABLEPRINTTEMPLATE)
  684. {
  685. hRes = FindResource(pPD->hInstance, pPD->lpPrintTemplateName, RT_DIALOG);
  686. if (hRes) {
  687. hTemplate = LoadResource(pPD->hInstance, hRes);
  688. }
  689. }
  690. }
  691. //
  692. // Warning! Warning! Warning!
  693. //
  694. // We have to set g_tlsLangID before any call for CDLoadString
  695. //
  696. TlsSetValue(g_tlsLangID, (LPVOID) GetDialogLanguage(pPD->hwndOwner, hTemplate));
  697. }
  698. //
  699. // Load all of the necessary strings.
  700. //
  701. CDLoadString(g_hinst, iszGeneralPage, pszTitle, ARRAYSIZE(pszTitle));
  702. CDLoadString(g_hinst, iszPrintCaption, pszCaption, ARRAYSIZE(pszCaption));
  703. //
  704. // See if the exclusion flags are set properly.
  705. //
  706. if (!(pPD->Flags & PD_EXCLUSIONFLAGS))
  707. {
  708. pPD->ExclusionFlags = PD_EXCL_COPIESANDCOLLATE;
  709. }
  710. //
  711. // Set up the General page.
  712. //
  713. PROPSHEETPAGE genPage = {0};
  714. genPage.dwSize = sizeof(PROPSHEETPAGE);
  715. genPage.dwFlags = PSP_DEFAULT | PSP_USETITLE;
  716. genPage.hInstance = g_hinst;
  717. genPage.pszTemplate = (pPD->Flags & PD_USELARGETEMPLATE) ? MAKEINTRESOURCE(IDD_PRINT_GENERAL_LARGE)
  718. : MAKEINTRESOURCE(IDD_PRINT_GENERAL);
  719. LangID = (LANGID)TlsGetValue(g_tlsLangID);
  720. if (LangID) {
  721. hRes = FindResourceExFallback(g_hinst, RT_DIALOG, genPage.pszTemplate, LangID);
  722. if (hRes) {
  723. if ((hTemplate = LoadResource(g_hinst, hRes)) &&
  724. LockResource(hTemplate)) {
  725. genPage.dwFlags |= PSP_DLGINDIRECT;
  726. genPage.pResource = (LPCDLGTEMPLATE)hTemplate;
  727. }
  728. }
  729. }
  730. genPage.pszIcon = NULL;
  731. genPage.pszTitle = pszTitle;
  732. genPage.pfnDlgProc = Print_GeneralDlgProc;
  733. genPage.lParam = (LPARAM)pPI;
  734. genPage.pfnCallback = NULL;
  735. genPage.pcRefParent = NULL;
  736. HPROPSHEETPAGE hGenPage = CreatePropertySheetPage( &genPage );
  737. if( hGenPage )
  738. {
  739. //
  740. // Initialize the property sheet header.
  741. //
  742. PROPSHEETHEADER psh = {0};
  743. psh.dwSize = sizeof(psh);
  744. psh.dwFlags = pPI->fOld ? PSH_USEICONID | PSH_NOAPPLYNOW : PSH_USEICONID;
  745. psh.hwndParent = pPD->hwndOwner;
  746. psh.hInstance = g_hinst;
  747. psh.pszIcon = MAKEINTRESOURCE(ICO_PRINTER);
  748. psh.pszCaption = pszCaption;
  749. psh.nPages = pPD->nPropertyPages + 1;
  750. psh.phpage = new HPROPSHEETPAGE[ psh.nPages ];
  751. if( psh.phpage )
  752. {
  753. psh.phpage[0] = hGenPage;
  754. memcpy( psh.phpage+1, pPD->lphPropertyPages, pPD->nPropertyPages * sizeof(psh.phpage[0]) );
  755. //
  756. // Bring up the property sheet pages.
  757. //
  758. bResult = (-1 != PropertySheet(&psh));
  759. delete [] psh.phpage;
  760. }
  761. else
  762. {
  763. pPI->hResult = E_OUTOFMEMORY;
  764. }
  765. }
  766. else
  767. {
  768. pPI->hResult = CreateError();
  769. }
  770. //
  771. // Return the result.
  772. //
  773. return (bResult);
  774. }
  775. LRESULT CALLBACK PrshtSubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp, UINT_PTR uID, ULONG_PTR dwRefData)
  776. {
  777. LRESULT lres;
  778. switch (wm)
  779. {
  780. case WM_NCDESTROY:
  781. // Clean up subclass
  782. RemoveWindowSubclass(hwnd, PrshtSubclassProc, 0);
  783. lres = DefSubclassProc(hwnd, wm, wp, lp);
  784. break;
  785. case ( WM_HELP ) :
  786. {
  787. HWND hwndItem = (HWND)((LPHELPINFO)lp)->hItemHandle;
  788. if (hwndItem == GetDlgItem(hwnd, IDOK))
  789. {
  790. WinHelp( hwndItem,
  791. NULL,
  792. HELP_WM_HELP,
  793. (ULONG_PTR)(LPTSTR)aPrintExHelpIDs );
  794. lres = TRUE;
  795. }
  796. else
  797. {
  798. lres = DefSubclassProc(hwnd, wm, wp, lp);
  799. }
  800. break;
  801. }
  802. case ( WM_CONTEXTMENU ) :
  803. {
  804. if ((HWND)wp == GetDlgItem(hwnd, IDOK))
  805. {
  806. WinHelp( (HWND)wp,
  807. NULL,
  808. HELP_CONTEXTMENU,
  809. (ULONG_PTR)(LPVOID)aPrintExHelpIDs );
  810. lres = TRUE;
  811. }
  812. else
  813. {
  814. lres = DefSubclassProc(hwnd, wm, wp, lp);
  815. }
  816. break;
  817. }
  818. default:
  819. lres = DefSubclassProc(hwnd, wm, wp, lp);
  820. break;
  821. }
  822. return lres;
  823. }
  824. ////////////////////////////////////////////////////////////////////////////
  825. //
  826. // Print_GeneralDlgProc
  827. //
  828. ////////////////////////////////////////////////////////////////////////////
  829. BOOL_PTR CALLBACK Print_GeneralDlgProc(
  830. HWND hDlg,
  831. UINT uMsg,
  832. WPARAM wParam,
  833. LPARAM lParam)
  834. {
  835. CPrintBrowser *pDlgStruct = NULL;
  836. if (uMsg != WM_INITDIALOG)
  837. {
  838. pDlgStruct = Print_HwndToBrowser(hDlg);
  839. }
  840. switch (uMsg)
  841. {
  842. case ( WM_INITDIALOG ) :
  843. {
  844. if (!Print_InitDialog(hDlg, wParam, lParam))
  845. {
  846. PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL);
  847. }
  848. g_hwndActivePrint = hDlg;
  849. //Subclass the Main Property sheet for Help Messages
  850. SetWindowSubclass(GetParent(hDlg), PrshtSubclassProc, 0, 0);
  851. break;
  852. }
  853. case ( WM_NCDESTROY ) :
  854. {
  855. Print_StoreBrowser(hDlg, NULL);
  856. if (pDlgStruct)
  857. {
  858. pDlgStruct->OnDestroyMessage();
  859. pDlgStruct->Release();
  860. }
  861. break;
  862. }
  863. case ( WM_ERASEBKGND ) :
  864. {
  865. //
  866. // This code is to workaround: Windows NT Bugs#344991
  867. //
  868. HWND hwndView = GetDlgItem(hDlg, IDC_PRINTER_LISTVIEW);
  869. if (hwndView)
  870. {
  871. //
  872. // Get the printer folder view rect.
  873. //
  874. RECT rcView;
  875. if (GetWindowRect(hwndView, &rcView))
  876. {
  877. MapWindowRect(HWND_DESKTOP, hDlg, &rcView);
  878. //
  879. // Exclude the printer folder view rect from the cliping region.
  880. //
  881. if (ERROR == ExcludeClipRect(reinterpret_cast<HDC>(wParam),
  882. rcView.left, rcView.top, rcView.right, rcView.bottom))
  883. {
  884. ASSERT(FALSE);
  885. }
  886. }
  887. }
  888. break;
  889. }
  890. case ( WM_ACTIVATE ) :
  891. {
  892. if (wParam == WA_INACTIVE)
  893. {
  894. //
  895. // Make sure some other Print dialog has not already grabbed
  896. // the focus. This is a process global, so it should not
  897. // need to be protected.
  898. //
  899. if (g_hwndActivePrint == hDlg)
  900. {
  901. g_hwndActivePrint = NULL;
  902. }
  903. }
  904. else
  905. {
  906. g_hwndActivePrint = hDlg;
  907. }
  908. break;
  909. }
  910. case ( WM_COMMAND ) :
  911. {
  912. if (pDlgStruct)
  913. {
  914. return (pDlgStruct->OnCommandMessage(wParam, lParam));
  915. }
  916. break;
  917. }
  918. case ( WM_DRAWITEM ) :
  919. {
  920. break;
  921. }
  922. case ( WM_MEASUREITEM ) :
  923. {
  924. break;
  925. }
  926. case ( WM_NOTIFY ) :
  927. {
  928. if (pDlgStruct)
  929. {
  930. return (pDlgStruct->OnNotifyMessage(wParam, (LPNMHDR)lParam));
  931. }
  932. break;
  933. }
  934. case ( WM_HELP ) :
  935. {
  936. HWND hwndItem = (HWND)((LPHELPINFO)lParam)->hItemHandle;
  937. //
  938. // We assume that the defview has one child window that
  939. // covers the entire defview window.
  940. //
  941. HWND hwndDefView = GetDlgItem(hDlg, IDC_PRINTER_LISTVIEW);
  942. if (GetParent(hwndItem) == hwndDefView)
  943. {
  944. hwndItem = hwndDefView;
  945. }
  946. WinHelp( hwndItem,
  947. NULL,
  948. HELP_WM_HELP,
  949. (ULONG_PTR)(LPTSTR)aPrintExHelpIDs );
  950. return (TRUE);
  951. }
  952. case ( WM_CONTEXTMENU ) :
  953. {
  954. WinHelp( (HWND)wParam,
  955. NULL,
  956. HELP_CONTEXTMENU,
  957. (ULONG_PTR)(LPVOID)aPrintExHelpIDs );
  958. return (TRUE);
  959. }
  960. case ( CWM_GETISHELLBROWSER ) :
  961. {
  962. ::SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LRESULT)pDlgStruct);
  963. return (TRUE);
  964. }
  965. case ( CDM_SELCHANGE ) :
  966. {
  967. if (pDlgStruct)
  968. {
  969. pDlgStruct->OnSelChange();
  970. }
  971. break;
  972. }
  973. case ( CDM_PRINTNOTIFY ) :
  974. {
  975. if (pDlgStruct)
  976. {
  977. LPITEMIDLIST *ppidl;
  978. LONG lEvent;
  979. BOOL bRet = FALSE;
  980. LPSHChangeNotificationLock pLock;
  981. //
  982. // Get the change notification info from the shared memory
  983. // block identified by the handle passed in the wParam.
  984. //
  985. pLock = SHChangeNotification_Lock( (HANDLE)wParam,
  986. (DWORD)lParam,
  987. &ppidl,
  988. &lEvent );
  989. if (pLock == NULL)
  990. {
  991. return (FALSE);
  992. }
  993. //
  994. // Handle the change notification.
  995. //
  996. bRet = pDlgStruct->OnChangeNotify( lEvent,
  997. (LPCITEMIDLIST *)ppidl );
  998. //
  999. // Release the shared block.
  1000. //
  1001. SHChangeNotification_Unlock(pLock);
  1002. //
  1003. // Return the result.
  1004. //
  1005. return (bRet);
  1006. }
  1007. break;
  1008. }
  1009. case ( CDM_NOPRINTERS ) :
  1010. {
  1011. //
  1012. // There are no printers, so bring up the dialog telling the
  1013. // user that they need to install a printer.
  1014. //
  1015. if (pDlgStruct)
  1016. {
  1017. pDlgStruct->OnNoPrinters((HWND)wParam, (HRESULT)lParam);
  1018. }
  1019. }
  1020. case ( CDM_INITDONE ) :
  1021. {
  1022. if (pDlgStruct)
  1023. {
  1024. pDlgStruct->OnInitDone();
  1025. }
  1026. break;
  1027. }
  1028. default :
  1029. {
  1030. break;
  1031. }
  1032. }
  1033. //
  1034. // Return the result.
  1035. //
  1036. return (FALSE);
  1037. }
  1038. ////////////////////////////////////////////////////////////////////////////
  1039. //
  1040. // Print_GeneralChildDlgProc
  1041. //
  1042. ////////////////////////////////////////////////////////////////////////////
  1043. BOOL_PTR CALLBACK Print_GeneralChildDlgProc(
  1044. HWND hDlg,
  1045. UINT uMsg,
  1046. WPARAM wParam,
  1047. LPARAM lParam)
  1048. {
  1049. LRESULT lResult = FALSE;
  1050. CPrintBrowser *pDlgStruct = Print_HwndToBrowser(GetParent(hDlg));
  1051. //
  1052. // See if we need to call an application callback to handle the
  1053. // message.
  1054. //
  1055. if (pDlgStruct)
  1056. {
  1057. if (pDlgStruct->HandleMessage(hDlg, uMsg, wParam, lParam, &lResult) != S_FALSE)
  1058. {
  1059. if (uMsg == WM_INITDIALOG)
  1060. {
  1061. PostMessage(GetParent(hDlg), CDM_INITDONE, 0, 0);
  1062. }
  1063. //
  1064. // BUGBUG: The return from a dlgproc is different than a winproc.
  1065. //
  1066. return (BOOLFROMPTR(lResult));
  1067. }
  1068. }
  1069. //
  1070. // If we get to this point, we need to handle the message.
  1071. //
  1072. switch (uMsg)
  1073. {
  1074. case ( WM_INITDIALOG ) :
  1075. {
  1076. if (pDlgStruct)
  1077. {
  1078. if (!pDlgStruct->OnChildInitDialog(hDlg, wParam, lParam))
  1079. {
  1080. PropSheet_PressButton( GetParent(GetParent(hDlg)),
  1081. PSBTN_CANCEL );
  1082. }
  1083. }
  1084. break;
  1085. }
  1086. case ( WM_DESTROY ) :
  1087. {
  1088. break;
  1089. }
  1090. case ( WM_ACTIVATE ) :
  1091. {
  1092. break;
  1093. }
  1094. case ( WM_COMMAND ) :
  1095. {
  1096. if (pDlgStruct)
  1097. {
  1098. return (pDlgStruct->OnChildCommandMessage(wParam, lParam));
  1099. }
  1100. break;
  1101. }
  1102. case ( WM_DRAWITEM ) :
  1103. {
  1104. break;
  1105. }
  1106. case ( WM_MEASUREITEM ) :
  1107. {
  1108. break;
  1109. }
  1110. case ( WM_NOTIFY ) :
  1111. {
  1112. break;
  1113. }
  1114. case ( WM_HELP ) :
  1115. {
  1116. WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
  1117. NULL,
  1118. HELP_WM_HELP,
  1119. (ULONG_PTR)(LPTSTR)aPrintExChildHelpIDs );
  1120. return (TRUE);
  1121. }
  1122. case ( WM_CONTEXTMENU ) :
  1123. {
  1124. WinHelp( (HWND)wParam,
  1125. NULL,
  1126. HELP_CONTEXTMENU,
  1127. (ULONG_PTR)(LPVOID)aPrintExChildHelpIDs );
  1128. return (TRUE);
  1129. }
  1130. default :
  1131. {
  1132. break;
  1133. }
  1134. }
  1135. //
  1136. // Return the result.
  1137. //
  1138. return (FALSE);
  1139. }
  1140. ////////////////////////////////////////////////////////////////////////////
  1141. //
  1142. // Print_MessageHookProc
  1143. //
  1144. // Handles the input event messages.
  1145. //
  1146. ////////////////////////////////////////////////////////////////////////////
  1147. LRESULT CALLBACK Print_MessageHookProc(
  1148. int nCode,
  1149. WPARAM wParam,
  1150. LPARAM lParam)
  1151. {
  1152. PMSG pMsg;
  1153. //
  1154. // See if the nCode is negative. If so, call the default hook proc.
  1155. //
  1156. if (nCode < 0)
  1157. {
  1158. return (DefHookProc(nCode, wParam, lParam, &g_hHook));
  1159. }
  1160. //
  1161. // Make sure we only handle dialog box messages.
  1162. //
  1163. if (nCode != MSGF_DIALOGBOX)
  1164. {
  1165. return (0);
  1166. }
  1167. //
  1168. // Get the msg structure.
  1169. //
  1170. pMsg = (PMSG)lParam;
  1171. //
  1172. // Make sure the message is one of the WM_KEY* messages.
  1173. //
  1174. if (Print_IsInRange(pMsg->message, WM_KEYFIRST, WM_KEYLAST))
  1175. {
  1176. HWND hwndActivePrint = g_hwndActivePrint;
  1177. HWND hwndFocus = GetFocusedChild(hwndActivePrint, pMsg->hwnd);
  1178. CPrintBrowser *pDlgStruct;
  1179. if (hwndFocus &&
  1180. (pDlgStruct = Print_HwndToBrowser(hwndActivePrint)) != NULL)
  1181. {
  1182. return (pDlgStruct->OnAccelerator( hwndActivePrint,
  1183. hwndFocus,
  1184. g_haccPrint,
  1185. pMsg ));
  1186. }
  1187. }
  1188. //
  1189. // Return that the message was not handled.
  1190. //
  1191. return (0);
  1192. }
  1193. ////////////////////////////////////////////////////////////////////////////
  1194. //
  1195. // Print_InitDialog
  1196. //
  1197. ////////////////////////////////////////////////////////////////////////////
  1198. BOOL Print_InitDialog(
  1199. HWND hDlg,
  1200. WPARAM wParam,
  1201. LPARAM lParam)
  1202. {
  1203. //
  1204. // Create the CPrintBrowser object and store it in DWL_USER.
  1205. //
  1206. CPrintBrowser *pDlgStruct = new CPrintBrowser(hDlg);
  1207. if (pDlgStruct == NULL)
  1208. {
  1209. return (FALSE);
  1210. }
  1211. Print_StoreBrowser(hDlg, pDlgStruct);
  1212. //
  1213. // Let the class function do the work.
  1214. //
  1215. return (pDlgStruct->OnInitDialog(wParam, lParam));
  1216. }
  1217. ////////////////////////////////////////////////////////////////////////////
  1218. //
  1219. // Print_ICoCreateInstance
  1220. //
  1221. // Create an instance of the specified shell class.
  1222. //
  1223. ////////////////////////////////////////////////////////////////////////////
  1224. HRESULT Print_ICoCreateInstance(
  1225. REFCLSID rclsid,
  1226. REFIID riid,
  1227. LPCITEMIDLIST pidl,
  1228. LPVOID *ppv)
  1229. {
  1230. LPSHELLFOLDER pshf = NULL;
  1231. HRESULT hres = E_FAIL;
  1232. //
  1233. // Initialize the pointer to the shell view.
  1234. //
  1235. *ppv = NULL;
  1236. //
  1237. // Get the IShellFolder interface to the desktop folder and then
  1238. // bind to it. This is equivalent to calling CoCreateInstance
  1239. // with CLSID_ShellDesktop.
  1240. //
  1241. hres = SHGetDesktopFolder(&pshf);
  1242. if (SUCCEEDED(hres))
  1243. {
  1244. hres = pshf->BindToObject(pidl, NULL, riid, ppv);
  1245. pshf->Release();
  1246. }
  1247. //
  1248. // Return the result.
  1249. //
  1250. return (hres);
  1251. }
  1252. ////////////////////////////////////////////////////////////////////////////
  1253. //
  1254. // Print_SaveDevNames
  1255. //
  1256. // Saves the current devnames in the pPD structure.
  1257. //
  1258. ////////////////////////////////////////////////////////////////////////////
  1259. BOOL Print_SaveDevNames(
  1260. LPTSTR pCurPrinter,
  1261. LPPRINTDLGEX pPD)
  1262. {
  1263. TCHAR szPortName[MAX_PATH];
  1264. TCHAR szPrinterName[MAX_PATH];
  1265. DWORD cbDevNames;
  1266. LPDEVNAMES pDN;
  1267. //
  1268. // Get the port name.
  1269. //
  1270. szPortName[0] = 0;
  1271. Print_GetPortName(pCurPrinter, szPortName, ARRAYSIZE(szPortName));
  1272. //
  1273. // Compute the size of the DevNames structure.
  1274. //
  1275. cbDevNames = lstrlen(szDriver) + 1 +
  1276. lstrlen(szPortName) + 1 +
  1277. lstrlen(pCurPrinter) + 1 +
  1278. DN_PADDINGCHARS;
  1279. cbDevNames *= sizeof(TCHAR);
  1280. cbDevNames += sizeof(DEVNAMES);
  1281. //
  1282. // Allocate the new DevNames structure.
  1283. //
  1284. pDN = NULL;
  1285. if (pPD->hDevNames)
  1286. {
  1287. HANDLE handle;
  1288. handle = GlobalReAlloc(pPD->hDevNames, cbDevNames, GHND);
  1289. //Check that realloc succeeded.
  1290. if (handle)
  1291. {
  1292. pPD->hDevNames = handle;
  1293. }
  1294. else
  1295. {
  1296. //Realloc didn't succeed. Free the memory occupied.
  1297. GlobalFree(pPD->hDevNames);
  1298. pPD->hDevNames = NULL;
  1299. }
  1300. }
  1301. else
  1302. {
  1303. pPD->hDevNames = GlobalAlloc(GHND, cbDevNames);
  1304. }
  1305. //
  1306. // Fill in the DevNames structure with the appropriate information.
  1307. //
  1308. if ( (pPD->hDevNames) &&
  1309. (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames)) )
  1310. {
  1311. //
  1312. // Save the driver name - winspool.
  1313. //
  1314. pDN->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
  1315. StringCchCopy((LPTSTR)pDN + pDN->wDriverOffset, lstrlen(szDriver) + 1, szDriver);
  1316. //
  1317. // Save the printer name.
  1318. //
  1319. pDN->wDeviceOffset = pDN->wDriverOffset + lstrlen(szDriver) + 1;
  1320. StringCchCopy((LPTSTR)pDN + pDN->wDeviceOffset, lstrlen(pCurPrinter) + 1, pCurPrinter);
  1321. //
  1322. // Save the port name.
  1323. //
  1324. pDN->wOutputOffset = pDN->wDeviceOffset + lstrlen(pCurPrinter) + 1;
  1325. StringCchCopy((LPTSTR)pDN + pDN->wOutputOffset, lstrlen(szPortName) + 1, szPortName);
  1326. //
  1327. // Save whether or not it's the default printer.
  1328. //
  1329. if (pPD->Flags & PD_RETURNDEFAULT)
  1330. {
  1331. pDN->wDefault = DN_DEFAULTPRN;
  1332. }
  1333. else
  1334. {
  1335. szPrinterName[0] = 0;
  1336. PrintGetDefaultPrinterName(szPrinterName, ARRAYSIZE(szPrinterName));
  1337. if (szPrinterName[0] && !lstrcmp(pCurPrinter, szPrinterName))
  1338. {
  1339. pDN->wDefault = DN_DEFAULTPRN;
  1340. }
  1341. else
  1342. {
  1343. pDN->wDefault = 0;
  1344. }
  1345. }
  1346. //
  1347. // Unlock it.
  1348. //
  1349. GlobalUnlock(pPD->hDevNames);
  1350. }
  1351. else
  1352. {
  1353. SetLastError(ERROR_OUTOFMEMORY);
  1354. return (FALSE);
  1355. }
  1356. //
  1357. // Return success.
  1358. //
  1359. return (TRUE);
  1360. }
  1361. ////////////////////////////////////////////////////////////////////////////
  1362. //
  1363. // Print_GetPortName
  1364. //
  1365. // Gets the port name for the given printer and stores it in the
  1366. // given buffer.
  1367. //
  1368. ////////////////////////////////////////////////////////////////////////////
  1369. VOID Print_GetPortName(
  1370. LPTSTR pCurPrinter,
  1371. LPTSTR pBuffer,
  1372. int cchBuffer)
  1373. {
  1374. HANDLE hPrinter;
  1375. DWORD cbPrinter = 0;
  1376. PRINTER_INFO_2 *pPrinter = NULL;
  1377. //
  1378. // Initialize the buffer.
  1379. //
  1380. if (!cchBuffer)
  1381. {
  1382. return;
  1383. }
  1384. pBuffer[0] = 0;
  1385. //
  1386. // Open the current printer.
  1387. //
  1388. if (OpenPrinter(pCurPrinter, &hPrinter, NULL))
  1389. {
  1390. //
  1391. // Get the size of the buffer needed to hold the printer info 2
  1392. // information.
  1393. //
  1394. if (!GetPrinter( hPrinter,
  1395. 2,
  1396. (LPBYTE)pPrinter,
  1397. cbPrinter,
  1398. &cbPrinter ))
  1399. {
  1400. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  1401. {
  1402. //
  1403. // Allocate a buffer to hold the printer info 2 information.
  1404. //
  1405. if (pPrinter = (PRINTER_INFO_2 *)LocalAlloc(LPTR, cbPrinter))
  1406. {
  1407. //
  1408. // Get the printer info 2 information.
  1409. //
  1410. if (GetPrinter( hPrinter,
  1411. 2,
  1412. (LPBYTE)pPrinter,
  1413. cbPrinter,
  1414. &cbPrinter ))
  1415. {
  1416. //
  1417. // Save the port name in the given buffer.
  1418. //
  1419. lstrcpyn(pBuffer, pPrinter->pPortName, cchBuffer);
  1420. pBuffer[cchBuffer - 1] = 0;
  1421. }
  1422. }
  1423. }
  1424. }
  1425. //
  1426. // Close the printer.
  1427. //
  1428. ClosePrinter(hPrinter);
  1429. }
  1430. //
  1431. // Free the printer info 2 information for the current printer.
  1432. //
  1433. if (pPrinter)
  1434. {
  1435. LocalFree(pPrinter);
  1436. }
  1437. }
  1438. ////////////////////////////////////////////////////////////////////////////
  1439. //
  1440. // Print_GetDevModeWrapper
  1441. //
  1442. // Calls PrintGetDevMode.
  1443. //
  1444. ////////////////////////////////////////////////////////////////////////////
  1445. HANDLE Print_GetDevModeWrapper(
  1446. LPTSTR pszDeviceName)
  1447. {
  1448. HANDLE hPrinter;
  1449. HANDLE hDevMode = NULL;
  1450. if (OpenPrinter(pszDeviceName, &hPrinter, NULL))
  1451. {
  1452. hDevMode = PrintGetDevMode(0, hPrinter, pszDeviceName, NULL);
  1453. ClosePrinter(hPrinter);
  1454. }
  1455. //
  1456. // Return the handle to the devmode.
  1457. //
  1458. return (hDevMode);
  1459. }
  1460. ////////////////////////////////////////////////////////////////////////////
  1461. //
  1462. // Print_NewPrintDlg
  1463. //
  1464. // Converts the old style pPD structure to the new one and then calls
  1465. // the PrintDlgEx function.
  1466. //
  1467. ////////////////////////////////////////////////////////////////////////////
  1468. BOOL Print_NewPrintDlg(
  1469. PPRINTINFO pPI)
  1470. {
  1471. LPPRINTDLG pPD = pPI->pPD;
  1472. PRINTINFOEX PIEx;
  1473. PRINTDLGEX PDEx;
  1474. PRINTPAGERANGE PageRange;
  1475. HRESULT hResult;
  1476. // PrintDlg did the following for the page ranges. Do the same thing for PrintDlgEx
  1477. if (!(pPD->Flags & PD_PAGENUMS))
  1478. {
  1479. if (pPD->nFromPage != 0xFFFF)
  1480. {
  1481. if (pPD->nFromPage < pPD->nMinPage)
  1482. {
  1483. pPD->nFromPage = pPD->nMinPage;
  1484. }
  1485. else if (pPD->nFromPage > pPD->nMaxPage)
  1486. {
  1487. pPD->nFromPage = pPD->nMaxPage;
  1488. }
  1489. }
  1490. if (pPD->nToPage != 0xFFFF)
  1491. {
  1492. if (pPD->nToPage < pPD->nMinPage)
  1493. {
  1494. pPD->nToPage = pPD->nMinPage;
  1495. }
  1496. else if (pPD->nToPage > pPD->nMaxPage)
  1497. {
  1498. pPD->nToPage = pPD->nMaxPage;
  1499. }
  1500. }
  1501. }
  1502. //
  1503. // Set up the PRINTINFOEX structure.
  1504. //
  1505. PIEx.ApiType = pPI->ApiType;
  1506. PIEx.pPD = &PDEx;
  1507. PIEx.fOld = TRUE;
  1508. //
  1509. // Copy the page range.
  1510. //
  1511. PageRange.nFromPage = pPD->nFromPage;
  1512. PageRange.nToPage = pPD->nToPage;
  1513. //
  1514. // Set up the PRINTDLGEX structure with the appropriate values from
  1515. // the PRINTDLG structure.
  1516. //
  1517. PDEx.lStructSize = sizeof(PRINTDLGEX);
  1518. PDEx.hwndOwner = pPD->hwndOwner;
  1519. PDEx.hDevMode = pPD->hDevMode;
  1520. PDEx.hDevNames = pPD->hDevNames;
  1521. PDEx.hDC = pPD->hDC;
  1522. PDEx.Flags = (pPD->Flags & ~(PD_SHOWHELP | PD_NONETWORKBUTTON)) |
  1523. (PD_NOCURRENTPAGE);
  1524. PDEx.Flags2 = 0;
  1525. PDEx.ExclusionFlags = 0;
  1526. PDEx.nPageRanges = 1;
  1527. PDEx.nMaxPageRanges = 1;
  1528. PDEx.lpPageRanges = &PageRange;
  1529. PDEx.nMinPage = pPD->nMinPage;
  1530. PDEx.nMaxPage = pPD->nMaxPage;
  1531. PDEx.nCopies = pPD->nCopies;
  1532. PDEx.hInstance = pPD->hInstance;
  1533. PDEx.lpCallback = NULL;
  1534. PDEx.lpPrintTemplateName = NULL;
  1535. PDEx.nPropertyPages = 0;
  1536. PDEx.lphPropertyPages = NULL;
  1537. PDEx.nStartPage = START_PAGE_GENERAL;
  1538. PDEx.dwResultAction = 0;
  1539. //
  1540. // Since we're in the old dialog, allow the the hInstance to be
  1541. // non-NULL even if there is not a template.
  1542. //
  1543. if (!(pPD->Flags & (PD_ENABLEPRINTTEMPLATE | PD_ENABLEPRINTTEMPLATEHANDLE)))
  1544. {
  1545. PDEx.hInstance = NULL;
  1546. }
  1547. //
  1548. // Initialize the error code to 0.
  1549. //
  1550. StoreExtendedError(CDERR_GENERALCODES);
  1551. //
  1552. // Call PrintDlgExX to bring up the dialog.
  1553. //
  1554. hResult = PrintDlgExX(&PIEx);
  1555. //
  1556. // See if the call failed. If so, store the error and return FALSE.
  1557. //
  1558. if (FAILED(hResult))
  1559. {
  1560. StoreExtendedError(PIEx.dwExtendedError);
  1561. return (FALSE);
  1562. }
  1563. //
  1564. // The call succeeded, so convert the PRINTDLGEX structure back to
  1565. // the PRINTDLG structure if PD_RESULT_CANCEL is not set.
  1566. //
  1567. if (PDEx.dwResultAction != PD_RESULT_CANCEL)
  1568. {
  1569. pPD->hDevMode = PDEx.hDevMode;
  1570. pPD->hDevNames = PDEx.hDevNames;
  1571. pPD->hDC = PDEx.hDC;
  1572. pPD->Flags = PDEx.Flags & ~(PD_NOCURRENTPAGE);
  1573. pPD->nFromPage = (WORD)PageRange.nFromPage;
  1574. pPD->nToPage = (WORD)PageRange.nToPage;
  1575. pPD->nCopies = (WORD)PDEx.nCopies;
  1576. }
  1577. //
  1578. // Return TRUE if the user hit Print.
  1579. //
  1580. if (PDEx.dwResultAction == PD_RESULT_PRINT)
  1581. {
  1582. return (TRUE);
  1583. }
  1584. //
  1585. // Return FALSE for cancel.
  1586. //
  1587. return (FALSE);
  1588. }
  1589. ////////////////////////////////////////////////////////////////////////////
  1590. //
  1591. // CPrintBrowser::CPrintBrowser
  1592. //
  1593. // CPrintBrowser constructor.
  1594. //
  1595. ////////////////////////////////////////////////////////////////////////////
  1596. CPrintBrowser::CPrintBrowser(
  1597. HWND hDlg)
  1598. : cRef(1),
  1599. hwndDlg(hDlg),
  1600. hSubDlg(NULL),
  1601. hwndView(NULL),
  1602. hwndUpDown(NULL),
  1603. psv(NULL),
  1604. psfv(NULL),
  1605. psfRoot(NULL),
  1606. pidlRoot(NULL),
  1607. ppf(NULL),
  1608. pPI(NULL),
  1609. pPD(NULL),
  1610. pCallback(NULL),
  1611. pSite(NULL),
  1612. pDMInit(NULL),
  1613. pDMCur(NULL),
  1614. cchCurPrinter(0),
  1615. pszCurPrinter(NULL),
  1616. nCopies(1),
  1617. nMaxCopies(1),
  1618. nPageRanges(0),
  1619. nMaxPageRanges(0),
  1620. pPageRanges(NULL),
  1621. fSelChangePending(FALSE),
  1622. fFirstSel(1),
  1623. fCollateRequested(FALSE),
  1624. fAPWSelected(FALSE),
  1625. fNoAccessPrinterSelected(FALSE),
  1626. fDirtyDevmode(FALSE),
  1627. fDevmodeEdit(FALSE),
  1628. fAllowCollate(FALSE),
  1629. nInitDone(0),
  1630. nListSep(0),
  1631. uRegister(0),
  1632. uDefViewMode(VIEW_MODE_DEFAULT),
  1633. pInternalDevMode(NULL),
  1634. hPrinter(NULL)
  1635. {
  1636. HMENU hMenu;
  1637. hMenu = GetSystemMenu(hDlg, FALSE);
  1638. DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND);
  1639. DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND);
  1640. DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND);
  1641. szListSep[0] = 0;
  1642. szScratch[0] = 0;
  1643. szPrinter[0] = 0;
  1644. pDMSave = (LPDEVMODE)GlobalAlloc(GPTR, sizeof(DEVMODE));
  1645. Shell_GetImageLists(NULL, &himl);
  1646. }
  1647. ////////////////////////////////////////////////////////////////////////////
  1648. //
  1649. // CPrintBrowser::~CPrintBrowser
  1650. //
  1651. // CPrintBrowser destructor.
  1652. //
  1653. ////////////////////////////////////////////////////////////////////////////
  1654. CPrintBrowser::~CPrintBrowser()
  1655. {
  1656. //
  1657. // Deregister notifications.
  1658. //
  1659. if (uRegister)
  1660. {
  1661. SHChangeNotifyDeregister(uRegister);
  1662. uRegister = 0;
  1663. }
  1664. //
  1665. // Release the printer folder private interface.
  1666. //
  1667. if (ppf != NULL)
  1668. {
  1669. ppf->Release();
  1670. ppf = NULL;
  1671. }
  1672. //
  1673. // Release the printer shell folder.
  1674. //
  1675. if (psfRoot != NULL)
  1676. {
  1677. psfRoot->Release();
  1678. psfRoot = NULL;
  1679. }
  1680. //
  1681. // Free the pidl.
  1682. //
  1683. if (pidlRoot != NULL)
  1684. {
  1685. SHFree(pidlRoot);
  1686. pidlRoot = NULL;
  1687. }
  1688. //
  1689. // Free the devmodes.
  1690. //
  1691. if (pDMInit)
  1692. {
  1693. GlobalFree(pDMInit);
  1694. pDMInit = NULL;
  1695. }
  1696. if (pDMSave)
  1697. {
  1698. GlobalFree(pDMSave);
  1699. pDMSave = NULL;
  1700. }
  1701. //
  1702. // Free the current printer buffer.
  1703. //
  1704. cchCurPrinter = 0;
  1705. if (pszCurPrinter)
  1706. {
  1707. GlobalFree(pszCurPrinter);
  1708. pszCurPrinter = NULL;
  1709. }
  1710. //
  1711. // Free the page range.
  1712. //
  1713. nPageRanges = 0;
  1714. nMaxPageRanges = 0;
  1715. if (pPageRanges)
  1716. {
  1717. GlobalFree(pPageRanges);
  1718. pPageRanges = NULL;
  1719. }
  1720. if (pInternalDevMode)
  1721. {
  1722. GlobalFree(pInternalDevMode);
  1723. pInternalDevMode = NULL;
  1724. }
  1725. if (hPrinter)
  1726. {
  1727. ClosePrinter(hPrinter);
  1728. hPrinter = NULL;
  1729. }
  1730. }
  1731. ////////////////////////////////////////////////////////////////////////////
  1732. //
  1733. // CPrintBrowser::QueryInterface
  1734. //
  1735. // Standard OLE2 style methods for this object.
  1736. //
  1737. ////////////////////////////////////////////////////////////////////////////
  1738. HRESULT STDMETHODCALLTYPE CPrintBrowser::QueryInterface(
  1739. REFIID riid,
  1740. LPVOID *ppvObj)
  1741. {
  1742. if (IsEqualIID(riid, IID_IShellBrowser) || IsEqualIID(riid, IID_IUnknown))
  1743. {
  1744. *ppvObj = (IShellBrowser *)this;
  1745. ++cRef;
  1746. return (S_OK);
  1747. }
  1748. else if (IsEqualIID(riid, IID_ICommDlgBrowser))
  1749. {
  1750. *ppvObj = (ICommDlgBrowser2 *)this;
  1751. ++cRef;
  1752. return (S_OK);
  1753. }
  1754. else if (IsEqualIID(riid, IID_ICommDlgBrowser2))
  1755. {
  1756. *ppvObj = (ICommDlgBrowser2 *)this;
  1757. ++cRef;
  1758. return (S_OK);
  1759. }
  1760. else if (IsEqualIID(riid, IID_IPrintDialogServices))
  1761. {
  1762. *ppvObj = (IPrintDialogServices *)this;
  1763. ++cRef;
  1764. return (S_OK);
  1765. }
  1766. *ppvObj = NULL;
  1767. return (E_NOINTERFACE);
  1768. }
  1769. ////////////////////////////////////////////////////////////////////////////
  1770. //
  1771. // CPrintBrowser::AddRef
  1772. //
  1773. ////////////////////////////////////////////////////////////////////////////
  1774. ULONG STDMETHODCALLTYPE CPrintBrowser::AddRef()
  1775. {
  1776. return (++cRef);
  1777. }
  1778. ////////////////////////////////////////////////////////////////////////////
  1779. //
  1780. // CPrintBrowser::Release
  1781. //
  1782. ////////////////////////////////////////////////////////////////////////////
  1783. ULONG STDMETHODCALLTYPE CPrintBrowser::Release()
  1784. {
  1785. cRef--;
  1786. if (cRef > 0)
  1787. {
  1788. return (cRef);
  1789. }
  1790. delete this;
  1791. return (0);
  1792. }
  1793. ////////////////////////////////////////////////////////////////////////////
  1794. //
  1795. // CPrintBrowser::GetWindow
  1796. //
  1797. ////////////////////////////////////////////////////////////////////////////
  1798. STDMETHODIMP CPrintBrowser::GetWindow(
  1799. HWND *phwnd)
  1800. {
  1801. *phwnd = hwndDlg;
  1802. return (S_OK);
  1803. }
  1804. ////////////////////////////////////////////////////////////////////////////
  1805. //
  1806. // CPrintBrowser::ContextSensitiveHelp
  1807. //
  1808. ////////////////////////////////////////////////////////////////////////////
  1809. STDMETHODIMP CPrintBrowser::ContextSensitiveHelp(
  1810. BOOL fEnable)
  1811. {
  1812. //
  1813. // Shouldn't need in a common dialog.
  1814. //
  1815. return (S_OK);
  1816. }
  1817. ////////////////////////////////////////////////////////////////////////////
  1818. //
  1819. // CPrintBrowser::InsertMenusSB
  1820. //
  1821. ////////////////////////////////////////////////////////////////////////////
  1822. STDMETHODIMP CPrintBrowser::InsertMenusSB(
  1823. HMENU hmenuShared,
  1824. LPOLEMENUGROUPWIDTHS lpMenuWidths)
  1825. {
  1826. return (E_NOTIMPL);
  1827. }
  1828. ////////////////////////////////////////////////////////////////////////////
  1829. //
  1830. // CPrintBrowser::SetMenuSB
  1831. //
  1832. ////////////////////////////////////////////////////////////////////////////
  1833. STDMETHODIMP CPrintBrowser::SetMenuSB(
  1834. HMENU hmenuShared,
  1835. HOLEMENU holemenu,
  1836. HWND hwndActiveObject)
  1837. {
  1838. return (E_NOTIMPL);
  1839. }
  1840. ////////////////////////////////////////////////////////////////////////////
  1841. //
  1842. // CPrintBrowser::RemoveMenusSB
  1843. //
  1844. ////////////////////////////////////////////////////////////////////////////
  1845. STDMETHODIMP CPrintBrowser::RemoveMenusSB(
  1846. HMENU hmenuShared)
  1847. {
  1848. return (E_NOTIMPL);
  1849. }
  1850. ////////////////////////////////////////////////////////////////////////////
  1851. //
  1852. // CPrintBrowser::SetStatusTextSB
  1853. //
  1854. ////////////////////////////////////////////////////////////////////////////
  1855. STDMETHODIMP CPrintBrowser::SetStatusTextSB(
  1856. LPCOLESTR pwch)
  1857. {
  1858. //
  1859. // We don't have any status bar.
  1860. //
  1861. return (S_OK);
  1862. }
  1863. ////////////////////////////////////////////////////////////////////////////
  1864. //
  1865. // CPrintBrowser::EnableModelessSB
  1866. //
  1867. ////////////////////////////////////////////////////////////////////////////
  1868. STDMETHODIMP CPrintBrowser::EnableModelessSB(
  1869. BOOL fEnable)
  1870. {
  1871. //
  1872. // We don't have any modeless window to be enabled/disabled.
  1873. //
  1874. return (S_OK);
  1875. }
  1876. ////////////////////////////////////////////////////////////////////////////
  1877. //
  1878. // CPrintBrowser::TranslateAcceleratorSB
  1879. //
  1880. ////////////////////////////////////////////////////////////////////////////
  1881. STDMETHODIMP CPrintBrowser::TranslateAcceleratorSB(
  1882. LPMSG pmsg,
  1883. WORD wID)
  1884. {
  1885. //
  1886. // We don't use the Key Stroke.
  1887. //
  1888. return S_FALSE;
  1889. }
  1890. ////////////////////////////////////////////////////////////////////////////
  1891. //
  1892. // CPrintBrowser::BrowseObject
  1893. //
  1894. ////////////////////////////////////////////////////////////////////////////
  1895. STDMETHODIMP CPrintBrowser::BrowseObject(
  1896. LPCITEMIDLIST pidl,
  1897. UINT wFlags)
  1898. {
  1899. //
  1900. // We don't support browsing, or more precisely, CDefView doesn't.
  1901. //
  1902. return (S_OK);
  1903. }
  1904. ////////////////////////////////////////////////////////////////////////////
  1905. //
  1906. // CPrintBrowser::GetViewStateStream
  1907. //
  1908. ////////////////////////////////////////////////////////////////////////////
  1909. STDMETHODIMP CPrintBrowser::GetViewStateStream(
  1910. DWORD grfMode,
  1911. LPSTREAM *pStrm)
  1912. {
  1913. return (E_NOTIMPL);
  1914. }
  1915. ////////////////////////////////////////////////////////////////////////////
  1916. //
  1917. // CPrintBrowser::GetControlWindow
  1918. //
  1919. ////////////////////////////////////////////////////////////////////////////
  1920. STDMETHODIMP CPrintBrowser::GetControlWindow(
  1921. UINT id,
  1922. HWND *lphwnd)
  1923. {
  1924. return (E_NOTIMPL);
  1925. }
  1926. ////////////////////////////////////////////////////////////////////////////
  1927. //
  1928. // CPrintBrowser::SendControlMsg
  1929. //
  1930. ////////////////////////////////////////////////////////////////////////////
  1931. STDMETHODIMP CPrintBrowser::SendControlMsg(
  1932. UINT id,
  1933. UINT uMsg,
  1934. WPARAM wParam,
  1935. LPARAM lParam,
  1936. LRESULT *pret)
  1937. {
  1938. LRESULT lres = 0;
  1939. if (pret)
  1940. {
  1941. *pret = lres;
  1942. }
  1943. return (S_OK);
  1944. }
  1945. ////////////////////////////////////////////////////////////////////////////
  1946. //
  1947. // CPrintBrowser::QueryActiveShellView
  1948. //
  1949. ////////////////////////////////////////////////////////////////////////////
  1950. STDMETHODIMP CPrintBrowser::QueryActiveShellView(
  1951. LPSHELLVIEW *ppsv)
  1952. {
  1953. if (psv)
  1954. {
  1955. *ppsv = psv;
  1956. psv->AddRef();
  1957. return (S_OK);
  1958. }
  1959. *ppsv = NULL;
  1960. return (E_NOINTERFACE);
  1961. }
  1962. ////////////////////////////////////////////////////////////////////////////
  1963. //
  1964. // CPrintBrowser::OnViewWindowActive
  1965. //
  1966. ////////////////////////////////////////////////////////////////////////////
  1967. STDMETHODIMP CPrintBrowser::OnViewWindowActive(
  1968. LPSHELLVIEW psv)
  1969. {
  1970. //
  1971. // No need to process this. We don't do menus.
  1972. //
  1973. return (S_OK);
  1974. }
  1975. ////////////////////////////////////////////////////////////////////////////
  1976. //
  1977. // CPrintBrowser::SetToolbarItems
  1978. //
  1979. ////////////////////////////////////////////////////////////////////////////
  1980. STDMETHODIMP CPrintBrowser::SetToolbarItems(
  1981. LPTBBUTTON lpButtons,
  1982. UINT nButtons,
  1983. UINT uFlags)
  1984. {
  1985. //
  1986. // We don't let containers customize our toolbar.
  1987. //
  1988. return (S_OK);
  1989. }
  1990. ////////////////////////////////////////////////////////////////////////////
  1991. //
  1992. // CPrintBrowser::OnDefaultCommand
  1993. //
  1994. // Process a double-click or Enter keystroke in the view control.
  1995. //
  1996. ////////////////////////////////////////////////////////////////////////////
  1997. STDMETHODIMP CPrintBrowser::OnDefaultCommand(
  1998. struct IShellView *ppshv)
  1999. {
  2000. //
  2001. // Make sure it's the correct shell view.
  2002. //
  2003. if (ppshv != psv)
  2004. {
  2005. return (E_INVALIDARG);
  2006. }
  2007. //
  2008. // See if the Add Printer Wizard is selected.
  2009. //
  2010. if (fAPWSelected)
  2011. {
  2012. //
  2013. // Invoke the Add Printer Wizard (modeless).
  2014. //
  2015. InvokeAddPrinterWizardModal(hwndDlg, NULL);
  2016. }
  2017. else if (fNoAccessPrinterSelected)
  2018. {
  2019. //
  2020. // Display error message indicated we do not have access.
  2021. //
  2022. ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterAccess);
  2023. }
  2024. else
  2025. {
  2026. //
  2027. // Simulate the pressing of the OK button.
  2028. //
  2029. PropSheet_PressButton(GetParent(hwndDlg), PSBTN_OK);
  2030. }
  2031. //
  2032. // Tell the shell that the action has been processed.
  2033. //
  2034. return (S_OK);
  2035. }
  2036. ////////////////////////////////////////////////////////////////////////////
  2037. //
  2038. // CPrintBrowser::OnStateChange
  2039. //
  2040. // Process selection change in the view control.
  2041. //
  2042. ////////////////////////////////////////////////////////////////////////////
  2043. STDMETHODIMP CPrintBrowser::OnStateChange(
  2044. struct IShellView *ppshv,
  2045. ULONG uChange)
  2046. {
  2047. if (ppshv != psv)
  2048. {
  2049. return (E_INVALIDARG);
  2050. }
  2051. switch (uChange)
  2052. {
  2053. case ( CDBOSC_SETFOCUS ) :
  2054. {
  2055. break;
  2056. }
  2057. case ( CDBOSC_KILLFOCUS ) :
  2058. {
  2059. break;
  2060. }
  2061. case ( CDBOSC_SELCHANGE ) :
  2062. {
  2063. //
  2064. // Post one of these messages, since we seem to get a whole
  2065. // bunch of them.
  2066. //
  2067. if (!fSelChangePending)
  2068. {
  2069. fSelChangePending = TRUE;
  2070. PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0);
  2071. }
  2072. break;
  2073. }
  2074. case ( CDBOSC_RENAME ) :
  2075. {
  2076. break;
  2077. }
  2078. default :
  2079. {
  2080. return (E_NOTIMPL);
  2081. }
  2082. }
  2083. return (S_OK);
  2084. }
  2085. ////////////////////////////////////////////////////////////////////////////
  2086. //
  2087. // CPrintBrowser::IncludeObject
  2088. //
  2089. // Tell the view control which objects to include in its enumerations.
  2090. //
  2091. ////////////////////////////////////////////////////////////////////////////
  2092. STDMETHODIMP CPrintBrowser::IncludeObject(
  2093. struct IShellView *ppshv,
  2094. LPCITEMIDLIST pidl)
  2095. {
  2096. //
  2097. // Make sure it's my shell view.
  2098. //
  2099. if (ppshv != psv)
  2100. {
  2101. return (E_INVALIDARG);
  2102. }
  2103. //
  2104. // If we have the printer folder private interface, return ok only
  2105. // if it's a printer.
  2106. //
  2107. if (ppf)
  2108. {
  2109. return (ppf->IsPrinter(pidl) ? S_OK : S_FALSE);
  2110. }
  2111. //
  2112. // This shouldn't happen at this point, but just in case we don't have
  2113. // a printer folder private interface, simply return ok.
  2114. //
  2115. return (S_OK);
  2116. }
  2117. ////////////////////////////////////////////////////////////////////////////
  2118. //
  2119. // CPrintBrowser::Notify
  2120. //
  2121. // Notification to decide whether or not a printer should be selected.
  2122. //
  2123. ////////////////////////////////////////////////////////////////////////////
  2124. STDMETHODIMP CPrintBrowser::Notify(
  2125. struct IShellView *ppshv,
  2126. DWORD dwNotify)
  2127. {
  2128. HRESULT hr = S_OK;
  2129. //
  2130. // Make sure it's my shell view.
  2131. //
  2132. if (ppshv != psv)
  2133. {
  2134. return (E_INVALIDARG);
  2135. }
  2136. switch (dwNotify)
  2137. {
  2138. case (CDB2N_CONTEXTMENU_DONE):
  2139. {
  2140. HWND hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL);
  2141. if (hwndListView)
  2142. {
  2143. HWND hwndEdit = ListView_GetEditControl(hwndListView);
  2144. if (NULL == hwndEdit)
  2145. {
  2146. // if not in edit mode then re-select the current item
  2147. SelectSVItem();
  2148. }
  2149. }
  2150. break;
  2151. }
  2152. default:
  2153. {
  2154. hr = S_FALSE;
  2155. break;
  2156. }
  2157. }
  2158. //
  2159. // This shouldn't happen at this point, but just in case we don't have
  2160. // a printer folder private interface, simply return ok.
  2161. //
  2162. return (hr);
  2163. }
  2164. ////////////////////////////////////////////////////////////////////////////
  2165. //
  2166. // CPrintBrowser::GetDefaultMenuText
  2167. //
  2168. // Returns the default menu text.
  2169. //
  2170. ////////////////////////////////////////////////////////////////////////////
  2171. STDMETHODIMP CPrintBrowser::GetDefaultMenuText(
  2172. struct IShellView *ppshv,
  2173. WCHAR *pszText,
  2174. INT cchMax)
  2175. {
  2176. //
  2177. // Make sure it's my shell view.
  2178. //
  2179. if (ppshv != psv)
  2180. {
  2181. return (E_INVALIDARG);
  2182. }
  2183. //
  2184. // If the add printer wizard is the selected item, do not change
  2185. // the default menu text.
  2186. //
  2187. if (fAPWSelected)
  2188. {
  2189. return (S_FALSE);
  2190. }
  2191. //
  2192. // Change the default menu text from 'Select' to 'Print'.
  2193. //
  2194. if (!CDLoadString(g_hinst, iszDefaultMenuText, szScratch, ARRAYSIZE(szScratch)))
  2195. {
  2196. return (E_FAIL);
  2197. }
  2198. //
  2199. // Just copy the default menu text to the provided buffer if there
  2200. // is room.
  2201. //
  2202. if (lstrlen(szScratch) < cchMax)
  2203. {
  2204. lstrcpyn(pszText, szScratch, cchMax);
  2205. }
  2206. else
  2207. {
  2208. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  2209. }
  2210. return (S_OK);
  2211. }
  2212. ////////////////////////////////////////////////////////////////////////////
  2213. //
  2214. // CPrintBrowser::GetViewFlags
  2215. //
  2216. // Returns Flags to customize the view .
  2217. //
  2218. ////////////////////////////////////////////////////////////////////////////
  2219. STDMETHODIMP CPrintBrowser::GetViewFlags(DWORD *pdwFlags)
  2220. {
  2221. if (pdwFlags)
  2222. {
  2223. *pdwFlags = 0;
  2224. }
  2225. return S_OK;
  2226. }
  2227. ////////////////////////////////////////////////////////////////////////////
  2228. //
  2229. // CPrintBrowser::InitDone
  2230. //
  2231. // Notifies the sub dialog that initialization of the General page is
  2232. // complete.
  2233. //
  2234. ////////////////////////////////////////////////////////////////////////////
  2235. HRESULT STDMETHODCALLTYPE CPrintBrowser::InitDone()
  2236. {
  2237. HRESULT hResult = S_FALSE;
  2238. //
  2239. // Notify the sub dialog that initialization is complete.
  2240. //
  2241. if (pCallback)
  2242. {
  2243. if (pPI->ApiType == COMDLG_ANSI)
  2244. {
  2245. ThunkPrintDlgExW2A(pPI);
  2246. }
  2247. hResult = pCallback->InitDone();
  2248. if (pPI->ApiType == COMDLG_ANSI)
  2249. {
  2250. ThunkPrintDlgExA2W(pPI);
  2251. }
  2252. }
  2253. //
  2254. // Return the result.
  2255. //
  2256. return (hResult);
  2257. }
  2258. ////////////////////////////////////////////////////////////////////////////
  2259. //
  2260. // CPrintBrowser::SelectionChange
  2261. //
  2262. // Notifies the sub dialog that a selection change has taken place.
  2263. //
  2264. ////////////////////////////////////////////////////////////////////////////
  2265. HRESULT STDMETHODCALLTYPE CPrintBrowser::SelectionChange()
  2266. {
  2267. HRESULT hResult = S_FALSE;
  2268. //
  2269. // Handle the Print To File here.
  2270. //
  2271. InitPrintToFile();
  2272. //
  2273. // Notify the sub dialog that a selection change has taken place.
  2274. //
  2275. if (pCallback)
  2276. {
  2277. if (pPI->ApiType == COMDLG_ANSI)
  2278. {
  2279. ThunkPrintDlgExW2A(pPI);
  2280. }
  2281. hResult = pCallback->SelectionChange();
  2282. if (pPI->ApiType == COMDLG_ANSI)
  2283. {
  2284. ThunkPrintDlgExA2W(pPI);
  2285. }
  2286. }
  2287. //
  2288. // Handle the selection change.
  2289. //
  2290. if (hResult == S_FALSE)
  2291. {
  2292. //
  2293. // Handle copies and collate.
  2294. //
  2295. InitCopiesAndCollate();
  2296. //
  2297. // Handle the page ranges.
  2298. //
  2299. InitPageRangeGroup();
  2300. //
  2301. // Return success.
  2302. //
  2303. hResult = S_OK;
  2304. }
  2305. //
  2306. // Return the result.
  2307. //
  2308. return (hResult);
  2309. }
  2310. ////////////////////////////////////////////////////////////////////////////
  2311. //
  2312. // CPrintBrowser::HandleMessage
  2313. //
  2314. // Process a message for the child window by calling the application
  2315. // callback function.
  2316. //
  2317. ////////////////////////////////////////////////////////////////////////////
  2318. HRESULT CPrintBrowser::HandleMessage(
  2319. HWND hDlg,
  2320. UINT uMsg,
  2321. WPARAM wParam,
  2322. LPARAM lParam,
  2323. LRESULT *pResult)
  2324. {
  2325. HRESULT hResult = S_FALSE;
  2326. BOOL bTest;
  2327. UINT nRet, ErrorId;
  2328. DWORD nTmpCopies;
  2329. //
  2330. // Initialize the return value.
  2331. //
  2332. *pResult = FALSE;
  2333. //
  2334. // See if the message should be handled.
  2335. //
  2336. if (pCallback)
  2337. {
  2338. if (pPI->ApiType == COMDLG_ANSI)
  2339. {
  2340. ThunkPrintDlgExW2A(pPI);
  2341. }
  2342. hResult = pCallback->HandleMessage(hDlg, uMsg, wParam, lParam, pResult);
  2343. if (pPI->ApiType == COMDLG_ANSI)
  2344. {
  2345. ThunkPrintDlgExA2W(pPI);
  2346. }
  2347. }
  2348. //
  2349. // Handle the message.
  2350. //
  2351. if ((hResult == S_FALSE) && (uMsg == WM_NOTIFY))
  2352. {
  2353. switch (((LPNMHDR)lParam)->code)
  2354. {
  2355. case ( PSN_KILLACTIVE ) :
  2356. {
  2357. //
  2358. // Make sure the page has valid entries.
  2359. // If invalid entries are found, then set the DWL_MSGRESULT
  2360. // of the General page to be TRUE and return TRUE in order
  2361. // to prevent the page from losing the activation.
  2362. //
  2363. //
  2364. // Validate the number of copies and store it in the
  2365. // nCopies member.
  2366. //
  2367. if ((GetDlgItem(hSubDlg, IDC_COPIES)) &&
  2368. (fAPWSelected == FALSE))
  2369. {
  2370. nTmpCopies = nCopies;
  2371. nCopies = GetDlgItemInt(hSubDlg, IDC_COPIES, &bTest, FALSE);
  2372. if (!bTest || !nCopies)
  2373. {
  2374. nCopies = nTmpCopies;
  2375. ShowError(hSubDlg, IDC_COPIES, iszCopiesZero);
  2376. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
  2377. *pResult = TRUE;
  2378. return (E_FAIL);
  2379. }
  2380. }
  2381. //
  2382. // Validate the page range and store it in the pRange member.
  2383. //
  2384. if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_PAGES) &&
  2385. GetDlgItem(hSubDlg, IDC_RANGE_EDIT))
  2386. {
  2387. nRet = GetDlgItemText( hSubDlg,
  2388. IDC_RANGE_EDIT,
  2389. szScratch,
  2390. ARRAYSIZE(szScratch) );
  2391. ErrorId = iszBadPageRange;
  2392. if (!nRet || !IsValidPageRange(szScratch, &ErrorId))
  2393. {
  2394. ShowError(hSubDlg,
  2395. IDC_RANGE_EDIT,
  2396. ErrorId,
  2397. (ErrorId == iszTooManyPageRanges)
  2398. ? nMaxPageRanges
  2399. : pPD->nMinPage,
  2400. pPD->nMaxPage);
  2401. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
  2402. *pResult = TRUE;
  2403. return (E_FAIL);
  2404. }
  2405. }
  2406. //
  2407. // Message has now been handled.
  2408. //
  2409. hResult = S_OK;
  2410. break;
  2411. }
  2412. case ( PSN_APPLY ) :
  2413. {
  2414. //
  2415. // Clear the flags that need to be set based on the
  2416. // contents of the General page.
  2417. //
  2418. pPD->Flags &= ~((DWORD)( PD_PAGENUMS |
  2419. PD_SELECTION |
  2420. PD_CURRENTPAGE ));
  2421. //
  2422. // Save the page range information.
  2423. //
  2424. if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_SELECTION))
  2425. {
  2426. pPD->Flags |= PD_SELECTION;
  2427. }
  2428. else if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_CURRENT))
  2429. {
  2430. pPD->Flags |= PD_CURRENTPAGE;
  2431. }
  2432. else if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_PAGES))
  2433. {
  2434. pPD->Flags |= PD_PAGENUMS;
  2435. //
  2436. // Copy the page ranges to the pPageRanges structure
  2437. // in the PrintDlg structure.
  2438. //
  2439. if (GetDlgItem(hSubDlg, IDC_RANGE_EDIT))
  2440. {
  2441. pPD->nPageRanges = nPageRanges;
  2442. CopyMemory( pPD->lpPageRanges,
  2443. pPageRanges,
  2444. nPageRanges * sizeof(PRINTPAGERANGE) );
  2445. }
  2446. }
  2447. //
  2448. // Message has now been handled.
  2449. //
  2450. hResult = S_OK;
  2451. break;
  2452. }
  2453. }
  2454. }
  2455. //
  2456. // Return the result.
  2457. //
  2458. return (hResult);
  2459. }
  2460. ////////////////////////////////////////////////////////////////////////////
  2461. //
  2462. // CPrintBrowser::GetCurrentDevMode
  2463. //
  2464. // Returns the current devmode structure.
  2465. //
  2466. ////////////////////////////////////////////////////////////////////////////
  2467. HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentDevMode(
  2468. LPDEVMODE pDevMode,
  2469. UINT *pcbSize)
  2470. {
  2471. UINT cbSize;
  2472. //
  2473. // Make sure pcbSize is valid.
  2474. //
  2475. if ((pcbSize == NULL) || (*pcbSize && !pDevMode))
  2476. {
  2477. return (E_INVALIDARG);
  2478. }
  2479. //
  2480. // When there is no current devmode, set the size to zero and return
  2481. // TRUE.
  2482. //
  2483. if (!pDMCur)
  2484. {
  2485. *pcbSize = 0;
  2486. return (S_OK);
  2487. }
  2488. //
  2489. // Save the current printer name and the current devmode in the
  2490. // class.
  2491. //
  2492. GetCurrentPrinter();
  2493. //
  2494. // See if we just need to get the size of the buffer.
  2495. //
  2496. if (*pcbSize == 0)
  2497. {
  2498. //
  2499. // Return the size of the buffer needed.
  2500. //
  2501. if (pPI->ApiType == COMDLG_ANSI)
  2502. {
  2503. *pcbSize = sizeof(DEVMODEA) + pDMCur->dmDriverExtra;
  2504. }
  2505. else
  2506. {
  2507. *pcbSize = pDMCur->dmSize + pDMCur->dmDriverExtra;
  2508. }
  2509. }
  2510. else
  2511. {
  2512. //
  2513. // Make sure the copies and collate information is up to date.
  2514. //
  2515. SaveCopiesAndCollateInDevMode(pDMCur, pszCurPrinter);
  2516. //
  2517. // Return the devmode information as well as the size of the
  2518. // buffer.
  2519. //
  2520. if (pPI->ApiType == COMDLG_ANSI)
  2521. {
  2522. cbSize = sizeof(DEVMODEA) + pDMCur->dmDriverExtra;
  2523. if (*pcbSize < cbSize)
  2524. {
  2525. return (E_INVALIDARG);
  2526. }
  2527. ThunkDevModeW2A(pDMCur, (LPDEVMODEA)pDevMode);
  2528. *pcbSize = cbSize;
  2529. }
  2530. else
  2531. {
  2532. cbSize = pDMCur->dmSize + pDMCur->dmDriverExtra;
  2533. if (*pcbSize < cbSize)
  2534. {
  2535. return (E_INVALIDARG);
  2536. }
  2537. CopyMemory(pDevMode, pDMCur, cbSize);
  2538. *pcbSize = cbSize;
  2539. }
  2540. }
  2541. //
  2542. // Return success.
  2543. //
  2544. return (S_OK);
  2545. }
  2546. ////////////////////////////////////////////////////////////////////////////
  2547. //
  2548. // CPrintBrowser::GetCurrentPrinterName
  2549. //
  2550. // Returns the current printer name.
  2551. //
  2552. ////////////////////////////////////////////////////////////////////////////
  2553. HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentPrinterName(
  2554. LPTSTR pPrinterName,
  2555. UINT *pcchSize)
  2556. {
  2557. UINT cchSize;
  2558. //
  2559. // Make sure pcchSize is valid.
  2560. //
  2561. if ((pcchSize == NULL) || (*pcchSize && !pPrinterName))
  2562. {
  2563. return (E_INVALIDARG);
  2564. }
  2565. //
  2566. // Save the current printer name and the current devmode in the
  2567. // class.
  2568. //
  2569. GetCurrentPrinter();
  2570. //
  2571. // When there is no current printer, set the size to zero and return
  2572. // TRUE.
  2573. //
  2574. if ((pszCurPrinter == NULL) || (pszCurPrinter[0] == 0))
  2575. {
  2576. *pcchSize = 0;
  2577. return (S_OK);
  2578. }
  2579. //
  2580. // See if we just need to get the size of the buffer.
  2581. //
  2582. if (*pcchSize == 0)
  2583. {
  2584. if (pPI->ApiType == COMDLG_ANSI)
  2585. {
  2586. *pcchSize = WideCharToMultiByte( CP_ACP,
  2587. 0,
  2588. pszCurPrinter,
  2589. -1,
  2590. NULL,
  2591. 0,
  2592. NULL,
  2593. NULL );
  2594. }
  2595. else
  2596. {
  2597. *pcchSize = lstrlen(pszCurPrinter) + 1;
  2598. }
  2599. }
  2600. else
  2601. {
  2602. if (pPI->ApiType == COMDLG_ANSI)
  2603. {
  2604. *pcchSize = SHUnicodeToAnsi(pszCurPrinter,(LPSTR)pPrinterName,*pcchSize);
  2605. if (*pcchSize == 0)
  2606. {
  2607. return (E_INVALIDARG);
  2608. }
  2609. }
  2610. else
  2611. {
  2612. cchSize = lstrlen(pszCurPrinter) + 1;
  2613. if (*pcchSize < cchSize)
  2614. {
  2615. return (E_INVALIDARG);
  2616. }
  2617. StringCchCopy(pPrinterName, cchSize, pszCurPrinter);
  2618. *pcchSize = cchSize;
  2619. }
  2620. }
  2621. //
  2622. // Return success.
  2623. //
  2624. return (S_OK);
  2625. }
  2626. ////////////////////////////////////////////////////////////////////////////
  2627. //
  2628. // CPrintBrowser::GetCurrentPortName
  2629. //
  2630. // Returns the current port name.
  2631. //
  2632. ////////////////////////////////////////////////////////////////////////////
  2633. HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentPortName(
  2634. LPTSTR pPortName,
  2635. UINT *pcchSize)
  2636. {
  2637. UINT cchSize;
  2638. TCHAR szPortName[MAX_PATH];
  2639. //
  2640. // Make sure pcchSize is valid.
  2641. //
  2642. if ((pcchSize == NULL) || (*pcchSize && !pPortName))
  2643. {
  2644. return (E_INVALIDARG);
  2645. }
  2646. //
  2647. // Save the current printer name and the current devmode in the
  2648. // class.
  2649. //
  2650. GetCurrentPrinter();
  2651. //
  2652. // When there is no current printer, set the size to zero and return
  2653. // TRUE.
  2654. //
  2655. if ((pszCurPrinter == NULL) || (pszCurPrinter[0] == 0))
  2656. {
  2657. *pcchSize = 0;
  2658. return (S_OK);
  2659. }
  2660. //
  2661. // Get the port name for the current printer.
  2662. //
  2663. szPortName[0] = 0;
  2664. Print_GetPortName(pszCurPrinter, szPortName, ARRAYSIZE(szPortName));
  2665. //
  2666. // See if we just need to get the size of the buffer.
  2667. //
  2668. if (*pcchSize == 0)
  2669. {
  2670. if (pPI->ApiType == COMDLG_ANSI)
  2671. {
  2672. *pcchSize = WideCharToMultiByte( CP_ACP,
  2673. 0,
  2674. szPortName,
  2675. -1,
  2676. NULL,
  2677. 0,
  2678. NULL,
  2679. NULL );
  2680. }
  2681. else
  2682. {
  2683. *pcchSize = lstrlen(szPortName) + 1;
  2684. }
  2685. }
  2686. else
  2687. {
  2688. if (pPI->ApiType == COMDLG_ANSI)
  2689. {
  2690. *pcchSize = SHUnicodeToAnsi(szPortName,(LPSTR)pPortName,*pcchSize);
  2691. if (*pcchSize == 0)
  2692. {
  2693. return (E_INVALIDARG);
  2694. }
  2695. }
  2696. else
  2697. {
  2698. cchSize = lstrlen(szPortName) + 1;
  2699. if (*pcchSize < cchSize)
  2700. {
  2701. return (E_INVALIDARG);
  2702. }
  2703. StringCchCopy(pPortName, cchSize, szPortName);
  2704. *pcchSize = cchSize;
  2705. }
  2706. }
  2707. //
  2708. // Return success.
  2709. //
  2710. return (S_OK);
  2711. }
  2712. ////////////////////////////////////////////////////////////////////////////
  2713. //
  2714. // CPrintBrowser::OnInitDialog
  2715. //
  2716. // Process a WM_INITDIALOG message for the General page.
  2717. //
  2718. ////////////////////////////////////////////////////////////////////////////
  2719. BOOL CPrintBrowser::OnInitDialog(
  2720. WPARAM wParam,
  2721. LPARAM lParam)
  2722. {
  2723. HWND hCtl;
  2724. LPDEVMODE pDM;
  2725. LPDEVNAMES pDN;
  2726. HRESULT hrDevMode;
  2727. HRESULT hResult;
  2728. SHChangeNotifyEntry fsne;
  2729. //
  2730. // If disable printer addition policy is set then
  2731. // then disable find button on the print dialog
  2732. //
  2733. if( SHRestricted(REST_NOPRINTERADD) )
  2734. {
  2735. EnableWindow( GetDlgItem( hwndDlg, IDC_FIND_PRINTER ), FALSE );
  2736. }
  2737. //
  2738. // Always disable the preferences button in the begining
  2739. //
  2740. EnableWindow( GetDlgItem( hwndDlg, IDC_DRIVER ), FALSE );
  2741. //
  2742. // Get the pointer to the PRINTINFOEX structure from the lParam of
  2743. // the property sheet structure.
  2744. //
  2745. pPI = (PPRINTINFOEX)((LPPROPSHEETPAGE)lParam)->lParam;
  2746. pPD = pPI->pPD;
  2747. //Initialize Ole Before doing anything
  2748. pPI->hrOleInit = SHOleInitialize(0);
  2749. DEBUG_CODE(GdiSetBatchLimit(1));
  2750. //
  2751. // Initialize the error codes to success now that we have the
  2752. // pPI structure.
  2753. //
  2754. pPI->dwExtendedError = CDERR_GENERALCODES;
  2755. pPI->hResult = S_OK;
  2756. //
  2757. // Create the printer folder shell view.
  2758. //
  2759. hResult = CreatePrintShellView();
  2760. if (FAILED(hResult))
  2761. {
  2762. pPI->hResult = hResult;
  2763. return (FALSE);
  2764. }
  2765. //
  2766. // Insert the device pages for the appropriate printer.
  2767. //
  2768. // First: Try the printer in the DevMode.
  2769. // Second: Try the printer in the DevNames.
  2770. // Third: Use the default by passing in NULLs.
  2771. //
  2772. hrDevMode = E_FAIL;
  2773. if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode)))
  2774. {
  2775. DWORD cbSize = (DWORD)(pDM->dmSize + pDM->dmDriverExtra);
  2776. if (cbSize >= sizeof(DEVMODE) && (pDMInit = (LPDEVMODE)GlobalAlloc(GPTR, cbSize)))
  2777. {
  2778. CopyMemory(pDMInit, pDM, cbSize);
  2779. hrDevMode = InstallDevMode((LPTSTR)pDM->dmDeviceName, pDMInit);
  2780. }
  2781. GlobalUnlock(pPD->hDevMode);
  2782. }
  2783. if ((FAILED(hrDevMode)) &&
  2784. (pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames)))
  2785. {
  2786. LPTSTR pPrinter = (LPTSTR)pDN + pDN->wDeviceOffset;
  2787. hrDevMode = InstallDevMode(pPrinter, pDMInit);
  2788. GlobalUnlock(pPD->hDevNames);
  2789. }
  2790. if (FAILED(hrDevMode))
  2791. {
  2792. hrDevMode = InstallDevMode(NULL, pDMInit);
  2793. }
  2794. //
  2795. // Get the current printer name and the current devmode.
  2796. //
  2797. GetCurrentPrinter();
  2798. //
  2799. // Initialize the "Print to file" check box appropriately.
  2800. //
  2801. if (hCtl = GetDlgItem(hwndDlg, IDC_PRINT_TO_FILE))
  2802. {
  2803. if (pPD->Flags & PD_PRINTTOFILE)
  2804. {
  2805. CheckDlgButton(hwndDlg, IDC_PRINT_TO_FILE, TRUE);
  2806. }
  2807. if (pPD->Flags & PD_HIDEPRINTTOFILE)
  2808. {
  2809. EnableWindow(hCtl, FALSE);
  2810. ShowWindow(hCtl, SW_HIDE);
  2811. }
  2812. else if (pPD->Flags & PD_DISABLEPRINTTOFILE)
  2813. {
  2814. EnableWindow(hCtl, FALSE);
  2815. }
  2816. }
  2817. //
  2818. // Set the number of copies and the collation correctly.
  2819. //
  2820. pDM = pDMInit ? pDMInit : pDMCur;
  2821. if (pDMCur && (pDMCur->dmFields & DM_COPIES))
  2822. {
  2823. if (pDMInit || (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE))
  2824. {
  2825. pPD->nCopies = (DWORD)pDM->dmCopies;
  2826. }
  2827. else if (pPD->nCopies)
  2828. {
  2829. pDMCur->dmCopies = (short)pPD->nCopies;
  2830. }
  2831. }
  2832. if (pDMCur && (pDMCur->dmFields & DM_COLLATE))
  2833. {
  2834. if (pDMInit || (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE))
  2835. {
  2836. if (pDM->dmCollate == DMCOLLATE_FALSE)
  2837. {
  2838. pPD->Flags &= ~PD_COLLATE;
  2839. }
  2840. else
  2841. {
  2842. pPD->Flags |= PD_COLLATE;
  2843. }
  2844. }
  2845. else
  2846. {
  2847. pDMCur->dmCollate = (pPD->Flags & PD_COLLATE)
  2848. ? DMCOLLATE_TRUE
  2849. : DMCOLLATE_FALSE;
  2850. }
  2851. }
  2852. if (pPD->Flags & PD_COLLATE)
  2853. {
  2854. fCollateRequested = TRUE;
  2855. }
  2856. //
  2857. // Create the hook dialog.
  2858. //
  2859. hResult = CreateHookDialog();
  2860. if (FAILED(hResult))
  2861. {
  2862. pPI->hResult = hResult;
  2863. return (FALSE);
  2864. }
  2865. //
  2866. // Set the ClipChildren style bit on the main dialog so that we get
  2867. // proper repainting of the various children in the General page.
  2868. //
  2869. SetWindowLong( GetParent(hwndDlg),
  2870. GWL_STYLE,
  2871. GetWindowLong(GetParent(hwndDlg), GWL_STYLE) | WS_CLIPCHILDREN );
  2872. //
  2873. // Set the OK button to Print.
  2874. //
  2875. CDLoadString(g_hinst, iszPrintButton, szScratch, ARRAYSIZE(szScratch));
  2876. SetDlgItemText(GetParent(hwndDlg), IDOK, szScratch);
  2877. //
  2878. // Disable the Apply button.
  2879. //
  2880. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  2881. //
  2882. // Register change notifications.
  2883. //
  2884. if (pidlRoot)
  2885. {
  2886. fsne.pidl = pidlRoot;
  2887. fsne.fRecursive = FALSE;
  2888. uRegister = SHChangeNotifyRegister(
  2889. hwndDlg,
  2890. SHCNRF_NewDelivery | SHCNRF_ShellLevel |
  2891. SHCNRF_InterruptLevel,
  2892. SHCNE_ATTRIBUTES | SHCNE_UPDATEITEM | SHCNE_CREATE |
  2893. SHCNE_DELETE | SHCNE_RENAMEITEM,
  2894. CDM_PRINTNOTIFY,
  2895. 1,
  2896. &fsne );
  2897. }
  2898. //
  2899. // If we failed to insert the device page then tell the
  2900. // user what is wrong.
  2901. //
  2902. if (FAILED(hrDevMode) || !pDMCur)
  2903. {
  2904. //
  2905. // Something has failed. Show an error message.
  2906. //
  2907. PostMessage(hwndDlg, CDM_NOPRINTERS, (WPARAM)hwndDlg, (LPARAM)hrDevMode);
  2908. }
  2909. //
  2910. // Give the application the pointer to the IPrintDialogServices
  2911. // interface.
  2912. //
  2913. if (pPD->lpCallback)
  2914. {
  2915. pPD->lpCallback->QueryInterface(IID_IObjectWithSite, (LPVOID *)&pSite);
  2916. if (pSite)
  2917. {
  2918. pSite->SetSite((IPrintDialogServices *)this);
  2919. }
  2920. }
  2921. //
  2922. // Initialization is complete.
  2923. //
  2924. PostMessage(hwndDlg, CDM_INITDONE, 0, 0);
  2925. //
  2926. // Return success.
  2927. //
  2928. return (TRUE);
  2929. }
  2930. ////////////////////////////////////////////////////////////////////////////
  2931. //
  2932. // CPrintBrowser::OnChildInitDialog
  2933. //
  2934. // Process a WM_INITDIALOG message for the child window.
  2935. //
  2936. ////////////////////////////////////////////////////////////////////////////
  2937. BOOL CPrintBrowser::OnChildInitDialog(
  2938. HWND hDlg,
  2939. WPARAM wParam,
  2940. LPARAM lParam)
  2941. {
  2942. WORD wCheckID;
  2943. HWND hCtl;
  2944. //
  2945. // Save the handle to the child window.
  2946. //
  2947. hSubDlg = hDlg;
  2948. //
  2949. // Get the list separator for the current user locale.
  2950. //
  2951. nListSep = GetLocaleInfo( LOCALE_USER_DEFAULT,
  2952. LOCALE_SLIST,
  2953. szListSep,
  2954. ARRAYSIZE(szListSep) );
  2955. if (nListSep == 0)
  2956. {
  2957. szListSep[0] = TEXT(',');
  2958. szListSep[1] = 0;
  2959. nListSep = 2;
  2960. }
  2961. nListSep--;
  2962. //
  2963. // Set the number of copies.
  2964. //
  2965. pPD->nCopies = max(pPD->nCopies, 1);
  2966. pPD->nCopies = min(pPD->nCopies, MAX_COPIES);
  2967. SetDlgItemInt(hSubDlg, IDC_COPIES, pPD->nCopies, FALSE);
  2968. nCopies = pPD->nCopies;
  2969. if ((hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) &&
  2970. (GetWindowLong(hCtl, GWL_STYLE) & WS_VISIBLE))
  2971. {
  2972. //
  2973. // "9999" is the maximum value.
  2974. //
  2975. Edit_LimitText(hCtl, COPIES_EDIT_SIZE);
  2976. hwndUpDown = CreateUpDownControl( WS_CHILD | WS_BORDER | WS_VISIBLE |
  2977. UDS_ALIGNRIGHT | UDS_SETBUDDYINT |
  2978. UDS_NOTHOUSANDS | UDS_ARROWKEYS,
  2979. 0,
  2980. 0,
  2981. 0,
  2982. 0,
  2983. hSubDlg,
  2984. IDC_COPIES_UDARROW,
  2985. g_hinst,
  2986. hCtl,
  2987. MAX_COPIES,
  2988. 1,
  2989. pPD->nCopies );
  2990. //
  2991. // Adjust the width of the copies edit control using the current
  2992. // font and the scroll bar width. This is necessary to handle the
  2993. // the up down control from encroching on the space in the edit
  2994. // control when we are in High Contrast (extra large) mode.
  2995. //
  2996. SetCopiesEditWidth(hSubDlg, hCtl);
  2997. }
  2998. //
  2999. // Make sure the collate icon is centered. Only want to do this once.
  3000. //
  3001. if (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE))
  3002. {
  3003. SetWindowLong( hCtl,
  3004. GWL_STYLE,
  3005. GetWindowLong(hCtl, GWL_STYLE) | SS_CENTERIMAGE );
  3006. }
  3007. //
  3008. // Initialize the copies and collate info.
  3009. //
  3010. InitCopiesAndCollate();
  3011. //
  3012. // Set the page range.
  3013. //
  3014. if (pPD->Flags & PD_NOPAGENUMS)
  3015. {
  3016. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE);
  3017. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE);
  3018. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_TEXT1), FALSE);
  3019. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_TEXT2), FALSE);
  3020. pPD->Flags &= ~((DWORD)PD_PAGENUMS);
  3021. }
  3022. else
  3023. {
  3024. //
  3025. // See if the page range only consists of one page. If so,
  3026. // disable the Pages radio button and the associated edit control
  3027. // and disable and hide the collate check box.
  3028. //
  3029. if (pPD->nMinPage == pPD->nMaxPage)
  3030. {
  3031. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE);
  3032. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE);
  3033. pPD->Flags &= ~((DWORD)(PD_PAGENUMS | PD_COLLATE));
  3034. fCollateRequested = FALSE;
  3035. EnableWindow(GetDlgItem(hSubDlg, IDC_COLLATE), FALSE);
  3036. ShowWindow(GetDlgItem(hSubDlg, IDC_COLLATE), SW_HIDE);
  3037. }
  3038. else
  3039. {
  3040. //
  3041. // Initialize the page range members.
  3042. //
  3043. nPageRanges = pPD->nPageRanges;
  3044. nMaxPageRanges = pPD->nMaxPageRanges;
  3045. pPageRanges = (LPPRINTPAGERANGE)
  3046. GlobalAlloc(GPTR, nMaxPageRanges * sizeof(PRINTPAGERANGE));
  3047. if (!pPageRanges)
  3048. {
  3049. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  3050. pPI->hResult = E_OUTOFMEMORY;
  3051. return (FALSE);
  3052. }
  3053. CopyMemory( pPageRanges,
  3054. pPD->lpPageRanges,
  3055. nPageRanges * sizeof(PRINTPAGERANGE) );
  3056. //
  3057. // See if we should only accept a single page range.
  3058. //
  3059. if (nMaxPageRanges == 1)
  3060. {
  3061. hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT2);
  3062. ShowWindow(hCtl, SW_SHOW);
  3063. EnableWindow(hCtl, TRUE);
  3064. hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT1);
  3065. EnableWindow(hCtl, FALSE);
  3066. ShowWindow(hCtl, SW_HIDE);
  3067. }
  3068. else
  3069. {
  3070. hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT1);
  3071. ShowWindow(hCtl, SW_SHOW);
  3072. EnableWindow(hCtl, TRUE);
  3073. hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT2);
  3074. EnableWindow(hCtl, FALSE);
  3075. ShowWindow(hCtl, SW_HIDE);
  3076. }
  3077. //
  3078. // Validate the page ranges.
  3079. //
  3080. if (!ConvertPageRangesToString(szScratch, ARRAYSIZE(szScratch)))
  3081. {
  3082. pPI->dwExtendedError = PDERR_INITFAILURE;
  3083. pPI->hResult = E_INVALIDARG;
  3084. return (FALSE);
  3085. }
  3086. //
  3087. // Put the page range string in the edit control.
  3088. //
  3089. if (GetDlgItem(hSubDlg, IDC_RANGE_EDIT))
  3090. {
  3091. SetDlgItemText(hSubDlg, IDC_RANGE_EDIT, szScratch);
  3092. }
  3093. }
  3094. }
  3095. //
  3096. // See if we should disable the Selection radio button.
  3097. //
  3098. if (pPD->Flags & PD_NOSELECTION)
  3099. {
  3100. if (hCtl = GetDlgItem(hSubDlg, IDC_RANGE_SELECTION))
  3101. {
  3102. EnableWindow(hCtl, FALSE);
  3103. }
  3104. pPD->Flags &= ~((DWORD)PD_SELECTION);
  3105. }
  3106. //
  3107. // See if we should disable the Current Page radio button.
  3108. //
  3109. if (pPD->Flags & PD_NOCURRENTPAGE)
  3110. {
  3111. if (hCtl = GetDlgItem(hSubDlg, IDC_RANGE_CURRENT))
  3112. {
  3113. EnableWindow(hCtl, FALSE);
  3114. }
  3115. pPD->Flags &= ~((DWORD)PD_CURRENTPAGE);
  3116. }
  3117. //
  3118. // Choose one of the page range radio buttons.
  3119. //
  3120. if (pPD->Flags & PD_PAGENUMS)
  3121. {
  3122. wCheckID = IDC_RANGE_PAGES;
  3123. }
  3124. else if (pPD->Flags & PD_SELECTION)
  3125. {
  3126. wCheckID = IDC_RANGE_SELECTION;
  3127. }
  3128. else if (pPD->Flags & PD_CURRENTPAGE)
  3129. {
  3130. wCheckID = IDC_RANGE_CURRENT;
  3131. }
  3132. else // PD_ALL
  3133. {
  3134. wCheckID = IDC_RANGE_ALL;
  3135. }
  3136. CheckRadioButton(hSubDlg, IDC_RANGE_ALL, IDC_RANGE_PAGES, (int)wCheckID);
  3137. //
  3138. // See if the collate check box should be checked or not.
  3139. //
  3140. if (pPD->Flags & PD_COLLATE)
  3141. {
  3142. CheckDlgButton(hSubDlg, IDC_COLLATE, TRUE);
  3143. }
  3144. //
  3145. // Display the appropriate collate icon.
  3146. //
  3147. if ((GetWindowLong( GetDlgItem(hSubDlg, IDC_COLLATE),
  3148. GWL_STYLE ) & WS_VISIBLE) &&
  3149. (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)))
  3150. {
  3151. ShowWindow(hCtl, SW_HIDE);
  3152. SendMessage( hCtl,
  3153. STM_SETICON,
  3154. IsDlgButtonChecked(hSubDlg, IDC_COLLATE)
  3155. ? (LONG_PTR)hIconCollate
  3156. : (LONG_PTR)hIconNoCollate,
  3157. 0L );
  3158. ShowWindow(hCtl, SW_SHOW);
  3159. }
  3160. //
  3161. // Save the flags as they are now so I know what to enable
  3162. // when the selection changes from the Add Printer Wizard icon.
  3163. //
  3164. pPI->dwFlags = pPD->Flags;
  3165. if (pPD->nMinPage == pPD->nMaxPage)
  3166. {
  3167. pPI->dwFlags |= PD_NOPAGENUMS;
  3168. }
  3169. //
  3170. // Disable the Apply button.
  3171. //
  3172. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  3173. //
  3174. // Initialization is complete.
  3175. //
  3176. PostMessage(hwndDlg, CDM_INITDONE, 0, 0);
  3177. //
  3178. // Return success.
  3179. //
  3180. return (TRUE);
  3181. }
  3182. ////////////////////////////////////////////////////////////////////////////
  3183. //
  3184. // CPrintBrowser::OnDestroyMessage
  3185. //
  3186. // Process a WM_DESTROY message for the General page.
  3187. //
  3188. ////////////////////////////////////////////////////////////////////////////
  3189. VOID CPrintBrowser::OnDestroyMessage()
  3190. {
  3191. if (psfv)
  3192. {
  3193. psfv->Release();
  3194. psfv = NULL;
  3195. }
  3196. if (psv)
  3197. {
  3198. psv->DestroyViewWindow();
  3199. psv->Release();
  3200. psv = NULL;
  3201. }
  3202. if (pCallback)
  3203. {
  3204. pCallback->Release();
  3205. pCallback = NULL;
  3206. }
  3207. if (pSite)
  3208. {
  3209. pSite->SetSite(NULL);
  3210. pSite->Release();
  3211. pSite = NULL;
  3212. }
  3213. }
  3214. ////////////////////////////////////////////////////////////////////////////
  3215. //
  3216. // CPrintBrowser::OnCommandMessage
  3217. //
  3218. // Process a WM_COMMAND message for the General page.
  3219. //
  3220. ////////////////////////////////////////////////////////////////////////////
  3221. BOOL CPrintBrowser::OnCommandMessage(
  3222. WPARAM wParam,
  3223. LPARAM lParam)
  3224. {
  3225. switch (LOWORD(wParam))
  3226. {
  3227. case ( IDC_DRIVER ) :
  3228. {
  3229. //
  3230. // Show the driver UI calling DocumentProperties API.
  3231. //
  3232. if (pInternalDevMode)
  3233. {
  3234. DWORD dwSize = pInternalDevMode->dmSize + pInternalDevMode->dmDriverExtra;
  3235. //
  3236. // Allocate memory for the in/out devmodes and open separate temp printer handle.
  3237. //
  3238. LPDEVMODE pDevModeIn = (LPDEVMODE)GlobalAlloc(GPTR, dwSize);
  3239. LPDEVMODE pDevModeOut = (LPDEVMODE)GlobalAlloc(GPTR, dwSize);
  3240. HANDLE hTempPrinter = NULL;
  3241. if (pDevModeIn && pDevModeOut && OpenPrinter((LPTSTR)szPrinter, &hTempPrinter, NULL))
  3242. {
  3243. //
  3244. // Call DocumentProperties API to allow the user to edit the devmode.
  3245. //
  3246. fDirtyDevmode = FALSE;
  3247. memcpy(pDevModeIn, pInternalDevMode, dwSize);
  3248. memcpy(pDevModeOut, pInternalDevMode, dwSize);
  3249. //
  3250. // Update current copy and collation settings to DEVMODE before calling DocumentProperties()
  3251. //
  3252. pDevModeIn->dmCopies = nCopies;
  3253. pDevModeIn->dmCollate = fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
  3254. fDevmodeEdit = TRUE;
  3255. LONG lResult = g_pfnDocumentPropertiesWrap(hwndDlg, hTempPrinter, szPrinter, pDevModeOut,
  3256. pDevModeIn, DM_IN_BUFFER|DM_OUT_BUFFER|DM_IN_PROMPT|DM_OUT_DEFAULT, pPD->ExclusionFlags);
  3257. fDevmodeEdit = FALSE;
  3258. if (IDOK == lResult)
  3259. {
  3260. //
  3261. // Check if there is a change after the editing.
  3262. //
  3263. if (!fDirtyDevmode && pInternalDevMode && memcmp(pDevModeOut, pInternalDevMode, dwSize))
  3264. {
  3265. //
  3266. // Refresh the copies and collation in case of change in Preferences...
  3267. // We simulate a BN_CLICKED message since we need to refresh the collation icon
  3268. // when we change the collation settings.
  3269. //
  3270. if (nCopies != pDevModeOut->dmCopies)
  3271. {
  3272. SetDlgItemInt(hSubDlg, IDC_COPIES, pDevModeOut->dmCopies, FALSE);
  3273. }
  3274. if ((fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE) ^ pDevModeOut->dmCollate)
  3275. {
  3276. CheckDlgButton(hSubDlg, IDC_COLLATE, pDevModeOut->dmCollate ? BST_CHECKED : BST_UNCHECKED);
  3277. SendMessage(hSubDlg, WM_COMMAND, MAKEWPARAM(IDC_COLLATE ,BN_CLICKED), (LPARAM)GetDlgItem(hSubDlg, IDC_COLLATE));
  3278. }
  3279. //
  3280. // The internal devmode has been changed. Update it and enable the "Apply" button.
  3281. //
  3282. memcpy(pInternalDevMode, pDevModeOut, dwSize);
  3283. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3284. }
  3285. }
  3286. }
  3287. //
  3288. // Release the allocated resources.
  3289. //
  3290. if (pDevModeIn)
  3291. {
  3292. GlobalFree((HANDLE)pDevModeIn);
  3293. }
  3294. if (pDevModeOut)
  3295. {
  3296. GlobalFree((HANDLE)pDevModeOut);
  3297. }
  3298. if (hTempPrinter)
  3299. {
  3300. ClosePrinter(hTempPrinter);
  3301. }
  3302. // select the printer's list control
  3303. SendMessage(hwndDlg, WM_NEXTDLGCTL,
  3304. reinterpret_cast<WPARAM>(GetDlgItem(hwndDlg, IDC_PRINTER_LISTVIEW)), 1);
  3305. }
  3306. break;
  3307. }
  3308. case ( IDC_FIND_PRINTER ) :
  3309. {
  3310. //
  3311. // Turn on the hour glass.
  3312. //
  3313. HourGlass(TRUE);
  3314. //
  3315. // Bring up the Find Printer dialog.
  3316. //
  3317. szScratch[0] = 0;
  3318. if (FindPrinter(hwndDlg, szScratch, ARRAYSIZE(szScratch)) && (szScratch[0] != 0))
  3319. {
  3320. //
  3321. // Add the appropriate device pages and select the
  3322. // newly found printer.
  3323. //
  3324. if (!MergeDevMode(szScratch))
  3325. {
  3326. InstallDevMode(szScratch, NULL);
  3327. }
  3328. if (!fSelChangePending)
  3329. {
  3330. fFirstSel = 2;
  3331. fSelChangePending = TRUE;
  3332. PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0);
  3333. }
  3334. }
  3335. //
  3336. // Turn off the hour glass.
  3337. //
  3338. HourGlass(FALSE);
  3339. break;
  3340. }
  3341. case ( IDC_PRINT_TO_FILE ) :
  3342. {
  3343. //
  3344. // Enable the Apply button.
  3345. //
  3346. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3347. break;
  3348. }
  3349. case ( IDC_REFRESH ) :
  3350. {
  3351. if (psv)
  3352. {
  3353. psv->Refresh();
  3354. }
  3355. break;
  3356. }
  3357. default :
  3358. {
  3359. break;
  3360. }
  3361. }
  3362. //
  3363. // Return FALSE.
  3364. //
  3365. return (FALSE);
  3366. }
  3367. ////////////////////////////////////////////////////////////////////////////
  3368. //
  3369. // CPrintBrowser::OnChildCommandMessage
  3370. //
  3371. // Process a WM_COMMAND message for the child window.
  3372. //
  3373. ////////////////////////////////////////////////////////////////////////////
  3374. BOOL CPrintBrowser::OnChildCommandMessage(
  3375. WPARAM wParam,
  3376. LPARAM lParam)
  3377. {
  3378. HWND hCtl;
  3379. RECT rc;
  3380. DWORD nTmpCopies;
  3381. BOOL bTest;
  3382. switch (LOWORD(wParam))
  3383. {
  3384. case ( IDC_RANGE_ALL ) : // Print Range - All
  3385. case ( IDC_RANGE_SELECTION ) : // Print Range - Selection
  3386. case ( IDC_RANGE_CURRENT ) : // Print Range - Current Page
  3387. case ( IDC_RANGE_PAGES ) : // Print Range - Pages
  3388. {
  3389. CheckRadioButton( hSubDlg,
  3390. IDC_RANGE_ALL,
  3391. IDC_RANGE_PAGES,
  3392. GET_WM_COMMAND_ID(wParam, lParam) );
  3393. //
  3394. // Only move the focus to the "Pages" edit control when
  3395. // the up/down arrow is NOT used.
  3396. //
  3397. if ( !IS_KEY_PRESSED(VK_UP) &&
  3398. !IS_KEY_PRESSED(VK_DOWN) &&
  3399. ((BOOL)(GET_WM_COMMAND_ID(wParam, lParam) == IDC_RANGE_PAGES)) )
  3400. {
  3401. SendMessage( hSubDlg,
  3402. WM_NEXTDLGCTL,
  3403. (WPARAM)GetDlgItem(hSubDlg, IDC_RANGE_EDIT),
  3404. 1L );
  3405. }
  3406. //
  3407. // Enable the Apply button.
  3408. //
  3409. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3410. break;
  3411. }
  3412. case ( IDC_RANGE_EDIT ) : // Print Range - Pages edit control
  3413. {
  3414. if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
  3415. {
  3416. CheckRadioButton( hSubDlg,
  3417. IDC_RANGE_ALL,
  3418. IDC_RANGE_PAGES,
  3419. IDC_RANGE_PAGES );
  3420. //
  3421. // Enable the Apply button.
  3422. //
  3423. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3424. }
  3425. break;
  3426. }
  3427. case ( IDC_COPIES ) :
  3428. {
  3429. if ((GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) &&
  3430. (fAPWSelected == FALSE))
  3431. {
  3432. //
  3433. // Save the number of copies.
  3434. //
  3435. nTmpCopies = nCopies;
  3436. nCopies = GetDlgItemInt(hSubDlg, IDC_COPIES, &bTest, FALSE);
  3437. if (!bTest || !nCopies)
  3438. {
  3439. nCopies = nTmpCopies;
  3440. }
  3441. //
  3442. // If the printer can support collate and copy count > 1, enable collate.
  3443. // Otherwise, disable it.
  3444. //
  3445. if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE))
  3446. {
  3447. EnableWindow( hCtl, (fAllowCollate && (nCopies > 1) ? TRUE : FALSE) );
  3448. }
  3449. //
  3450. // Enable the Apply button.
  3451. //
  3452. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3453. }
  3454. break;
  3455. }
  3456. case ( IDC_COLLATE ) :
  3457. {
  3458. fCollateRequested = (IsDlgButtonChecked(hSubDlg, IDC_COLLATE))
  3459. ? TRUE
  3460. : FALSE;
  3461. if (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE))
  3462. {
  3463. ShowWindow(hCtl, SW_HIDE);
  3464. SendMessage( hCtl,
  3465. STM_SETICON,
  3466. fCollateRequested
  3467. ? (LONG_PTR)hIconCollate
  3468. : (LONG_PTR)hIconNoCollate,
  3469. 0L );
  3470. ShowWindow(hCtl, SW_SHOW);
  3471. //
  3472. // Make it redraw to get rid of the old one.
  3473. //
  3474. GetWindowRect(hCtl, &rc);
  3475. MapWindowRect(NULL, hwndDlg, &rc);
  3476. RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE);
  3477. }
  3478. //
  3479. // Enable the Apply button.
  3480. //
  3481. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3482. break;
  3483. }
  3484. default :
  3485. {
  3486. break;
  3487. }
  3488. }
  3489. //
  3490. // Return FALSE.
  3491. //
  3492. return (FALSE);
  3493. }
  3494. ////////////////////////////////////////////////////////////////////////////
  3495. //
  3496. // CPrintBrowser::OnNotifyMessage
  3497. //
  3498. // Process WM_NOTIFY messages for the General page.
  3499. //
  3500. ////////////////////////////////////////////////////////////////////////////
  3501. BOOL CPrintBrowser::OnNotifyMessage(
  3502. WPARAM wParam,
  3503. LPNMHDR pnm)
  3504. {
  3505. HWND hCtl;
  3506. LPDEVMODE pDM;
  3507. LPDEVNAMES pDN;
  3508. LRESULT lResult;
  3509. switch (pnm->code)
  3510. {
  3511. case ( PSN_SETACTIVE ) :
  3512. {
  3513. break;
  3514. }
  3515. case ( PSN_KILLACTIVE ) :
  3516. {
  3517. //
  3518. // Validation of the copies and page range values is done
  3519. // in the HandleMessage function for the sub dialog.
  3520. //
  3521. break;
  3522. }
  3523. case ( PSN_APPLY ) :
  3524. {
  3525. //
  3526. // Save the current printer information.
  3527. //
  3528. if (!GetCurrentPrinter() || !pDMCur)
  3529. {
  3530. ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected);
  3531. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
  3532. return (TRUE);
  3533. }
  3534. //
  3535. // Clear the flags that need to be set based on the contents
  3536. // of the General page.
  3537. //
  3538. pPD->Flags &= ~((DWORD)( PD_PRINTTOFILE |
  3539. PD_COLLATE |
  3540. PD_PAGENUMS |
  3541. PD_SELECTION |
  3542. PD_CURRENTPAGE ));
  3543. //
  3544. // Save the collate information.
  3545. //
  3546. if ((hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) &&
  3547. (fAPWSelected == FALSE))
  3548. {
  3549. if (IsDlgButtonChecked(hSubDlg, IDC_COLLATE))
  3550. {
  3551. pPD->Flags |= PD_COLLATE;
  3552. }
  3553. else
  3554. {
  3555. pPD->Flags &= ~PD_COLLATE;
  3556. }
  3557. }
  3558. //
  3559. // Save the info that the user hit OK.
  3560. //
  3561. pPI->FinalResult = 1;
  3562. pPI->fApply = TRUE;
  3563. //
  3564. // Save the print to file information.
  3565. //
  3566. if (IsDlgButtonChecked(hwndDlg, IDC_PRINT_TO_FILE))
  3567. {
  3568. pPD->Flags |= PD_PRINTTOFILE;
  3569. }
  3570. //
  3571. // Save the view mode for the printer folder.
  3572. //
  3573. SetViewMode();
  3574. //
  3575. // Disable the Apply button.
  3576. //
  3577. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  3578. break;
  3579. }
  3580. case PSN_LASTCHANCEAPPLY:
  3581. {
  3582. //
  3583. // Save the current printer information.
  3584. //
  3585. if (!GetCurrentPrinter() || !pDMCur)
  3586. {
  3587. ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected);
  3588. return (TRUE);
  3589. }
  3590. //
  3591. // Save the number of copies.
  3592. //
  3593. if ((hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) &&
  3594. (fAPWSelected == FALSE))
  3595. {
  3596. pPD->nCopies = nCopies;
  3597. if(!SetCopiesOnApply())
  3598. {
  3599. nCopies = pPD->nCopies;
  3600. SetDlgItemInt(hSubDlg, IDC_COPIES, nCopies, FALSE);
  3601. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
  3602. return (TRUE);
  3603. }
  3604. }
  3605. //
  3606. // Save the DevMode information.
  3607. //
  3608. SaveDevMode();
  3609. //
  3610. // Save the DevNames information.
  3611. //
  3612. if (!Print_SaveDevNames(pszCurPrinter, pPD))
  3613. {
  3614. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  3615. pPI->hResult = CreateError();
  3616. pPI->FinalResult = 0;
  3617. }
  3618. //
  3619. // Save the hDC or hIC, depending on which flag is set.
  3620. //
  3621. if (pPI->FinalResult)
  3622. {
  3623. pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode);
  3624. pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames);
  3625. if (pDM && pDN)
  3626. {
  3627. PrintReturnICDC((LPPRINTDLG)pPD, pDN, pDM);
  3628. }
  3629. if (pDM)
  3630. {
  3631. GlobalUnlock(pPD->hDevMode);
  3632. }
  3633. if (pDN)
  3634. {
  3635. GlobalUnlock(pPD->hDevNames);
  3636. }
  3637. }
  3638. break;
  3639. }
  3640. case ( PSN_QUERYCANCEL ) :
  3641. {
  3642. break;
  3643. }
  3644. case ( PSN_RESET ) :
  3645. {
  3646. //
  3647. // Save the info that the user hit CANCEL.
  3648. //
  3649. pPI->FinalResult = 0;
  3650. //
  3651. // Save the view mode for the printer folder.
  3652. //
  3653. SetViewMode();
  3654. break;
  3655. }
  3656. default :
  3657. {
  3658. break;
  3659. }
  3660. }
  3661. //
  3662. // Notify the sub dialog.
  3663. //
  3664. if (Print_IsInRange(pnm->code, PSN_LAST, PSN_FIRST) &&
  3665. (HandleMessage(hSubDlg, WM_NOTIFY, wParam, (LPARAM)pnm, &lResult) !=
  3666. S_FALSE))
  3667. {
  3668. //
  3669. // The return from a dlgproc is different than a winproc. The lResult is
  3670. // the real result.
  3671. //
  3672. return (BOOLFROMPTR(lResult) );
  3673. }
  3674. //
  3675. // Return FALSE.
  3676. //
  3677. return (FALSE);
  3678. }
  3679. ////////////////////////////////////////////////////////////////////////////
  3680. //
  3681. // CPrintBrowser::OnSelChange
  3682. //
  3683. // Process a CDM_SELCHANGE message for the dialog.
  3684. //
  3685. ////////////////////////////////////////////////////////////////////////////
  3686. BOOL CPrintBrowser::OnSelChange()
  3687. {
  3688. HRESULT hres;
  3689. LPCITEMIDLIST *ppidlSel = NULL;
  3690. UINT uItems = 0;
  3691. UINT uCount = 0;
  3692. TCHAR szPrinterNameBuf[kPrinterBufMax];
  3693. BOOL bChanged = FALSE;
  3694. HRESULT hr = S_OK;
  3695. //
  3696. // We get this message during init, so use it to set the
  3697. // initial selection.
  3698. //
  3699. if (fFirstSel)
  3700. {
  3701. //
  3702. // Select the appropriate item in the list view.
  3703. //
  3704. // If an item cannot be selected, it probably means that the
  3705. // printer that was passed in has been deleted. In this case,
  3706. // insert the driver pages and select the default printer.
  3707. //
  3708. if (!SelectSVItem())
  3709. {
  3710. //
  3711. // Insert the device page for the default printer.
  3712. //
  3713. if (FAILED(InstallDevMode(NULL, NULL)))
  3714. {
  3715. UninstallDevMode();
  3716. }
  3717. //
  3718. // Get the current printer and select the appropriate item
  3719. // in the list view.
  3720. //
  3721. SelectSVItem();
  3722. }
  3723. //
  3724. // Notify the sub dialog that the selection changed.
  3725. //
  3726. SelectionChange();
  3727. //
  3728. // Disable the Apply button if it's the very first time
  3729. // (during initialization).
  3730. //
  3731. if (fFirstSel == 1)
  3732. {
  3733. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  3734. }
  3735. //
  3736. // Reset the flags.
  3737. //
  3738. fFirstSel = 0;
  3739. fSelChangePending = FALSE;
  3740. //
  3741. // Return success.
  3742. //
  3743. return (TRUE);
  3744. }
  3745. //
  3746. // Reset the flag.
  3747. //
  3748. fSelChangePending = FALSE;
  3749. //
  3750. // Make sure we have the shell folder view interface.
  3751. //
  3752. if (!psfv)
  3753. {
  3754. return (FALSE);
  3755. }
  3756. //
  3757. // Get the selected object in the print folder.
  3758. //
  3759. hres = psfv->GetSelectedObjects(&ppidlSel, &uItems);
  3760. if (SUCCEEDED(hres) && (uItems > 0) && ppidlSel && *ppidlSel)
  3761. {
  3762. //
  3763. // Get the printer name.
  3764. //
  3765. szPrinterNameBuf[0] = 0;
  3766. GetViewItemText( psfRoot,
  3767. *ppidlSel,
  3768. szPrinterNameBuf,
  3769. ARRAYSIZE(szPrinterNameBuf),
  3770. SHGDN_FORPARSING);
  3771. // if the selection is same as current printer
  3772. if (pszCurPrinter && (lstrcmpi(szPrinterNameBuf, pszCurPrinter) == 0))
  3773. {
  3774. //Dont do anything.
  3775. LocalFree(ppidlSel);
  3776. return TRUE;
  3777. }
  3778. //
  3779. // See if it's the Add Printer Wizard.
  3780. //
  3781. if (lstrcmpi(szPrinterNameBuf, TEXT("WinUtils_NewObject")) == 0)
  3782. {
  3783. //
  3784. // It's the Add Printer Wizard.
  3785. //
  3786. fAPWSelected = TRUE;
  3787. //
  3788. // Disable the OK and Apply buttons.
  3789. //
  3790. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE);
  3791. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  3792. //
  3793. // Save the current devmode settings for selection changes.
  3794. //
  3795. if (pDMCur && pDMSave)
  3796. {
  3797. CopyMemory( pDMSave,
  3798. pDMCur,
  3799. (pDMCur->dmSize > sizeof(DEVMODE))
  3800. ? sizeof(DEVMODE)
  3801. : pDMCur->dmSize );
  3802. }
  3803. //
  3804. // Remove the device pages, since no printer is selected.
  3805. //
  3806. if (SUCCEEDED(UninstallDevMode()))
  3807. {
  3808. bChanged = TRUE;
  3809. }
  3810. //
  3811. // Update the current printer information and the printer
  3812. // status text (all should be empty).
  3813. //
  3814. GetCurrentPrinter();
  3815. UpdateStatus(NULL);
  3816. //
  3817. // Notify the sub dialog that the selection changed.
  3818. //
  3819. if (bChanged)
  3820. {
  3821. SelectionChange();
  3822. bChanged = FALSE;
  3823. }
  3824. }
  3825. else
  3826. {
  3827. //
  3828. // It's not the Add Printer Wizard.
  3829. //
  3830. fAPWSelected = FALSE;
  3831. if (!MergeDevMode(szPrinterNameBuf))
  3832. {
  3833. hr = InstallDevMode(szPrinterNameBuf, NULL);
  3834. }
  3835. if (SUCCEEDED(hr))
  3836. {
  3837. bChanged = TRUE;
  3838. }
  3839. else if (SUCCEEDED(UninstallDevMode()))
  3840. {
  3841. bChanged = TRUE;
  3842. }
  3843. //
  3844. // Get the current printer name and the current devmode and
  3845. // update the printer status text.
  3846. //
  3847. GetCurrentPrinter();
  3848. if (SUCCEEDED(hr))
  3849. {
  3850. //
  3851. // Clear the no access printer flag.
  3852. //
  3853. fNoAccessPrinterSelected = FALSE;
  3854. //
  3855. // Make sure the OK button is enabled.
  3856. //
  3857. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), TRUE);
  3858. //
  3859. // Update the printer status.
  3860. //
  3861. UpdateStatus(*ppidlSel);
  3862. }
  3863. else
  3864. {
  3865. //
  3866. // Save the fact we do not have access to this printer.
  3867. //
  3868. if (ERROR_ACCESS_DENIED == HRESULT_CODE(hr))
  3869. {
  3870. fNoAccessPrinterSelected = TRUE;
  3871. }
  3872. //
  3873. // Disable the OK and Apply buttons.
  3874. //
  3875. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE);
  3876. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  3877. //
  3878. // Nuke the status.
  3879. //
  3880. UpdateStatus(NULL);
  3881. }
  3882. }
  3883. //
  3884. // Free the pidl.
  3885. //
  3886. LocalFree(ppidlSel);
  3887. }
  3888. //
  3889. // See if anything changed.
  3890. //
  3891. if (bChanged)
  3892. {
  3893. //
  3894. // Enable the Apply button.
  3895. //
  3896. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  3897. //
  3898. // Notify the sub dialog that the selection changed.
  3899. //
  3900. SelectionChange();
  3901. }
  3902. //
  3903. // Return success.
  3904. //
  3905. return (TRUE);
  3906. }
  3907. ////////////////////////////////////////////////////////////////////////////
  3908. //
  3909. // CPrintBrowser::IsCurrentPrinter
  3910. //
  3911. // Checks whether the given pidl represents the current printer
  3912. //
  3913. ////////////////////////////////////////////////////////////////////////////
  3914. BOOL CPrintBrowser::IsCurrentPrinter(LPCITEMIDLIST pidl)
  3915. {
  3916. TCHAR szPrinterBufName[kPrinterBufMax];
  3917. if (pszCurPrinter)
  3918. {
  3919. szPrinterBufName[0] = 0;
  3920. GetViewItemText( psfRoot,
  3921. pidl,
  3922. szPrinterBufName,
  3923. ARRAYSIZE(szPrinterBufName),
  3924. SHGDN_FORPARSING);
  3925. if (lstrcmpi(szPrinterBufName, pszCurPrinter) == 0)
  3926. {
  3927. return TRUE;
  3928. }
  3929. }
  3930. return FALSE;
  3931. }
  3932. ////////////////////////////////////////////////////////////////////////////
  3933. //
  3934. // CPrintBrowser::OnRename
  3935. //
  3936. // Handles the Rename Notification
  3937. //
  3938. ////////////////////////////////////////////////////////////////////////////
  3939. BOOL CPrintBrowser::OnRename(LPCITEMIDLIST *ppidl)
  3940. {
  3941. TCHAR szPrinterBufName[kPrinterBufMax];
  3942. LPITEMIDLIST pidl;
  3943. TCHAR szNewPrinter[kPrinterBufMax];
  3944. pidl = ILFindLastID(ppidl[0]);
  3945. szNewPrinter[0] = 0;
  3946. GetViewItemText( psfRoot,
  3947. ILFindLastID(ppidl[1]),
  3948. szNewPrinter,
  3949. ARRAYSIZE(szNewPrinter),
  3950. SHGDN_FORPARSING);
  3951. //Has user clicked on Apply and saved any printer information ?
  3952. if (pPI->fApply)
  3953. {
  3954. //Yes. Check if the printer that is renamed is the one that is saved.
  3955. LPDEVNAMES pDN;
  3956. if ((pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames)))
  3957. {
  3958. //Get the saved printer name from the DEVNAMES structure.
  3959. szPrinterBufName[0] = 0;
  3960. GetViewItemText( psfRoot,
  3961. pidl,
  3962. szPrinterBufName,
  3963. ARRAYSIZE(szPrinterBufName),
  3964. SHGDN_FORPARSING);
  3965. //Is the saved printer and renamed printer the same ?
  3966. if (!lstrcmpi(szPrinterBufName, ((LPTSTR)pDN + pDN->wDeviceOffset)))
  3967. {
  3968. //Yes. Updated the saved DEVMODE and DEVNAMES Structure.
  3969. LPDEVMODE pDM;
  3970. //Update the dev names struture with the new printer name.
  3971. Print_SaveDevNames(szNewPrinter, pPD);
  3972. //Update the device name in the devmode to new name
  3973. if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode)))
  3974. {
  3975. lstrcpyn(pDM->dmDeviceName, szNewPrinter, CCHDEVICENAME);
  3976. GlobalUnlock(pPD->hDevMode);
  3977. }
  3978. }
  3979. GlobalUnlock(pPD->hDevNames);
  3980. }
  3981. }
  3982. if (IsCurrentPrinter(pidl))
  3983. {
  3984. if (!MergeDevMode(szNewPrinter))
  3985. {
  3986. InstallDevMode(szNewPrinter, NULL);
  3987. }
  3988. }
  3989. return TRUE;
  3990. }
  3991. ////////////////////////////////////////////////////////////////////////////
  3992. //
  3993. // CPrintBrowser::OnChangeNotify
  3994. //
  3995. // Handle the change notification message.
  3996. //
  3997. ////////////////////////////////////////////////////////////////////////////
  3998. BOOL CPrintBrowser::OnChangeNotify(
  3999. LONG lNotification,
  4000. LPCITEMIDLIST *ppidl)
  4001. {
  4002. LPCITEMIDLIST pidl;
  4003. UINT uRes = 0;
  4004. TCHAR szPrinterBufName[kPrinterBufMax];
  4005. //
  4006. // Get the pidl for the object.
  4007. //
  4008. pidl = ILFindLastID(ppidl[0]);
  4009. //
  4010. // Handle the notification.
  4011. //
  4012. switch (lNotification)
  4013. {
  4014. case ( SHCNE_ATTRIBUTES ) :
  4015. case ( SHCNE_UPDATEITEM ) :
  4016. {
  4017. if (NULL == pidl || ILIsEqual(ppidl[0], pidlRoot))
  4018. {
  4019. // pidl is NULL or equal to the local PF which means that full refresh
  4020. // has been requested. if the current object is the APW then try to select
  4021. // a printer.
  4022. if (!fSelChangePending)
  4023. {
  4024. fFirstSel = 2;
  4025. fSelChangePending = TRUE;
  4026. PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0);
  4027. }
  4028. }
  4029. else
  4030. {
  4031. //
  4032. // If the selected object is the one that changed, then
  4033. // update the status text.
  4034. if (IsCurrentPrinter(pidl))
  4035. {
  4036. UpdateStatus(pidl);
  4037. //
  4038. // Reinit the copies and collate because these attributes may be changed
  4039. //
  4040. InitCopiesAndCollate();
  4041. }
  4042. }
  4043. break;
  4044. }
  4045. case ( SHCNE_RENAMEITEM ) :
  4046. {
  4047. OnRename(ppidl);
  4048. break;
  4049. }
  4050. case ( SHCNE_CREATE ) :
  4051. {
  4052. //
  4053. // If the Add Printer Wizard is selected when we get this
  4054. // message, then select the newly created object.
  4055. //
  4056. if (fAPWSelected == TRUE)
  4057. {
  4058. //
  4059. // Get the printer name.
  4060. //
  4061. szPrinterBufName[0] = 0;
  4062. GetViewItemText( psfRoot,
  4063. pidl,
  4064. szPrinterBufName,
  4065. ARRAYSIZE(szPrinterBufName),
  4066. SHGDN_FORPARSING);
  4067. //
  4068. // Add the appropriate device pages and select the
  4069. // new printer.
  4070. //
  4071. if (!MergeDevMode(szPrinterBufName))
  4072. {
  4073. InstallDevMode(szPrinterBufName, NULL);
  4074. }
  4075. if (!fSelChangePending)
  4076. {
  4077. fFirstSel = 2;
  4078. fSelChangePending = TRUE;
  4079. PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0);
  4080. }
  4081. }
  4082. break;
  4083. }
  4084. case ( SHCNE_DELETE ) :
  4085. {
  4086. //
  4087. // Save the current devmode settings for selection changes.
  4088. //
  4089. if (pDMCur && pDMSave)
  4090. {
  4091. CopyMemory( pDMSave,
  4092. pDMCur,
  4093. (pDMCur->dmSize > sizeof(DEVMODE))
  4094. ? sizeof(DEVMODE)
  4095. : pDMCur->dmSize );
  4096. }
  4097. //
  4098. // Check if the current printer has just been deleted.
  4099. // If so - set appropriate flag and disable the print button.
  4100. if (IsCurrentPrinter(pidl))
  4101. {
  4102. TCHAR szSavePrinterName[kPrinterBufMax];
  4103. StringCchCopy(szSavePrinterName, ARRAYSIZE(szSavePrinterName), szPrinter);
  4104. //
  4105. // Uninstall the current devmode and select the new default
  4106. // printer if any.
  4107. //
  4108. UninstallDevMode();
  4109. InstallDevMode(NULL, NULL);
  4110. SelectSVItem();
  4111. //
  4112. // If the devmode editor is open, we need to notify the user
  4113. // that the printer has just been deleted.
  4114. //
  4115. if (fDevmodeEdit)
  4116. {
  4117. //
  4118. // Display error message which indicates that the printer you are currently
  4119. // editing properties for has just been deleted. Ask the user to close the
  4120. // driver UI dialog and select another printer.
  4121. //
  4122. fDirtyDevmode = TRUE;
  4123. ShowError(hwndDlg, 0, iszPrinterDeleted, szSavePrinterName);
  4124. }
  4125. }
  4126. break;
  4127. }
  4128. }
  4129. return (FALSE);
  4130. }
  4131. ////////////////////////////////////////////////////////////////////////////
  4132. //
  4133. // CPrintBrowser::OnAccelerator
  4134. //
  4135. // Handles an input event message.
  4136. //
  4137. ////////////////////////////////////////////////////////////////////////////
  4138. BOOL CPrintBrowser::OnAccelerator(
  4139. HWND hwndActivePrint,
  4140. HWND hwndFocus,
  4141. HACCEL haccPrint,
  4142. PMSG pMsg)
  4143. {
  4144. if (psv && (hwndFocus == hwndView))
  4145. {
  4146. if (psv->TranslateAccelerator(pMsg) == S_OK)
  4147. {
  4148. return (1);
  4149. }
  4150. if (haccPrint &&
  4151. TranslateAccelerator(hwndActivePrint, haccPrint, pMsg))
  4152. {
  4153. return (1);
  4154. }
  4155. }
  4156. //
  4157. // Return that the message was not handled.
  4158. //
  4159. return (0);
  4160. }
  4161. ////////////////////////////////////////////////////////////////////////////
  4162. //
  4163. // CPrintBrowser::OnNoPrinters
  4164. //
  4165. // Displays a message box telling the user that they have no printers
  4166. // installed.
  4167. //
  4168. ////////////////////////////////////////////////////////////////////////////
  4169. VOID CPrintBrowser::OnNoPrinters(HWND hDlg, HRESULT hr)
  4170. {
  4171. switch (HRESULT_CODE(hr))
  4172. {
  4173. case ERROR_FILE_NOT_FOUND:
  4174. {
  4175. //
  4176. // ERROR_FILE_NOT_FOUND means there are no printer's installed.
  4177. //
  4178. if (IDYES == ShowMessage(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinters, MB_YESNO|MB_ICONQUESTION, FALSE))
  4179. {
  4180. //
  4181. // invoke the add printer wizard here
  4182. //
  4183. InvokeAddPrinterWizardModal(hwndDlg, NULL);
  4184. }
  4185. }
  4186. break;
  4187. case ERROR_ACCESS_DENIED:
  4188. {
  4189. //
  4190. // Access is denied.
  4191. //
  4192. ShowError(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterAccess);
  4193. }
  4194. break;
  4195. default:
  4196. {
  4197. //
  4198. // Some other error have occured.
  4199. //
  4200. ShowError(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected);
  4201. }
  4202. break;
  4203. }
  4204. }
  4205. ////////////////////////////////////////////////////////////////////////////
  4206. //
  4207. // CPrintBrowser::OnInitDone
  4208. //
  4209. // Handle the CDM_INITDONE message. Initialization is complete, so
  4210. // call IPrintDialogCallback::InitDone and then switch to the chosen
  4211. // start page if it's not the General page.
  4212. //
  4213. ////////////////////////////////////////////////////////////////////////////
  4214. VOID CPrintBrowser::OnInitDone()
  4215. {
  4216. //
  4217. // See if we need to do this anymore. This routine shouldn't be
  4218. // entered more than twice, but just in case.
  4219. //
  4220. if (nInitDone != -1)
  4221. {
  4222. //
  4223. // Make sure we have seen the CDM_INITDONE message for the
  4224. // completion of both the main dialog and the sub dialog.
  4225. //
  4226. if (nInitDone < 1)
  4227. {
  4228. //
  4229. // We only want to go through this code once.
  4230. //
  4231. nInitDone = -1;
  4232. //
  4233. // Tell the sub dialog that initialization is complete.
  4234. //
  4235. InitDone();
  4236. //
  4237. // Switch to the appropriate start page.
  4238. //
  4239. if (pPD->nStartPage != START_PAGE_GENERAL)
  4240. {
  4241. PropSheet_SetCurSel( GetParent(hwndDlg),
  4242. NULL,
  4243. pPD->nStartPage + 1 );
  4244. }
  4245. }
  4246. else
  4247. {
  4248. nInitDone++;
  4249. }
  4250. }
  4251. }
  4252. ////////////////////////////////////////////////////////////////////////////
  4253. //
  4254. // CPrintBrowser::CreatePrintShellView
  4255. //
  4256. // Creates the shell view window for the printer folder.
  4257. //
  4258. ////////////////////////////////////////////////////////////////////////////
  4259. HRESULT CPrintBrowser::CreatePrintShellView()
  4260. {
  4261. RECT rcView;
  4262. FOLDERSETTINGS fs;
  4263. HRESULT hResult;
  4264. HWND hHiddenText;
  4265. //
  4266. // Get the Printer Folder pidl.
  4267. //
  4268. pidlRoot = SHCloneSpecialIDList(hwndDlg, CSIDL_PRINTERS, TRUE);
  4269. if (!pidlRoot)
  4270. {
  4271. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4272. return (E_FAIL);
  4273. }
  4274. //
  4275. // Create an instance of IShellFolder and store it in the CPrintBrowser
  4276. // class.
  4277. //
  4278. hResult = Print_ICoCreateInstance( CLSID_CPrinters,
  4279. IID_IShellFolder2,
  4280. pidlRoot,
  4281. (LPVOID *)&psfRoot );
  4282. if (FAILED(hResult))
  4283. {
  4284. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4285. return (hResult);
  4286. }
  4287. //
  4288. // Get the private printer folder interface.
  4289. //
  4290. hResult = psfRoot->QueryInterface(IID_IPrinterFolder, (LPVOID *)&ppf);
  4291. if (FAILED(hResult))
  4292. {
  4293. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4294. return (hResult);
  4295. }
  4296. //
  4297. // Create the printer folder view.
  4298. //
  4299. GetWindowRect(GetDlgItem(hwndDlg, IDC_PRINTER_LIST), &rcView);
  4300. MapWindowRect(HWND_DESKTOP, hwndDlg, &rcView);
  4301. fs.ViewMode = GetViewMode();
  4302. fs.fFlags = FWF_AUTOARRANGE | FWF_SINGLESEL | FWF_ALIGNLEFT |
  4303. FWF_SHOWSELALWAYS;
  4304. hResult = psfRoot->CreateViewObject(hwndDlg, IID_IShellView, (LPVOID *)&psv);
  4305. if (FAILED(hResult))
  4306. {
  4307. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4308. return (hResult);
  4309. }
  4310. hResult = psv->CreateViewWindow(NULL, &fs, this, &rcView, &hwndView);
  4311. if (FAILED(hResult))
  4312. {
  4313. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4314. return (hResult);
  4315. }
  4316. hResult = psv->UIActivate(SVUIA_INPLACEACTIVATE);
  4317. if (FAILED(hResult))
  4318. {
  4319. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4320. return (hResult);
  4321. }
  4322. //
  4323. // Get the shell folder view interface.
  4324. //
  4325. hResult = psv->QueryInterface(IID_IShellFolderView, (LPVOID *)&psfv);
  4326. if (FAILED(hResult))
  4327. {
  4328. pPI->dwExtendedError = CDERR_INITIALIZATION;
  4329. return (hResult);
  4330. }
  4331. //
  4332. // Move the view window to the right spot in the Z (tab) order.
  4333. //
  4334. SetWindowPos( hwndView,
  4335. HWND_TOP,
  4336. 0, 0, 0, 0,
  4337. SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE );
  4338. //
  4339. // Give it the right window ID for WinHelp and error selection.
  4340. //
  4341. SetWindowLong(hwndView, GWL_ID, IDC_PRINTER_LISTVIEW);
  4342. //
  4343. // Move the hidden text ahead of the list view, thus the parent name of
  4344. // the list view in MSAA is "Select Printer"
  4345. //
  4346. if (hHiddenText = GetDlgItem(hwndDlg, IDC_HIDDEN_TEXT))
  4347. {
  4348. SetParent(hHiddenText, hwndView);
  4349. SetWindowPos(hHiddenText,
  4350. HWND_TOP,
  4351. 0, 0, 0, 0,
  4352. SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOACTIVATE);
  4353. }
  4354. //
  4355. // Show the window after creating the ShellView so we do not get a
  4356. // big ugly gray spot.
  4357. //
  4358. ShowWindow(hwndDlg, SW_SHOW);
  4359. UpdateWindow(hwndDlg);
  4360. //
  4361. // Return success.
  4362. //
  4363. return (S_OK);
  4364. }
  4365. ////////////////////////////////////////////////////////////////////////////
  4366. //
  4367. // CPrintBrowser::GetViewMode
  4368. //
  4369. // Gets the view mode for the printer folder.
  4370. //
  4371. ////////////////////////////////////////////////////////////////////////////
  4372. UINT CPrintBrowser::GetViewMode()
  4373. {
  4374. HKEY hKey;
  4375. UINT ViewMode = FVM_ICON;
  4376. DWORD cbData;
  4377. //
  4378. // Open the Printers\Settings registry key and read the information
  4379. // from the ViewMode value entry.
  4380. //
  4381. if (RegOpenKeyEx( HKEY_CURRENT_USER,
  4382. c_szSettings,
  4383. 0L,
  4384. KEY_READ,
  4385. &hKey ) == ERROR_SUCCESS)
  4386. {
  4387. cbData = sizeof(ViewMode);
  4388. if (ERROR_SUCCESS == RegQueryValueEx(hKey, c_szViewMode, NULL, NULL, (LPBYTE)&ViewMode, &cbData))
  4389. {
  4390. //
  4391. // A "real" mode exist in the registry. Don't make
  4392. // smart decisions for the view mode thereafter.
  4393. //
  4394. uDefViewMode = ViewMode;
  4395. }
  4396. RegCloseKey(hKey);
  4397. }
  4398. //
  4399. // Make sure it's in the correct range.
  4400. //
  4401. if (ViewMode > FVM_DETAILS)
  4402. {
  4403. ViewMode = FVM_ICON;
  4404. }
  4405. //
  4406. // Return the view mode.
  4407. //
  4408. return (ViewMode);
  4409. }
  4410. ////////////////////////////////////////////////////////////////////////////
  4411. //
  4412. // CPrintBrowser::SetViewMode
  4413. //
  4414. // Gets the view mode for the printer folder.
  4415. //
  4416. ////////////////////////////////////////////////////////////////////////////
  4417. VOID CPrintBrowser::SetViewMode()
  4418. {
  4419. HWND hwndListView;
  4420. HKEY hKey;
  4421. UINT ViewMode = VIEW_MODE_DEFAULT;
  4422. DWORD cbData;
  4423. //
  4424. // Get the current view mode.
  4425. //
  4426. if (psv && (hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL)))
  4427. {
  4428. FOLDERSETTINGS fs;
  4429. psv->GetCurrentInfo(&fs);
  4430. ViewMode = fs.ViewMode;
  4431. }
  4432. //
  4433. // Check if the user changed the view mode
  4434. //
  4435. if( uDefViewMode != ViewMode )
  4436. {
  4437. //
  4438. // Open the Printers\Settings registry key and save the information
  4439. // to the ViewMode value entry.
  4440. //
  4441. if (RegOpenKeyEx( HKEY_CURRENT_USER,
  4442. c_szSettings,
  4443. 0L,
  4444. KEY_READ | KEY_WRITE,
  4445. &hKey ) == ERROR_SUCCESS)
  4446. {
  4447. cbData = sizeof(ViewMode);
  4448. RegSetValueEx(hKey, c_szViewMode, 0L, REG_DWORD, (LPBYTE)&ViewMode, cbData);
  4449. RegCloseKey(hKey);
  4450. }
  4451. }
  4452. }
  4453. ////////////////////////////////////////////////////////////////////////////
  4454. //
  4455. // CPrintBrowser::CreateHookDialog
  4456. //
  4457. // Creates the child window for the application specific area of the
  4458. // General page.
  4459. //
  4460. ////////////////////////////////////////////////////////////////////////////
  4461. HRESULT CPrintBrowser::CreateHookDialog()
  4462. {
  4463. DWORD Flags = pPD->Flags;
  4464. HANDLE hTemplate;
  4465. HINSTANCE hinst;
  4466. LPCTSTR pDlg;
  4467. RECT rcChild;
  4468. DWORD dwStyle;
  4469. LANGID LangID = (LANGID)TlsGetValue(g_tlsLangID);
  4470. //
  4471. // See if there is a template.
  4472. //
  4473. if (Flags & PD_ENABLEPRINTTEMPLATEHANDLE)
  4474. {
  4475. hTemplate = pPD->hInstance;
  4476. hinst = ::g_hinst;
  4477. }
  4478. else
  4479. {
  4480. if (Flags & PD_ENABLEPRINTTEMPLATE)
  4481. {
  4482. pDlg = pPD->lpPrintTemplateName;
  4483. hinst = pPD->hInstance;
  4484. LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  4485. }
  4486. else
  4487. {
  4488. hinst = ::g_hinst;
  4489. pDlg = MAKEINTRESOURCE(PRINTDLGEXORD);
  4490. }
  4491. HRSRC hRes = FindResourceExFallback(hinst, RT_DIALOG, pDlg, LangID);
  4492. if (hRes == NULL)
  4493. {
  4494. pPI->dwExtendedError = CDERR_FINDRESFAILURE;
  4495. return (E_HANDLE);
  4496. }
  4497. if ((hTemplate = LoadResource(hinst, hRes)) == NULL)
  4498. {
  4499. pPI->dwExtendedError = CDERR_LOADRESFAILURE;
  4500. return (E_HANDLE);
  4501. }
  4502. }
  4503. //
  4504. // Lock the resource.
  4505. //
  4506. if (!LockResource(hTemplate))
  4507. {
  4508. pPI->dwExtendedError = CDERR_LOADRESFAILURE;
  4509. return (E_HANDLE);
  4510. }
  4511. //
  4512. // Make sure the template is a child window.
  4513. //
  4514. dwStyle = ((LPDLGTEMPLATE)hTemplate)->style;
  4515. if (!(dwStyle & WS_CHILD))
  4516. {
  4517. //
  4518. // I don't want to go poking in their template, and I don't want to
  4519. // make a copy, so I will just fail. This also helps us weed out
  4520. // "old-style" templates that were accidentally used.
  4521. //
  4522. pPI->dwExtendedError = CDERR_DIALOGFAILURE;
  4523. return (E_INVALIDARG);
  4524. }
  4525. //
  4526. // Get the callback interface pointer, if necessary.
  4527. //
  4528. if (pPD->lpCallback)
  4529. {
  4530. pPD->lpCallback->QueryInterface( IID_IPrintDialogCallback,
  4531. (LPVOID *)&pCallback );
  4532. }
  4533. //
  4534. // Create the child dialog.
  4535. //
  4536. hSubDlg = CreateDialogIndirectParam( hinst,
  4537. (LPDLGTEMPLATE)hTemplate,
  4538. hwndDlg,
  4539. Print_GeneralChildDlgProc,
  4540. (LPARAM)pPD );
  4541. if (!hSubDlg)
  4542. {
  4543. pPI->dwExtendedError = CDERR_DIALOGFAILURE;
  4544. return (E_HANDLE);
  4545. }
  4546. //
  4547. // Put the window in the designated spot on the General property page.
  4548. //
  4549. GetWindowRect(GetDlgItem(hwndDlg, grp2), &rcChild);
  4550. MapWindowRect(NULL, hwndDlg, &rcChild);
  4551. SetWindowPos( hSubDlg,
  4552. HWND_BOTTOM,
  4553. rcChild.left,
  4554. rcChild.top,
  4555. rcChild.right - rcChild.left,
  4556. rcChild.bottom - rcChild.top,
  4557. SWP_SHOWWINDOW );
  4558. //
  4559. // Return success.
  4560. //
  4561. return (S_OK);
  4562. }
  4563. ////////////////////////////////////////////////////////////////////////////
  4564. //
  4565. // CPrintBrowser::UpdateStatus
  4566. //
  4567. // Updates the static text for the currently selected printer.
  4568. // The fields that are set are Status, Location, and Comment.
  4569. //
  4570. ////////////////////////////////////////////////////////////////////////////
  4571. BOOL CPrintBrowser::UpdateStatus(
  4572. LPCITEMIDLIST pidl)
  4573. {
  4574. HRESULT hres;
  4575. SHELLDETAILS Details;
  4576. TCHAR szText[MAX_PATH];
  4577. //
  4578. // If the pidl is NULL, then reset all of the static text to null
  4579. // strings.
  4580. //
  4581. if (!pidl)
  4582. {
  4583. szText[0] = 0;
  4584. SetDlgItemText(hwndDlg, IDC_STATUS, szText);
  4585. UpdateWindow(GetDlgItem(hwndDlg, IDC_STATUS));
  4586. SetDlgItemText(hwndDlg, IDC_LOCATION, szText);
  4587. UpdateWindow(GetDlgItem(hwndDlg, IDC_LOCATION));
  4588. SetDlgItemText(hwndDlg, IDC_COMMENT, szText);
  4589. UpdateWindow(GetDlgItem(hwndDlg, IDC_COMMENT));
  4590. return (TRUE);
  4591. }
  4592. //
  4593. // Get the STATUS details for the given object.
  4594. //
  4595. szText[0] = 0;
  4596. hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_STATUS, &Details);
  4597. if (FAILED(hres) ||
  4598. !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL))
  4599. {
  4600. szText[0] = 0;
  4601. }
  4602. SetDlgItemText(hwndDlg, IDC_STATUS, szText);
  4603. UpdateWindow(GetDlgItem(hwndDlg, IDC_STATUS));
  4604. //
  4605. // Get the LOCATION details for the given object.
  4606. //
  4607. szText[0] = 0;
  4608. hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_LOCATION, &Details);
  4609. if (FAILED(hres) ||
  4610. !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL))
  4611. {
  4612. szText[0] = 0;
  4613. }
  4614. SetDlgItemText(hwndDlg, IDC_LOCATION, szText);
  4615. UpdateWindow(GetDlgItem(hwndDlg, IDC_LOCATION));
  4616. //
  4617. // Get the COMMENT details for the given object.
  4618. //
  4619. szText[0] = 0;
  4620. hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_COMMENT, &Details);
  4621. if (FAILED(hres) ||
  4622. !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL))
  4623. {
  4624. szText[0] = 0;
  4625. }
  4626. SetDlgItemText(hwndDlg, IDC_COMMENT, szText);
  4627. UpdateWindow(GetDlgItem(hwndDlg, IDC_COMMENT));
  4628. //
  4629. // Return success.
  4630. //
  4631. return (TRUE);
  4632. }
  4633. ////////////////////////////////////////////////////////////////////////////
  4634. //
  4635. // CPrintBrowser::SelectSVItem
  4636. //
  4637. // Selects the item in the shell view with the given printer name.
  4638. //
  4639. ////////////////////////////////////////////////////////////////////////////
  4640. BOOL CPrintBrowser::SelectSVItem()
  4641. {
  4642. HRESULT hr = E_FAIL;
  4643. LPITEMIDLIST pidlItem = NULL;
  4644. BOOL bPrinterSelected = FALSE;
  4645. // Make sure we have a shell view and a shell folder view.
  4646. if (psv && psfv)
  4647. {
  4648. // Make sure we have the current printer information.
  4649. GetCurrentPrinter();
  4650. if (!pDMCur || !pszCurPrinter || !pszCurPrinter[0])
  4651. {
  4652. // If there is no current printer then we just select the add printer
  4653. // wizard object.
  4654. hr = psfRoot->ParseDisplayName(hwndDlg, NULL, TEXT("WinUtils_NewObject"), NULL, &pidlItem, NULL);
  4655. if (SUCCEEDED(hr) && pidlItem)
  4656. {
  4657. // just select the APW special object
  4658. SelectPrinterItem(pidlItem);
  4659. // Free up the PIDL using the shell allocator
  4660. FreePIDL(pidlItem);
  4661. // It's the Add Printer Wizard.
  4662. fAPWSelected = TRUE;
  4663. // Disable the OK and Apply buttons.
  4664. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE);
  4665. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  4666. }
  4667. }
  4668. else
  4669. {
  4670. // there is a current printer then we just select it
  4671. hr = psfRoot->ParseDisplayName(hwndDlg, NULL, pszCurPrinter, NULL, &pidlItem, NULL);
  4672. if (SUCCEEDED(hr) && pidlItem)
  4673. {
  4674. // select the printer and update the status
  4675. SelectPrinterItem(pidlItem);
  4676. UpdateStatus(pidlItem);
  4677. // Free up the PIDL using the shell allocator
  4678. FreePIDL(pidlItem);
  4679. // It's not the Add Printer Wizard.
  4680. fAPWSelected = FALSE;
  4681. // Enable the OK and Apply buttons.
  4682. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), TRUE);
  4683. PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
  4684. // A printer object has been selected
  4685. bPrinterSelected = TRUE;
  4686. }
  4687. }
  4688. }
  4689. return SUCCEEDED(hr) ? bPrinterSelected : FALSE;
  4690. }
  4691. ////////////////////////////////////////////////////////////////////////////
  4692. //
  4693. // CPrintBrowser::GetCurrentPrinter
  4694. //
  4695. // Saves the current printer name and the current devmode in the class.
  4696. //
  4697. ////////////////////////////////////////////////////////////////////////////
  4698. BOOL CPrintBrowser::GetCurrentPrinter()
  4699. {
  4700. DWORD dwSize = cchCurPrinter;
  4701. //
  4702. // Reset the devmode and the current printer string.
  4703. //
  4704. pDMCur = NULL;
  4705. if (pszCurPrinter && cchCurPrinter)
  4706. {
  4707. pszCurPrinter[0] = 0;
  4708. }
  4709. //
  4710. // Get the name of the current printer.
  4711. //
  4712. if (!GetInternalPrinterName(pszCurPrinter, &dwSize))
  4713. {
  4714. //
  4715. // Allocate a buffer large enough to hold the name of the
  4716. // current printer.
  4717. //
  4718. if (dwSize > cchCurPrinter)
  4719. {
  4720. if (pszCurPrinter)
  4721. {
  4722. LPTSTR pTemp = pszCurPrinter;
  4723. pszCurPrinter = NULL;
  4724. cchCurPrinter = 0;
  4725. GlobalFree(pTemp);
  4726. }
  4727. pszCurPrinter = (LPTSTR)GlobalAlloc(GPTR, dwSize * sizeof(TCHAR));
  4728. if (!pszCurPrinter)
  4729. {
  4730. return (FALSE);
  4731. }
  4732. cchCurPrinter = dwSize;
  4733. if (cchCurPrinter)
  4734. {
  4735. pszCurPrinter[0] = 0;
  4736. }
  4737. }
  4738. //
  4739. // Try to get the name of the current printer again.
  4740. //
  4741. if (!GetInternalPrinterName(pszCurPrinter,&dwSize))
  4742. {
  4743. return (FALSE);
  4744. }
  4745. }
  4746. //
  4747. // Get the current devmode.
  4748. //
  4749. pDMCur = GetCurrentDevMode();
  4750. if (!pDMCur)
  4751. {
  4752. pszCurPrinter[0] = 0;
  4753. return (FALSE);
  4754. }
  4755. //
  4756. // Return success.
  4757. //
  4758. return (TRUE);
  4759. }
  4760. ////////////////////////////////////////////////////////////////////////////
  4761. //
  4762. // CPrintBrowser::InitPrintToFile
  4763. //
  4764. // Initializes the print to file on a selection change.
  4765. //
  4766. ////////////////////////////////////////////////////////////////////////////
  4767. VOID CPrintBrowser::InitPrintToFile()
  4768. {
  4769. HWND hCtl = GetDlgItem(hwndDlg, IDC_PRINT_TO_FILE);
  4770. //
  4771. // See if there is a Print To File control.
  4772. //
  4773. if (hCtl)
  4774. {
  4775. //
  4776. // See if a printer is selected.
  4777. //
  4778. if (pDMCur)
  4779. {
  4780. //
  4781. // A printer is selected, so enable the print to file if
  4782. // appropriate.
  4783. //
  4784. if (!(pPI->dwFlags & (PD_HIDEPRINTTOFILE | PD_DISABLEPRINTTOFILE)))
  4785. {
  4786. EnableWindow(hCtl, TRUE);
  4787. }
  4788. }
  4789. else
  4790. {
  4791. //
  4792. // A printer is not selected, so disable it.
  4793. //
  4794. EnableWindow(hCtl, FALSE);
  4795. }
  4796. }
  4797. }
  4798. ////////////////////////////////////////////////////////////////////////////
  4799. //
  4800. // CPrintBrowser::InitPageRangeGroup
  4801. //
  4802. // Initializes the page range group on a selection change. It decides
  4803. // which controls should be enabled when a selection change occurs from
  4804. // the Add Printer Wizard.
  4805. //
  4806. ////////////////////////////////////////////////////////////////////////////
  4807. VOID CPrintBrowser::InitPageRangeGroup()
  4808. {
  4809. //
  4810. // See if a printer is selected.
  4811. //
  4812. if (pDMCur)
  4813. {
  4814. //
  4815. // A printer is selected, so enable the appropriate page range
  4816. // controls.
  4817. //
  4818. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_ALL), TRUE);
  4819. if (!(pPI->dwFlags & PD_NOSELECTION))
  4820. {
  4821. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_SELECTION), TRUE);
  4822. }
  4823. if (!(pPI->dwFlags & PD_NOCURRENTPAGE))
  4824. {
  4825. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_CURRENT), TRUE);
  4826. }
  4827. if (!(pPI->dwFlags & PD_NOPAGENUMS))
  4828. {
  4829. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), TRUE);
  4830. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), TRUE);
  4831. }
  4832. }
  4833. else
  4834. {
  4835. //
  4836. // A printer is not selected, so disable all of the page range
  4837. // controls.
  4838. //
  4839. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_ALL), FALSE);
  4840. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_SELECTION), FALSE);
  4841. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_CURRENT), FALSE);
  4842. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE);
  4843. EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE);
  4844. }
  4845. }
  4846. ////////////////////////////////////////////////////////////////////////////
  4847. //
  4848. // CPrintBrowser::InitCopiesAndCollate
  4849. //
  4850. // Initializes the copies and collate information in the devmode and the
  4851. // print dialog structure.
  4852. //
  4853. ////////////////////////////////////////////////////////////////////////////
  4854. VOID CPrintBrowser::InitCopiesAndCollate()
  4855. {
  4856. HWND hCtl;
  4857. UINT IsCollate = FALSE;
  4858. RECT rc;
  4859. BOOL bEnabledCopies = TRUE;
  4860. //
  4861. // Save the collate state so that the collate icon doesn't flicker on
  4862. // a selection change.
  4863. //
  4864. if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE))
  4865. {
  4866. IsCollate = IsDlgButtonChecked(hSubDlg, IDC_COLLATE);
  4867. }
  4868. //
  4869. // See what the printer driver can do and what the app requested
  4870. // and set the copies and collate accordingly.
  4871. //
  4872. if (pDMCur)
  4873. {
  4874. //
  4875. // If PD_USEDEVMODECOPIES(COLLATE), disable copies if the driver
  4876. // cannot copy.
  4877. //
  4878. if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES))
  4879. {
  4880. //
  4881. // Modify the edit control and up-down arrow if needed
  4882. //
  4883. WORD cDigits;
  4884. //
  4885. // If the calling application handles copies and collate, we
  4886. // set max copies as 9999, else, we get the max copies from driver
  4887. //
  4888. if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE)
  4889. {
  4890. szScratch[0] = 0;
  4891. Print_GetPortName(pszCurPrinter, szScratch, ARRAYSIZE(szScratch));
  4892. nMaxCopies = DeviceCapabilities( pszCurPrinter,
  4893. szScratch,
  4894. DC_COPIES,
  4895. NULL,
  4896. NULL );
  4897. //
  4898. // If DeviceCapabilities() returns error, disable the controls
  4899. //
  4900. if ((nMaxCopies < 1) || (nMaxCopies == (DWORD)(-1)))
  4901. {
  4902. nMaxCopies = 1;
  4903. nCopies = 1;
  4904. bEnabledCopies = FALSE;
  4905. }
  4906. }
  4907. else
  4908. {
  4909. //
  4910. // Assume the calling app will take care of multi-copies
  4911. //
  4912. nMaxCopies = MAX_COPIES;
  4913. }
  4914. if (nMaxCopies < nCopies)
  4915. {
  4916. nCopies = nMaxCopies;
  4917. }
  4918. cDigits = CountDigits(nMaxCopies);
  4919. Edit_LimitText(hCtl, cDigits);
  4920. SendMessage(GetDlgItem(hSubDlg, IDC_COPIES_UDARROW), UDM_SETRANGE,
  4921. 0, MAKELONG(nMaxCopies, 1));
  4922. InvalidateRect(GetDlgItem(hSubDlg, IDC_COPIES_UDARROW), NULL, FALSE);
  4923. }
  4924. //
  4925. // If PD_USEDEVMODECOPIES(COLLATE), disable collate if the driver
  4926. // cannot collate.
  4927. //
  4928. if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE))
  4929. {
  4930. DWORD dwCollate;
  4931. BOOL bEnabled = TRUE;
  4932. if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE)
  4933. {
  4934. szScratch[0] = 0;
  4935. Print_GetPortName(pszCurPrinter, szScratch, ARRAYSIZE(szScratch));
  4936. dwCollate = DeviceCapabilities( pszCurPrinter,
  4937. szScratch,
  4938. DC_COLLATE,
  4939. NULL,
  4940. NULL );
  4941. fAllowCollate = ((dwCollate < 1) || (dwCollate == (DWORD)-1)) ? FALSE : TRUE;
  4942. }
  4943. else
  4944. {
  4945. //
  4946. // Assume the calling app will take care of collation
  4947. //
  4948. fAllowCollate = TRUE;
  4949. }
  4950. if ( fAllowCollate )
  4951. {
  4952. EnableWindow(hCtl, (nCopies > 1));
  4953. CheckDlgButton( hSubDlg,
  4954. IDC_COLLATE,
  4955. fCollateRequested ? TRUE : FALSE );
  4956. }
  4957. else
  4958. {
  4959. EnableWindow(hCtl, FALSE);
  4960. CheckDlgButton(hSubDlg, IDC_COLLATE, FALSE);
  4961. }
  4962. //
  4963. // Display the appropriate collate icon if it changed.
  4964. //
  4965. if ((hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) &&
  4966. (IsCollate != IsDlgButtonChecked(hSubDlg, IDC_COLLATE)))
  4967. {
  4968. ShowWindow(hCtl, SW_HIDE);
  4969. SendMessage( hCtl,
  4970. STM_SETICON,
  4971. IsCollate
  4972. ? (LONG_PTR)hIconNoCollate
  4973. : (LONG_PTR)hIconCollate,
  4974. 0L );
  4975. ShowWindow(hCtl, SW_SHOW);
  4976. //
  4977. // Make it redraw to get rid of the old one.
  4978. //
  4979. GetWindowRect(hCtl, &rc);
  4980. MapWindowRect(NULL, hwndDlg, &rc);
  4981. RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE);
  4982. }
  4983. }
  4984. //
  4985. // We have to do it here because after setting the text, fAllowCollate
  4986. // will be used
  4987. //
  4988. if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES))
  4989. {
  4990. SetDlgItemInt(hSubDlg, IDC_COPIES, nCopies, FALSE);
  4991. EnableWindow(hCtl, bEnabledCopies);
  4992. EnableWindow(hwndUpDown, bEnabledCopies);
  4993. }
  4994. }
  4995. else if (fNoAccessPrinterSelected)
  4996. {
  4997. // if No Access Printer is selected merely disable the Copies and Collate
  4998. // Dont change any information user entered.
  4999. if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES))
  5000. {
  5001. EnableWindow(hCtl, FALSE);
  5002. EnableWindow(hwndUpDown, FALSE);
  5003. }
  5004. if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE))
  5005. {
  5006. EnableWindow(hCtl, FALSE);
  5007. }
  5008. //
  5009. // Disable the Apply button It gets turned back on when the copies and collate values are
  5010. // disabled.
  5011. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  5012. }
  5013. else
  5014. {
  5015. //
  5016. // A printer is not selected, so disable copies and collate.
  5017. //
  5018. if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES))
  5019. {
  5020. SetDlgItemInt(hSubDlg, IDC_COPIES, 1, FALSE);
  5021. EnableWindow(hCtl, FALSE);
  5022. EnableWindow(hwndUpDown, FALSE);
  5023. }
  5024. if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE))
  5025. {
  5026. EnableWindow(hCtl, FALSE);
  5027. CheckDlgButton(hSubDlg, IDC_COLLATE, FALSE);
  5028. if ((hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) && IsCollate)
  5029. {
  5030. ShowWindow(hCtl, SW_HIDE);
  5031. SendMessage( hCtl,
  5032. STM_SETICON,
  5033. (LONG_PTR)hIconNoCollate,
  5034. 0L );
  5035. ShowWindow(hCtl, SW_SHOW);
  5036. //
  5037. // Make it redraw to get rid of the old one.
  5038. //
  5039. GetWindowRect(hCtl, &rc);
  5040. MapWindowRect(NULL, hwndDlg, &rc);
  5041. RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE);
  5042. }
  5043. }
  5044. //
  5045. // Disable the Apply button since a printer is not selected.
  5046. // It gets turned back on when the copies and collate values are
  5047. // disabled.
  5048. //
  5049. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
  5050. }
  5051. }
  5052. ////////////////////////////////////////////////////////////////////////////
  5053. //
  5054. // CPrintBrowser::SaveCopiesAndCollateInDevMode
  5055. //
  5056. // Saves the copies and collate information in the given devmode. This
  5057. // routine does not affect the pPD structure.
  5058. //
  5059. ////////////////////////////////////////////////////////////////////////////
  5060. BOOL CPrintBrowser::SaveCopiesAndCollateInDevMode(
  5061. LPDEVMODE pDM,
  5062. LPTSTR pszPrinter)
  5063. {
  5064. //
  5065. // Make sure we have a devmode and a printer name.
  5066. //
  5067. if (!pDM || !pszPrinter || !(pszPrinter[0]))
  5068. {
  5069. return (FALSE);
  5070. }
  5071. //
  5072. // verify number of copies is less than max value
  5073. //
  5074. if( nMaxCopies < nCopies )
  5075. {
  5076. return (FALSE);
  5077. }
  5078. //
  5079. // Move the info to the devmode.
  5080. //
  5081. pDM->dmCopies = (short)nCopies;
  5082. SetField(pDM, dmCollate, (fAllowCollate && fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE));
  5083. //
  5084. // Return success.
  5085. //
  5086. return (TRUE);
  5087. }
  5088. ////////////////////////////////////////////////////////////////////////////
  5089. //
  5090. // CPrintBrowser::SetCopiesOnApply
  5091. //
  5092. // Sets the appropriate number of copies in the PrintDlgEx structure and
  5093. // in the DevMode structure.
  5094. //
  5095. ////////////////////////////////////////////////////////////////////////////
  5096. BOOL CPrintBrowser::SetCopiesOnApply()
  5097. {
  5098. if (pDMCur)
  5099. {
  5100. if (!(pDMCur->dmFields & DM_COPIES))
  5101. {
  5102. Print_LeaveInfoInPD:
  5103. //
  5104. // The driver cannot do copies, so leave the copy/collate
  5105. // info in the pPD.
  5106. //
  5107. pDMCur->dmCopies = 1;
  5108. SetField(pDMCur, dmCollate, DMCOLLATE_FALSE);
  5109. }
  5110. else if ((pDMCur->dmSpecVersion < 0x0400) ||
  5111. (!(pDMCur->dmFields & DM_COLLATE)))
  5112. {
  5113. //
  5114. // The driver can do copies, but not collate.
  5115. // Where the info goes depends on the PD_COLLATE flag.
  5116. //
  5117. if (pPD->Flags & PD_COLLATE)
  5118. {
  5119. goto Print_LeaveInfoInPD;
  5120. }
  5121. else
  5122. {
  5123. goto Print_PutInfoInDevMode;
  5124. }
  5125. }
  5126. else
  5127. {
  5128. Print_PutInfoInDevMode:
  5129. //
  5130. // Make sure we have a current printer.
  5131. //
  5132. if (!pszCurPrinter)
  5133. {
  5134. goto Print_LeaveInfoInPD;
  5135. }
  5136. //
  5137. // Make sure the driver can support the number of copies
  5138. // requested.
  5139. //
  5140. if (nMaxCopies < pPD->nCopies)
  5141. {
  5142. if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE)
  5143. {
  5144. ShowError(hSubDlg, IDC_COPIES, iszTooManyCopies, nMaxCopies);
  5145. pPD->nCopies = nMaxCopies;
  5146. return (FALSE);
  5147. }
  5148. else
  5149. {
  5150. goto Print_LeaveInfoInPD;
  5151. }
  5152. }
  5153. //
  5154. // The driver can do both copies and collate, so move the info
  5155. // to the devmode.
  5156. //
  5157. pDMCur->dmCopies = (short)pPD->nCopies;
  5158. SetField( pDMCur,
  5159. dmCollate,
  5160. (fAllowCollate && (pPD->Flags & PD_COLLATE))
  5161. ? DMCOLLATE_TRUE
  5162. : DMCOLLATE_FALSE );
  5163. pPD->nCopies = 1;
  5164. pPD->Flags &= ~PD_COLLATE;
  5165. }
  5166. }
  5167. //
  5168. // Return success.
  5169. //
  5170. return (TRUE);
  5171. }
  5172. ////////////////////////////////////////////////////////////////////////////
  5173. //
  5174. // CPrintBrowser::SaveDevMode
  5175. //
  5176. // Saves the current devmode in the pPD structure on Apply.
  5177. // Assumes pDMCur has the current information.
  5178. //
  5179. ////////////////////////////////////////////////////////////////////////////
  5180. VOID CPrintBrowser::SaveDevMode()
  5181. {
  5182. DWORD cbSize;
  5183. HANDLE hDevMode = NULL;
  5184. LPDEVMODE pDM;
  5185. //
  5186. // Allocate the space for the new DevMode and copy the
  5187. // information.
  5188. //
  5189. if (pDMCur)
  5190. {
  5191. cbSize = (DWORD)(pDMCur->dmSize + pDMCur->dmDriverExtra);
  5192. hDevMode = GlobalAlloc(GHND, cbSize);
  5193. if (hDevMode)
  5194. {
  5195. pDM = (LPDEVMODE)GlobalLock(hDevMode);
  5196. if (pDM)
  5197. {
  5198. CopyMemory(pDM, pDMCur, cbSize);
  5199. GlobalUnlock(hDevMode);
  5200. }
  5201. else
  5202. {
  5203. GlobalFree(hDevMode);
  5204. hDevMode = NULL;
  5205. }
  5206. }
  5207. }
  5208. if (!hDevMode)
  5209. {
  5210. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  5211. pPI->hResult = E_OUTOFMEMORY;
  5212. pPI->FinalResult = 0;
  5213. }
  5214. //
  5215. // Free the copy of the DevMode handle passed in by the app.
  5216. //
  5217. if (pPD->hDevMode)
  5218. {
  5219. GlobalFree(pPD->hDevMode);
  5220. pPD->hDevMode = NULL;
  5221. }
  5222. //
  5223. // Save the new DevMode in the pPD structure.
  5224. //
  5225. pPD->hDevMode = hDevMode;
  5226. }
  5227. ////////////////////////////////////////////////////////////////////////////
  5228. //
  5229. // CPrintBrowser::MergeDevMode
  5230. //
  5231. // Merges the current devmode with the default devmode of the newly
  5232. // selected printer.
  5233. //
  5234. ////////////////////////////////////////////////////////////////////////////
  5235. BOOL CPrintBrowser::MergeDevMode(
  5236. LPTSTR pszPrinterName)
  5237. {
  5238. HANDLE hDevMode = NULL;
  5239. LPDEVMODE pDMNew = NULL;
  5240. LPDEVMODE pDMOld = NULL;
  5241. BOOL bRet = TRUE;
  5242. DWORD dmFields;
  5243. short dmDefaultSource;
  5244. //
  5245. // See if the printer name is NULL. If so, we need to get the default
  5246. // printer loaded. This happens when a printer is deleted.
  5247. //
  5248. if (!pszPrinterName)
  5249. {
  5250. ASSERT(0);
  5251. return FALSE;
  5252. }
  5253. else
  5254. {
  5255. //
  5256. // Get the devmode for the old (current driver pages) printer.
  5257. //
  5258. GetCurrentPrinter();
  5259. pDMOld = pDMCur ? pDMCur : pDMSave;
  5260. if (!pDMOld)
  5261. {
  5262. return (FALSE);
  5263. }
  5264. hDevMode = Print_GetDevModeWrapper(pszPrinterName);
  5265. if (hDevMode)
  5266. {
  5267. pDMNew = (LPDEVMODE)GlobalLock(hDevMode);
  5268. }
  5269. else
  5270. {
  5271. return FALSE;
  5272. }
  5273. if (!pDMNew)
  5274. {
  5275. GlobalFree(hDevMode);
  5276. return FALSE;
  5277. }
  5278. dmFields = 0;
  5279. dmDefaultSource = pDMNew->dmDefaultSource;
  5280. if (pDMNew->dmFields & DM_DEFAULTSOURCE)
  5281. {
  5282. dmFields = DM_DEFAULTSOURCE;
  5283. }
  5284. //Check if the old devmode has any info to copy
  5285. if (pDMOld->dmFields)
  5286. {
  5287. CopyMemory(&(pDMNew->dmFields),
  5288. &(pDMOld->dmFields),
  5289. sizeof(DEVMODE) - FIELD_OFFSET(DEVMODE, dmFields));
  5290. }
  5291. pDMNew->dmFields |= dmFields;
  5292. pDMNew->dmDefaultSource = dmDefaultSource;
  5293. pDMNew->dmFields = pDMNew->dmFields & ( DM_ORIENTATION | DM_PAPERSIZE |
  5294. DM_PAPERLENGTH | DM_PAPERWIDTH |
  5295. DM_SCALE | DM_COPIES |
  5296. DM_COLLATE | DM_FORMNAME |
  5297. DM_DEFAULTSOURCE);
  5298. //
  5299. // Insert the device pages - this call will yield a proper devmode.
  5300. //
  5301. if (FAILED(UninstallDevMode()) || FAILED(InstallDevMode(pszPrinterName, pDMNew)))
  5302. {
  5303. bRet = FALSE;
  5304. }
  5305. //Free the new devmode that was allocated
  5306. if (hDevMode)
  5307. {
  5308. GlobalUnlock(hDevMode);
  5309. GlobalFree(hDevMode);
  5310. }
  5311. }
  5312. //
  5313. // Return the result.
  5314. //
  5315. return (bRet);
  5316. }
  5317. ////////////////////////////////////////////////////////////////////////////
  5318. //
  5319. // CPrintBrowser::IsValidPageRange
  5320. //
  5321. // Checks the validity of the page range string.
  5322. //
  5323. ////////////////////////////////////////////////////////////////////////////
  5324. BOOL CPrintBrowser::IsValidPageRange(
  5325. LPTSTR pszString,
  5326. UINT *pErrorId)
  5327. {
  5328. LPTSTR pStr = pszString;
  5329. BOOL bDigit = FALSE;
  5330. BOOL bOld;
  5331. UINT Number, Ctr;
  5332. DWORD nNumRanges = 0;
  5333. BOOL bFrom = TRUE;
  5334. //
  5335. // Initially set the error id to 0.
  5336. //
  5337. *pErrorId = 0;
  5338. //
  5339. // See if we can only have a single page range.
  5340. //
  5341. bOld = (nMaxPageRanges == 1);
  5342. //
  5343. // Go through the string and validate the entries.
  5344. //
  5345. while (*pStr)
  5346. {
  5347. if (ISDIGIT(*pStr))
  5348. {
  5349. //
  5350. // Make sure there is room for another range.
  5351. //
  5352. if (nNumRanges >= nMaxPageRanges)
  5353. {
  5354. break;
  5355. }
  5356. //
  5357. // Found a digit.
  5358. //
  5359. bDigit = TRUE;
  5360. //
  5361. // Make sure the page number is in the given page range.
  5362. //
  5363. Number = 0;
  5364. while (ISDIGIT(*pStr))
  5365. {
  5366. Number *= 10;
  5367. Number += *pStr - TEXT('0');
  5368. pStr++;
  5369. }
  5370. pStr--;
  5371. if ((Number < pPD->nMinPage) || (Number > pPD->nMaxPage))
  5372. {
  5373. *pErrorId = iszBadPageRange;
  5374. return (FALSE);
  5375. }
  5376. //
  5377. // Save the value in the page range structure.
  5378. //
  5379. if (bFrom)
  5380. {
  5381. pPageRanges[nNumRanges].nFromPage = Number;
  5382. bFrom = FALSE;
  5383. }
  5384. else
  5385. {
  5386. pPageRanges[nNumRanges].nToPage = Number;
  5387. bFrom = TRUE;
  5388. nNumRanges++;
  5389. }
  5390. }
  5391. else if (*pStr == TEXT('-'))
  5392. {
  5393. //
  5394. // Found a hyphen. Make sure there is a digit preceding it
  5395. // and following it. Also, make sure there isn't something
  5396. // like 1-2-3.
  5397. //
  5398. if (!bDigit || bFrom || !ISDIGIT(*(pStr + 1)))
  5399. {
  5400. *pErrorId = bOld ? iszBadPageRangeSyntaxOld
  5401. : iszBadPageRangeSyntaxNew;
  5402. return (FALSE);
  5403. }
  5404. bDigit = FALSE;
  5405. }
  5406. else if ((*pStr == szListSep[0]) || (*pStr == TEXT(',')))
  5407. {
  5408. //
  5409. // Found a list separator. Make sure there is a digit
  5410. // preceding it.
  5411. //
  5412. if (!bDigit)
  5413. {
  5414. *pErrorId = bOld ? iszBadPageRangeSyntaxOld
  5415. : iszBadPageRangeSyntaxNew;
  5416. return (FALSE);
  5417. }
  5418. bDigit = FALSE;
  5419. //
  5420. // If it's the list separator string instead of the simple
  5421. // comma, then make sure the entire list separator string
  5422. // is there.
  5423. // This will advance the string up to the last character
  5424. // of the list separator string.
  5425. //
  5426. if ((*pStr == szListSep[0]) &&
  5427. ((szListSep[0] != TEXT(',')) || (!ISDIGIT(*(pStr + 1)))))
  5428. {
  5429. for (Ctr = 1; Ctr < nListSep; Ctr++)
  5430. {
  5431. pStr++;
  5432. if (*pStr != szListSep[Ctr])
  5433. {
  5434. *pErrorId = bOld ? iszBadPageRangeSyntaxOld
  5435. : iszBadPageRangeSyntaxNew;
  5436. return (FALSE);
  5437. }
  5438. }
  5439. }
  5440. //
  5441. // Make sure the From/To page range is complete.
  5442. //
  5443. if (!bFrom)
  5444. {
  5445. pPageRanges[nNumRanges].nToPage = pPageRanges[nNumRanges].nFromPage;
  5446. bFrom = TRUE;
  5447. nNumRanges++;
  5448. }
  5449. }
  5450. else
  5451. {
  5452. //
  5453. // Found an invalid character.
  5454. //
  5455. *pErrorId = bOld ? iszBadPageRangeSyntaxOld
  5456. : iszBadPageRangeSyntaxNew;
  5457. return (FALSE);
  5458. }
  5459. //
  5460. // Advance the string pointer.
  5461. //
  5462. pStr++;
  5463. }
  5464. //
  5465. // Make sure we reached the end of the string.
  5466. //
  5467. if (*pStr)
  5468. {
  5469. *pErrorId = iszTooManyPageRanges;
  5470. return (FALSE);
  5471. }
  5472. //
  5473. // Make sure the last thing in the string was a digit.
  5474. //
  5475. if (!bDigit)
  5476. {
  5477. *pErrorId = bOld ? iszBadPageRangeSyntaxOld
  5478. : iszBadPageRangeSyntaxNew;
  5479. return (FALSE);
  5480. }
  5481. //
  5482. // Make sure the last From/To page range is complete.
  5483. //
  5484. if (!bFrom)
  5485. {
  5486. pPageRanges[nNumRanges].nToPage = pPageRanges[nNumRanges].nFromPage;
  5487. bFrom = TRUE;
  5488. nNumRanges++;
  5489. }
  5490. //
  5491. // Save the number of page ranges.
  5492. //
  5493. nPageRanges = nNumRanges;
  5494. //
  5495. // Return success.
  5496. //
  5497. return (TRUE);
  5498. }
  5499. ////////////////////////////////////////////////////////////////////////////
  5500. //
  5501. // CPrintBrowser::ConvertPageRangesToString
  5502. //
  5503. // Converts the page ranges to a string.
  5504. //
  5505. ////////////////////////////////////////////////////////////////////////////
  5506. BOOL CPrintBrowser::ConvertPageRangesToString(
  5507. LPTSTR pszString,
  5508. UINT cchLen)
  5509. {
  5510. LPTSTR pStr = pszString;
  5511. DWORD nFromPage, nToPage;
  5512. UINT cch = cchLen - 1;
  5513. UINT Ctr, Ctr2, Count;
  5514. //
  5515. // Initialize the string.
  5516. //
  5517. if (cchLen)
  5518. {
  5519. pszString[0] = 0;
  5520. }
  5521. //
  5522. // Validate the ranges and create the string.
  5523. //
  5524. for (Ctr = 0; Ctr < nPageRanges; Ctr++)
  5525. {
  5526. //
  5527. // Get the range.
  5528. //
  5529. nFromPage = pPageRanges[Ctr].nFromPage;
  5530. nToPage = pPageRanges[Ctr].nToPage;
  5531. //
  5532. // Make sure the range is valid.
  5533. //
  5534. if ((nFromPage < pPD->nMinPage) || (nFromPage > pPD->nMaxPage) ||
  5535. (nToPage < pPD->nMinPage) || (nToPage > pPD->nMaxPage))
  5536. {
  5537. return (FALSE);
  5538. }
  5539. //
  5540. // Make sure it's not 0xFFFFFFFF.
  5541. //
  5542. if (nFromPage == 0xFFFFFFFF)
  5543. {
  5544. continue;
  5545. }
  5546. //
  5547. // Put it in the string.
  5548. //
  5549. Count = IntegerToString(nFromPage, pStr, cch);
  5550. if (!Count)
  5551. {
  5552. return (FALSE);
  5553. }
  5554. pStr += Count;
  5555. cch -= Count;
  5556. if ((nFromPage == nToPage) || (nToPage == 0xFFFFFFFF))
  5557. {
  5558. if (Ctr < nPageRanges - 1)
  5559. {
  5560. if (cch < nListSep)
  5561. {
  5562. return (FALSE);
  5563. }
  5564. for (Ctr2 = 0; Ctr2 < nListSep; Ctr2++)
  5565. {
  5566. *pStr = szListSep[Ctr2];
  5567. pStr++;
  5568. }
  5569. cch -= nListSep;
  5570. }
  5571. }
  5572. else
  5573. {
  5574. if (!cch)
  5575. {
  5576. return (FALSE);
  5577. }
  5578. *pStr = TEXT('-');
  5579. pStr++;
  5580. cch--;
  5581. Count = IntegerToString(nToPage, pStr, cch);
  5582. if (!Count)
  5583. {
  5584. return (FALSE);
  5585. }
  5586. pStr += Count;
  5587. cch -= Count;
  5588. if (Ctr < nPageRanges - 1)
  5589. {
  5590. if (cch < nListSep)
  5591. {
  5592. return (FALSE);
  5593. }
  5594. for (Ctr2 = 0; Ctr2 < nListSep; Ctr2++)
  5595. {
  5596. *pStr = szListSep[Ctr2];
  5597. pStr++;
  5598. }
  5599. cch -= nListSep;
  5600. }
  5601. }
  5602. }
  5603. *pStr = '\0';
  5604. //
  5605. // Return success.
  5606. //
  5607. return (TRUE);
  5608. }
  5609. ////////////////////////////////////////////////////////////////////////////
  5610. //
  5611. // CPrintBrowser::IntegerToString
  5612. //
  5613. // Converts an integer to a string and returns the number of characters
  5614. // written to the buffer (not including the null).
  5615. //
  5616. ////////////////////////////////////////////////////////////////////////////
  5617. UINT CPrintBrowser::IntegerToString(
  5618. DWORD Value,
  5619. LPTSTR pszString,
  5620. UINT cchLen)
  5621. {
  5622. DWORD TempValue = Value;
  5623. UINT NumChars = 1;
  5624. UINT Ctr;
  5625. //
  5626. // Get the number of characters needed.
  5627. //
  5628. while (TempValue = TempValue / 10)
  5629. {
  5630. NumChars++;
  5631. }
  5632. //
  5633. // Make sure there is enough room in the buffer.
  5634. //
  5635. if (NumChars > cchLen)
  5636. {
  5637. return (0);
  5638. }
  5639. //
  5640. // Make the string.
  5641. //
  5642. TempValue = Value;
  5643. for (Ctr = NumChars; Ctr > 0; Ctr--)
  5644. {
  5645. pszString[Ctr - 1] = ((WORD)(TempValue % 10)) + TEXT('0');
  5646. TempValue = TempValue / 10;
  5647. }
  5648. //
  5649. // Return the number of characters written to the buffer.
  5650. //
  5651. return (NumChars);
  5652. }
  5653. ////////////////////////////////////////////////////////////////////////////
  5654. //
  5655. // CPrintBrowser::ShowError
  5656. //
  5657. // Shows up an error message box
  5658. //
  5659. ////////////////////////////////////////////////////////////////////////////
  5660. VOID CPrintBrowser::ShowError(HWND hDlg, UINT uCtrlID, UINT uMsgID, ...)
  5661. {
  5662. va_list args;
  5663. va_start(args, uMsgID);
  5664. InternalShowMessage(hDlg, uCtrlID, uMsgID, MB_ICONEXCLAMATION|MB_OK, TRUE, args);
  5665. va_end(args);
  5666. }
  5667. ////////////////////////////////////////////////////////////////////////////
  5668. //
  5669. // CPrintBrowser::ShowMessage
  5670. //
  5671. // Shows up a message box with the specified flags & parameters
  5672. //
  5673. ////////////////////////////////////////////////////////////////////////////
  5674. int CPrintBrowser::ShowMessage(HWND hDlg, UINT uCtrlID, UINT uMsgID, UINT uType, BOOL bBeep, ...)
  5675. {
  5676. va_list args;
  5677. va_start(args, bBeep);
  5678. int iRet = InternalShowMessage(hDlg, uCtrlID, uMsgID, uType, bBeep, args);
  5679. va_end(args);
  5680. return iRet;
  5681. }
  5682. ////////////////////////////////////////////////////////////////////////////
  5683. //
  5684. // CPrintBrowser::InternalShowMessage
  5685. //
  5686. // Shows up a message box with the specified flags & parameters
  5687. // Internal version
  5688. //
  5689. // Assumes the control is not disabled.
  5690. //
  5691. ////////////////////////////////////////////////////////////////////////////
  5692. int CPrintBrowser::InternalShowMessage(HWND hDlg, UINT uCtrlID, UINT uMsgID, UINT uType, BOOL bBeep, va_list args)
  5693. {
  5694. int iRet = IDCANCEL;
  5695. if (!(pPI->dwFlags & PD_NOWARNING))
  5696. {
  5697. TCHAR szTitle[MAX_PATH];
  5698. TCHAR szFormat[MAX_PATH];
  5699. TCHAR szMessage[MAX_PATH];
  5700. //
  5701. // Get msg box title & load the format string
  5702. //
  5703. if ( GetWindowText(GetParent(hwndDlg), szTitle, ARRAYSIZE(szTitle)) &&
  5704. CDLoadString(g_hinst, uMsgID, szFormat, ARRAYSIZE(szFormat)) )
  5705. {
  5706. if (bBeep)
  5707. {
  5708. MessageBeep(MB_ICONEXCLAMATION);
  5709. }
  5710. //
  5711. // format the message to be shown and call MessageBox over
  5712. // the last active popup
  5713. //
  5714. wvnsprintf(szMessage, ARRAYSIZE(szMessage), szFormat, args);
  5715. HWND hWndOwner = ::GetWindow(GetParent(hwndDlg), GW_OWNER);
  5716. HWND hWndLastPopup = GetLastActivePopup(hWndOwner);
  5717. iRet = MessageBox(hWndLastPopup, szMessage, szTitle, uType);
  5718. }
  5719. HWND hCtrl = ((0 == uCtrlID) ? NULL : GetDlgItem(hDlg, uCtrlID));
  5720. if (hCtrl)
  5721. {
  5722. //
  5723. // select & highlight the invalid value. we assume it
  5724. // is an edit box, if it isn't then EM_SETSEL won't be
  5725. // processed and it's OK.
  5726. //
  5727. SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hCtrl, 1L);
  5728. SendMessage(hCtrl, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  5729. }
  5730. }
  5731. return iRet;
  5732. }
  5733. ////////////////////////////////////////////////////////////////////////////
  5734. //
  5735. // CPrintBrowser::FitViewModeBest
  5736. //
  5737. // Adjust the view mode if the mini printers folder, so the printer names
  5738. // fit best. This i8s necessary mainly because of accessibility problems.
  5739. //
  5740. ////////////////////////////////////////////////////////////////////////////
  5741. BOOL CPrintBrowser::FitViewModeBest(HWND hwndListView)
  5742. {
  5743. BOOL bResult = FALSE;
  5744. if (VIEW_MODE_DEFAULT == uDefViewMode)
  5745. {
  5746. //
  5747. // Asssume icon view by default.
  5748. //
  5749. uDefViewMode = FVM_ICON;
  5750. //
  5751. // If we are in a large icons view then check if something
  5752. // doesn't fit vertically - the only reliable way to do this
  5753. // is to check if we scrolled the view (origin.y > 0)
  5754. //
  5755. if (LVS_ICON == (GetWindowLong(hwndListView, GWL_STYLE) & LVS_TYPEMASK))
  5756. {
  5757. POINT ptOrg;
  5758. ListView_GetOrigin(hwndListView, &ptOrg);
  5759. if (ptOrg.y > 0)
  5760. {
  5761. //
  5762. // Switch the defview to List mode.
  5763. //
  5764. SendMessage(hwndView, WM_COMMAND, (WPARAM)SFVIDM_VIEW_LIST,0);
  5765. uDefViewMode = FVM_LIST;
  5766. bResult = TRUE;
  5767. }
  5768. }
  5769. }
  5770. return bResult;
  5771. }
  5772. VOID CPrintBrowser::SelectPrinterItem(LPITEMIDLIST pidlItem)
  5773. {
  5774. BOOL bLocked = FALSE;
  5775. HWND hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL);
  5776. if (hwndListView)
  5777. {
  5778. //
  5779. // Disable the window update to prevent flickers
  5780. //
  5781. bLocked = LockWindowUpdate(hwndListView);
  5782. }
  5783. //
  5784. // Try to make the printer item visible first
  5785. //
  5786. psv->SelectItem(pidlItem, SVSI_SELECT | SVSI_FOCUSED | SVSI_ENSUREVISIBLE);
  5787. //
  5788. // Check to see if the view mode need to be changed
  5789. //
  5790. if (hwndListView && FitViewModeBest(hwndListView))
  5791. {
  5792. //
  5793. // The view mode has been changed - call select item again
  5794. // to ensure the visibility of the slected item in the new
  5795. // view mode.
  5796. //
  5797. psv->SelectItem(pidlItem, SVSI_SELECT | SVSI_FOCUSED | SVSI_ENSUREVISIBLE);
  5798. }
  5799. if (hwndListView && bLocked)
  5800. {
  5801. //
  5802. // Enable the window update
  5803. //
  5804. LockWindowUpdate(NULL);
  5805. }
  5806. }
  5807. ////////////////////////////////////////////////////////////////////////////
  5808. //
  5809. // CPrintBrowser::FindPrinter
  5810. //
  5811. // Invokes the find in the DS ui using printui!bPrinterSetup interface
  5812. //
  5813. ////////////////////////////////////////////////////////////////////////////
  5814. BOOL CPrintBrowser::FindPrinter(HWND hwnd, LPTSTR pszBuffer, UINT cchSize)
  5815. {
  5816. BOOL bReturn = FALSE;
  5817. if (g_pfnPrinterSetup)
  5818. {
  5819. //
  5820. // Invoke the DSUI to find a printer
  5821. //
  5822. bReturn = g_pfnPrinterSetup(hwnd, MSP_FINDPRINTER, cchSize, pszBuffer, &cchSize, NULL);
  5823. // select the printer's list control
  5824. SendMessage(hwndDlg, WM_NEXTDLGCTL,
  5825. reinterpret_cast<WPARAM>(GetDlgItem(hwndDlg, IDC_PRINTER_LISTVIEW)), 1);
  5826. }
  5827. return bReturn;
  5828. }
  5829. ////////////////////////////////////////////////////////////////////////////
  5830. //
  5831. // CPrintBrowser::GetInternalPrinterName
  5832. //
  5833. // Returns the current printer name
  5834. //
  5835. ////////////////////////////////////////////////////////////////////////////
  5836. BOOL CPrintBrowser::GetInternalPrinterName(LPTSTR pszBuffer, DWORD *pdwSize)
  5837. {
  5838. BOOL bReturn = FALSE;
  5839. if (pdwSize)
  5840. {
  5841. //
  5842. // If a buffer was provided and it is large enough, then copy the printer name.
  5843. //
  5844. DWORD iLen = _tcslen(szPrinter);
  5845. if (pszBuffer && *pdwSize > iLen)
  5846. {
  5847. StringCchCopy(pszBuffer, *pdwSize, szPrinter);
  5848. bReturn = TRUE;
  5849. }
  5850. else
  5851. {
  5852. //
  5853. // Set the required length and the last error code.
  5854. //
  5855. *pdwSize = iLen + 1;
  5856. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  5857. }
  5858. }
  5859. return bReturn;
  5860. }
  5861. ////////////////////////////////////////////////////////////////////////////
  5862. //
  5863. // CPrintBrowser::GetCurrentDevMode
  5864. //
  5865. // Returns the current internal devmode
  5866. //
  5867. ////////////////////////////////////////////////////////////////////////////
  5868. LPDEVMODE CPrintBrowser::GetCurrentDevMode()
  5869. {
  5870. return pInternalDevMode;
  5871. }
  5872. ////////////////////////////////////////////////////////////////////////////
  5873. //
  5874. // CPrintBrowser::GetDefaultDevMode
  5875. //
  5876. // Retrieve the default devmode for the specified printer.
  5877. //
  5878. ////////////////////////////////////////////////////////////////////////////
  5879. HRESULT CPrintBrowser::GetDefaultDevMode(HANDLE hPrinter, LPCTSTR pszPrinterName, PDEVMODE *ppDevMode)
  5880. {
  5881. HRESULT hr = S_OK;
  5882. LONG lResult = 0;
  5883. PDEVMODE pDevMode = NULL;
  5884. if (SUCCEEDED(hr))
  5885. {
  5886. //
  5887. // Call document properties to get the size of the devmode.
  5888. //
  5889. lResult = DocumentProperties(NULL, hPrinter, (LPTSTR)pszPrinterName, NULL, NULL, 0);
  5890. hr = (lResult >= 0) ? S_OK : CreateError();
  5891. }
  5892. if (SUCCEEDED(hr))
  5893. {
  5894. //
  5895. // If the size of the devmode was returned then allocate memory.
  5896. //
  5897. // GPTR initializes the memory with zeros.
  5898. //
  5899. pDevMode = (PDEVMODE)GlobalAlloc(GPTR, lResult);
  5900. hr = pDevMode ? S_OK : E_OUTOFMEMORY;
  5901. }
  5902. //
  5903. // If allocated then copy back the pointer.
  5904. //
  5905. if (SUCCEEDED(hr))
  5906. {
  5907. //
  5908. // Call document properties to get the default dev mode.
  5909. //
  5910. lResult = DocumentProperties(NULL, hPrinter, (LPTSTR)pszPrinterName, pDevMode, NULL, DM_OUT_BUFFER);
  5911. hr = (lResult >= 0) ? S_OK : CreateError();
  5912. }
  5913. if (SUCCEEDED(hr))
  5914. {
  5915. //
  5916. // Everything has succeeded. Move locals to out parameters.
  5917. //
  5918. *ppDevMode = pDevMode;
  5919. pDevMode = NULL;
  5920. }
  5921. //
  5922. // Cleanup...
  5923. //
  5924. if (pDevMode)
  5925. {
  5926. GlobalFree((HANDLE)pDevMode);
  5927. pDevMode = NULL;
  5928. }
  5929. return hr;
  5930. }
  5931. ////////////////////////////////////////////////////////////////////////////
  5932. //
  5933. // CPrintBrowser::WrapEnumPrinters
  5934. //
  5935. // Wraps EnumPrinters API into more friendly interface
  5936. //
  5937. ////////////////////////////////////////////////////////////////////////////
  5938. HRESULT CPrintBrowser::WrapEnumPrinters(DWORD dwFlags, LPCTSTR pszServer, DWORD dwLevel, PVOID* ppvBuffer, PDWORD pcbBuffer, PDWORD pcPrinters)
  5939. {
  5940. HRESULT hr = S_OK;
  5941. DWORD cbNeeded;
  5942. BOOL bResult = FALSE;
  5943. if (SUCCEEDED(hr))
  5944. {
  5945. hr = (ppvBuffer && pcbBuffer && pcPrinters) ? S_OK : E_INVALIDARG;
  5946. }
  5947. if (SUCCEEDED(hr))
  5948. {
  5949. //
  5950. // Pre-initialize *pcbPrinter if it's not set.
  5951. //
  5952. if (!*pcbBuffer)
  5953. {
  5954. *pcbBuffer = kInitialPrinterHint;
  5955. }
  5956. do
  5957. {
  5958. if (!*ppvBuffer)
  5959. {
  5960. *ppvBuffer = (PVOID)GlobalAlloc(GPTR, *pcbBuffer);
  5961. if (!*ppvBuffer)
  5962. {
  5963. *pcbBuffer = 0;
  5964. *pcPrinters = 0;
  5965. hr = E_OUTOFMEMORY;
  5966. break;
  5967. }
  5968. }
  5969. if (SUCCEEDED(hr))
  5970. {
  5971. bResult = EnumPrinters(dwFlags, (LPTSTR)pszServer, dwLevel, (PBYTE)*ppvBuffer, *pcbBuffer, &cbNeeded, pcPrinters);
  5972. hr = bResult ? S_OK : CreateError();
  5973. }
  5974. if (SUCCEEDED(hr))
  5975. {
  5976. //
  5977. // Everything went fine
  5978. //
  5979. break;
  5980. }
  5981. //
  5982. // Check to see whether the buffer is too small.
  5983. //
  5984. GlobalFree((HANDLE)(*ppvBuffer));
  5985. *ppvBuffer = NULL;
  5986. if (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hr))
  5987. {
  5988. //
  5989. // Reset hr & continue.
  5990. //
  5991. hr = S_OK;
  5992. *pcbBuffer = cbNeeded;
  5993. continue;
  5994. }
  5995. //
  5996. // Something else (not the buffer) went wrong.
  5997. // Bail out.
  5998. //
  5999. *pcbBuffer = 0;
  6000. *pcPrinters = 0;
  6001. break;
  6002. } while(1);
  6003. }
  6004. return hr;
  6005. }
  6006. ////////////////////////////////////////////////////////////////////////////
  6007. //
  6008. // CPrintBrowser::GetUsablePrinter
  6009. //
  6010. // Try to find a usable printer
  6011. //
  6012. ////////////////////////////////////////////////////////////////////////////
  6013. HRESULT CPrintBrowser::GetUsablePrinter(LPTSTR szPrinterNameBuf, DWORD *pcchBuf)
  6014. {
  6015. HRESULT hr = S_OK;
  6016. BOOL bStatus = FALSE;
  6017. DWORD cchBuf = *pcchBuf;
  6018. HANDLE hPrinter = NULL;
  6019. PDEVMODE pDevMode = NULL;
  6020. PRINTER_INFO_4 *pInfo4 = NULL;
  6021. DWORD cInfo4 = 0;
  6022. DWORD cbInfo4 = 0;
  6023. if (SUCCEEDED(hr))
  6024. {
  6025. hr = (szPrinterNameBuf && pcchBuf) ? S_OK : E_INVALIDARG;
  6026. }
  6027. if (SUCCEEDED(hr))
  6028. {
  6029. do
  6030. {
  6031. if (SUCCEEDED(hr))
  6032. {
  6033. //
  6034. // Attempt to the get the default printer.
  6035. //
  6036. bStatus = GetDefaultPrinter(szPrinterNameBuf, pcchBuf);
  6037. hr = bStatus ? S_OK : CreateError();
  6038. }
  6039. if (SUCCEEDED(hr))
  6040. {
  6041. bStatus = OpenPrinter(szPrinterNameBuf, &hPrinter, NULL);
  6042. hr = bStatus ? S_OK : CreateError();
  6043. }
  6044. if (SUCCEEDED(hr))
  6045. {
  6046. //
  6047. // Try to get the default devmode for this printer.
  6048. //
  6049. hr = GetDefaultDevMode(hPrinter, szPrinterNameBuf, &pDevMode);
  6050. }
  6051. if (SUCCEEDED(hr))
  6052. {
  6053. //
  6054. // The default printer is usable. Exit.
  6055. //
  6056. break;
  6057. }
  6058. else
  6059. {
  6060. //
  6061. // The default printer is not usable. Now we should enumerate
  6062. // all the printers and find a usable one. Reset hr here.
  6063. //
  6064. hr = S_OK;
  6065. }
  6066. if (SUCCEEDED(hr))
  6067. {
  6068. //
  6069. // Enumerate the current printers.
  6070. //
  6071. hr = WrapEnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS,
  6072. NULL,
  6073. 4,
  6074. reinterpret_cast<PVOID *>(&pInfo4),
  6075. &cbInfo4,
  6076. &cInfo4);
  6077. }
  6078. if (SUCCEEDED(hr))
  6079. {
  6080. // ERROR_FILE_NOT_FOUND will be an indication that the we have
  6081. // no printers installer (i.e. printer's folder is empty) in
  6082. // which case we should suggest the user to install a printer.
  6083. hr = cInfo4 ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  6084. }
  6085. if (SUCCEEDED(hr))
  6086. {
  6087. //
  6088. // Open the printers until we find one we have access to.
  6089. //
  6090. for (UINT i = 0; i<cInfo4; i++)
  6091. {
  6092. if (hPrinter)
  6093. {
  6094. ClosePrinter(hPrinter);
  6095. hPrinter = NULL;
  6096. }
  6097. if (pDevMode)
  6098. {
  6099. GlobalFree((HANDLE)pDevMode);
  6100. pDevMode = NULL;
  6101. }
  6102. if (SUCCEEDED(hr))
  6103. {
  6104. bStatus = OpenPrinter(pInfo4[i].pPrinterName, &hPrinter, NULL);
  6105. hr = bStatus ? S_OK : CreateError();
  6106. }
  6107. if (SUCCEEDED(hr))
  6108. {
  6109. //
  6110. // Try to get the default devmode for this printer.
  6111. //
  6112. hr = GetDefaultDevMode(hPrinter, pInfo4[i].pPrinterName, &pDevMode);
  6113. }
  6114. if (SUCCEEDED(hr))
  6115. {
  6116. //
  6117. // Found a usable printer
  6118. //
  6119. StringCchCopy(szPrinterNameBuf, cchBuf, pInfo4[i].pPrinterName);
  6120. break;
  6121. }
  6122. }
  6123. }
  6124. }
  6125. while (false);
  6126. }
  6127. //
  6128. // Cleanup...
  6129. //
  6130. if (pInfo4)
  6131. {
  6132. GlobalFree((HANDLE)pInfo4);
  6133. }
  6134. if (hPrinter)
  6135. {
  6136. ClosePrinter(hPrinter);
  6137. hPrinter = NULL;
  6138. }
  6139. if (pDevMode)
  6140. {
  6141. GlobalFree((HANDLE)pDevMode);
  6142. pDevMode = NULL;
  6143. }
  6144. return hr;
  6145. }
  6146. ////////////////////////////////////////////////////////////////////////////
  6147. //
  6148. // CPrintBrowser::GetInternalDevMode
  6149. //
  6150. // Get the internal devmode for this printer and merge with pInDevMode
  6151. //
  6152. ////////////////////////////////////////////////////////////////////////////
  6153. HRESULT CPrintBrowser::GetInternalDevMode(PDEVMODE *ppOutDevMode, LPCTSTR pszPrinter, HANDLE hPrinter, PDEVMODE pInDevMode)
  6154. {
  6155. HRESULT hr = S_OK;
  6156. LONG lResult = 0;
  6157. PDEVMODE pDevMode = NULL;
  6158. if (SUCCEEDED(hr))
  6159. {
  6160. //
  6161. // Validate parameters.
  6162. //
  6163. hr = ppOutDevMode ? S_OK : E_INVALIDARG;
  6164. }
  6165. if (SUCCEEDED(hr))
  6166. {
  6167. *ppOutDevMode = NULL;
  6168. //
  6169. // Get the default devmode for this printer.
  6170. //
  6171. hr = GetDefaultDevMode(hPrinter, pszPrinter, &pDevMode);
  6172. }
  6173. //
  6174. // If fetched a default devmode and we were passed a devmode
  6175. // then call the driver to merge the devmodes for us.
  6176. //
  6177. if (SUCCEEDED(hr))
  6178. {
  6179. if (pInDevMode)
  6180. {
  6181. //
  6182. // Call document properties to get a merged copy of the devmode.
  6183. //
  6184. lResult = DocumentProperties(NULL,
  6185. hPrinter,
  6186. const_cast<LPTSTR>(pszPrinter),
  6187. pDevMode,
  6188. pInDevMode,
  6189. DM_IN_BUFFER|DM_OUT_BUFFER);
  6190. hr = (lResult >= 0) ? S_OK : CreateError();
  6191. }
  6192. }
  6193. if (SUCCEEDED(hr))
  6194. {
  6195. //
  6196. // Everything has succeeded. Move locals to out parameters.
  6197. //
  6198. *ppOutDevMode = pDevMode;
  6199. pDevMode = NULL;
  6200. }
  6201. //
  6202. // Cleanup...
  6203. //
  6204. if (pDevMode)
  6205. {
  6206. GlobalFree((HANDLE)pDevMode);
  6207. pDevMode = NULL;
  6208. }
  6209. return hr;
  6210. }
  6211. ////////////////////////////////////////////////////////////////////////////
  6212. //
  6213. // CPrintBrowser::InstallDevMode
  6214. //
  6215. // Install a new internal devmode
  6216. //
  6217. ////////////////////////////////////////////////////////////////////////////
  6218. HRESULT CPrintBrowser::InstallDevMode(LPCTSTR pszPrinterName, PDEVMODE pDevModeToMerge)
  6219. {
  6220. HRESULT hr = S_OK;
  6221. BOOL bStatus = FALSE;
  6222. TCHAR szBuffer[kPrinterBufMax];
  6223. HANDLE hTempPrinter = NULL;
  6224. PDEVMODE pTempDevMode = NULL;
  6225. DWORD dwSize;
  6226. if (SUCCEEDED(hr))
  6227. {
  6228. dwSize = ARRAYSIZE(szBuffer);
  6229. //
  6230. // If a null printer name was specified use the default printer.
  6231. //
  6232. if (!pszPrinterName || !*pszPrinterName)
  6233. {
  6234. hr = GetUsablePrinter(szBuffer, &dwSize);
  6235. if (SUCCEEDED(hr))
  6236. {
  6237. pszPrinterName = szBuffer;
  6238. }
  6239. else
  6240. {
  6241. //
  6242. // GetDefaultPrinter fails with ERROR_FILE_NOT_FOUND if we
  6243. // have no printers.
  6244. //
  6245. // ERROR_FILE_NOT_FOUND will be an indication that the we have
  6246. // no printers installer (i.e. printer's folder is empty) in
  6247. // which case we should suggest the user to install a printer.
  6248. //
  6249. bStatus = GetDefaultPrinter(szBuffer, &dwSize);
  6250. hr = bStatus ? S_OK : CreateError();
  6251. if (SUCCEEDED(hr))
  6252. {
  6253. pszPrinterName = szBuffer;
  6254. }
  6255. }
  6256. }
  6257. }
  6258. if (SUCCEEDED(hr))
  6259. {
  6260. //
  6261. // Check if this is not the current printer in which case,
  6262. // just do nothing.
  6263. //
  6264. if (pszPrinterName && _tcsicmp(pszPrinterName, szPrinter))
  6265. {
  6266. if (SUCCEEDED(hr))
  6267. {
  6268. bStatus = OpenPrinter((LPTSTR)pszPrinterName, &hTempPrinter, NULL);
  6269. hr = bStatus ? S_OK : CreateError();
  6270. }
  6271. if (SUCCEEDED(hr))
  6272. {
  6273. hr = GetInternalDevMode(&pTempDevMode, pszPrinterName, hTempPrinter, pDevModeToMerge);
  6274. }
  6275. if (SUCCEEDED(hr))
  6276. {
  6277. if (hPrinter)
  6278. {
  6279. ClosePrinter(hPrinter);
  6280. hPrinter = NULL;
  6281. }
  6282. if (pInternalDevMode)
  6283. {
  6284. GlobalFree((HANDLE)pInternalDevMode);
  6285. pInternalDevMode = NULL;
  6286. }
  6287. StringCchCopy(szPrinter, ARRAYSIZE(szPrinter), pszPrinterName);
  6288. hPrinter = hTempPrinter;
  6289. hTempPrinter = NULL;
  6290. pInternalDevMode = pTempDevMode;
  6291. pTempDevMode = NULL;
  6292. }
  6293. }
  6294. }
  6295. if (SUCCEEDED(hr))
  6296. {
  6297. if (pInternalDevMode)
  6298. {
  6299. //
  6300. // Enable the driver UI button
  6301. //
  6302. EnableWindow(GetDlgItem( hwndDlg, IDC_DRIVER ), TRUE);
  6303. }
  6304. }
  6305. //
  6306. // Cleanup...
  6307. //
  6308. if (hTempPrinter)
  6309. {
  6310. ClosePrinter(hTempPrinter);
  6311. hTempPrinter = NULL;
  6312. }
  6313. if (pTempDevMode)
  6314. {
  6315. GlobalFree((HANDLE)pTempDevMode);
  6316. pTempDevMode = NULL;
  6317. }
  6318. return hr;
  6319. }
  6320. ////////////////////////////////////////////////////////////////////////////
  6321. //
  6322. // CPrintBrowser::UninstallDevMode
  6323. //
  6324. // Unintall the current devmode
  6325. //
  6326. ////////////////////////////////////////////////////////////////////////////
  6327. HRESULT CPrintBrowser::UninstallDevMode()
  6328. {
  6329. if (hPrinter)
  6330. {
  6331. ClosePrinter(hPrinter);
  6332. hPrinter = NULL;
  6333. }
  6334. if (pInternalDevMode)
  6335. {
  6336. GlobalFree((HANDLE)pInternalDevMode);
  6337. pInternalDevMode = NULL;
  6338. }
  6339. //
  6340. // Clear the internal printer name.
  6341. //
  6342. szPrinter[0] = 0;
  6343. //
  6344. // Disable the driver UI button
  6345. //
  6346. EnableWindow(GetDlgItem( hwndDlg, IDC_DRIVER ), FALSE);
  6347. return S_OK;
  6348. }
  6349. ////////////////////////////////////////////////////////////////////////////
  6350. //
  6351. // InvokeAddPrinterWizardModal
  6352. //
  6353. // This is a global API declared in comdlg32.h
  6354. //
  6355. ////////////////////////////////////////////////////////////////////////////
  6356. HRESULT
  6357. InvokeAddPrinterWizardModal(
  6358. IN HWND hwnd,
  6359. OUT BOOL *pbPrinterAdded
  6360. )
  6361. {
  6362. HRESULT hr = S_OK;
  6363. if (Print_LoadLibraries() && g_pfnPrinterSetup)
  6364. {
  6365. BOOL bPrinterAdded = FALSE;
  6366. TCHAR szBuffer[kPrinterBufMax];
  6367. UINT uSize = ARRAYSIZE(szBuffer);
  6368. szBuffer[0] = 0;
  6369. //
  6370. // Invoke the Add Printer Wizard here
  6371. //
  6372. bPrinterAdded = g_pfnPrinterSetup(hwnd, MSP_NEWPRINTER, uSize, szBuffer, &uSize, NULL);
  6373. if (pbPrinterAdded)
  6374. {
  6375. *pbPrinterAdded = bPrinterAdded;
  6376. }
  6377. }
  6378. else
  6379. {
  6380. hr = CreateError();
  6381. }
  6382. return hr;
  6383. }
  6384. /*========================================================================*/
  6385. /* Ansi->Unicode Thunk routines */
  6386. /*========================================================================*/
  6387. ////////////////////////////////////////////////////////////////////////////
  6388. //
  6389. // ThunkPrintDlgEx
  6390. //
  6391. ////////////////////////////////////////////////////////////////////////////
  6392. HRESULT ThunkPrintDlgEx(
  6393. PPRINTINFOEX pPI,
  6394. LPPRINTDLGEXA pPDA)
  6395. {
  6396. LPPRINTDLGEXW pPDW;
  6397. LPDEVMODEA pDMA;
  6398. DWORD cbLen;
  6399. if (!pPDA)
  6400. {
  6401. pPI->dwExtendedError = CDERR_INITIALIZATION;
  6402. return (E_INVALIDARG);
  6403. }
  6404. if (pPDA->lStructSize != sizeof(PRINTDLGEXA))
  6405. {
  6406. pPI->dwExtendedError = CDERR_STRUCTSIZE;
  6407. return (E_INVALIDARG);
  6408. }
  6409. if (!(pPDW = (LPPRINTDLGEXW)GlobalAlloc(GPTR, sizeof(PRINTDLGEXW))))
  6410. {
  6411. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  6412. return (E_OUTOFMEMORY);
  6413. }
  6414. //
  6415. // IN-only constant stuff.
  6416. //
  6417. pPDW->lStructSize = sizeof(PRINTDLGEXW);
  6418. pPDW->hwndOwner = pPDA->hwndOwner;
  6419. pPDW->ExclusionFlags = pPDA->ExclusionFlags;
  6420. pPDW->hInstance = pPDA->hInstance;
  6421. pPDW->lpCallback = pPDA->lpCallback;
  6422. pPDW->nPropertyPages = pPDA->nPropertyPages;
  6423. pPDW->lphPropertyPages = pPDA->lphPropertyPages;
  6424. pPDW->nStartPage = pPDA->nStartPage;
  6425. //
  6426. // IN-OUT Variable Structs.
  6427. //
  6428. if ((pPDA->hDevMode) && (pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode)))
  6429. {
  6430. //
  6431. // Make sure the device name in the devmode is not too long such that
  6432. // it has overwritten the other devmode fields.
  6433. //
  6434. if ((pDMA->dmSize < MIN_DEVMODE_SIZEA) ||
  6435. (lstrlenA((LPCSTR)pDMA->dmDeviceName) > CCHDEVICENAME))
  6436. {
  6437. pPDW->hDevMode = NULL;
  6438. }
  6439. else
  6440. {
  6441. pPDW->hDevMode = GlobalAlloc( GHND,
  6442. sizeof(DEVMODEW) + pDMA->dmDriverExtra );
  6443. }
  6444. GlobalUnlock(pPDA->hDevMode);
  6445. }
  6446. else
  6447. {
  6448. pPDW->hDevMode = NULL;
  6449. }
  6450. //
  6451. // Thunk Device Names A => W
  6452. //
  6453. pPDW->hDevNames = NULL;
  6454. if (pPDA->hDevNames)
  6455. {
  6456. // ignore the error case since we can't handle it either way.
  6457. HRESULT hr = ThunkDevNamesA2W(pPDA->hDevNames, &pPDW->hDevNames);
  6458. ASSERT(SUCCEEDED(hr));
  6459. }
  6460. //
  6461. // IN-only constant strings.
  6462. //
  6463. // Init Print TemplateName constant.
  6464. //
  6465. if ((pPDA->Flags & PD_ENABLEPRINTTEMPLATE) && (pPDA->lpPrintTemplateName))
  6466. {
  6467. //
  6468. // See if it's a string or an integer.
  6469. //
  6470. if (!IS_INTRESOURCE(pPDA->lpPrintTemplateName))
  6471. {
  6472. //
  6473. // String.
  6474. //
  6475. cbLen = lstrlenA(pPDA->lpPrintTemplateName) + 1;
  6476. if (!(pPDW->lpPrintTemplateName = (LPCWSTR)
  6477. GlobalAlloc( GPTR,
  6478. (cbLen * sizeof(WCHAR)) )))
  6479. {
  6480. pPI->dwExtendedError = CDERR_MEMALLOCFAILURE;
  6481. return (E_OUTOFMEMORY);
  6482. }
  6483. else
  6484. {
  6485. pPI->fPrintTemplateAlloc = TRUE;
  6486. SHAnsiToUnicode(pPDA->lpPrintTemplateName,(LPWSTR)pPDW->lpPrintTemplateName,cbLen);
  6487. }
  6488. }
  6489. else
  6490. {
  6491. //
  6492. // Integer.
  6493. //
  6494. pPDW->lpPrintTemplateName = (LPCWSTR)pPDA->lpPrintTemplateName;
  6495. }
  6496. }
  6497. else
  6498. {
  6499. pPDW->lpPrintTemplateName = NULL;
  6500. }
  6501. //
  6502. // Store the info in the PRINTINFOEX structure.
  6503. //
  6504. pPI->pPD = pPDW;
  6505. pPI->pPDA = pPDA;
  6506. pPI->ApiType = COMDLG_ANSI;
  6507. return (S_OK);
  6508. }
  6509. ////////////////////////////////////////////////////////////////////////////
  6510. //
  6511. // FreeThunkPrintDlgEx
  6512. //
  6513. ////////////////////////////////////////////////////////////////////////////
  6514. VOID FreeThunkPrintDlgEx(
  6515. PPRINTINFOEX pPI)
  6516. {
  6517. LPPRINTDLGEXW pPDW = pPI->pPD;
  6518. if (!pPDW)
  6519. {
  6520. return;
  6521. }
  6522. if (pPDW->hDevNames)
  6523. {
  6524. GlobalFree(pPDW->hDevNames);
  6525. }
  6526. if (pPDW->hDevMode)
  6527. {
  6528. GlobalFree(pPDW->hDevMode);
  6529. }
  6530. if (pPI->fPrintTemplateAlloc)
  6531. {
  6532. GlobalFree((LPWSTR)(pPDW->lpPrintTemplateName));
  6533. }
  6534. GlobalFree(pPDW);
  6535. pPI->pPD = NULL;
  6536. }
  6537. ////////////////////////////////////////////////////////////////////////////
  6538. //
  6539. // ThunkPrintDlgExA2W
  6540. //
  6541. ////////////////////////////////////////////////////////////////////////////
  6542. VOID ThunkPrintDlgExA2W(
  6543. PPRINTINFOEX pPI)
  6544. {
  6545. LPPRINTDLGEXW pPDW = pPI->pPD;
  6546. LPPRINTDLGEXA pPDA = pPI->pPDA;
  6547. //
  6548. // Copy info A => W
  6549. //
  6550. pPDW->hDC = pPDA->hDC;
  6551. pPDW->Flags = pPDA->Flags;
  6552. pPDW->Flags2 = pPDA->Flags2;
  6553. pPDW->nPageRanges = pPDA->nPageRanges;
  6554. pPDW->nMaxPageRanges = pPDA->nMaxPageRanges;
  6555. pPDW->lpPageRanges = pPDA->lpPageRanges;
  6556. pPDW->nMinPage = pPDA->nMinPage;
  6557. pPDW->nMaxPage = pPDA->nMaxPage;
  6558. pPDW->nCopies = pPDA->nCopies;
  6559. //
  6560. // Thunk Device Names A => W
  6561. //
  6562. if (pPDA->hDevNames)
  6563. {
  6564. // ignore the error case since we can't handle it either way.
  6565. HRESULT hr = ThunkDevNamesA2W(pPDA->hDevNames, &pPDW->hDevNames);
  6566. ASSERT(SUCCEEDED(hr));
  6567. }
  6568. //
  6569. // Thunk Device Mode A => W
  6570. //
  6571. if (pPDA->hDevMode && pPDW->hDevMode)
  6572. {
  6573. LPDEVMODEW pDMW = (LPDEVMODEW)GlobalLock(pPDW->hDevMode);
  6574. LPDEVMODEA pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode);
  6575. ThunkDevModeA2W(pDMA, pDMW);
  6576. GlobalUnlock(pPDW->hDevMode);
  6577. GlobalUnlock(pPDA->hDevMode);
  6578. }
  6579. }
  6580. ////////////////////////////////////////////////////////////////////////////
  6581. //
  6582. // ThunkPrintDlgExW2A
  6583. //
  6584. ////////////////////////////////////////////////////////////////////////////
  6585. VOID ThunkPrintDlgExW2A(
  6586. PPRINTINFOEX pPI)
  6587. {
  6588. LPPRINTDLGEXA pPDA = pPI->pPDA;
  6589. LPPRINTDLGEXW pPDW = pPI->pPD;
  6590. //
  6591. // Copy info W => A
  6592. //
  6593. pPDA->hDC = pPDW->hDC;
  6594. pPDA->Flags = pPDW->Flags;
  6595. pPDA->Flags2 = pPDW->Flags2;
  6596. pPDA->nPageRanges = pPDW->nPageRanges;
  6597. pPDA->nMaxPageRanges = pPDW->nMaxPageRanges;
  6598. pPDA->lpPageRanges = pPDW->lpPageRanges;
  6599. pPDA->nMinPage = pPDW->nMinPage;
  6600. pPDA->nMaxPage = pPDW->nMaxPage;
  6601. pPDA->nCopies = pPDW->nCopies;
  6602. pPDA->dwResultAction = pPDW->dwResultAction;
  6603. //
  6604. // Thunk Device Names W => A
  6605. //
  6606. if (pPDW->hDevNames)
  6607. {
  6608. // ignore the error case since we can't handle it either way.
  6609. HRESULT hr = ThunkDevNamesW2A(pPDW->hDevNames, &pPDA->hDevNames);
  6610. ASSERT(SUCCEEDED(hr));
  6611. }
  6612. //
  6613. // Thunk Device Mode W => A
  6614. //
  6615. if (pPDW->hDevMode)
  6616. {
  6617. LPDEVMODEW pDMW = (LPDEVMODEW)GlobalLock(pPDW->hDevMode);
  6618. LPDEVMODEA pDMA;
  6619. if (pPDA->hDevMode)
  6620. {
  6621. HANDLE handle;
  6622. handle = GlobalReAlloc( pPDA->hDevMode,
  6623. sizeof(DEVMODEA) + pDMW->dmDriverExtra,
  6624. GHND );
  6625. //Check that realloc succeeded.
  6626. if (handle)
  6627. {
  6628. pPDA->hDevMode = handle;
  6629. }
  6630. else
  6631. {
  6632. //Realloc didn't succeed. Free the memory occupied.
  6633. pPDA->hDevMode = GlobalFree(pPDA->hDevMode);
  6634. }
  6635. }
  6636. else
  6637. {
  6638. pPDA->hDevMode = GlobalAlloc( GHND,
  6639. sizeof(DEVMODEA) + pDMW->dmDriverExtra );
  6640. }
  6641. if (pPDA->hDevMode)
  6642. {
  6643. pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode);
  6644. ThunkDevModeW2A(pDMW, pDMA);
  6645. GlobalUnlock(pPDA->hDevMode);
  6646. }
  6647. GlobalUnlock(pPDW->hDevMode);
  6648. }
  6649. }