/*++ Copyright (c) 1990-1998, Microsoft Corporation All rights reserved. Module Name: printnew.cpp Abstract: This module implements the Win32 property sheet print dialogs. Revision History: 11-04-97 JulieB Created. Feb-2000 LazarI major redesign (not to use printui anymore) Oct-2000 LazarI messages cleanup & redesign --*/ // precompiled headers #include "precomp.h" #pragma hdrstop #include "cdids.h" #include "prnsetup.h" #include "printnew.h" #include "util.h" #ifndef ARRAYSIZE #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #endif // ARRAYSIZE inline static HRESULT CreateError() { DWORD dw = GetLastError(); if (ERROR_SUCCESS == dw) return E_FAIL; return HRESULT_FROM_WIN32(dw); } // // Constant Declarations. // #define CDM_SELCHANGE (CDM_LAST + 102) #define CDM_PRINTNOTIFY (CDM_LAST + 103) #define CDM_NOPRINTERS (CDM_LAST + 104) #define CDM_INITDONE (CDM_LAST + 105) #define PRINTERS_ICOL_NAME 0 #define PRINTERS_ICOL_QUEUESIZE 1 #define PRINTERS_ICOL_STATUS 2 #define PRINTERS_ICOL_COMMENT 3 #define PRINTERS_ICOL_LOCATION 4 #define PRINTERS_ICOL_MODEL 5 #define SZ_PRINTUI TEXT("printui.dll") // // Default view mode value // #define VIEW_MODE_DEFAULT (UINT )(-1) // // Macro Definitions. // #define Print_HwndToBrowser(hwnd) ((CPrintBrowser *)GetWindowLongPtr(hwnd, DWLP_USER)) #define Print_StoreBrowser(hwnd, pbrs) (SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pbrs)) #define Print_IsInRange(id, idFirst, idLast) \ ((UINT)((id) - idFirst) <= (UINT)(idLast - idFirst)) // // Global Variables. // HWND g_hwndActivePrint = NULL; HACCEL g_haccPrint = NULL; HHOOK g_hHook = NULL; int g_nHookRef = -1; // // Extern Declarations. // extern HWND GetFocusedChild( HWND hwndDlg, HWND hwndFocus); extern void GetViewItemText( IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pBuf, UINT cchBuf, DWORD dwFlags); // Frees up the PIDL using the shell allocator static void FreePIDL(LPITEMIDLIST pidl) { if (pidl) { LPMALLOC pShellMalloc; if (SUCCEEDED(SHGetMalloc(&pShellMalloc))) { pShellMalloc->Free(pidl); pShellMalloc->Release(); } } } //////////////////////////////////////////////////////////////////////////// // // PrintDlgExA // // ANSI entry point for PrintDlgEx when this code is built UNICODE. // //////////////////////////////////////////////////////////////////////////// HRESULT WINAPI PrintDlgExA( LPPRINTDLGEXA pPDA) { PRINTINFOEX PI; HRESULT hResult; ZeroMemory(&PI, sizeof(PRINTINFOEX)); hResult = ThunkPrintDlgEx(&PI, pPDA); if (SUCCEEDED(hResult)) { ThunkPrintDlgExA2W(&PI); hResult = PrintDlgExX(&PI); ThunkPrintDlgExW2A(&PI); } FreeThunkPrintDlgEx(&PI); return (hResult); } //////////////////////////////////////////////////////////////////////////// // // PrintDlgEx // // The PrintDlgEx function displays a Print dialog that enables the // user to specify the properties of a particular print job. // //////////////////////////////////////////////////////////////////////////// HRESULT WINAPI PrintDlgEx( LPPRINTDLGEX pPD) { PRINTINFOEX PI; ZeroMemory(&PI, sizeof(PRINTINFOEX)); PI.pPD = pPD; PI.ApiType = COMDLG_WIDE; return ( PrintDlgExX(&PI) ); } //////////////////////////////////////////////////////////////////////////// // // PrintDlgExX // // Worker routine for the PrintDlgEx api. // //////////////////////////////////////////////////////////////////////////// HRESULT PrintDlgExX( PPRINTINFOEX pPI) { LPPRINTDLGEX pPD = pPI->pPD; BOOL hResult; DWORD dwFlags; DWORD nCopies; LPPRINTPAGERANGE pPageRanges; DWORD nFromPage, nToPage; UINT Ctr; BOOL bHooked = FALSE; // // Make sure the print dlg structure exists and that we're not being // called from a wow app. // if ((!pPD) || (IS16BITWOWAPP(pPD))) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (E_INVALIDARG); } // // Make sure the size of the print dlg structure is valid. // if (pPD->lStructSize != sizeof(PRINTDLGEX)) { pPI->dwExtendedError = CDERR_STRUCTSIZE; return (E_INVALIDARG); } // // Make sure the owner window exists and is valid. // if (!pPD->hwndOwner || !IsWindow(pPD->hwndOwner)) { pPI->dwExtendedError = CDERR_DIALOGFAILURE; return (E_HANDLE); } // // Make sure only valid flags are passed into this routine. // if ((pPD->Flags & ~(PD_ALLPAGES | PD_SELECTION | PD_PAGENUMS | PD_NOSELECTION | PD_NOPAGENUMS | PD_COLLATE | PD_PRINTTOFILE | PD_NOWARNING | PD_RETURNDC | PD_RETURNIC | PD_RETURNDEFAULT | PD_ENABLEPRINTTEMPLATE | PD_ENABLEPRINTTEMPLATEHANDLE | PD_USEDEVMODECOPIESANDCOLLATE | PD_DISABLEPRINTTOFILE | PD_HIDEPRINTTOFILE | PD_CURRENTPAGE | PD_NOCURRENTPAGE | PD_EXCLUSIONFLAGS | PD_USELARGETEMPLATE | CD_WX86APP)) || (pPD->Flags2 != 0) || (pPD->ExclusionFlags & ~(PD_EXCL_COPIESANDCOLLATE)) || (pPD->dwResultAction != 0)) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } // // Check the template settings as much as we can here. // if (pPD->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { if (!pPD->hInstance) { pPI->dwExtendedError = CDERR_NOHINSTANCE; return (E_HANDLE); } } else if (pPD->Flags & PD_ENABLEPRINTTEMPLATE) { if (!pPD->lpPrintTemplateName) { pPI->dwExtendedError = CDERR_NOTEMPLATE; return (E_POINTER); } if (!pPD->hInstance) { pPI->dwExtendedError = CDERR_NOHINSTANCE; return (E_HANDLE); } } else { if (pPD->lpPrintTemplateName || pPD->hInstance) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } } // // Check the application property pages and the start page value. // if ((pPD->nPropertyPages && (pPD->lphPropertyPages == NULL)) || ((pPD->nStartPage != START_PAGE_GENERAL) && (pPD->nStartPage >= pPD->nPropertyPages))) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } // // Check the page range boundaries if the PD_NOPAGENUMS flag is // not set. // if (!(pPD->Flags & PD_NOPAGENUMS)) { if ((pPD->nMinPage > pPD->nMaxPage) || (pPD->nPageRanges > pPD->nMaxPageRanges) || (pPD->nMaxPageRanges == 0) || ((pPD->nMaxPageRanges) && (!pPD->lpPageRanges))) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } // // Check each of the given ranges. // pPageRanges = pPD->lpPageRanges; for (Ctr = 0; Ctr < pPD->nPageRanges; Ctr++) { // // Get the range. // nFromPage = pPageRanges[Ctr].nFromPage; nToPage = pPageRanges[Ctr].nToPage; // // Make sure the range is valid. // if ((nFromPage < pPD->nMinPage) || (nFromPage > pPD->nMaxPage) || (nToPage < pPD->nMinPage) || (nToPage > pPD->nMaxPage)) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } } } // // Get the process version of the app for later use. // pPI->ProcessVersion = GetProcessVersion(0); // // Init hDC. // pPD->hDC = 0; // // Do minimal work when requesting a default printer. // if (pPD->Flags & PD_RETURNDEFAULT) { return (Print_ReturnDefault(pPI)); } // // Load the necessary libraries. // if (!Print_LoadLibraries()) { pPI->dwExtendedError = PDERR_LOADDRVFAILURE; hResult = CreateError(); goto PrintDlgExX_DisplayWarning; } // // Load the necessary icons. // if (!Print_LoadIcons()) { // // If the icons cannot be loaded, then fail. // pPI->dwExtendedError = PDERR_SETUPFAILURE; hResult = CreateError(); goto PrintDlgExX_DisplayWarning; } // // Make sure the page ranges info is valid. // if ((!(pPD->Flags & PD_NOPAGENUMS)) && ((pPD->nMinPage > pPD->nMaxPage) || (pPD->nPageRanges > pPD->nMaxPageRanges) || (pPD->nMaxPageRanges == 0) || ((pPD->nMaxPageRanges) && (!(pPD->lpPageRanges))))) { pPI->dwExtendedError = PDERR_INITFAILURE; return (E_INVALIDARG); } // // Save the original information passed in by the app in case the // user hits cancel. // // Only the values that are modified at times other than during // PSN_APPLY need to be saved. // dwFlags = pPD->Flags; nCopies = pPD->nCopies; pPI->dwFlags = dwFlags; // // Set up the hook proc for input event messages. // if (InterlockedIncrement((LPLONG)&g_nHookRef) == 0) { g_hHook = SetWindowsHookEx( WH_MSGFILTER, Print_MessageHookProc, 0, GetCurrentThreadId() ); if (g_hHook) { bHooked = TRUE; } else { --g_nHookRef; } } else { bHooked = TRUE; } // // Load the print folder accelerators. // if (!g_haccPrint) { g_haccPrint = LoadAccelerators( g_hinst, MAKEINTRESOURCE(IDA_PRINTFOLDER) ); } // // Initialize the error codes to failure in case we die before we // actually bring up the property pages. // pPI->dwExtendedError = CDERR_INITIALIZATION; pPI->hResult = E_FAIL; pPI->hrOleInit = E_FAIL; // // Warning! Warning! Warning! // // We have to set g_tlsLangID before any call for CDLoadString // TlsSetValue(g_tlsLangID, (LPVOID) MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); // // Bring up the dialog. // Print_InvokePropertySheets(pPI, pPD); hResult = pPI->hResult; //Ole Would have been initialized during the WM_INITDIALOG processing. // Uninitialize Ole Now SHOleUninitialize(pPI->hrOleInit); // // Unhook the input event messages. // if (bHooked) { // // Put this in a local so we don't need a critical section. // HHOOK hHook = g_hHook; if (InterlockedDecrement((LPLONG)&g_nHookRef) < 0) { UnhookWindowsHookEx(hHook); } } // // If the user hit cancel or if there was an error, restore the original // values passed in by the app. // // Only the values that are modified at times other than during // PSN_APPLY need to be restored here. // if ((pPI->FinalResult == 0) && (!pPI->fApply)) { pPD->Flags = dwFlags; pPD->nCopies = nCopies; } // // See if we need to fill in the dwResultAction member field. // if (SUCCEEDED(hResult)) { if (pPI->FinalResult != 0) { pPD->dwResultAction = PD_RESULT_PRINT; } else if (pPI->fApply) { pPD->dwResultAction = PD_RESULT_APPLY; } else { pPD->dwResultAction = PD_RESULT_CANCEL; } } // // Display any error messages. // PrintDlgExX_DisplayWarning: if ((!(dwFlags & PD_NOWARNING)) && FAILED(hResult) && (pPI->ProcessVersion >= 0x40000)) { TCHAR szWarning[SCRATCHBUF_SIZE]; TCHAR szTitle[SCRATCHBUF_SIZE]; int iszWarning; szTitle[0] = TEXT('\0'); if (pPD->hwndOwner) { GetWindowText(pPD->hwndOwner, szTitle, ARRAYSIZE(szTitle)); } if (!szTitle[0]) { CDLoadString(g_hinst, iszWarningTitle, szTitle, ARRAYSIZE(szTitle)); } switch (hResult) { case ( E_OUTOFMEMORY ) : { iszWarning = iszMemoryError; break; } default : { iszWarning = iszGeneralWarning; break; } } CDLoadString(g_hinst, iszWarning, szWarning, ARRAYSIZE(szWarning)); MessageBeep(MB_ICONEXCLAMATION); MessageBox( pPD->hwndOwner, szWarning, szTitle, MB_ICONEXCLAMATION | MB_OK ); } // // Return the result. // return (hResult); } //////////////////////////////////////////////////////////////////////////// // // Print_ReturnDefault // //////////////////////////////////////////////////////////////////////////// HRESULT Print_ReturnDefault( PPRINTINFOEX pPI) { LPPRINTDLGEX pPD = pPI->pPD; TCHAR szPrinterName[MAX_PRINTERNAME]; LPDEVNAMES pDN; LPDEVMODE pDM; // // Initialize the error code to 0. // pPI->dwExtendedError = CDERR_GENERALCODES; // // Make sure the hDevMode and hDevNames fields are NULL. // if (pPD->hDevMode || pPD->hDevNames) { pPI->dwExtendedError = PDERR_RETDEFFAILURE; return (E_HANDLE); } // // Get the default printer name. // szPrinterName[0] = 0; PrintGetDefaultPrinterName(szPrinterName, ARRAYSIZE(szPrinterName)); if (szPrinterName[0] == 0) { pPI->dwExtendedError = PDERR_NODEFAULTPRN; return (E_FAIL); } // // Allocate and fill in the DevNames structure. // if (!Print_SaveDevNames(szPrinterName, pPD)) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; return CreateError(); } // // Allocate and fill in the DevMode structure. // pPD->hDevMode = Print_GetDevModeWrapper(szPrinterName); // // Get the device or information context, depending on which one // was requested (if any). // if ((pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames))) { if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode))) { PrintReturnICDC((LPPRINTDLG)pPD, pDN, pDM); GlobalUnlock(pPD->hDevMode); GlobalUnlock(pPD->hDevNames); return (S_OK); } else { GlobalUnlock(pPD->hDevNames); } } // // Make sure the pointers are NULL since we failed. // if (pPD->hDevNames) { GlobalFree(pPD->hDevNames); pPD->hDevNames = NULL; } if (pPD->hDevMode) { GlobalFree(pPD->hDevMode); pPD->hDevMode = NULL; } // // Return failure. // pPI->dwExtendedError = PDERR_NODEFAULTPRN; return (E_FAIL); } typedef BOOL (*PFN_bPrinterSetup)( HWND hwnd, // handle to parent window UINT uAction, // setup action UINT cchPrinterName, // size of pszPrinterName buffer in characters LPTSTR pszPrinterName, // in/out buffer for the printer name UINT *pcchPrinterName, // out buffer where we put the required number of characters LPCTSTR pszServerName // server name ); typedef LONG (*PFN_DocumentPropertiesWrap)( HWND hwnd, // handle to parent window HANDLE hPrinter, // handle to printer object LPTSTR pDeviceName, // device name PDEVMODE pDevModeOutput, // modified device mode PDEVMODE pDevModeInput, // original device mode DWORD fMode, // mode options DWORD fExclusionFlags // exclusion flags ); EXTERN_C CRITICAL_SECTION g_csLocal; static HINSTANCE hPrintUI = NULL; static PFN_bPrinterSetup g_pfnPrinterSetup = NULL; static PFN_DocumentPropertiesWrap g_pfnDocumentPropertiesWrap = NULL; //////////////////////////////////////////////////////////////////////////// // // Print_LoadLibraries // //////////////////////////////////////////////////////////////////////////// BOOL Print_LoadLibraries() { // // Make sure we hold the global CS while initializing // the global variables. // EnterCriticalSection(&g_csLocal); // // Load PrintUI. // if (!hPrintUI) { if ((hPrintUI = LoadLibrary(SZ_PRINTUI))) { // // Get the proc addresses of bPrinterSetup private API. // g_pfnPrinterSetup = (PFN_bPrinterSetup)GetProcAddress(hPrintUI, "bPrinterSetup"); g_pfnDocumentPropertiesWrap = (PFN_DocumentPropertiesWrap)GetProcAddress(hPrintUI, "DocumentPropertiesWrap"); if (NULL == g_pfnPrinterSetup || NULL == g_pfnDocumentPropertiesWrap) { // failed to get addresses of core printui APIs FreeLibrary(hPrintUI); hPrintUI = NULL; } } } // // Leave the global CS. // LeaveCriticalSection(&g_csLocal); // // Return the result. // return (hPrintUI != NULL); } //////////////////////////////////////////////////////////////////////////// // // Print_UnloadLibraries // //////////////////////////////////////////////////////////////////////////// VOID Print_UnloadLibraries() { if (hPrintUI) { FreeLibrary(hPrintUI); hPrintUI = NULL; } } //////////////////////////////////////////////////////////////////////////// // // Print_LoadIcons // //////////////////////////////////////////////////////////////////////////// BOOL Print_LoadIcons() { // // Load the collation images. // hIconCollate = LoadImage( g_hinst, MAKEINTRESOURCE(ICO_COLLATE), IMAGE_ICON, 0, 0, LR_SHARED); hIconNoCollate = LoadImage( g_hinst, MAKEINTRESOURCE(ICO_NO_COLLATE), IMAGE_ICON, 0, 0, LR_SHARED); // // Return TRUE only if all icons/images were loaded properly. // return (hIconCollate && hIconNoCollate); } //////////////////////////////////////////////////////////////////////////// // // Print_InvokePropertySheets // //////////////////////////////////////////////////////////////////////////// BOOL Print_InvokePropertySheets( PPRINTINFOEX pPI, LPPRINTDLGEX pPD) { BOOL bResult = FALSE; TCHAR pszTitle[MAX_PATH]; TCHAR pszCaption[MAX_PATH]; HANDLE hTemplate = NULL; HRSRC hRes; LANGID LangID; if (GET_BIDI_LOCALIZED_SYSTEM_LANGID(NULL)) { if (pPD->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { hTemplate = pPD->hInstance; } else { if (pPD->Flags & PD_ENABLEPRINTTEMPLATE) { hRes = FindResource(pPD->hInstance, pPD->lpPrintTemplateName, RT_DIALOG); if (hRes) { hTemplate = LoadResource(pPD->hInstance, hRes); } } } // // Warning! Warning! Warning! // // We have to set g_tlsLangID before any call for CDLoadString // TlsSetValue(g_tlsLangID, (LPVOID) GetDialogLanguage(pPD->hwndOwner, hTemplate)); } // // Load all of the necessary strings. // CDLoadString(g_hinst, iszGeneralPage, pszTitle, ARRAYSIZE(pszTitle)); CDLoadString(g_hinst, iszPrintCaption, pszCaption, ARRAYSIZE(pszCaption)); // // See if the exclusion flags are set properly. // if (!(pPD->Flags & PD_EXCLUSIONFLAGS)) { pPD->ExclusionFlags = PD_EXCL_COPIESANDCOLLATE; } // // Set up the General page. // PROPSHEETPAGE genPage = {0}; genPage.dwSize = sizeof(PROPSHEETPAGE); genPage.dwFlags = PSP_DEFAULT | PSP_USETITLE; genPage.hInstance = g_hinst; genPage.pszTemplate = (pPD->Flags & PD_USELARGETEMPLATE) ? MAKEINTRESOURCE(IDD_PRINT_GENERAL_LARGE) : MAKEINTRESOURCE(IDD_PRINT_GENERAL); LangID = (LANGID)TlsGetValue(g_tlsLangID); if (LangID) { hRes = FindResourceExFallback(g_hinst, RT_DIALOG, genPage.pszTemplate, LangID); if (hRes) { if ((hTemplate = LoadResource(g_hinst, hRes)) && LockResource(hTemplate)) { genPage.dwFlags |= PSP_DLGINDIRECT; genPage.pResource = (LPCDLGTEMPLATE)hTemplate; } } } genPage.pszIcon = NULL; genPage.pszTitle = pszTitle; genPage.pfnDlgProc = Print_GeneralDlgProc; genPage.lParam = (LPARAM)pPI; genPage.pfnCallback = NULL; genPage.pcRefParent = NULL; HPROPSHEETPAGE hGenPage = CreatePropertySheetPage( &genPage ); if( hGenPage ) { // // Initialize the property sheet header. // PROPSHEETHEADER psh = {0}; psh.dwSize = sizeof(psh); psh.dwFlags = pPI->fOld ? PSH_USEICONID | PSH_NOAPPLYNOW : PSH_USEICONID; psh.hwndParent = pPD->hwndOwner; psh.hInstance = g_hinst; psh.pszIcon = MAKEINTRESOURCE(ICO_PRINTER); psh.pszCaption = pszCaption; psh.nPages = pPD->nPropertyPages + 1; psh.phpage = new HPROPSHEETPAGE[ psh.nPages ]; if( psh.phpage ) { psh.phpage[0] = hGenPage; memcpy( psh.phpage+1, pPD->lphPropertyPages, pPD->nPropertyPages * sizeof(psh.phpage[0]) ); // // Bring up the property sheet pages. // bResult = (-1 != PropertySheet(&psh)); delete [] psh.phpage; } else { pPI->hResult = E_OUTOFMEMORY; } } else { pPI->hResult = CreateError(); } // // Return the result. // return (bResult); } LRESULT CALLBACK PrshtSubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp, UINT_PTR uID, ULONG_PTR dwRefData) { LRESULT lres; switch (wm) { case WM_NCDESTROY: // Clean up subclass RemoveWindowSubclass(hwnd, PrshtSubclassProc, 0); lres = DefSubclassProc(hwnd, wm, wp, lp); break; case ( WM_HELP ) : { HWND hwndItem = (HWND)((LPHELPINFO)lp)->hItemHandle; if (hwndItem == GetDlgItem(hwnd, IDOK)) { WinHelp( hwndItem, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)aPrintExHelpIDs ); lres = TRUE; } else { lres = DefSubclassProc(hwnd, wm, wp, lp); } break; } case ( WM_CONTEXTMENU ) : { if ((HWND)wp == GetDlgItem(hwnd, IDOK)) { WinHelp( (HWND)wp, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)aPrintExHelpIDs ); lres = TRUE; } else { lres = DefSubclassProc(hwnd, wm, wp, lp); } break; } default: lres = DefSubclassProc(hwnd, wm, wp, lp); break; } return lres; } //////////////////////////////////////////////////////////////////////////// // // Print_GeneralDlgProc // //////////////////////////////////////////////////////////////////////////// BOOL_PTR CALLBACK Print_GeneralDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPrintBrowser *pDlgStruct = NULL; if (uMsg != WM_INITDIALOG) { pDlgStruct = Print_HwndToBrowser(hDlg); } switch (uMsg) { case ( WM_INITDIALOG ) : { if (!Print_InitDialog(hDlg, wParam, lParam)) { PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL); } g_hwndActivePrint = hDlg; //Subclass the Main Property sheet for Help Messages SetWindowSubclass(GetParent(hDlg), PrshtSubclassProc, 0, 0); break; } case ( WM_NCDESTROY ) : { Print_StoreBrowser(hDlg, NULL); if (pDlgStruct) { pDlgStruct->OnDestroyMessage(); pDlgStruct->Release(); } break; } case ( WM_ERASEBKGND ) : { // // This code is to workaround: Windows NT Bugs#344991 // HWND hwndView = GetDlgItem(hDlg, IDC_PRINTER_LISTVIEW); if (hwndView) { // // Get the printer folder view rect. // RECT rcView; if (GetWindowRect(hwndView, &rcView)) { MapWindowRect(HWND_DESKTOP, hDlg, &rcView); // // Exclude the printer folder view rect from the cliping region. // if (ERROR == ExcludeClipRect(reinterpret_cast(wParam), rcView.left, rcView.top, rcView.right, rcView.bottom)) { ASSERT(FALSE); } } } break; } case ( WM_ACTIVATE ) : { if (wParam == WA_INACTIVE) { // // Make sure some other Print dialog has not already grabbed // the focus. This is a process global, so it should not // need to be protected. // if (g_hwndActivePrint == hDlg) { g_hwndActivePrint = NULL; } } else { g_hwndActivePrint = hDlg; } break; } case ( WM_COMMAND ) : { if (pDlgStruct) { return (pDlgStruct->OnCommandMessage(wParam, lParam)); } break; } case ( WM_DRAWITEM ) : { break; } case ( WM_MEASUREITEM ) : { break; } case ( WM_NOTIFY ) : { if (pDlgStruct) { return (pDlgStruct->OnNotifyMessage(wParam, (LPNMHDR)lParam)); } break; } case ( WM_HELP ) : { HWND hwndItem = (HWND)((LPHELPINFO)lParam)->hItemHandle; // // We assume that the defview has one child window that // covers the entire defview window. // HWND hwndDefView = GetDlgItem(hDlg, IDC_PRINTER_LISTVIEW); if (GetParent(hwndItem) == hwndDefView) { hwndItem = hwndDefView; } WinHelp( hwndItem, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)aPrintExHelpIDs ); return (TRUE); } case ( WM_CONTEXTMENU ) : { WinHelp( (HWND)wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)aPrintExHelpIDs ); return (TRUE); } case ( CWM_GETISHELLBROWSER ) : { ::SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LRESULT)pDlgStruct); return (TRUE); } case ( CDM_SELCHANGE ) : { if (pDlgStruct) { pDlgStruct->OnSelChange(); } break; } case ( CDM_PRINTNOTIFY ) : { if (pDlgStruct) { LPITEMIDLIST *ppidl; LONG lEvent; BOOL bRet = FALSE; LPSHChangeNotificationLock pLock; // // Get the change notification info from the shared memory // block identified by the handle passed in the wParam. // pLock = SHChangeNotification_Lock( (HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent ); if (pLock == NULL) { return (FALSE); } // // Handle the change notification. // bRet = pDlgStruct->OnChangeNotify( lEvent, (LPCITEMIDLIST *)ppidl ); // // Release the shared block. // SHChangeNotification_Unlock(pLock); // // Return the result. // return (bRet); } break; } case ( CDM_NOPRINTERS ) : { // // There are no printers, so bring up the dialog telling the // user that they need to install a printer. // if (pDlgStruct) { pDlgStruct->OnNoPrinters((HWND)wParam, (HRESULT)lParam); } } case ( CDM_INITDONE ) : { if (pDlgStruct) { pDlgStruct->OnInitDone(); } break; } default : { break; } } // // Return the result. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // Print_GeneralChildDlgProc // //////////////////////////////////////////////////////////////////////////// BOOL_PTR CALLBACK Print_GeneralChildDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = FALSE; CPrintBrowser *pDlgStruct = Print_HwndToBrowser(GetParent(hDlg)); // // See if we need to call an application callback to handle the // message. // if (pDlgStruct) { if (pDlgStruct->HandleMessage(hDlg, uMsg, wParam, lParam, &lResult) != S_FALSE) { if (uMsg == WM_INITDIALOG) { PostMessage(GetParent(hDlg), CDM_INITDONE, 0, 0); } // // BUGBUG: The return from a dlgproc is different than a winproc. // return (BOOLFROMPTR(lResult)); } } // // If we get to this point, we need to handle the message. // switch (uMsg) { case ( WM_INITDIALOG ) : { if (pDlgStruct) { if (!pDlgStruct->OnChildInitDialog(hDlg, wParam, lParam)) { PropSheet_PressButton( GetParent(GetParent(hDlg)), PSBTN_CANCEL ); } } break; } case ( WM_DESTROY ) : { break; } case ( WM_ACTIVATE ) : { break; } case ( WM_COMMAND ) : { if (pDlgStruct) { return (pDlgStruct->OnChildCommandMessage(wParam, lParam)); } break; } case ( WM_DRAWITEM ) : { break; } case ( WM_MEASUREITEM ) : { break; } case ( WM_NOTIFY ) : { break; } case ( WM_HELP ) : { WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)aPrintExChildHelpIDs ); return (TRUE); } case ( WM_CONTEXTMENU ) : { WinHelp( (HWND)wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)aPrintExChildHelpIDs ); return (TRUE); } default : { break; } } // // Return the result. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // Print_MessageHookProc // // Handles the input event messages. // //////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK Print_MessageHookProc( int nCode, WPARAM wParam, LPARAM lParam) { PMSG pMsg; // // See if the nCode is negative. If so, call the default hook proc. // if (nCode < 0) { return (DefHookProc(nCode, wParam, lParam, &g_hHook)); } // // Make sure we only handle dialog box messages. // if (nCode != MSGF_DIALOGBOX) { return (0); } // // Get the msg structure. // pMsg = (PMSG)lParam; // // Make sure the message is one of the WM_KEY* messages. // if (Print_IsInRange(pMsg->message, WM_KEYFIRST, WM_KEYLAST)) { HWND hwndActivePrint = g_hwndActivePrint; HWND hwndFocus = GetFocusedChild(hwndActivePrint, pMsg->hwnd); CPrintBrowser *pDlgStruct; if (hwndFocus && (pDlgStruct = Print_HwndToBrowser(hwndActivePrint)) != NULL) { return (pDlgStruct->OnAccelerator( hwndActivePrint, hwndFocus, g_haccPrint, pMsg )); } } // // Return that the message was not handled. // return (0); } //////////////////////////////////////////////////////////////////////////// // // Print_InitDialog // //////////////////////////////////////////////////////////////////////////// BOOL Print_InitDialog( HWND hDlg, WPARAM wParam, LPARAM lParam) { // // Create the CPrintBrowser object and store it in DWL_USER. // CPrintBrowser *pDlgStruct = new CPrintBrowser(hDlg); if (pDlgStruct == NULL) { return (FALSE); } Print_StoreBrowser(hDlg, pDlgStruct); // // Let the class function do the work. // return (pDlgStruct->OnInitDialog(wParam, lParam)); } //////////////////////////////////////////////////////////////////////////// // // Print_ICoCreateInstance // // Create an instance of the specified shell class. // //////////////////////////////////////////////////////////////////////////// HRESULT Print_ICoCreateInstance( REFCLSID rclsid, REFIID riid, LPCITEMIDLIST pidl, LPVOID *ppv) { LPSHELLFOLDER pshf = NULL; HRESULT hres = E_FAIL; // // Initialize the pointer to the shell view. // *ppv = NULL; // // Get the IShellFolder interface to the desktop folder and then // bind to it. This is equivalent to calling CoCreateInstance // with CLSID_ShellDesktop. // hres = SHGetDesktopFolder(&pshf); if (SUCCEEDED(hres)) { hres = pshf->BindToObject(pidl, NULL, riid, ppv); pshf->Release(); } // // Return the result. // return (hres); } //////////////////////////////////////////////////////////////////////////// // // Print_SaveDevNames // // Saves the current devnames in the pPD structure. // //////////////////////////////////////////////////////////////////////////// BOOL Print_SaveDevNames( LPTSTR pCurPrinter, LPPRINTDLGEX pPD) { TCHAR szPortName[MAX_PATH]; TCHAR szPrinterName[MAX_PATH]; DWORD cbDevNames; LPDEVNAMES pDN; // // Get the port name. // szPortName[0] = 0; Print_GetPortName(pCurPrinter, szPortName, ARRAYSIZE(szPortName)); // // Compute the size of the DevNames structure. // cbDevNames = lstrlen(szDriver) + 1 + lstrlen(szPortName) + 1 + lstrlen(pCurPrinter) + 1 + DN_PADDINGCHARS; cbDevNames *= sizeof(TCHAR); cbDevNames += sizeof(DEVNAMES); // // Allocate the new DevNames structure. // pDN = NULL; if (pPD->hDevNames) { HANDLE handle; handle = GlobalReAlloc(pPD->hDevNames, cbDevNames, GHND); //Check that realloc succeeded. if (handle) { pPD->hDevNames = handle; } else { //Realloc didn't succeed. Free the memory occupied. GlobalFree(pPD->hDevNames); pPD->hDevNames = NULL; } } else { pPD->hDevNames = GlobalAlloc(GHND, cbDevNames); } // // Fill in the DevNames structure with the appropriate information. // if ( (pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames)) ) { // // Save the driver name - winspool. // pDN->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR); StringCchCopy((LPTSTR)pDN + pDN->wDriverOffset, lstrlen(szDriver) + 1, szDriver); // // Save the printer name. // pDN->wDeviceOffset = pDN->wDriverOffset + lstrlen(szDriver) + 1; StringCchCopy((LPTSTR)pDN + pDN->wDeviceOffset, lstrlen(pCurPrinter) + 1, pCurPrinter); // // Save the port name. // pDN->wOutputOffset = pDN->wDeviceOffset + lstrlen(pCurPrinter) + 1; StringCchCopy((LPTSTR)pDN + pDN->wOutputOffset, lstrlen(szPortName) + 1, szPortName); // // Save whether or not it's the default printer. // if (pPD->Flags & PD_RETURNDEFAULT) { pDN->wDefault = DN_DEFAULTPRN; } else { szPrinterName[0] = 0; PrintGetDefaultPrinterName(szPrinterName, ARRAYSIZE(szPrinterName)); if (szPrinterName[0] && !lstrcmp(pCurPrinter, szPrinterName)) { pDN->wDefault = DN_DEFAULTPRN; } else { pDN->wDefault = 0; } } // // Unlock it. // GlobalUnlock(pPD->hDevNames); } else { SetLastError(ERROR_OUTOFMEMORY); return (FALSE); } // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // Print_GetPortName // // Gets the port name for the given printer and stores it in the // given buffer. // //////////////////////////////////////////////////////////////////////////// VOID Print_GetPortName( LPTSTR pCurPrinter, LPTSTR pBuffer, int cchBuffer) { HANDLE hPrinter; DWORD cbPrinter = 0; PRINTER_INFO_2 *pPrinter = NULL; // // Initialize the buffer. // if (!cchBuffer) { return; } pBuffer[0] = 0; // // Open the current printer. // if (OpenPrinter(pCurPrinter, &hPrinter, NULL)) { // // Get the size of the buffer needed to hold the printer info 2 // information. // if (!GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbPrinter )) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // // Allocate a buffer to hold the printer info 2 information. // if (pPrinter = (PRINTER_INFO_2 *)LocalAlloc(LPTR, cbPrinter)) { // // Get the printer info 2 information. // if (GetPrinter( hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbPrinter )) { // // Save the port name in the given buffer. // lstrcpyn(pBuffer, pPrinter->pPortName, cchBuffer); pBuffer[cchBuffer - 1] = 0; } } } } // // Close the printer. // ClosePrinter(hPrinter); } // // Free the printer info 2 information for the current printer. // if (pPrinter) { LocalFree(pPrinter); } } //////////////////////////////////////////////////////////////////////////// // // Print_GetDevModeWrapper // // Calls PrintGetDevMode. // //////////////////////////////////////////////////////////////////////////// HANDLE Print_GetDevModeWrapper( LPTSTR pszDeviceName) { HANDLE hPrinter; HANDLE hDevMode = NULL; if (OpenPrinter(pszDeviceName, &hPrinter, NULL)) { hDevMode = PrintGetDevMode(0, hPrinter, pszDeviceName, NULL); ClosePrinter(hPrinter); } // // Return the handle to the devmode. // return (hDevMode); } //////////////////////////////////////////////////////////////////////////// // // Print_NewPrintDlg // // Converts the old style pPD structure to the new one and then calls // the PrintDlgEx function. // //////////////////////////////////////////////////////////////////////////// BOOL Print_NewPrintDlg( PPRINTINFO pPI) { LPPRINTDLG pPD = pPI->pPD; PRINTINFOEX PIEx; PRINTDLGEX PDEx; PRINTPAGERANGE PageRange; HRESULT hResult; // PrintDlg did the following for the page ranges. Do the same thing for PrintDlgEx if (!(pPD->Flags & PD_PAGENUMS)) { if (pPD->nFromPage != 0xFFFF) { if (pPD->nFromPage < pPD->nMinPage) { pPD->nFromPage = pPD->nMinPage; } else if (pPD->nFromPage > pPD->nMaxPage) { pPD->nFromPage = pPD->nMaxPage; } } if (pPD->nToPage != 0xFFFF) { if (pPD->nToPage < pPD->nMinPage) { pPD->nToPage = pPD->nMinPage; } else if (pPD->nToPage > pPD->nMaxPage) { pPD->nToPage = pPD->nMaxPage; } } } // // Set up the PRINTINFOEX structure. // PIEx.ApiType = pPI->ApiType; PIEx.pPD = &PDEx; PIEx.fOld = TRUE; // // Copy the page range. // PageRange.nFromPage = pPD->nFromPage; PageRange.nToPage = pPD->nToPage; // // Set up the PRINTDLGEX structure with the appropriate values from // the PRINTDLG structure. // PDEx.lStructSize = sizeof(PRINTDLGEX); PDEx.hwndOwner = pPD->hwndOwner; PDEx.hDevMode = pPD->hDevMode; PDEx.hDevNames = pPD->hDevNames; PDEx.hDC = pPD->hDC; PDEx.Flags = (pPD->Flags & ~(PD_SHOWHELP | PD_NONETWORKBUTTON)) | (PD_NOCURRENTPAGE); PDEx.Flags2 = 0; PDEx.ExclusionFlags = 0; PDEx.nPageRanges = 1; PDEx.nMaxPageRanges = 1; PDEx.lpPageRanges = &PageRange; PDEx.nMinPage = pPD->nMinPage; PDEx.nMaxPage = pPD->nMaxPage; PDEx.nCopies = pPD->nCopies; PDEx.hInstance = pPD->hInstance; PDEx.lpCallback = NULL; PDEx.lpPrintTemplateName = NULL; PDEx.nPropertyPages = 0; PDEx.lphPropertyPages = NULL; PDEx.nStartPage = START_PAGE_GENERAL; PDEx.dwResultAction = 0; // // Since we're in the old dialog, allow the the hInstance to be // non-NULL even if there is not a template. // if (!(pPD->Flags & (PD_ENABLEPRINTTEMPLATE | PD_ENABLEPRINTTEMPLATEHANDLE))) { PDEx.hInstance = NULL; } // // Initialize the error code to 0. // StoreExtendedError(CDERR_GENERALCODES); // // Call PrintDlgExX to bring up the dialog. // hResult = PrintDlgExX(&PIEx); // // See if the call failed. If so, store the error and return FALSE. // if (FAILED(hResult)) { StoreExtendedError(PIEx.dwExtendedError); return (FALSE); } // // The call succeeded, so convert the PRINTDLGEX structure back to // the PRINTDLG structure if PD_RESULT_CANCEL is not set. // if (PDEx.dwResultAction != PD_RESULT_CANCEL) { pPD->hDevMode = PDEx.hDevMode; pPD->hDevNames = PDEx.hDevNames; pPD->hDC = PDEx.hDC; pPD->Flags = PDEx.Flags & ~(PD_NOCURRENTPAGE); pPD->nFromPage = (WORD)PageRange.nFromPage; pPD->nToPage = (WORD)PageRange.nToPage; pPD->nCopies = (WORD)PDEx.nCopies; } // // Return TRUE if the user hit Print. // if (PDEx.dwResultAction == PD_RESULT_PRINT) { return (TRUE); } // // Return FALSE for cancel. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::CPrintBrowser // // CPrintBrowser constructor. // //////////////////////////////////////////////////////////////////////////// CPrintBrowser::CPrintBrowser( HWND hDlg) : cRef(1), hwndDlg(hDlg), hSubDlg(NULL), hwndView(NULL), hwndUpDown(NULL), psv(NULL), psfv(NULL), psfRoot(NULL), pidlRoot(NULL), ppf(NULL), pPI(NULL), pPD(NULL), pCallback(NULL), pSite(NULL), pDMInit(NULL), pDMCur(NULL), cchCurPrinter(0), pszCurPrinter(NULL), nCopies(1), nMaxCopies(1), nPageRanges(0), nMaxPageRanges(0), pPageRanges(NULL), fSelChangePending(FALSE), fFirstSel(1), fCollateRequested(FALSE), fAPWSelected(FALSE), fNoAccessPrinterSelected(FALSE), fDirtyDevmode(FALSE), fDevmodeEdit(FALSE), fAllowCollate(FALSE), nInitDone(0), nListSep(0), uRegister(0), uDefViewMode(VIEW_MODE_DEFAULT), pInternalDevMode(NULL), hPrinter(NULL) { HMENU hMenu; hMenu = GetSystemMenu(hDlg, FALSE); DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND); DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND); DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND); szListSep[0] = 0; szScratch[0] = 0; szPrinter[0] = 0; pDMSave = (LPDEVMODE)GlobalAlloc(GPTR, sizeof(DEVMODE)); Shell_GetImageLists(NULL, &himl); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::~CPrintBrowser // // CPrintBrowser destructor. // //////////////////////////////////////////////////////////////////////////// CPrintBrowser::~CPrintBrowser() { // // Deregister notifications. // if (uRegister) { SHChangeNotifyDeregister(uRegister); uRegister = 0; } // // Release the printer folder private interface. // if (ppf != NULL) { ppf->Release(); ppf = NULL; } // // Release the printer shell folder. // if (psfRoot != NULL) { psfRoot->Release(); psfRoot = NULL; } // // Free the pidl. // if (pidlRoot != NULL) { SHFree(pidlRoot); pidlRoot = NULL; } // // Free the devmodes. // if (pDMInit) { GlobalFree(pDMInit); pDMInit = NULL; } if (pDMSave) { GlobalFree(pDMSave); pDMSave = NULL; } // // Free the current printer buffer. // cchCurPrinter = 0; if (pszCurPrinter) { GlobalFree(pszCurPrinter); pszCurPrinter = NULL; } // // Free the page range. // nPageRanges = 0; nMaxPageRanges = 0; if (pPageRanges) { GlobalFree(pPageRanges); pPageRanges = NULL; } if (pInternalDevMode) { GlobalFree(pInternalDevMode); pInternalDevMode = NULL; } if (hPrinter) { ClosePrinter(hPrinter); hPrinter = NULL; } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::QueryInterface // // Standard OLE2 style methods for this object. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::QueryInterface( REFIID riid, LPVOID *ppvObj) { if (IsEqualIID(riid, IID_IShellBrowser) || IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IShellBrowser *)this; ++cRef; return (S_OK); } else if (IsEqualIID(riid, IID_ICommDlgBrowser)) { *ppvObj = (ICommDlgBrowser2 *)this; ++cRef; return (S_OK); } else if (IsEqualIID(riid, IID_ICommDlgBrowser2)) { *ppvObj = (ICommDlgBrowser2 *)this; ++cRef; return (S_OK); } else if (IsEqualIID(riid, IID_IPrintDialogServices)) { *ppvObj = (IPrintDialogServices *)this; ++cRef; return (S_OK); } *ppvObj = NULL; return (E_NOINTERFACE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::AddRef // //////////////////////////////////////////////////////////////////////////// ULONG STDMETHODCALLTYPE CPrintBrowser::AddRef() { return (++cRef); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::Release // //////////////////////////////////////////////////////////////////////////// ULONG STDMETHODCALLTYPE CPrintBrowser::Release() { cRef--; if (cRef > 0) { return (cRef); } delete this; return (0); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetWindow // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::GetWindow( HWND *phwnd) { *phwnd = hwndDlg; return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::ContextSensitiveHelp // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::ContextSensitiveHelp( BOOL fEnable) { // // Shouldn't need in a common dialog. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InsertMenusSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::InsertMenusSB( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { return (E_NOTIMPL); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SetMenuSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::SetMenuSB( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) { return (E_NOTIMPL); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::RemoveMenusSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::RemoveMenusSB( HMENU hmenuShared) { return (E_NOTIMPL); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SetStatusTextSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::SetStatusTextSB( LPCOLESTR pwch) { // // We don't have any status bar. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::EnableModelessSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::EnableModelessSB( BOOL fEnable) { // // We don't have any modeless window to be enabled/disabled. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::TranslateAcceleratorSB // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::TranslateAcceleratorSB( LPMSG pmsg, WORD wID) { // // We don't use the Key Stroke. // return S_FALSE; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::BrowseObject // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::BrowseObject( LPCITEMIDLIST pidl, UINT wFlags) { // // We don't support browsing, or more precisely, CDefView doesn't. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetViewStateStream // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::GetViewStateStream( DWORD grfMode, LPSTREAM *pStrm) { return (E_NOTIMPL); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetControlWindow // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::GetControlWindow( UINT id, HWND *lphwnd) { return (E_NOTIMPL); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SendControlMsg // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::SendControlMsg( UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) { LRESULT lres = 0; if (pret) { *pret = lres; } return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::QueryActiveShellView // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::QueryActiveShellView( LPSHELLVIEW *ppsv) { if (psv) { *ppsv = psv; psv->AddRef(); return (S_OK); } *ppsv = NULL; return (E_NOINTERFACE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnViewWindowActive // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::OnViewWindowActive( LPSHELLVIEW psv) { // // No need to process this. We don't do menus. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SetToolbarItems // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::SetToolbarItems( LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags) { // // We don't let containers customize our toolbar. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnDefaultCommand // // Process a double-click or Enter keystroke in the view control. // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::OnDefaultCommand( struct IShellView *ppshv) { // // Make sure it's the correct shell view. // if (ppshv != psv) { return (E_INVALIDARG); } // // See if the Add Printer Wizard is selected. // if (fAPWSelected) { // // Invoke the Add Printer Wizard (modeless). // InvokeAddPrinterWizardModal(hwndDlg, NULL); } else if (fNoAccessPrinterSelected) { // // Display error message indicated we do not have access. // ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterAccess); } else { // // Simulate the pressing of the OK button. // PropSheet_PressButton(GetParent(hwndDlg), PSBTN_OK); } // // Tell the shell that the action has been processed. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnStateChange // // Process selection change in the view control. // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::OnStateChange( struct IShellView *ppshv, ULONG uChange) { if (ppshv != psv) { return (E_INVALIDARG); } switch (uChange) { case ( CDBOSC_SETFOCUS ) : { break; } case ( CDBOSC_KILLFOCUS ) : { break; } case ( CDBOSC_SELCHANGE ) : { // // Post one of these messages, since we seem to get a whole // bunch of them. // if (!fSelChangePending) { fSelChangePending = TRUE; PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0); } break; } case ( CDBOSC_RENAME ) : { break; } default : { return (E_NOTIMPL); } } return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::IncludeObject // // Tell the view control which objects to include in its enumerations. // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::IncludeObject( struct IShellView *ppshv, LPCITEMIDLIST pidl) { // // Make sure it's my shell view. // if (ppshv != psv) { return (E_INVALIDARG); } // // If we have the printer folder private interface, return ok only // if it's a printer. // if (ppf) { return (ppf->IsPrinter(pidl) ? S_OK : S_FALSE); } // // This shouldn't happen at this point, but just in case we don't have // a printer folder private interface, simply return ok. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::Notify // // Notification to decide whether or not a printer should be selected. // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::Notify( struct IShellView *ppshv, DWORD dwNotify) { HRESULT hr = S_OK; // // Make sure it's my shell view. // if (ppshv != psv) { return (E_INVALIDARG); } switch (dwNotify) { case (CDB2N_CONTEXTMENU_DONE): { HWND hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL); if (hwndListView) { HWND hwndEdit = ListView_GetEditControl(hwndListView); if (NULL == hwndEdit) { // if not in edit mode then re-select the current item SelectSVItem(); } } break; } default: { hr = S_FALSE; break; } } // // This shouldn't happen at this point, but just in case we don't have // a printer folder private interface, simply return ok. // return (hr); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetDefaultMenuText // // Returns the default menu text. // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::GetDefaultMenuText( struct IShellView *ppshv, WCHAR *pszText, INT cchMax) { // // Make sure it's my shell view. // if (ppshv != psv) { return (E_INVALIDARG); } // // If the add printer wizard is the selected item, do not change // the default menu text. // if (fAPWSelected) { return (S_FALSE); } // // Change the default menu text from 'Select' to 'Print'. // if (!CDLoadString(g_hinst, iszDefaultMenuText, szScratch, ARRAYSIZE(szScratch))) { return (E_FAIL); } // // Just copy the default menu text to the provided buffer if there // is room. // if (lstrlen(szScratch) < cchMax) { lstrcpyn(pszText, szScratch, cchMax); } else { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetViewFlags // // Returns Flags to customize the view . // //////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPrintBrowser::GetViewFlags(DWORD *pdwFlags) { if (pdwFlags) { *pdwFlags = 0; } return S_OK; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InitDone // // Notifies the sub dialog that initialization of the General page is // complete. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::InitDone() { HRESULT hResult = S_FALSE; // // Notify the sub dialog that initialization is complete. // if (pCallback) { if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExW2A(pPI); } hResult = pCallback->InitDone(); if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExA2W(pPI); } } // // Return the result. // return (hResult); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SelectionChange // // Notifies the sub dialog that a selection change has taken place. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::SelectionChange() { HRESULT hResult = S_FALSE; // // Handle the Print To File here. // InitPrintToFile(); // // Notify the sub dialog that a selection change has taken place. // if (pCallback) { if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExW2A(pPI); } hResult = pCallback->SelectionChange(); if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExA2W(pPI); } } // // Handle the selection change. // if (hResult == S_FALSE) { // // Handle copies and collate. // InitCopiesAndCollate(); // // Handle the page ranges. // InitPageRangeGroup(); // // Return success. // hResult = S_OK; } // // Return the result. // return (hResult); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::HandleMessage // // Process a message for the child window by calling the application // callback function. // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::HandleMessage( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult) { HRESULT hResult = S_FALSE; BOOL bTest; UINT nRet, ErrorId; DWORD nTmpCopies; // // Initialize the return value. // *pResult = FALSE; // // See if the message should be handled. // if (pCallback) { if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExW2A(pPI); } hResult = pCallback->HandleMessage(hDlg, uMsg, wParam, lParam, pResult); if (pPI->ApiType == COMDLG_ANSI) { ThunkPrintDlgExA2W(pPI); } } // // Handle the message. // if ((hResult == S_FALSE) && (uMsg == WM_NOTIFY)) { switch (((LPNMHDR)lParam)->code) { case ( PSN_KILLACTIVE ) : { // // Make sure the page has valid entries. // If invalid entries are found, then set the DWL_MSGRESULT // of the General page to be TRUE and return TRUE in order // to prevent the page from losing the activation. // // // Validate the number of copies and store it in the // nCopies member. // if ((GetDlgItem(hSubDlg, IDC_COPIES)) && (fAPWSelected == FALSE)) { nTmpCopies = nCopies; nCopies = GetDlgItemInt(hSubDlg, IDC_COPIES, &bTest, FALSE); if (!bTest || !nCopies) { nCopies = nTmpCopies; ShowError(hSubDlg, IDC_COPIES, iszCopiesZero); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); *pResult = TRUE; return (E_FAIL); } } // // Validate the page range and store it in the pRange member. // if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_PAGES) && GetDlgItem(hSubDlg, IDC_RANGE_EDIT)) { nRet = GetDlgItemText( hSubDlg, IDC_RANGE_EDIT, szScratch, ARRAYSIZE(szScratch) ); ErrorId = iszBadPageRange; if (!nRet || !IsValidPageRange(szScratch, &ErrorId)) { ShowError(hSubDlg, IDC_RANGE_EDIT, ErrorId, (ErrorId == iszTooManyPageRanges) ? nMaxPageRanges : pPD->nMinPage, pPD->nMaxPage); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); *pResult = TRUE; return (E_FAIL); } } // // Message has now been handled. // hResult = S_OK; break; } case ( PSN_APPLY ) : { // // Clear the flags that need to be set based on the // contents of the General page. // pPD->Flags &= ~((DWORD)( PD_PAGENUMS | PD_SELECTION | PD_CURRENTPAGE )); // // Save the page range information. // if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_SELECTION)) { pPD->Flags |= PD_SELECTION; } else if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_CURRENT)) { pPD->Flags |= PD_CURRENTPAGE; } else if (IsDlgButtonChecked(hSubDlg, IDC_RANGE_PAGES)) { pPD->Flags |= PD_PAGENUMS; // // Copy the page ranges to the pPageRanges structure // in the PrintDlg structure. // if (GetDlgItem(hSubDlg, IDC_RANGE_EDIT)) { pPD->nPageRanges = nPageRanges; CopyMemory( pPD->lpPageRanges, pPageRanges, nPageRanges * sizeof(PRINTPAGERANGE) ); } } // // Message has now been handled. // hResult = S_OK; break; } } } // // Return the result. // return (hResult); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetCurrentDevMode // // Returns the current devmode structure. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentDevMode( LPDEVMODE pDevMode, UINT *pcbSize) { UINT cbSize; // // Make sure pcbSize is valid. // if ((pcbSize == NULL) || (*pcbSize && !pDevMode)) { return (E_INVALIDARG); } // // When there is no current devmode, set the size to zero and return // TRUE. // if (!pDMCur) { *pcbSize = 0; return (S_OK); } // // Save the current printer name and the current devmode in the // class. // GetCurrentPrinter(); // // See if we just need to get the size of the buffer. // if (*pcbSize == 0) { // // Return the size of the buffer needed. // if (pPI->ApiType == COMDLG_ANSI) { *pcbSize = sizeof(DEVMODEA) + pDMCur->dmDriverExtra; } else { *pcbSize = pDMCur->dmSize + pDMCur->dmDriverExtra; } } else { // // Make sure the copies and collate information is up to date. // SaveCopiesAndCollateInDevMode(pDMCur, pszCurPrinter); // // Return the devmode information as well as the size of the // buffer. // if (pPI->ApiType == COMDLG_ANSI) { cbSize = sizeof(DEVMODEA) + pDMCur->dmDriverExtra; if (*pcbSize < cbSize) { return (E_INVALIDARG); } ThunkDevModeW2A(pDMCur, (LPDEVMODEA)pDevMode); *pcbSize = cbSize; } else { cbSize = pDMCur->dmSize + pDMCur->dmDriverExtra; if (*pcbSize < cbSize) { return (E_INVALIDARG); } CopyMemory(pDevMode, pDMCur, cbSize); *pcbSize = cbSize; } } // // Return success. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetCurrentPrinterName // // Returns the current printer name. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentPrinterName( LPTSTR pPrinterName, UINT *pcchSize) { UINT cchSize; // // Make sure pcchSize is valid. // if ((pcchSize == NULL) || (*pcchSize && !pPrinterName)) { return (E_INVALIDARG); } // // Save the current printer name and the current devmode in the // class. // GetCurrentPrinter(); // // When there is no current printer, set the size to zero and return // TRUE. // if ((pszCurPrinter == NULL) || (pszCurPrinter[0] == 0)) { *pcchSize = 0; return (S_OK); } // // See if we just need to get the size of the buffer. // if (*pcchSize == 0) { if (pPI->ApiType == COMDLG_ANSI) { *pcchSize = WideCharToMultiByte( CP_ACP, 0, pszCurPrinter, -1, NULL, 0, NULL, NULL ); } else { *pcchSize = lstrlen(pszCurPrinter) + 1; } } else { if (pPI->ApiType == COMDLG_ANSI) { *pcchSize = SHUnicodeToAnsi(pszCurPrinter,(LPSTR)pPrinterName,*pcchSize); if (*pcchSize == 0) { return (E_INVALIDARG); } } else { cchSize = lstrlen(pszCurPrinter) + 1; if (*pcchSize < cchSize) { return (E_INVALIDARG); } StringCchCopy(pPrinterName, cchSize, pszCurPrinter); *pcchSize = cchSize; } } // // Return success. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetCurrentPortName // // Returns the current port name. // //////////////////////////////////////////////////////////////////////////// HRESULT STDMETHODCALLTYPE CPrintBrowser::GetCurrentPortName( LPTSTR pPortName, UINT *pcchSize) { UINT cchSize; TCHAR szPortName[MAX_PATH]; // // Make sure pcchSize is valid. // if ((pcchSize == NULL) || (*pcchSize && !pPortName)) { return (E_INVALIDARG); } // // Save the current printer name and the current devmode in the // class. // GetCurrentPrinter(); // // When there is no current printer, set the size to zero and return // TRUE. // if ((pszCurPrinter == NULL) || (pszCurPrinter[0] == 0)) { *pcchSize = 0; return (S_OK); } // // Get the port name for the current printer. // szPortName[0] = 0; Print_GetPortName(pszCurPrinter, szPortName, ARRAYSIZE(szPortName)); // // See if we just need to get the size of the buffer. // if (*pcchSize == 0) { if (pPI->ApiType == COMDLG_ANSI) { *pcchSize = WideCharToMultiByte( CP_ACP, 0, szPortName, -1, NULL, 0, NULL, NULL ); } else { *pcchSize = lstrlen(szPortName) + 1; } } else { if (pPI->ApiType == COMDLG_ANSI) { *pcchSize = SHUnicodeToAnsi(szPortName,(LPSTR)pPortName,*pcchSize); if (*pcchSize == 0) { return (E_INVALIDARG); } } else { cchSize = lstrlen(szPortName) + 1; if (*pcchSize < cchSize) { return (E_INVALIDARG); } StringCchCopy(pPortName, cchSize, szPortName); *pcchSize = cchSize; } } // // Return success. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnInitDialog // // Process a WM_INITDIALOG message for the General page. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnInitDialog( WPARAM wParam, LPARAM lParam) { HWND hCtl; LPDEVMODE pDM; LPDEVNAMES pDN; HRESULT hrDevMode; HRESULT hResult; SHChangeNotifyEntry fsne; // // If disable printer addition policy is set then // then disable find button on the print dialog // if( SHRestricted(REST_NOPRINTERADD) ) { EnableWindow( GetDlgItem( hwndDlg, IDC_FIND_PRINTER ), FALSE ); } // // Always disable the preferences button in the begining // EnableWindow( GetDlgItem( hwndDlg, IDC_DRIVER ), FALSE ); // // Get the pointer to the PRINTINFOEX structure from the lParam of // the property sheet structure. // pPI = (PPRINTINFOEX)((LPPROPSHEETPAGE)lParam)->lParam; pPD = pPI->pPD; //Initialize Ole Before doing anything pPI->hrOleInit = SHOleInitialize(0); DEBUG_CODE(GdiSetBatchLimit(1)); // // Initialize the error codes to success now that we have the // pPI structure. // pPI->dwExtendedError = CDERR_GENERALCODES; pPI->hResult = S_OK; // // Create the printer folder shell view. // hResult = CreatePrintShellView(); if (FAILED(hResult)) { pPI->hResult = hResult; return (FALSE); } // // Insert the device pages for the appropriate printer. // // First: Try the printer in the DevMode. // Second: Try the printer in the DevNames. // Third: Use the default by passing in NULLs. // hrDevMode = E_FAIL; if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode))) { DWORD cbSize = (DWORD)(pDM->dmSize + pDM->dmDriverExtra); if (cbSize >= sizeof(DEVMODE) && (pDMInit = (LPDEVMODE)GlobalAlloc(GPTR, cbSize))) { CopyMemory(pDMInit, pDM, cbSize); hrDevMode = InstallDevMode((LPTSTR)pDM->dmDeviceName, pDMInit); } GlobalUnlock(pPD->hDevMode); } if ((FAILED(hrDevMode)) && (pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames))) { LPTSTR pPrinter = (LPTSTR)pDN + pDN->wDeviceOffset; hrDevMode = InstallDevMode(pPrinter, pDMInit); GlobalUnlock(pPD->hDevNames); } if (FAILED(hrDevMode)) { hrDevMode = InstallDevMode(NULL, pDMInit); } // // Get the current printer name and the current devmode. // GetCurrentPrinter(); // // Initialize the "Print to file" check box appropriately. // if (hCtl = GetDlgItem(hwndDlg, IDC_PRINT_TO_FILE)) { if (pPD->Flags & PD_PRINTTOFILE) { CheckDlgButton(hwndDlg, IDC_PRINT_TO_FILE, TRUE); } if (pPD->Flags & PD_HIDEPRINTTOFILE) { EnableWindow(hCtl, FALSE); ShowWindow(hCtl, SW_HIDE); } else if (pPD->Flags & PD_DISABLEPRINTTOFILE) { EnableWindow(hCtl, FALSE); } } // // Set the number of copies and the collation correctly. // pDM = pDMInit ? pDMInit : pDMCur; if (pDMCur && (pDMCur->dmFields & DM_COPIES)) { if (pDMInit || (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE)) { pPD->nCopies = (DWORD)pDM->dmCopies; } else if (pPD->nCopies) { pDMCur->dmCopies = (short)pPD->nCopies; } } if (pDMCur && (pDMCur->dmFields & DM_COLLATE)) { if (pDMInit || (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE)) { if (pDM->dmCollate == DMCOLLATE_FALSE) { pPD->Flags &= ~PD_COLLATE; } else { pPD->Flags |= PD_COLLATE; } } else { pDMCur->dmCollate = (pPD->Flags & PD_COLLATE) ? DMCOLLATE_TRUE : DMCOLLATE_FALSE; } } if (pPD->Flags & PD_COLLATE) { fCollateRequested = TRUE; } // // Create the hook dialog. // hResult = CreateHookDialog(); if (FAILED(hResult)) { pPI->hResult = hResult; return (FALSE); } // // Set the ClipChildren style bit on the main dialog so that we get // proper repainting of the various children in the General page. // SetWindowLong( GetParent(hwndDlg), GWL_STYLE, GetWindowLong(GetParent(hwndDlg), GWL_STYLE) | WS_CLIPCHILDREN ); // // Set the OK button to Print. // CDLoadString(g_hinst, iszPrintButton, szScratch, ARRAYSIZE(szScratch)); SetDlgItemText(GetParent(hwndDlg), IDOK, szScratch); // // Disable the Apply button. // PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); // // Register change notifications. // if (pidlRoot) { fsne.pidl = pidlRoot; fsne.fRecursive = FALSE; uRegister = SHChangeNotifyRegister( hwndDlg, SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel, SHCNE_ATTRIBUTES | SHCNE_UPDATEITEM | SHCNE_CREATE | SHCNE_DELETE | SHCNE_RENAMEITEM, CDM_PRINTNOTIFY, 1, &fsne ); } // // If we failed to insert the device page then tell the // user what is wrong. // if (FAILED(hrDevMode) || !pDMCur) { // // Something has failed. Show an error message. // PostMessage(hwndDlg, CDM_NOPRINTERS, (WPARAM)hwndDlg, (LPARAM)hrDevMode); } // // Give the application the pointer to the IPrintDialogServices // interface. // if (pPD->lpCallback) { pPD->lpCallback->QueryInterface(IID_IObjectWithSite, (LPVOID *)&pSite); if (pSite) { pSite->SetSite((IPrintDialogServices *)this); } } // // Initialization is complete. // PostMessage(hwndDlg, CDM_INITDONE, 0, 0); // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnChildInitDialog // // Process a WM_INITDIALOG message for the child window. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnChildInitDialog( HWND hDlg, WPARAM wParam, LPARAM lParam) { WORD wCheckID; HWND hCtl; // // Save the handle to the child window. // hSubDlg = hDlg; // // Get the list separator for the current user locale. // nListSep = GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SLIST, szListSep, ARRAYSIZE(szListSep) ); if (nListSep == 0) { szListSep[0] = TEXT(','); szListSep[1] = 0; nListSep = 2; } nListSep--; // // Set the number of copies. // pPD->nCopies = max(pPD->nCopies, 1); pPD->nCopies = min(pPD->nCopies, MAX_COPIES); SetDlgItemInt(hSubDlg, IDC_COPIES, pPD->nCopies, FALSE); nCopies = pPD->nCopies; if ((hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) && (GetWindowLong(hCtl, GWL_STYLE) & WS_VISIBLE)) { // // "9999" is the maximum value. // Edit_LimitText(hCtl, COPIES_EDIT_SIZE); hwndUpDown = CreateUpDownControl( WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_NOTHOUSANDS | UDS_ARROWKEYS, 0, 0, 0, 0, hSubDlg, IDC_COPIES_UDARROW, g_hinst, hCtl, MAX_COPIES, 1, pPD->nCopies ); // // Adjust the width of the copies edit control using the current // font and the scroll bar width. This is necessary to handle the // the up down control from encroching on the space in the edit // control when we are in High Contrast (extra large) mode. // SetCopiesEditWidth(hSubDlg, hCtl); } // // Make sure the collate icon is centered. Only want to do this once. // if (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) { SetWindowLong( hCtl, GWL_STYLE, GetWindowLong(hCtl, GWL_STYLE) | SS_CENTERIMAGE ); } // // Initialize the copies and collate info. // InitCopiesAndCollate(); // // Set the page range. // if (pPD->Flags & PD_NOPAGENUMS) { EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_TEXT1), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_TEXT2), FALSE); pPD->Flags &= ~((DWORD)PD_PAGENUMS); } else { // // See if the page range only consists of one page. If so, // disable the Pages radio button and the associated edit control // and disable and hide the collate check box. // if (pPD->nMinPage == pPD->nMaxPage) { EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE); pPD->Flags &= ~((DWORD)(PD_PAGENUMS | PD_COLLATE)); fCollateRequested = FALSE; EnableWindow(GetDlgItem(hSubDlg, IDC_COLLATE), FALSE); ShowWindow(GetDlgItem(hSubDlg, IDC_COLLATE), SW_HIDE); } else { // // Initialize the page range members. // nPageRanges = pPD->nPageRanges; nMaxPageRanges = pPD->nMaxPageRanges; pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, nMaxPageRanges * sizeof(PRINTPAGERANGE)); if (!pPageRanges) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; pPI->hResult = E_OUTOFMEMORY; return (FALSE); } CopyMemory( pPageRanges, pPD->lpPageRanges, nPageRanges * sizeof(PRINTPAGERANGE) ); // // See if we should only accept a single page range. // if (nMaxPageRanges == 1) { hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT2); ShowWindow(hCtl, SW_SHOW); EnableWindow(hCtl, TRUE); hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT1); EnableWindow(hCtl, FALSE); ShowWindow(hCtl, SW_HIDE); } else { hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT1); ShowWindow(hCtl, SW_SHOW); EnableWindow(hCtl, TRUE); hCtl = GetDlgItem(hSubDlg, IDC_RANGE_TEXT2); EnableWindow(hCtl, FALSE); ShowWindow(hCtl, SW_HIDE); } // // Validate the page ranges. // if (!ConvertPageRangesToString(szScratch, ARRAYSIZE(szScratch))) { pPI->dwExtendedError = PDERR_INITFAILURE; pPI->hResult = E_INVALIDARG; return (FALSE); } // // Put the page range string in the edit control. // if (GetDlgItem(hSubDlg, IDC_RANGE_EDIT)) { SetDlgItemText(hSubDlg, IDC_RANGE_EDIT, szScratch); } } } // // See if we should disable the Selection radio button. // if (pPD->Flags & PD_NOSELECTION) { if (hCtl = GetDlgItem(hSubDlg, IDC_RANGE_SELECTION)) { EnableWindow(hCtl, FALSE); } pPD->Flags &= ~((DWORD)PD_SELECTION); } // // See if we should disable the Current Page radio button. // if (pPD->Flags & PD_NOCURRENTPAGE) { if (hCtl = GetDlgItem(hSubDlg, IDC_RANGE_CURRENT)) { EnableWindow(hCtl, FALSE); } pPD->Flags &= ~((DWORD)PD_CURRENTPAGE); } // // Choose one of the page range radio buttons. // if (pPD->Flags & PD_PAGENUMS) { wCheckID = IDC_RANGE_PAGES; } else if (pPD->Flags & PD_SELECTION) { wCheckID = IDC_RANGE_SELECTION; } else if (pPD->Flags & PD_CURRENTPAGE) { wCheckID = IDC_RANGE_CURRENT; } else // PD_ALL { wCheckID = IDC_RANGE_ALL; } CheckRadioButton(hSubDlg, IDC_RANGE_ALL, IDC_RANGE_PAGES, (int)wCheckID); // // See if the collate check box should be checked or not. // if (pPD->Flags & PD_COLLATE) { CheckDlgButton(hSubDlg, IDC_COLLATE, TRUE); } // // Display the appropriate collate icon. // if ((GetWindowLong( GetDlgItem(hSubDlg, IDC_COLLATE), GWL_STYLE ) & WS_VISIBLE) && (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE))) { ShowWindow(hCtl, SW_HIDE); SendMessage( hCtl, STM_SETICON, IsDlgButtonChecked(hSubDlg, IDC_COLLATE) ? (LONG_PTR)hIconCollate : (LONG_PTR)hIconNoCollate, 0L ); ShowWindow(hCtl, SW_SHOW); } // // Save the flags as they are now so I know what to enable // when the selection changes from the Add Printer Wizard icon. // pPI->dwFlags = pPD->Flags; if (pPD->nMinPage == pPD->nMaxPage) { pPI->dwFlags |= PD_NOPAGENUMS; } // // Disable the Apply button. // PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); // // Initialization is complete. // PostMessage(hwndDlg, CDM_INITDONE, 0, 0); // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnDestroyMessage // // Process a WM_DESTROY message for the General page. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::OnDestroyMessage() { if (psfv) { psfv->Release(); psfv = NULL; } if (psv) { psv->DestroyViewWindow(); psv->Release(); psv = NULL; } if (pCallback) { pCallback->Release(); pCallback = NULL; } if (pSite) { pSite->SetSite(NULL); pSite->Release(); pSite = NULL; } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnCommandMessage // // Process a WM_COMMAND message for the General page. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnCommandMessage( WPARAM wParam, LPARAM lParam) { switch (LOWORD(wParam)) { case ( IDC_DRIVER ) : { // // Show the driver UI calling DocumentProperties API. // if (pInternalDevMode) { DWORD dwSize = pInternalDevMode->dmSize + pInternalDevMode->dmDriverExtra; // // Allocate memory for the in/out devmodes and open separate temp printer handle. // LPDEVMODE pDevModeIn = (LPDEVMODE)GlobalAlloc(GPTR, dwSize); LPDEVMODE pDevModeOut = (LPDEVMODE)GlobalAlloc(GPTR, dwSize); HANDLE hTempPrinter = NULL; if (pDevModeIn && pDevModeOut && OpenPrinter((LPTSTR)szPrinter, &hTempPrinter, NULL)) { // // Call DocumentProperties API to allow the user to edit the devmode. // fDirtyDevmode = FALSE; memcpy(pDevModeIn, pInternalDevMode, dwSize); memcpy(pDevModeOut, pInternalDevMode, dwSize); // // Update current copy and collation settings to DEVMODE before calling DocumentProperties() // pDevModeIn->dmCopies = nCopies; pDevModeIn->dmCollate = fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE; fDevmodeEdit = TRUE; LONG lResult = g_pfnDocumentPropertiesWrap(hwndDlg, hTempPrinter, szPrinter, pDevModeOut, pDevModeIn, DM_IN_BUFFER|DM_OUT_BUFFER|DM_IN_PROMPT|DM_OUT_DEFAULT, pPD->ExclusionFlags); fDevmodeEdit = FALSE; if (IDOK == lResult) { // // Check if there is a change after the editing. // if (!fDirtyDevmode && pInternalDevMode && memcmp(pDevModeOut, pInternalDevMode, dwSize)) { // // Refresh the copies and collation in case of change in Preferences... // We simulate a BN_CLICKED message since we need to refresh the collation icon // when we change the collation settings. // if (nCopies != pDevModeOut->dmCopies) { SetDlgItemInt(hSubDlg, IDC_COPIES, pDevModeOut->dmCopies, FALSE); } if ((fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE) ^ pDevModeOut->dmCollate) { CheckDlgButton(hSubDlg, IDC_COLLATE, pDevModeOut->dmCollate ? BST_CHECKED : BST_UNCHECKED); SendMessage(hSubDlg, WM_COMMAND, MAKEWPARAM(IDC_COLLATE ,BN_CLICKED), (LPARAM)GetDlgItem(hSubDlg, IDC_COLLATE)); } // // The internal devmode has been changed. Update it and enable the "Apply" button. // memcpy(pInternalDevMode, pDevModeOut, dwSize); PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } } } // // Release the allocated resources. // if (pDevModeIn) { GlobalFree((HANDLE)pDevModeIn); } if (pDevModeOut) { GlobalFree((HANDLE)pDevModeOut); } if (hTempPrinter) { ClosePrinter(hTempPrinter); } // select the printer's list control SendMessage(hwndDlg, WM_NEXTDLGCTL, reinterpret_cast(GetDlgItem(hwndDlg, IDC_PRINTER_LISTVIEW)), 1); } break; } case ( IDC_FIND_PRINTER ) : { // // Turn on the hour glass. // HourGlass(TRUE); // // Bring up the Find Printer dialog. // szScratch[0] = 0; if (FindPrinter(hwndDlg, szScratch, ARRAYSIZE(szScratch)) && (szScratch[0] != 0)) { // // Add the appropriate device pages and select the // newly found printer. // if (!MergeDevMode(szScratch)) { InstallDevMode(szScratch, NULL); } if (!fSelChangePending) { fFirstSel = 2; fSelChangePending = TRUE; PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0); } } // // Turn off the hour glass. // HourGlass(FALSE); break; } case ( IDC_PRINT_TO_FILE ) : { // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } case ( IDC_REFRESH ) : { if (psv) { psv->Refresh(); } break; } default : { break; } } // // Return FALSE. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnChildCommandMessage // // Process a WM_COMMAND message for the child window. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnChildCommandMessage( WPARAM wParam, LPARAM lParam) { HWND hCtl; RECT rc; DWORD nTmpCopies; BOOL bTest; switch (LOWORD(wParam)) { case ( IDC_RANGE_ALL ) : // Print Range - All case ( IDC_RANGE_SELECTION ) : // Print Range - Selection case ( IDC_RANGE_CURRENT ) : // Print Range - Current Page case ( IDC_RANGE_PAGES ) : // Print Range - Pages { CheckRadioButton( hSubDlg, IDC_RANGE_ALL, IDC_RANGE_PAGES, GET_WM_COMMAND_ID(wParam, lParam) ); // // Only move the focus to the "Pages" edit control when // the up/down arrow is NOT used. // if ( !IS_KEY_PRESSED(VK_UP) && !IS_KEY_PRESSED(VK_DOWN) && ((BOOL)(GET_WM_COMMAND_ID(wParam, lParam) == IDC_RANGE_PAGES)) ) { SendMessage( hSubDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hSubDlg, IDC_RANGE_EDIT), 1L ); } // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } case ( IDC_RANGE_EDIT ) : // Print Range - Pages edit control { if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) { CheckRadioButton( hSubDlg, IDC_RANGE_ALL, IDC_RANGE_PAGES, IDC_RANGE_PAGES ); // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } break; } case ( IDC_COPIES ) : { if ((GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE) && (fAPWSelected == FALSE)) { // // Save the number of copies. // nTmpCopies = nCopies; nCopies = GetDlgItemInt(hSubDlg, IDC_COPIES, &bTest, FALSE); if (!bTest || !nCopies) { nCopies = nTmpCopies; } // // If the printer can support collate and copy count > 1, enable collate. // Otherwise, disable it. // if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) { EnableWindow( hCtl, (fAllowCollate && (nCopies > 1) ? TRUE : FALSE) ); } // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } break; } case ( IDC_COLLATE ) : { fCollateRequested = (IsDlgButtonChecked(hSubDlg, IDC_COLLATE)) ? TRUE : FALSE; if (hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) { ShowWindow(hCtl, SW_HIDE); SendMessage( hCtl, STM_SETICON, fCollateRequested ? (LONG_PTR)hIconCollate : (LONG_PTR)hIconNoCollate, 0L ); ShowWindow(hCtl, SW_SHOW); // // Make it redraw to get rid of the old one. // GetWindowRect(hCtl, &rc); MapWindowRect(NULL, hwndDlg, &rc); RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE); } // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } default : { break; } } // // Return FALSE. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnNotifyMessage // // Process WM_NOTIFY messages for the General page. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnNotifyMessage( WPARAM wParam, LPNMHDR pnm) { HWND hCtl; LPDEVMODE pDM; LPDEVNAMES pDN; LRESULT lResult; switch (pnm->code) { case ( PSN_SETACTIVE ) : { break; } case ( PSN_KILLACTIVE ) : { // // Validation of the copies and page range values is done // in the HandleMessage function for the sub dialog. // break; } case ( PSN_APPLY ) : { // // Save the current printer information. // if (!GetCurrentPrinter() || !pDMCur) { ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); return (TRUE); } // // Clear the flags that need to be set based on the contents // of the General page. // pPD->Flags &= ~((DWORD)( PD_PRINTTOFILE | PD_COLLATE | PD_PAGENUMS | PD_SELECTION | PD_CURRENTPAGE )); // // Save the collate information. // if ((hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) && (fAPWSelected == FALSE)) { if (IsDlgButtonChecked(hSubDlg, IDC_COLLATE)) { pPD->Flags |= PD_COLLATE; } else { pPD->Flags &= ~PD_COLLATE; } } // // Save the info that the user hit OK. // pPI->FinalResult = 1; pPI->fApply = TRUE; // // Save the print to file information. // if (IsDlgButtonChecked(hwndDlg, IDC_PRINT_TO_FILE)) { pPD->Flags |= PD_PRINTTOFILE; } // // Save the view mode for the printer folder. // SetViewMode(); // // Disable the Apply button. // PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); break; } case PSN_LASTCHANCEAPPLY: { // // Save the current printer information. // if (!GetCurrentPrinter() || !pDMCur) { ShowError(hwndDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected); return (TRUE); } // // Save the number of copies. // if ((hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) && (fAPWSelected == FALSE)) { pPD->nCopies = nCopies; if(!SetCopiesOnApply()) { nCopies = pPD->nCopies; SetDlgItemInt(hSubDlg, IDC_COPIES, nCopies, FALSE); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); return (TRUE); } } // // Save the DevMode information. // SaveDevMode(); // // Save the DevNames information. // if (!Print_SaveDevNames(pszCurPrinter, pPD)) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; pPI->hResult = CreateError(); pPI->FinalResult = 0; } // // Save the hDC or hIC, depending on which flag is set. // if (pPI->FinalResult) { pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode); pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames); if (pDM && pDN) { PrintReturnICDC((LPPRINTDLG)pPD, pDN, pDM); } if (pDM) { GlobalUnlock(pPD->hDevMode); } if (pDN) { GlobalUnlock(pPD->hDevNames); } } break; } case ( PSN_QUERYCANCEL ) : { break; } case ( PSN_RESET ) : { // // Save the info that the user hit CANCEL. // pPI->FinalResult = 0; // // Save the view mode for the printer folder. // SetViewMode(); break; } default : { break; } } // // Notify the sub dialog. // if (Print_IsInRange(pnm->code, PSN_LAST, PSN_FIRST) && (HandleMessage(hSubDlg, WM_NOTIFY, wParam, (LPARAM)pnm, &lResult) != S_FALSE)) { // // The return from a dlgproc is different than a winproc. The lResult is // the real result. // return (BOOLFROMPTR(lResult) ); } // // Return FALSE. // return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnSelChange // // Process a CDM_SELCHANGE message for the dialog. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnSelChange() { HRESULT hres; LPCITEMIDLIST *ppidlSel = NULL; UINT uItems = 0; UINT uCount = 0; TCHAR szPrinterNameBuf[kPrinterBufMax]; BOOL bChanged = FALSE; HRESULT hr = S_OK; // // We get this message during init, so use it to set the // initial selection. // if (fFirstSel) { // // Select the appropriate item in the list view. // // If an item cannot be selected, it probably means that the // printer that was passed in has been deleted. In this case, // insert the driver pages and select the default printer. // if (!SelectSVItem()) { // // Insert the device page for the default printer. // if (FAILED(InstallDevMode(NULL, NULL))) { UninstallDevMode(); } // // Get the current printer and select the appropriate item // in the list view. // SelectSVItem(); } // // Notify the sub dialog that the selection changed. // SelectionChange(); // // Disable the Apply button if it's the very first time // (during initialization). // if (fFirstSel == 1) { PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); } // // Reset the flags. // fFirstSel = 0; fSelChangePending = FALSE; // // Return success. // return (TRUE); } // // Reset the flag. // fSelChangePending = FALSE; // // Make sure we have the shell folder view interface. // if (!psfv) { return (FALSE); } // // Get the selected object in the print folder. // hres = psfv->GetSelectedObjects(&ppidlSel, &uItems); if (SUCCEEDED(hres) && (uItems > 0) && ppidlSel && *ppidlSel) { // // Get the printer name. // szPrinterNameBuf[0] = 0; GetViewItemText( psfRoot, *ppidlSel, szPrinterNameBuf, ARRAYSIZE(szPrinterNameBuf), SHGDN_FORPARSING); // if the selection is same as current printer if (pszCurPrinter && (lstrcmpi(szPrinterNameBuf, pszCurPrinter) == 0)) { //Dont do anything. LocalFree(ppidlSel); return TRUE; } // // See if it's the Add Printer Wizard. // if (lstrcmpi(szPrinterNameBuf, TEXT("WinUtils_NewObject")) == 0) { // // It's the Add Printer Wizard. // fAPWSelected = TRUE; // // Disable the OK and Apply buttons. // EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE); PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); // // Save the current devmode settings for selection changes. // if (pDMCur && pDMSave) { CopyMemory( pDMSave, pDMCur, (pDMCur->dmSize > sizeof(DEVMODE)) ? sizeof(DEVMODE) : pDMCur->dmSize ); } // // Remove the device pages, since no printer is selected. // if (SUCCEEDED(UninstallDevMode())) { bChanged = TRUE; } // // Update the current printer information and the printer // status text (all should be empty). // GetCurrentPrinter(); UpdateStatus(NULL); // // Notify the sub dialog that the selection changed. // if (bChanged) { SelectionChange(); bChanged = FALSE; } } else { // // It's not the Add Printer Wizard. // fAPWSelected = FALSE; if (!MergeDevMode(szPrinterNameBuf)) { hr = InstallDevMode(szPrinterNameBuf, NULL); } if (SUCCEEDED(hr)) { bChanged = TRUE; } else if (SUCCEEDED(UninstallDevMode())) { bChanged = TRUE; } // // Get the current printer name and the current devmode and // update the printer status text. // GetCurrentPrinter(); if (SUCCEEDED(hr)) { // // Clear the no access printer flag. // fNoAccessPrinterSelected = FALSE; // // Make sure the OK button is enabled. // EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), TRUE); // // Update the printer status. // UpdateStatus(*ppidlSel); } else { // // Save the fact we do not have access to this printer. // if (ERROR_ACCESS_DENIED == HRESULT_CODE(hr)) { fNoAccessPrinterSelected = TRUE; } // // Disable the OK and Apply buttons. // EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE); PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); // // Nuke the status. // UpdateStatus(NULL); } } // // Free the pidl. // LocalFree(ppidlSel); } // // See if anything changed. // if (bChanged) { // // Enable the Apply button. // PropSheet_Changed(GetParent(hwndDlg), hwndDlg); // // Notify the sub dialog that the selection changed. // SelectionChange(); } // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::IsCurrentPrinter // // Checks whether the given pidl represents the current printer // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::IsCurrentPrinter(LPCITEMIDLIST pidl) { TCHAR szPrinterBufName[kPrinterBufMax]; if (pszCurPrinter) { szPrinterBufName[0] = 0; GetViewItemText( psfRoot, pidl, szPrinterBufName, ARRAYSIZE(szPrinterBufName), SHGDN_FORPARSING); if (lstrcmpi(szPrinterBufName, pszCurPrinter) == 0) { return TRUE; } } return FALSE; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnRename // // Handles the Rename Notification // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnRename(LPCITEMIDLIST *ppidl) { TCHAR szPrinterBufName[kPrinterBufMax]; LPITEMIDLIST pidl; TCHAR szNewPrinter[kPrinterBufMax]; pidl = ILFindLastID(ppidl[0]); szNewPrinter[0] = 0; GetViewItemText( psfRoot, ILFindLastID(ppidl[1]), szNewPrinter, ARRAYSIZE(szNewPrinter), SHGDN_FORPARSING); //Has user clicked on Apply and saved any printer information ? if (pPI->fApply) { //Yes. Check if the printer that is renamed is the one that is saved. LPDEVNAMES pDN; if ((pPD->hDevNames) && (pDN = (LPDEVNAMES)GlobalLock(pPD->hDevNames))) { //Get the saved printer name from the DEVNAMES structure. szPrinterBufName[0] = 0; GetViewItemText( psfRoot, pidl, szPrinterBufName, ARRAYSIZE(szPrinterBufName), SHGDN_FORPARSING); //Is the saved printer and renamed printer the same ? if (!lstrcmpi(szPrinterBufName, ((LPTSTR)pDN + pDN->wDeviceOffset))) { //Yes. Updated the saved DEVMODE and DEVNAMES Structure. LPDEVMODE pDM; //Update the dev names struture with the new printer name. Print_SaveDevNames(szNewPrinter, pPD); //Update the device name in the devmode to new name if ((pPD->hDevMode) && (pDM = (LPDEVMODE)GlobalLock(pPD->hDevMode))) { lstrcpyn(pDM->dmDeviceName, szNewPrinter, CCHDEVICENAME); GlobalUnlock(pPD->hDevMode); } } GlobalUnlock(pPD->hDevNames); } } if (IsCurrentPrinter(pidl)) { if (!MergeDevMode(szNewPrinter)) { InstallDevMode(szNewPrinter, NULL); } } return TRUE; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnChangeNotify // // Handle the change notification message. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnChangeNotify( LONG lNotification, LPCITEMIDLIST *ppidl) { LPCITEMIDLIST pidl; UINT uRes = 0; TCHAR szPrinterBufName[kPrinterBufMax]; // // Get the pidl for the object. // pidl = ILFindLastID(ppidl[0]); // // Handle the notification. // switch (lNotification) { case ( SHCNE_ATTRIBUTES ) : case ( SHCNE_UPDATEITEM ) : { if (NULL == pidl || ILIsEqual(ppidl[0], pidlRoot)) { // pidl is NULL or equal to the local PF which means that full refresh // has been requested. if the current object is the APW then try to select // a printer. if (!fSelChangePending) { fFirstSel = 2; fSelChangePending = TRUE; PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0); } } else { // // If the selected object is the one that changed, then // update the status text. if (IsCurrentPrinter(pidl)) { UpdateStatus(pidl); // // Reinit the copies and collate because these attributes may be changed // InitCopiesAndCollate(); } } break; } case ( SHCNE_RENAMEITEM ) : { OnRename(ppidl); break; } case ( SHCNE_CREATE ) : { // // If the Add Printer Wizard is selected when we get this // message, then select the newly created object. // if (fAPWSelected == TRUE) { // // Get the printer name. // szPrinterBufName[0] = 0; GetViewItemText( psfRoot, pidl, szPrinterBufName, ARRAYSIZE(szPrinterBufName), SHGDN_FORPARSING); // // Add the appropriate device pages and select the // new printer. // if (!MergeDevMode(szPrinterBufName)) { InstallDevMode(szPrinterBufName, NULL); } if (!fSelChangePending) { fFirstSel = 2; fSelChangePending = TRUE; PostMessage(hwndDlg, CDM_SELCHANGE, 0, 0); } } break; } case ( SHCNE_DELETE ) : { // // Save the current devmode settings for selection changes. // if (pDMCur && pDMSave) { CopyMemory( pDMSave, pDMCur, (pDMCur->dmSize > sizeof(DEVMODE)) ? sizeof(DEVMODE) : pDMCur->dmSize ); } // // Check if the current printer has just been deleted. // If so - set appropriate flag and disable the print button. if (IsCurrentPrinter(pidl)) { TCHAR szSavePrinterName[kPrinterBufMax]; StringCchCopy(szSavePrinterName, ARRAYSIZE(szSavePrinterName), szPrinter); // // Uninstall the current devmode and select the new default // printer if any. // UninstallDevMode(); InstallDevMode(NULL, NULL); SelectSVItem(); // // If the devmode editor is open, we need to notify the user // that the printer has just been deleted. // if (fDevmodeEdit) { // // Display error message which indicates that the printer you are currently // editing properties for has just been deleted. Ask the user to close the // driver UI dialog and select another printer. // fDirtyDevmode = TRUE; ShowError(hwndDlg, 0, iszPrinterDeleted, szSavePrinterName); } } break; } } return (FALSE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnAccelerator // // Handles an input event message. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::OnAccelerator( HWND hwndActivePrint, HWND hwndFocus, HACCEL haccPrint, PMSG pMsg) { if (psv && (hwndFocus == hwndView)) { if (psv->TranslateAccelerator(pMsg) == S_OK) { return (1); } if (haccPrint && TranslateAccelerator(hwndActivePrint, haccPrint, pMsg)) { return (1); } } // // Return that the message was not handled. // return (0); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnNoPrinters // // Displays a message box telling the user that they have no printers // installed. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::OnNoPrinters(HWND hDlg, HRESULT hr) { switch (HRESULT_CODE(hr)) { case ERROR_FILE_NOT_FOUND: { // // ERROR_FILE_NOT_FOUND means there are no printer's installed. // if (IDYES == ShowMessage(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinters, MB_YESNO|MB_ICONQUESTION, FALSE)) { // // invoke the add printer wizard here // InvokeAddPrinterWizardModal(hwndDlg, NULL); } } break; case ERROR_ACCESS_DENIED: { // // Access is denied. // ShowError(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterAccess); } break; default: { // // Some other error have occured. // ShowError(hDlg, IDC_PRINTER_LISTVIEW, iszNoPrinterSelected); } break; } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::OnInitDone // // Handle the CDM_INITDONE message. Initialization is complete, so // call IPrintDialogCallback::InitDone and then switch to the chosen // start page if it's not the General page. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::OnInitDone() { // // See if we need to do this anymore. This routine shouldn't be // entered more than twice, but just in case. // if (nInitDone != -1) { // // Make sure we have seen the CDM_INITDONE message for the // completion of both the main dialog and the sub dialog. // if (nInitDone < 1) { // // We only want to go through this code once. // nInitDone = -1; // // Tell the sub dialog that initialization is complete. // InitDone(); // // Switch to the appropriate start page. // if (pPD->nStartPage != START_PAGE_GENERAL) { PropSheet_SetCurSel( GetParent(hwndDlg), NULL, pPD->nStartPage + 1 ); } } else { nInitDone++; } } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::CreatePrintShellView // // Creates the shell view window for the printer folder. // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::CreatePrintShellView() { RECT rcView; FOLDERSETTINGS fs; HRESULT hResult; HWND hHiddenText; // // Get the Printer Folder pidl. // pidlRoot = SHCloneSpecialIDList(hwndDlg, CSIDL_PRINTERS, TRUE); if (!pidlRoot) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (E_FAIL); } // // Create an instance of IShellFolder and store it in the CPrintBrowser // class. // hResult = Print_ICoCreateInstance( CLSID_CPrinters, IID_IShellFolder2, pidlRoot, (LPVOID *)&psfRoot ); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } // // Get the private printer folder interface. // hResult = psfRoot->QueryInterface(IID_IPrinterFolder, (LPVOID *)&ppf); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } // // Create the printer folder view. // GetWindowRect(GetDlgItem(hwndDlg, IDC_PRINTER_LIST), &rcView); MapWindowRect(HWND_DESKTOP, hwndDlg, &rcView); fs.ViewMode = GetViewMode(); fs.fFlags = FWF_AUTOARRANGE | FWF_SINGLESEL | FWF_ALIGNLEFT | FWF_SHOWSELALWAYS; hResult = psfRoot->CreateViewObject(hwndDlg, IID_IShellView, (LPVOID *)&psv); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } hResult = psv->CreateViewWindow(NULL, &fs, this, &rcView, &hwndView); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } hResult = psv->UIActivate(SVUIA_INPLACEACTIVATE); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } // // Get the shell folder view interface. // hResult = psv->QueryInterface(IID_IShellFolderView, (LPVOID *)&psfv); if (FAILED(hResult)) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (hResult); } // // Move the view window to the right spot in the Z (tab) order. // SetWindowPos( hwndView, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE ); // // Give it the right window ID for WinHelp and error selection. // SetWindowLong(hwndView, GWL_ID, IDC_PRINTER_LISTVIEW); // // Move the hidden text ahead of the list view, thus the parent name of // the list view in MSAA is "Select Printer" // if (hHiddenText = GetDlgItem(hwndDlg, IDC_HIDDEN_TEXT)) { SetParent(hHiddenText, hwndView); SetWindowPos(hHiddenText, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOACTIVATE); } // // Show the window after creating the ShellView so we do not get a // big ugly gray spot. // ShowWindow(hwndDlg, SW_SHOW); UpdateWindow(hwndDlg); // // Return success. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetViewMode // // Gets the view mode for the printer folder. // //////////////////////////////////////////////////////////////////////////// UINT CPrintBrowser::GetViewMode() { HKEY hKey; UINT ViewMode = FVM_ICON; DWORD cbData; // // Open the Printers\Settings registry key and read the information // from the ViewMode value entry. // if (RegOpenKeyEx( HKEY_CURRENT_USER, c_szSettings, 0L, KEY_READ, &hKey ) == ERROR_SUCCESS) { cbData = sizeof(ViewMode); if (ERROR_SUCCESS == RegQueryValueEx(hKey, c_szViewMode, NULL, NULL, (LPBYTE)&ViewMode, &cbData)) { // // A "real" mode exist in the registry. Don't make // smart decisions for the view mode thereafter. // uDefViewMode = ViewMode; } RegCloseKey(hKey); } // // Make sure it's in the correct range. // if (ViewMode > FVM_DETAILS) { ViewMode = FVM_ICON; } // // Return the view mode. // return (ViewMode); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SetViewMode // // Gets the view mode for the printer folder. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::SetViewMode() { HWND hwndListView; HKEY hKey; UINT ViewMode = VIEW_MODE_DEFAULT; DWORD cbData; // // Get the current view mode. // if (psv && (hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL))) { FOLDERSETTINGS fs; psv->GetCurrentInfo(&fs); ViewMode = fs.ViewMode; } // // Check if the user changed the view mode // if( uDefViewMode != ViewMode ) { // // Open the Printers\Settings registry key and save the information // to the ViewMode value entry. // if (RegOpenKeyEx( HKEY_CURRENT_USER, c_szSettings, 0L, KEY_READ | KEY_WRITE, &hKey ) == ERROR_SUCCESS) { cbData = sizeof(ViewMode); RegSetValueEx(hKey, c_szViewMode, 0L, REG_DWORD, (LPBYTE)&ViewMode, cbData); RegCloseKey(hKey); } } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::CreateHookDialog // // Creates the child window for the application specific area of the // General page. // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::CreateHookDialog() { DWORD Flags = pPD->Flags; HANDLE hTemplate; HINSTANCE hinst; LPCTSTR pDlg; RECT rcChild; DWORD dwStyle; LANGID LangID = (LANGID)TlsGetValue(g_tlsLangID); // // See if there is a template. // if (Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { hTemplate = pPD->hInstance; hinst = ::g_hinst; } else { if (Flags & PD_ENABLEPRINTTEMPLATE) { pDlg = pPD->lpPrintTemplateName; hinst = pPD->hInstance; LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); } else { hinst = ::g_hinst; pDlg = MAKEINTRESOURCE(PRINTDLGEXORD); } HRSRC hRes = FindResourceExFallback(hinst, RT_DIALOG, pDlg, LangID); if (hRes == NULL) { pPI->dwExtendedError = CDERR_FINDRESFAILURE; return (E_HANDLE); } if ((hTemplate = LoadResource(hinst, hRes)) == NULL) { pPI->dwExtendedError = CDERR_LOADRESFAILURE; return (E_HANDLE); } } // // Lock the resource. // if (!LockResource(hTemplate)) { pPI->dwExtendedError = CDERR_LOADRESFAILURE; return (E_HANDLE); } // // Make sure the template is a child window. // dwStyle = ((LPDLGTEMPLATE)hTemplate)->style; if (!(dwStyle & WS_CHILD)) { // // I don't want to go poking in their template, and I don't want to // make a copy, so I will just fail. This also helps us weed out // "old-style" templates that were accidentally used. // pPI->dwExtendedError = CDERR_DIALOGFAILURE; return (E_INVALIDARG); } // // Get the callback interface pointer, if necessary. // if (pPD->lpCallback) { pPD->lpCallback->QueryInterface( IID_IPrintDialogCallback, (LPVOID *)&pCallback ); } // // Create the child dialog. // hSubDlg = CreateDialogIndirectParam( hinst, (LPDLGTEMPLATE)hTemplate, hwndDlg, Print_GeneralChildDlgProc, (LPARAM)pPD ); if (!hSubDlg) { pPI->dwExtendedError = CDERR_DIALOGFAILURE; return (E_HANDLE); } // // Put the window in the designated spot on the General property page. // GetWindowRect(GetDlgItem(hwndDlg, grp2), &rcChild); MapWindowRect(NULL, hwndDlg, &rcChild); SetWindowPos( hSubDlg, HWND_BOTTOM, rcChild.left, rcChild.top, rcChild.right - rcChild.left, rcChild.bottom - rcChild.top, SWP_SHOWWINDOW ); // // Return success. // return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::UpdateStatus // // Updates the static text for the currently selected printer. // The fields that are set are Status, Location, and Comment. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::UpdateStatus( LPCITEMIDLIST pidl) { HRESULT hres; SHELLDETAILS Details; TCHAR szText[MAX_PATH]; // // If the pidl is NULL, then reset all of the static text to null // strings. // if (!pidl) { szText[0] = 0; SetDlgItemText(hwndDlg, IDC_STATUS, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_STATUS)); SetDlgItemText(hwndDlg, IDC_LOCATION, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_LOCATION)); SetDlgItemText(hwndDlg, IDC_COMMENT, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_COMMENT)); return (TRUE); } // // Get the STATUS details for the given object. // szText[0] = 0; hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_STATUS, &Details); if (FAILED(hres) || !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL)) { szText[0] = 0; } SetDlgItemText(hwndDlg, IDC_STATUS, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_STATUS)); // // Get the LOCATION details for the given object. // szText[0] = 0; hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_LOCATION, &Details); if (FAILED(hres) || !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL)) { szText[0] = 0; } SetDlgItemText(hwndDlg, IDC_LOCATION, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_LOCATION)); // // Get the COMMENT details for the given object. // szText[0] = 0; hres = psfRoot->GetDetailsOf(pidl, PRINTERS_ICOL_COMMENT, &Details); if (FAILED(hres) || !StrRetToStrN(szText, ARRAYSIZE(szText), &Details.str, NULL)) { szText[0] = 0; } SetDlgItemText(hwndDlg, IDC_COMMENT, szText); UpdateWindow(GetDlgItem(hwndDlg, IDC_COMMENT)); // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SelectSVItem // // Selects the item in the shell view with the given printer name. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::SelectSVItem() { HRESULT hr = E_FAIL; LPITEMIDLIST pidlItem = NULL; BOOL bPrinterSelected = FALSE; // Make sure we have a shell view and a shell folder view. if (psv && psfv) { // Make sure we have the current printer information. GetCurrentPrinter(); if (!pDMCur || !pszCurPrinter || !pszCurPrinter[0]) { // If there is no current printer then we just select the add printer // wizard object. hr = psfRoot->ParseDisplayName(hwndDlg, NULL, TEXT("WinUtils_NewObject"), NULL, &pidlItem, NULL); if (SUCCEEDED(hr) && pidlItem) { // just select the APW special object SelectPrinterItem(pidlItem); // Free up the PIDL using the shell allocator FreePIDL(pidlItem); // It's the Add Printer Wizard. fAPWSelected = TRUE; // Disable the OK and Apply buttons. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), FALSE); PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); } } else { // there is a current printer then we just select it hr = psfRoot->ParseDisplayName(hwndDlg, NULL, pszCurPrinter, NULL, &pidlItem, NULL); if (SUCCEEDED(hr) && pidlItem) { // select the printer and update the status SelectPrinterItem(pidlItem); UpdateStatus(pidlItem); // Free up the PIDL using the shell allocator FreePIDL(pidlItem); // It's not the Add Printer Wizard. fAPWSelected = FALSE; // Enable the OK and Apply buttons. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), TRUE); PropSheet_Changed(GetParent(hwndDlg), hwndDlg); // A printer object has been selected bPrinterSelected = TRUE; } } } return SUCCEEDED(hr) ? bPrinterSelected : FALSE; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetCurrentPrinter // // Saves the current printer name and the current devmode in the class. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::GetCurrentPrinter() { DWORD dwSize = cchCurPrinter; // // Reset the devmode and the current printer string. // pDMCur = NULL; if (pszCurPrinter && cchCurPrinter) { pszCurPrinter[0] = 0; } // // Get the name of the current printer. // if (!GetInternalPrinterName(pszCurPrinter, &dwSize)) { // // Allocate a buffer large enough to hold the name of the // current printer. // if (dwSize > cchCurPrinter) { if (pszCurPrinter) { LPTSTR pTemp = pszCurPrinter; pszCurPrinter = NULL; cchCurPrinter = 0; GlobalFree(pTemp); } pszCurPrinter = (LPTSTR)GlobalAlloc(GPTR, dwSize * sizeof(TCHAR)); if (!pszCurPrinter) { return (FALSE); } cchCurPrinter = dwSize; if (cchCurPrinter) { pszCurPrinter[0] = 0; } } // // Try to get the name of the current printer again. // if (!GetInternalPrinterName(pszCurPrinter,&dwSize)) { return (FALSE); } } // // Get the current devmode. // pDMCur = GetCurrentDevMode(); if (!pDMCur) { pszCurPrinter[0] = 0; return (FALSE); } // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InitPrintToFile // // Initializes the print to file on a selection change. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::InitPrintToFile() { HWND hCtl = GetDlgItem(hwndDlg, IDC_PRINT_TO_FILE); // // See if there is a Print To File control. // if (hCtl) { // // See if a printer is selected. // if (pDMCur) { // // A printer is selected, so enable the print to file if // appropriate. // if (!(pPI->dwFlags & (PD_HIDEPRINTTOFILE | PD_DISABLEPRINTTOFILE))) { EnableWindow(hCtl, TRUE); } } else { // // A printer is not selected, so disable it. // EnableWindow(hCtl, FALSE); } } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InitPageRangeGroup // // Initializes the page range group on a selection change. It decides // which controls should be enabled when a selection change occurs from // the Add Printer Wizard. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::InitPageRangeGroup() { // // See if a printer is selected. // if (pDMCur) { // // A printer is selected, so enable the appropriate page range // controls. // EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_ALL), TRUE); if (!(pPI->dwFlags & PD_NOSELECTION)) { EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_SELECTION), TRUE); } if (!(pPI->dwFlags & PD_NOCURRENTPAGE)) { EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_CURRENT), TRUE); } if (!(pPI->dwFlags & PD_NOPAGENUMS)) { EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), TRUE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), TRUE); } } else { // // A printer is not selected, so disable all of the page range // controls. // EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_ALL), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_SELECTION), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_CURRENT), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_PAGES), FALSE); EnableWindow(GetDlgItem(hSubDlg, IDC_RANGE_EDIT), FALSE); } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InitCopiesAndCollate // // Initializes the copies and collate information in the devmode and the // print dialog structure. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::InitCopiesAndCollate() { HWND hCtl; UINT IsCollate = FALSE; RECT rc; BOOL bEnabledCopies = TRUE; // // Save the collate state so that the collate icon doesn't flicker on // a selection change. // if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) { IsCollate = IsDlgButtonChecked(hSubDlg, IDC_COLLATE); } // // See what the printer driver can do and what the app requested // and set the copies and collate accordingly. // if (pDMCur) { // // If PD_USEDEVMODECOPIES(COLLATE), disable copies if the driver // cannot copy. // if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) { // // Modify the edit control and up-down arrow if needed // WORD cDigits; // // If the calling application handles copies and collate, we // set max copies as 9999, else, we get the max copies from driver // if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { szScratch[0] = 0; Print_GetPortName(pszCurPrinter, szScratch, ARRAYSIZE(szScratch)); nMaxCopies = DeviceCapabilities( pszCurPrinter, szScratch, DC_COPIES, NULL, NULL ); // // If DeviceCapabilities() returns error, disable the controls // if ((nMaxCopies < 1) || (nMaxCopies == (DWORD)(-1))) { nMaxCopies = 1; nCopies = 1; bEnabledCopies = FALSE; } } else { // // Assume the calling app will take care of multi-copies // nMaxCopies = MAX_COPIES; } if (nMaxCopies < nCopies) { nCopies = nMaxCopies; } cDigits = CountDigits(nMaxCopies); Edit_LimitText(hCtl, cDigits); SendMessage(GetDlgItem(hSubDlg, IDC_COPIES_UDARROW), UDM_SETRANGE, 0, MAKELONG(nMaxCopies, 1)); InvalidateRect(GetDlgItem(hSubDlg, IDC_COPIES_UDARROW), NULL, FALSE); } // // If PD_USEDEVMODECOPIES(COLLATE), disable collate if the driver // cannot collate. // if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) { DWORD dwCollate; BOOL bEnabled = TRUE; if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { szScratch[0] = 0; Print_GetPortName(pszCurPrinter, szScratch, ARRAYSIZE(szScratch)); dwCollate = DeviceCapabilities( pszCurPrinter, szScratch, DC_COLLATE, NULL, NULL ); fAllowCollate = ((dwCollate < 1) || (dwCollate == (DWORD)-1)) ? FALSE : TRUE; } else { // // Assume the calling app will take care of collation // fAllowCollate = TRUE; } if ( fAllowCollate ) { EnableWindow(hCtl, (nCopies > 1)); CheckDlgButton( hSubDlg, IDC_COLLATE, fCollateRequested ? TRUE : FALSE ); } else { EnableWindow(hCtl, FALSE); CheckDlgButton(hSubDlg, IDC_COLLATE, FALSE); } // // Display the appropriate collate icon if it changed. // if ((hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) && (IsCollate != IsDlgButtonChecked(hSubDlg, IDC_COLLATE))) { ShowWindow(hCtl, SW_HIDE); SendMessage( hCtl, STM_SETICON, IsCollate ? (LONG_PTR)hIconNoCollate : (LONG_PTR)hIconCollate, 0L ); ShowWindow(hCtl, SW_SHOW); // // Make it redraw to get rid of the old one. // GetWindowRect(hCtl, &rc); MapWindowRect(NULL, hwndDlg, &rc); RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE); } } // // We have to do it here because after setting the text, fAllowCollate // will be used // if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) { SetDlgItemInt(hSubDlg, IDC_COPIES, nCopies, FALSE); EnableWindow(hCtl, bEnabledCopies); EnableWindow(hwndUpDown, bEnabledCopies); } } else if (fNoAccessPrinterSelected) { // if No Access Printer is selected merely disable the Copies and Collate // Dont change any information user entered. if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) { EnableWindow(hCtl, FALSE); EnableWindow(hwndUpDown, FALSE); } if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) { EnableWindow(hCtl, FALSE); } // // Disable the Apply button It gets turned back on when the copies and collate values are // disabled. PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); } else { // // A printer is not selected, so disable copies and collate. // if (hCtl = GetDlgItem(hSubDlg, IDC_COPIES)) { SetDlgItemInt(hSubDlg, IDC_COPIES, 1, FALSE); EnableWindow(hCtl, FALSE); EnableWindow(hwndUpDown, FALSE); } if (hCtl = GetDlgItem(hSubDlg, IDC_COLLATE)) { EnableWindow(hCtl, FALSE); CheckDlgButton(hSubDlg, IDC_COLLATE, FALSE); if ((hCtl = GetDlgItem(hSubDlg, IDI_COLLATE)) && IsCollate) { ShowWindow(hCtl, SW_HIDE); SendMessage( hCtl, STM_SETICON, (LONG_PTR)hIconNoCollate, 0L ); ShowWindow(hCtl, SW_SHOW); // // Make it redraw to get rid of the old one. // GetWindowRect(hCtl, &rc); MapWindowRect(NULL, hwndDlg, &rc); RedrawWindow(hwndDlg, &rc, NULL, RDW_ERASE | RDW_INVALIDATE); } } // // Disable the Apply button since a printer is not selected. // It gets turned back on when the copies and collate values are // disabled. // PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg); } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SaveCopiesAndCollateInDevMode // // Saves the copies and collate information in the given devmode. This // routine does not affect the pPD structure. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::SaveCopiesAndCollateInDevMode( LPDEVMODE pDM, LPTSTR pszPrinter) { // // Make sure we have a devmode and a printer name. // if (!pDM || !pszPrinter || !(pszPrinter[0])) { return (FALSE); } // // verify number of copies is less than max value // if( nMaxCopies < nCopies ) { return (FALSE); } // // Move the info to the devmode. // pDM->dmCopies = (short)nCopies; SetField(pDM, dmCollate, (fAllowCollate && fCollateRequested ? DMCOLLATE_TRUE : DMCOLLATE_FALSE)); // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SetCopiesOnApply // // Sets the appropriate number of copies in the PrintDlgEx structure and // in the DevMode structure. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::SetCopiesOnApply() { if (pDMCur) { if (!(pDMCur->dmFields & DM_COPIES)) { Print_LeaveInfoInPD: // // The driver cannot do copies, so leave the copy/collate // info in the pPD. // pDMCur->dmCopies = 1; SetField(pDMCur, dmCollate, DMCOLLATE_FALSE); } else if ((pDMCur->dmSpecVersion < 0x0400) || (!(pDMCur->dmFields & DM_COLLATE))) { // // The driver can do copies, but not collate. // Where the info goes depends on the PD_COLLATE flag. // if (pPD->Flags & PD_COLLATE) { goto Print_LeaveInfoInPD; } else { goto Print_PutInfoInDevMode; } } else { Print_PutInfoInDevMode: // // Make sure we have a current printer. // if (!pszCurPrinter) { goto Print_LeaveInfoInPD; } // // Make sure the driver can support the number of copies // requested. // if (nMaxCopies < pPD->nCopies) { if (pPD->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { ShowError(hSubDlg, IDC_COPIES, iszTooManyCopies, nMaxCopies); pPD->nCopies = nMaxCopies; return (FALSE); } else { goto Print_LeaveInfoInPD; } } // // The driver can do both copies and collate, so move the info // to the devmode. // pDMCur->dmCopies = (short)pPD->nCopies; SetField( pDMCur, dmCollate, (fAllowCollate && (pPD->Flags & PD_COLLATE)) ? DMCOLLATE_TRUE : DMCOLLATE_FALSE ); pPD->nCopies = 1; pPD->Flags &= ~PD_COLLATE; } } // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::SaveDevMode // // Saves the current devmode in the pPD structure on Apply. // Assumes pDMCur has the current information. // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::SaveDevMode() { DWORD cbSize; HANDLE hDevMode = NULL; LPDEVMODE pDM; // // Allocate the space for the new DevMode and copy the // information. // if (pDMCur) { cbSize = (DWORD)(pDMCur->dmSize + pDMCur->dmDriverExtra); hDevMode = GlobalAlloc(GHND, cbSize); if (hDevMode) { pDM = (LPDEVMODE)GlobalLock(hDevMode); if (pDM) { CopyMemory(pDM, pDMCur, cbSize); GlobalUnlock(hDevMode); } else { GlobalFree(hDevMode); hDevMode = NULL; } } } if (!hDevMode) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; pPI->hResult = E_OUTOFMEMORY; pPI->FinalResult = 0; } // // Free the copy of the DevMode handle passed in by the app. // if (pPD->hDevMode) { GlobalFree(pPD->hDevMode); pPD->hDevMode = NULL; } // // Save the new DevMode in the pPD structure. // pPD->hDevMode = hDevMode; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::MergeDevMode // // Merges the current devmode with the default devmode of the newly // selected printer. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::MergeDevMode( LPTSTR pszPrinterName) { HANDLE hDevMode = NULL; LPDEVMODE pDMNew = NULL; LPDEVMODE pDMOld = NULL; BOOL bRet = TRUE; DWORD dmFields; short dmDefaultSource; // // See if the printer name is NULL. If so, we need to get the default // printer loaded. This happens when a printer is deleted. // if (!pszPrinterName) { ASSERT(0); return FALSE; } else { // // Get the devmode for the old (current driver pages) printer. // GetCurrentPrinter(); pDMOld = pDMCur ? pDMCur : pDMSave; if (!pDMOld) { return (FALSE); } hDevMode = Print_GetDevModeWrapper(pszPrinterName); if (hDevMode) { pDMNew = (LPDEVMODE)GlobalLock(hDevMode); } else { return FALSE; } if (!pDMNew) { GlobalFree(hDevMode); return FALSE; } dmFields = 0; dmDefaultSource = pDMNew->dmDefaultSource; if (pDMNew->dmFields & DM_DEFAULTSOURCE) { dmFields = DM_DEFAULTSOURCE; } //Check if the old devmode has any info to copy if (pDMOld->dmFields) { CopyMemory(&(pDMNew->dmFields), &(pDMOld->dmFields), sizeof(DEVMODE) - FIELD_OFFSET(DEVMODE, dmFields)); } pDMNew->dmFields |= dmFields; pDMNew->dmDefaultSource = dmDefaultSource; pDMNew->dmFields = pDMNew->dmFields & ( DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_SCALE | DM_COPIES | DM_COLLATE | DM_FORMNAME | DM_DEFAULTSOURCE); // // Insert the device pages - this call will yield a proper devmode. // if (FAILED(UninstallDevMode()) || FAILED(InstallDevMode(pszPrinterName, pDMNew))) { bRet = FALSE; } //Free the new devmode that was allocated if (hDevMode) { GlobalUnlock(hDevMode); GlobalFree(hDevMode); } } // // Return the result. // return (bRet); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::IsValidPageRange // // Checks the validity of the page range string. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::IsValidPageRange( LPTSTR pszString, UINT *pErrorId) { LPTSTR pStr = pszString; BOOL bDigit = FALSE; BOOL bOld; UINT Number, Ctr; DWORD nNumRanges = 0; BOOL bFrom = TRUE; // // Initially set the error id to 0. // *pErrorId = 0; // // See if we can only have a single page range. // bOld = (nMaxPageRanges == 1); // // Go through the string and validate the entries. // while (*pStr) { if (ISDIGIT(*pStr)) { // // Make sure there is room for another range. // if (nNumRanges >= nMaxPageRanges) { break; } // // Found a digit. // bDigit = TRUE; // // Make sure the page number is in the given page range. // Number = 0; while (ISDIGIT(*pStr)) { Number *= 10; Number += *pStr - TEXT('0'); pStr++; } pStr--; if ((Number < pPD->nMinPage) || (Number > pPD->nMaxPage)) { *pErrorId = iszBadPageRange; return (FALSE); } // // Save the value in the page range structure. // if (bFrom) { pPageRanges[nNumRanges].nFromPage = Number; bFrom = FALSE; } else { pPageRanges[nNumRanges].nToPage = Number; bFrom = TRUE; nNumRanges++; } } else if (*pStr == TEXT('-')) { // // Found a hyphen. Make sure there is a digit preceding it // and following it. Also, make sure there isn't something // like 1-2-3. // if (!bDigit || bFrom || !ISDIGIT(*(pStr + 1))) { *pErrorId = bOld ? iszBadPageRangeSyntaxOld : iszBadPageRangeSyntaxNew; return (FALSE); } bDigit = FALSE; } else if ((*pStr == szListSep[0]) || (*pStr == TEXT(','))) { // // Found a list separator. Make sure there is a digit // preceding it. // if (!bDigit) { *pErrorId = bOld ? iszBadPageRangeSyntaxOld : iszBadPageRangeSyntaxNew; return (FALSE); } bDigit = FALSE; // // If it's the list separator string instead of the simple // comma, then make sure the entire list separator string // is there. // This will advance the string up to the last character // of the list separator string. // if ((*pStr == szListSep[0]) && ((szListSep[0] != TEXT(',')) || (!ISDIGIT(*(pStr + 1))))) { for (Ctr = 1; Ctr < nListSep; Ctr++) { pStr++; if (*pStr != szListSep[Ctr]) { *pErrorId = bOld ? iszBadPageRangeSyntaxOld : iszBadPageRangeSyntaxNew; return (FALSE); } } } // // Make sure the From/To page range is complete. // if (!bFrom) { pPageRanges[nNumRanges].nToPage = pPageRanges[nNumRanges].nFromPage; bFrom = TRUE; nNumRanges++; } } else { // // Found an invalid character. // *pErrorId = bOld ? iszBadPageRangeSyntaxOld : iszBadPageRangeSyntaxNew; return (FALSE); } // // Advance the string pointer. // pStr++; } // // Make sure we reached the end of the string. // if (*pStr) { *pErrorId = iszTooManyPageRanges; return (FALSE); } // // Make sure the last thing in the string was a digit. // if (!bDigit) { *pErrorId = bOld ? iszBadPageRangeSyntaxOld : iszBadPageRangeSyntaxNew; return (FALSE); } // // Make sure the last From/To page range is complete. // if (!bFrom) { pPageRanges[nNumRanges].nToPage = pPageRanges[nNumRanges].nFromPage; bFrom = TRUE; nNumRanges++; } // // Save the number of page ranges. // nPageRanges = nNumRanges; // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::ConvertPageRangesToString // // Converts the page ranges to a string. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::ConvertPageRangesToString( LPTSTR pszString, UINT cchLen) { LPTSTR pStr = pszString; DWORD nFromPage, nToPage; UINT cch = cchLen - 1; UINT Ctr, Ctr2, Count; // // Initialize the string. // if (cchLen) { pszString[0] = 0; } // // Validate the ranges and create the string. // for (Ctr = 0; Ctr < nPageRanges; Ctr++) { // // Get the range. // nFromPage = pPageRanges[Ctr].nFromPage; nToPage = pPageRanges[Ctr].nToPage; // // Make sure the range is valid. // if ((nFromPage < pPD->nMinPage) || (nFromPage > pPD->nMaxPage) || (nToPage < pPD->nMinPage) || (nToPage > pPD->nMaxPage)) { return (FALSE); } // // Make sure it's not 0xFFFFFFFF. // if (nFromPage == 0xFFFFFFFF) { continue; } // // Put it in the string. // Count = IntegerToString(nFromPage, pStr, cch); if (!Count) { return (FALSE); } pStr += Count; cch -= Count; if ((nFromPage == nToPage) || (nToPage == 0xFFFFFFFF)) { if (Ctr < nPageRanges - 1) { if (cch < nListSep) { return (FALSE); } for (Ctr2 = 0; Ctr2 < nListSep; Ctr2++) { *pStr = szListSep[Ctr2]; pStr++; } cch -= nListSep; } } else { if (!cch) { return (FALSE); } *pStr = TEXT('-'); pStr++; cch--; Count = IntegerToString(nToPage, pStr, cch); if (!Count) { return (FALSE); } pStr += Count; cch -= Count; if (Ctr < nPageRanges - 1) { if (cch < nListSep) { return (FALSE); } for (Ctr2 = 0; Ctr2 < nListSep; Ctr2++) { *pStr = szListSep[Ctr2]; pStr++; } cch -= nListSep; } } } *pStr = '\0'; // // Return success. // return (TRUE); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::IntegerToString // // Converts an integer to a string and returns the number of characters // written to the buffer (not including the null). // //////////////////////////////////////////////////////////////////////////// UINT CPrintBrowser::IntegerToString( DWORD Value, LPTSTR pszString, UINT cchLen) { DWORD TempValue = Value; UINT NumChars = 1; UINT Ctr; // // Get the number of characters needed. // while (TempValue = TempValue / 10) { NumChars++; } // // Make sure there is enough room in the buffer. // if (NumChars > cchLen) { return (0); } // // Make the string. // TempValue = Value; for (Ctr = NumChars; Ctr > 0; Ctr--) { pszString[Ctr - 1] = ((WORD)(TempValue % 10)) + TEXT('0'); TempValue = TempValue / 10; } // // Return the number of characters written to the buffer. // return (NumChars); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::ShowError // // Shows up an error message box // //////////////////////////////////////////////////////////////////////////// VOID CPrintBrowser::ShowError(HWND hDlg, UINT uCtrlID, UINT uMsgID, ...) { va_list args; va_start(args, uMsgID); InternalShowMessage(hDlg, uCtrlID, uMsgID, MB_ICONEXCLAMATION|MB_OK, TRUE, args); va_end(args); } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::ShowMessage // // Shows up a message box with the specified flags & parameters // //////////////////////////////////////////////////////////////////////////// int CPrintBrowser::ShowMessage(HWND hDlg, UINT uCtrlID, UINT uMsgID, UINT uType, BOOL bBeep, ...) { va_list args; va_start(args, bBeep); int iRet = InternalShowMessage(hDlg, uCtrlID, uMsgID, uType, bBeep, args); va_end(args); return iRet; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InternalShowMessage // // Shows up a message box with the specified flags & parameters // Internal version // // Assumes the control is not disabled. // //////////////////////////////////////////////////////////////////////////// int CPrintBrowser::InternalShowMessage(HWND hDlg, UINT uCtrlID, UINT uMsgID, UINT uType, BOOL bBeep, va_list args) { int iRet = IDCANCEL; if (!(pPI->dwFlags & PD_NOWARNING)) { TCHAR szTitle[MAX_PATH]; TCHAR szFormat[MAX_PATH]; TCHAR szMessage[MAX_PATH]; // // Get msg box title & load the format string // if ( GetWindowText(GetParent(hwndDlg), szTitle, ARRAYSIZE(szTitle)) && CDLoadString(g_hinst, uMsgID, szFormat, ARRAYSIZE(szFormat)) ) { if (bBeep) { MessageBeep(MB_ICONEXCLAMATION); } // // format the message to be shown and call MessageBox over // the last active popup // wvnsprintf(szMessage, ARRAYSIZE(szMessage), szFormat, args); HWND hWndOwner = ::GetWindow(GetParent(hwndDlg), GW_OWNER); HWND hWndLastPopup = GetLastActivePopup(hWndOwner); iRet = MessageBox(hWndLastPopup, szMessage, szTitle, uType); } HWND hCtrl = ((0 == uCtrlID) ? NULL : GetDlgItem(hDlg, uCtrlID)); if (hCtrl) { // // select & highlight the invalid value. we assume it // is an edit box, if it isn't then EM_SETSEL won't be // processed and it's OK. // SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hCtrl, 1L); SendMessage(hCtrl, EM_SETSEL, (WPARAM)0, (LPARAM)-1); } } return iRet; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::FitViewModeBest // // Adjust the view mode if the mini printers folder, so the printer names // fit best. This i8s necessary mainly because of accessibility problems. // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::FitViewModeBest(HWND hwndListView) { BOOL bResult = FALSE; if (VIEW_MODE_DEFAULT == uDefViewMode) { // // Asssume icon view by default. // uDefViewMode = FVM_ICON; // // If we are in a large icons view then check if something // doesn't fit vertically - the only reliable way to do this // is to check if we scrolled the view (origin.y > 0) // if (LVS_ICON == (GetWindowLong(hwndListView, GWL_STYLE) & LVS_TYPEMASK)) { POINT ptOrg; ListView_GetOrigin(hwndListView, &ptOrg); if (ptOrg.y > 0) { // // Switch the defview to List mode. // SendMessage(hwndView, WM_COMMAND, (WPARAM)SFVIDM_VIEW_LIST,0); uDefViewMode = FVM_LIST; bResult = TRUE; } } } return bResult; } VOID CPrintBrowser::SelectPrinterItem(LPITEMIDLIST pidlItem) { BOOL bLocked = FALSE; HWND hwndListView = FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL); if (hwndListView) { // // Disable the window update to prevent flickers // bLocked = LockWindowUpdate(hwndListView); } // // Try to make the printer item visible first // psv->SelectItem(pidlItem, SVSI_SELECT | SVSI_FOCUSED | SVSI_ENSUREVISIBLE); // // Check to see if the view mode need to be changed // if (hwndListView && FitViewModeBest(hwndListView)) { // // The view mode has been changed - call select item again // to ensure the visibility of the slected item in the new // view mode. // psv->SelectItem(pidlItem, SVSI_SELECT | SVSI_FOCUSED | SVSI_ENSUREVISIBLE); } if (hwndListView && bLocked) { // // Enable the window update // LockWindowUpdate(NULL); } } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::FindPrinter // // Invokes the find in the DS ui using printui!bPrinterSetup interface // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::FindPrinter(HWND hwnd, LPTSTR pszBuffer, UINT cchSize) { BOOL bReturn = FALSE; if (g_pfnPrinterSetup) { // // Invoke the DSUI to find a printer // bReturn = g_pfnPrinterSetup(hwnd, MSP_FINDPRINTER, cchSize, pszBuffer, &cchSize, NULL); // select the printer's list control SendMessage(hwndDlg, WM_NEXTDLGCTL, reinterpret_cast(GetDlgItem(hwndDlg, IDC_PRINTER_LISTVIEW)), 1); } return bReturn; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetInternalPrinterName // // Returns the current printer name // //////////////////////////////////////////////////////////////////////////// BOOL CPrintBrowser::GetInternalPrinterName(LPTSTR pszBuffer, DWORD *pdwSize) { BOOL bReturn = FALSE; if (pdwSize) { // // If a buffer was provided and it is large enough, then copy the printer name. // DWORD iLen = _tcslen(szPrinter); if (pszBuffer && *pdwSize > iLen) { StringCchCopy(pszBuffer, *pdwSize, szPrinter); bReturn = TRUE; } else { // // Set the required length and the last error code. // *pdwSize = iLen + 1; SetLastError( ERROR_INSUFFICIENT_BUFFER ); } } return bReturn; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetCurrentDevMode // // Returns the current internal devmode // //////////////////////////////////////////////////////////////////////////// LPDEVMODE CPrintBrowser::GetCurrentDevMode() { return pInternalDevMode; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetDefaultDevMode // // Retrieve the default devmode for the specified printer. // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::GetDefaultDevMode(HANDLE hPrinter, LPCTSTR pszPrinterName, PDEVMODE *ppDevMode) { HRESULT hr = S_OK; LONG lResult = 0; PDEVMODE pDevMode = NULL; if (SUCCEEDED(hr)) { // // Call document properties to get the size of the devmode. // lResult = DocumentProperties(NULL, hPrinter, (LPTSTR)pszPrinterName, NULL, NULL, 0); hr = (lResult >= 0) ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { // // If the size of the devmode was returned then allocate memory. // // GPTR initializes the memory with zeros. // pDevMode = (PDEVMODE)GlobalAlloc(GPTR, lResult); hr = pDevMode ? S_OK : E_OUTOFMEMORY; } // // If allocated then copy back the pointer. // if (SUCCEEDED(hr)) { // // Call document properties to get the default dev mode. // lResult = DocumentProperties(NULL, hPrinter, (LPTSTR)pszPrinterName, pDevMode, NULL, DM_OUT_BUFFER); hr = (lResult >= 0) ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { // // Everything has succeeded. Move locals to out parameters. // *ppDevMode = pDevMode; pDevMode = NULL; } // // Cleanup... // if (pDevMode) { GlobalFree((HANDLE)pDevMode); pDevMode = NULL; } return hr; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::WrapEnumPrinters // // Wraps EnumPrinters API into more friendly interface // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::WrapEnumPrinters(DWORD dwFlags, LPCTSTR pszServer, DWORD dwLevel, PVOID* ppvBuffer, PDWORD pcbBuffer, PDWORD pcPrinters) { HRESULT hr = S_OK; DWORD cbNeeded; BOOL bResult = FALSE; if (SUCCEEDED(hr)) { hr = (ppvBuffer && pcbBuffer && pcPrinters) ? S_OK : E_INVALIDARG; } if (SUCCEEDED(hr)) { // // Pre-initialize *pcbPrinter if it's not set. // if (!*pcbBuffer) { *pcbBuffer = kInitialPrinterHint; } do { if (!*ppvBuffer) { *ppvBuffer = (PVOID)GlobalAlloc(GPTR, *pcbBuffer); if (!*ppvBuffer) { *pcbBuffer = 0; *pcPrinters = 0; hr = E_OUTOFMEMORY; break; } } if (SUCCEEDED(hr)) { bResult = EnumPrinters(dwFlags, (LPTSTR)pszServer, dwLevel, (PBYTE)*ppvBuffer, *pcbBuffer, &cbNeeded, pcPrinters); hr = bResult ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { // // Everything went fine // break; } // // Check to see whether the buffer is too small. // GlobalFree((HANDLE)(*ppvBuffer)); *ppvBuffer = NULL; if (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hr)) { // // Reset hr & continue. // hr = S_OK; *pcbBuffer = cbNeeded; continue; } // // Something else (not the buffer) went wrong. // Bail out. // *pcbBuffer = 0; *pcPrinters = 0; break; } while(1); } return hr; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::GetUsablePrinter // // Try to find a usable printer // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::GetUsablePrinter(LPTSTR szPrinterNameBuf, DWORD *pcchBuf) { HRESULT hr = S_OK; BOOL bStatus = FALSE; DWORD cchBuf = *pcchBuf; HANDLE hPrinter = NULL; PDEVMODE pDevMode = NULL; PRINTER_INFO_4 *pInfo4 = NULL; DWORD cInfo4 = 0; DWORD cbInfo4 = 0; if (SUCCEEDED(hr)) { hr = (szPrinterNameBuf && pcchBuf) ? S_OK : E_INVALIDARG; } if (SUCCEEDED(hr)) { do { if (SUCCEEDED(hr)) { // // Attempt to the get the default printer. // bStatus = GetDefaultPrinter(szPrinterNameBuf, pcchBuf); hr = bStatus ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { bStatus = OpenPrinter(szPrinterNameBuf, &hPrinter, NULL); hr = bStatus ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { // // Try to get the default devmode for this printer. // hr = GetDefaultDevMode(hPrinter, szPrinterNameBuf, &pDevMode); } if (SUCCEEDED(hr)) { // // The default printer is usable. Exit. // break; } else { // // The default printer is not usable. Now we should enumerate // all the printers and find a usable one. Reset hr here. // hr = S_OK; } if (SUCCEEDED(hr)) { // // Enumerate the current printers. // hr = WrapEnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 4, reinterpret_cast(&pInfo4), &cbInfo4, &cInfo4); } if (SUCCEEDED(hr)) { // ERROR_FILE_NOT_FOUND will be an indication that the we have // no printers installer (i.e. printer's folder is empty) in // which case we should suggest the user to install a printer. hr = cInfo4 ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } if (SUCCEEDED(hr)) { // // Open the printers until we find one we have access to. // for (UINT i = 0; i(pszPrinter), pDevMode, pInDevMode, DM_IN_BUFFER|DM_OUT_BUFFER); hr = (lResult >= 0) ? S_OK : CreateError(); } } if (SUCCEEDED(hr)) { // // Everything has succeeded. Move locals to out parameters. // *ppOutDevMode = pDevMode; pDevMode = NULL; } // // Cleanup... // if (pDevMode) { GlobalFree((HANDLE)pDevMode); pDevMode = NULL; } return hr; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::InstallDevMode // // Install a new internal devmode // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::InstallDevMode(LPCTSTR pszPrinterName, PDEVMODE pDevModeToMerge) { HRESULT hr = S_OK; BOOL bStatus = FALSE; TCHAR szBuffer[kPrinterBufMax]; HANDLE hTempPrinter = NULL; PDEVMODE pTempDevMode = NULL; DWORD dwSize; if (SUCCEEDED(hr)) { dwSize = ARRAYSIZE(szBuffer); // // If a null printer name was specified use the default printer. // if (!pszPrinterName || !*pszPrinterName) { hr = GetUsablePrinter(szBuffer, &dwSize); if (SUCCEEDED(hr)) { pszPrinterName = szBuffer; } else { // // GetDefaultPrinter fails with ERROR_FILE_NOT_FOUND if we // have no printers. // // ERROR_FILE_NOT_FOUND will be an indication that the we have // no printers installer (i.e. printer's folder is empty) in // which case we should suggest the user to install a printer. // bStatus = GetDefaultPrinter(szBuffer, &dwSize); hr = bStatus ? S_OK : CreateError(); if (SUCCEEDED(hr)) { pszPrinterName = szBuffer; } } } } if (SUCCEEDED(hr)) { // // Check if this is not the current printer in which case, // just do nothing. // if (pszPrinterName && _tcsicmp(pszPrinterName, szPrinter)) { if (SUCCEEDED(hr)) { bStatus = OpenPrinter((LPTSTR)pszPrinterName, &hTempPrinter, NULL); hr = bStatus ? S_OK : CreateError(); } if (SUCCEEDED(hr)) { hr = GetInternalDevMode(&pTempDevMode, pszPrinterName, hTempPrinter, pDevModeToMerge); } if (SUCCEEDED(hr)) { if (hPrinter) { ClosePrinter(hPrinter); hPrinter = NULL; } if (pInternalDevMode) { GlobalFree((HANDLE)pInternalDevMode); pInternalDevMode = NULL; } StringCchCopy(szPrinter, ARRAYSIZE(szPrinter), pszPrinterName); hPrinter = hTempPrinter; hTempPrinter = NULL; pInternalDevMode = pTempDevMode; pTempDevMode = NULL; } } } if (SUCCEEDED(hr)) { if (pInternalDevMode) { // // Enable the driver UI button // EnableWindow(GetDlgItem( hwndDlg, IDC_DRIVER ), TRUE); } } // // Cleanup... // if (hTempPrinter) { ClosePrinter(hTempPrinter); hTempPrinter = NULL; } if (pTempDevMode) { GlobalFree((HANDLE)pTempDevMode); pTempDevMode = NULL; } return hr; } //////////////////////////////////////////////////////////////////////////// // // CPrintBrowser::UninstallDevMode // // Unintall the current devmode // //////////////////////////////////////////////////////////////////////////// HRESULT CPrintBrowser::UninstallDevMode() { if (hPrinter) { ClosePrinter(hPrinter); hPrinter = NULL; } if (pInternalDevMode) { GlobalFree((HANDLE)pInternalDevMode); pInternalDevMode = NULL; } // // Clear the internal printer name. // szPrinter[0] = 0; // // Disable the driver UI button // EnableWindow(GetDlgItem( hwndDlg, IDC_DRIVER ), FALSE); return S_OK; } //////////////////////////////////////////////////////////////////////////// // // InvokeAddPrinterWizardModal // // This is a global API declared in comdlg32.h // //////////////////////////////////////////////////////////////////////////// HRESULT InvokeAddPrinterWizardModal( IN HWND hwnd, OUT BOOL *pbPrinterAdded ) { HRESULT hr = S_OK; if (Print_LoadLibraries() && g_pfnPrinterSetup) { BOOL bPrinterAdded = FALSE; TCHAR szBuffer[kPrinterBufMax]; UINT uSize = ARRAYSIZE(szBuffer); szBuffer[0] = 0; // // Invoke the Add Printer Wizard here // bPrinterAdded = g_pfnPrinterSetup(hwnd, MSP_NEWPRINTER, uSize, szBuffer, &uSize, NULL); if (pbPrinterAdded) { *pbPrinterAdded = bPrinterAdded; } } else { hr = CreateError(); } return hr; } /*========================================================================*/ /* Ansi->Unicode Thunk routines */ /*========================================================================*/ //////////////////////////////////////////////////////////////////////////// // // ThunkPrintDlgEx // //////////////////////////////////////////////////////////////////////////// HRESULT ThunkPrintDlgEx( PPRINTINFOEX pPI, LPPRINTDLGEXA pPDA) { LPPRINTDLGEXW pPDW; LPDEVMODEA pDMA; DWORD cbLen; if (!pPDA) { pPI->dwExtendedError = CDERR_INITIALIZATION; return (E_INVALIDARG); } if (pPDA->lStructSize != sizeof(PRINTDLGEXA)) { pPI->dwExtendedError = CDERR_STRUCTSIZE; return (E_INVALIDARG); } if (!(pPDW = (LPPRINTDLGEXW)GlobalAlloc(GPTR, sizeof(PRINTDLGEXW)))) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; return (E_OUTOFMEMORY); } // // IN-only constant stuff. // pPDW->lStructSize = sizeof(PRINTDLGEXW); pPDW->hwndOwner = pPDA->hwndOwner; pPDW->ExclusionFlags = pPDA->ExclusionFlags; pPDW->hInstance = pPDA->hInstance; pPDW->lpCallback = pPDA->lpCallback; pPDW->nPropertyPages = pPDA->nPropertyPages; pPDW->lphPropertyPages = pPDA->lphPropertyPages; pPDW->nStartPage = pPDA->nStartPage; // // IN-OUT Variable Structs. // if ((pPDA->hDevMode) && (pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode))) { // // Make sure the device name in the devmode is not too long such that // it has overwritten the other devmode fields. // if ((pDMA->dmSize < MIN_DEVMODE_SIZEA) || (lstrlenA((LPCSTR)pDMA->dmDeviceName) > CCHDEVICENAME)) { pPDW->hDevMode = NULL; } else { pPDW->hDevMode = GlobalAlloc( GHND, sizeof(DEVMODEW) + pDMA->dmDriverExtra ); } GlobalUnlock(pPDA->hDevMode); } else { pPDW->hDevMode = NULL; } // // Thunk Device Names A => W // pPDW->hDevNames = NULL; if (pPDA->hDevNames) { // ignore the error case since we can't handle it either way. HRESULT hr = ThunkDevNamesA2W(pPDA->hDevNames, &pPDW->hDevNames); ASSERT(SUCCEEDED(hr)); } // // IN-only constant strings. // // Init Print TemplateName constant. // if ((pPDA->Flags & PD_ENABLEPRINTTEMPLATE) && (pPDA->lpPrintTemplateName)) { // // See if it's a string or an integer. // if (!IS_INTRESOURCE(pPDA->lpPrintTemplateName)) { // // String. // cbLen = lstrlenA(pPDA->lpPrintTemplateName) + 1; if (!(pPDW->lpPrintTemplateName = (LPCWSTR) GlobalAlloc( GPTR, (cbLen * sizeof(WCHAR)) ))) { pPI->dwExtendedError = CDERR_MEMALLOCFAILURE; return (E_OUTOFMEMORY); } else { pPI->fPrintTemplateAlloc = TRUE; SHAnsiToUnicode(pPDA->lpPrintTemplateName,(LPWSTR)pPDW->lpPrintTemplateName,cbLen); } } else { // // Integer. // pPDW->lpPrintTemplateName = (LPCWSTR)pPDA->lpPrintTemplateName; } } else { pPDW->lpPrintTemplateName = NULL; } // // Store the info in the PRINTINFOEX structure. // pPI->pPD = pPDW; pPI->pPDA = pPDA; pPI->ApiType = COMDLG_ANSI; return (S_OK); } //////////////////////////////////////////////////////////////////////////// // // FreeThunkPrintDlgEx // //////////////////////////////////////////////////////////////////////////// VOID FreeThunkPrintDlgEx( PPRINTINFOEX pPI) { LPPRINTDLGEXW pPDW = pPI->pPD; if (!pPDW) { return; } if (pPDW->hDevNames) { GlobalFree(pPDW->hDevNames); } if (pPDW->hDevMode) { GlobalFree(pPDW->hDevMode); } if (pPI->fPrintTemplateAlloc) { GlobalFree((LPWSTR)(pPDW->lpPrintTemplateName)); } GlobalFree(pPDW); pPI->pPD = NULL; } //////////////////////////////////////////////////////////////////////////// // // ThunkPrintDlgExA2W // //////////////////////////////////////////////////////////////////////////// VOID ThunkPrintDlgExA2W( PPRINTINFOEX pPI) { LPPRINTDLGEXW pPDW = pPI->pPD; LPPRINTDLGEXA pPDA = pPI->pPDA; // // Copy info A => W // pPDW->hDC = pPDA->hDC; pPDW->Flags = pPDA->Flags; pPDW->Flags2 = pPDA->Flags2; pPDW->nPageRanges = pPDA->nPageRanges; pPDW->nMaxPageRanges = pPDA->nMaxPageRanges; pPDW->lpPageRanges = pPDA->lpPageRanges; pPDW->nMinPage = pPDA->nMinPage; pPDW->nMaxPage = pPDA->nMaxPage; pPDW->nCopies = pPDA->nCopies; // // Thunk Device Names A => W // if (pPDA->hDevNames) { // ignore the error case since we can't handle it either way. HRESULT hr = ThunkDevNamesA2W(pPDA->hDevNames, &pPDW->hDevNames); ASSERT(SUCCEEDED(hr)); } // // Thunk Device Mode A => W // if (pPDA->hDevMode && pPDW->hDevMode) { LPDEVMODEW pDMW = (LPDEVMODEW)GlobalLock(pPDW->hDevMode); LPDEVMODEA pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode); ThunkDevModeA2W(pDMA, pDMW); GlobalUnlock(pPDW->hDevMode); GlobalUnlock(pPDA->hDevMode); } } //////////////////////////////////////////////////////////////////////////// // // ThunkPrintDlgExW2A // //////////////////////////////////////////////////////////////////////////// VOID ThunkPrintDlgExW2A( PPRINTINFOEX pPI) { LPPRINTDLGEXA pPDA = pPI->pPDA; LPPRINTDLGEXW pPDW = pPI->pPD; // // Copy info W => A // pPDA->hDC = pPDW->hDC; pPDA->Flags = pPDW->Flags; pPDA->Flags2 = pPDW->Flags2; pPDA->nPageRanges = pPDW->nPageRanges; pPDA->nMaxPageRanges = pPDW->nMaxPageRanges; pPDA->lpPageRanges = pPDW->lpPageRanges; pPDA->nMinPage = pPDW->nMinPage; pPDA->nMaxPage = pPDW->nMaxPage; pPDA->nCopies = pPDW->nCopies; pPDA->dwResultAction = pPDW->dwResultAction; // // Thunk Device Names W => A // if (pPDW->hDevNames) { // ignore the error case since we can't handle it either way. HRESULT hr = ThunkDevNamesW2A(pPDW->hDevNames, &pPDA->hDevNames); ASSERT(SUCCEEDED(hr)); } // // Thunk Device Mode W => A // if (pPDW->hDevMode) { LPDEVMODEW pDMW = (LPDEVMODEW)GlobalLock(pPDW->hDevMode); LPDEVMODEA pDMA; if (pPDA->hDevMode) { HANDLE handle; handle = GlobalReAlloc( pPDA->hDevMode, sizeof(DEVMODEA) + pDMW->dmDriverExtra, GHND ); //Check that realloc succeeded. if (handle) { pPDA->hDevMode = handle; } else { //Realloc didn't succeed. Free the memory occupied. pPDA->hDevMode = GlobalFree(pPDA->hDevMode); } } else { pPDA->hDevMode = GlobalAlloc( GHND, sizeof(DEVMODEA) + pDMW->dmDriverExtra ); } if (pPDA->hDevMode) { pDMA = (LPDEVMODEA)GlobalLock(pPDA->hDevMode); ThunkDevModeW2A(pDMW, pDMA); GlobalUnlock(pPDA->hDevMode); } GlobalUnlock(pPDW->hDevMode); } }