Source code of Windows XP (NT5)
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.

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