Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2895 lines
98 KiB

#include "shellprv.h"
#pragma hdrstop
#include "copy.h"
#include <regstr.h>
#ifdef WINNT
extern IDataObjectVtbl c_CPrintersIDLDataVtbl;
VOID
Printer_AddPrinterPropPages(LPCTSTR pszPrinterName, LPPROPSHEETHEADER lpsh)
{
HKEY hkeyBaseProgID;
//
// Add hooked pages if they exist in the registry
//
hkeyBaseProgID = NULL;
RegOpenKey(HKEY_CLASSES_ROOT, c_szPrinters, &hkeyBaseProgID);
if (hkeyBaseProgID)
{
// we need an IDataObject
LPCITEMIDLIST pidlParent = GetSpecialFolderIDList(NULL, CSIDL_PRINTERS, FALSE);
if (pidlParent)
{
HRESULT hres;
LPDATAOBJECT lpdtobj;
IDPRINTER idp;
LPITEMIDLIST pidp;
Printers_FillPidl(&idp, pszPrinterName);
pidp = (LPITEMIDLIST)&idp;
hres = CIDLData_CreateFromIDArray2(&c_CPrintersIDLDataVtbl, pidlParent, 1,
&pidp, &lpdtobj);
if (hres == NOERROR)
{
// add the hooked pages
HDCA hdca = DCA_Create();
if (hdca)
{
DCA_AddItemsFromKey(hdca, hkeyBaseProgID, c_szPropSheet);
DCA_AppendClassSheetInfo(hdca, hkeyBaseProgID, lpsh, lpdtobj);
DCA_Destroy(hdca);
}
lpdtobj->lpVtbl->Release(lpdtobj);
}
}
RegCloseKey(hkeyBaseProgID);
}
}
#else
// Not in any header files, and GetFileNameFromBrowse doesn't have dwFlags
BOOL _GetFileNameFromBrowse(HWND hwnd, LPTSTR szFilePath, UINT cbFilePath,
LPCTSTR szWorkingDir, LPCTSTR szDefExt, LPCTSTR szFilters, LPCTSTR szTitle,
DWORD dwFlags);
#define DATATYPE_NAMELEN 64 // length of DeviceCapability()s datatype name buffer
// these two defines are from SDK\INC16\PRINT.H, which, for some reason,
// isn't includable from here and I don't want to figure out why right now...
#define DC_EMF_COMPLIANT 20
#define DC_DATATYPE_PRODUCED 21
#define SetDlgFocus(hDlg, hwnd) SendMessage(hDlg, WM_NEXTDLGCTL,(WPARAM)(hwnd), 1L)
// these are the Attributes bits we play with
#define PS_ATTRIBUTE_MASK (PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_QUEUED|PRINTER_ATTRIBUTE_ENABLE_BIDI)
typedef struct tagPRINTER_INFO_2_COPY {
TCHAR pPrinterName[MAXNAMELEN];
TCHAR pComment[256];
TCHAR pPortName[MAX_PATH];
TCHAR pDriverName[MAXNAMELEN];
TCHAR pSepFile[MAX_PATH];
TCHAR pPrintProcessor[128];
TCHAR pDatatype[128];
DWORD Attributes;
DWORD StartTime;
DWORD UntilTime;
// from PRINTER_INFO_5
DWORD DeviceNotSelectedTimeout;
DWORD TransmissionRetryTimeout;
} PRINTER_INFO_2_COPY, * LPPRINTER_INFO_2_COPY;
// This information is available to each prop sheet page
typedef struct _PRINTERSTUFF
{
HANDLE hPrinter;
PRINTER_INFO_2_COPY sPrinter;
UINT uFlags;
UINT nPages;
// Starts out FALSE.
// If a page is visited, it's set to TRUE.
// If apply pressed and it's TRUE, save and set to FALSE.
// If apply pressed and it's FALSE, then info saved by another page.
BOOL fSaveEverything;
// TRUE during PSN_SETACTIVE to avoid turning on the Apply button...
BOOL fInitializing;
// A random perf flag for IDDC_PRINTTO -- port stuff is slow
BOOL fPortModified;
// MRU of ports connected to
HANDLE hmru;
// icon to display
HICON hIcon;
} PRINTERSTUFF, * LPPRINTERSTUFF;
// uFlags defines:
#define PS_OLDSTYLE 0x0001 // this is an old (3.1) driver
#define DETAIL_PORTS_INITIALIZED 0x0002 // the ports combobox has been set up
#define DETAIL_PORTS_FILLED 0x0004 // the ports combobox has been filled
// hmru registry location:
TCHAR const c_szPrnPortsMRU[] = REGSTR_PATH_EXPLORER TEXT("\\PrnPortsMRU");
TCHAR const c_szLPT[] = TEXT("LPT");
// Each page gets one of these
// psPrinterStuff points to info shared between pages
typedef struct _PRINTERPAGEINFO // ppi
{
PROPSHEETPAGE psp; // prop sheet page description
LPPRINTERSTUFF psPrinterStuff; // pointer to shared sheet info
} PRINTERPAGEINFO, * LPPRINTERPAGEINFO;
typedef struct _DELPORTDLG // dpd
{
LPPRINTERPAGEINFO pppi;
HWND hwndCB;
} DELPORTDLG, * LPDELPORTDLG;
void GeneralDlg_SetFields(HWND hDlg, LPPRINTERPAGEINFO pppi);
void DetailDlg_SetFields(HWND hDlg, LPPRINTERPAGEINFO pppi);
BOOL CALLBACK Printer_AddPortDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK Printer_DelPortDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK Printer_SpoolSettingsDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam);
LONG GeneralDlg_SaveEverything(HWND hDlg, LPPRINTERPAGEINFO pppi, int fSave);
UINT _AddPrinterPropPages(LPPRINTERSTUFF psPrinterStuff, HWND hWnd, LPPROPSHEETHEADER lpsh);
// for GeneralDlg_SaveEverything(..., fSave)
#define GDSE_SAVE 0 // save changes, return PSN_ return code
#define GDSE_QUERY_TESTPAGE 1 // if a change affects testpage, return TRUE
// not currently used, but may be useful some day
//#define GDSE_QUERY_SAVE 2 // if a change exists, return TRUE
// from shprsht.c
BOOL CALLBACK _AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam);
//==========================================================================
// Private helper functions
//==========================================================================
void Dlg_CB_GetSelText(HWND hDlg, UINT uID, LPTSTR szText, int cchTextMax)
{
HWND hCB;
int iCurSel;
VDATEINPUTBUF(szText, TCHAR, cchTextMax);
hCB = GetDlgItem(hDlg, uID);
iCurSel = ComboBox_GetCurSel(hCB);
if (iCurSel != CB_ERR)
{
ComboBox_GetLBText(hCB, iCurSel, szText);
}
else
{
ComboBox_GetText(hCB, szText, cchTextMax);
ComboBox_AddString(hCB, szText);
}
}
BOOL Printer_SelDlgComboEntry(HWND hWnd, int nID, LPCTSTR lpszEntry, BOOL bAdd)
{
if (!lpszEntry || !*lpszEntry)
{
return FALSE;
}
if (nID)
{
hWnd = GetDlgItem(hWnd, nID);
}
nID = ComboBox_FindStringExact(hWnd, 0, lpszEntry);
if (nID<0 && bAdd)
{
nID = ComboBox_AddString(hWnd, lpszEntry);
}
SendMessage(hWnd, CB_SETCURSEL, nID, 0L);
return(nID >= 0);
}
// Effects: removes every property sheet except the first two (General, Detail)
void _RemovePropSheets(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
int i;
HWND hdlgParent = GetParent(hDlg);
// General is page 0, Detail is page 1. So delete all others.
for (i = pppi->psPrinterStuff->nPages-1 ; i >= 2 ; i--)
{
PropSheet_RemovePage(hdlgParent, i, NULL);
}
return;
}
// Effects: rebuilds extension sheets and adds them to property sheet
void _RebuildPropSheets(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
HPROPSHEETPAGE ahpage[MAX_FILE_PROP_PAGES];
PROPSHEETHEADER psh;
HWND hwndParent;
UINT i;
DebugMsg(DM_TRACE, TEXT("sh TR - rebuilding printer property sheets"));
//
// Initialize PROPSHEETHEADER
//
psh.dwSize = SIZEOF(psh);
psh.dwFlags = PSH_PROPTITLE;
psh.hwndParent = hDlg;
psh.pszCaption = NULL;
psh.nPages = 0;
psh.nStartPage = 0;
psh.phpage = ahpage;
pppi->psPrinterStuff->nPages = _AddPrinterPropPages(pppi->psPrinterStuff, hDlg, &psh);
// Destroy General and Detail pages (if they were added)
if (!SHRestricted(REST_NOPRINTERTABS))
{
Assert(psh.nPages >= 2);
for (i=0 ; i<2 ; i++)
DestroyPropertySheetPage(psh.phpage[i]);
}
// Add all other pages
hwndParent = GetParent(hDlg);
for ( ; i<psh.nPages ; i++)
{
// BUGBUG: if this page doesn't get added for some reason, nobody
// will call DestroyPropertySheetPage on the hpage!
//
PropSheet_AddPage(hwndParent, psh.phpage[i]);
}
// If we go from a 4.0 to a 3.1 driver or vice-versa, we need to update
// the "Setup..." button. There are other fields that may need to be
// updated due to changed information (port name change, whatever)
// NOTE: This assumes we're on the detail page
DetailDlg_SetFields(hDlg, pppi);
return;
}
void PrtProp_Apply(HWND hdlg, LPPRINTERPAGEINFO pppi)
{
if (pppi->psPrinterStuff->fSaveEverything)
{
LONG lRet = GeneralDlg_SaveEverything(hdlg, pppi, GDSE_SAVE);
if (lRet == PSNRET_NOERROR)
{
pppi->psPrinterStuff->fSaveEverything = FALSE;
}
SetWindowLong(hdlg, DWL_MSGRESULT, lRet);
}
}
//==========================================================================
// Detail page
//==========================================================================
// If pName is not a prefix in hcbPorts, add "pName (pDescription)", handling
// the case where pDescription is null (3rd party port drivers may screw up)
VOID AddPortToCombobox(HWND hcbPorts, LPTSTR pName, LPTSTR pDescription)
{
if (CB_ERR == ComboBox_FindString(hcbPorts, 0, pName))
{
LPTSTR lpPortName = NULL;
if (Str_SetPtr(&lpPortName, pName))
{
LPTSTR lpFree = NULL;
LPTSTR lpPort = NULL;
if (pDescription && *pDescription)
{
lpFree =
lpPort = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_PRTPROP_PORT_FORMAT), pName, pDescription);
}
if (!lpPort)
lpPort = pName;
ComboBox_SetItemData(hcbPorts,
ComboBox_AddString(hcbPorts, lpPort),
lpPortName);
if (lpFree)
SHFree(lpFree);
}
}
}
// Get port name (sans description) and return TRUE iff UNC port
BOOL GetPortFromCombobox(HWND hcbPorts, LPTSTR pBuf, int cchBuf)
{
int iCurSel;
LPTSTR lpPortName;
VDATEINPUTBUF(pBuf, TCHAR, cchBuf);
iCurSel = ComboBox_GetCurSel(hcbPorts);
if (iCurSel != CB_ERR)
{
if (ComboBox_GetLBTextLen(hcbPorts, iCurSel) < cchBuf)
{
ComboBox_GetLBText(hcbPorts, iCurSel, pBuf);
goto try_again;
}
}
if (ComboBox_GetText(hcbPorts, pBuf, cchBuf))
{
iCurSel = ComboBox_FindString(hcbPorts, 0, pBuf);
if (iCurSel != CB_ERR)
{
try_again:
lpPortName = (LPTSTR)ComboBox_GetItemData(hcbPorts, iCurSel);
if (lpPortName)
{
lstrcpyn(pBuf, lpPortName, cchBuf);
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
VOID NukePortsFromCombobox(HWND hcbPorts)
{
LPTSTR lpPortName;
do {
lpPortName = (LPTSTR)ComboBox_GetItemData(hcbPorts, 0);
if (lpPortName && lpPortName != (LPTSTR)(LPARAM)CB_ERR)
{
Str_SetPtr(&lpPortName, NULL);
}
} while (CB_ERR != ComboBox_DeleteString(hcbPorts, 0));
// probably not necessary
ComboBox_ResetContent(hcbPorts);
}
VOID EnumNetworkPorts(HWND hcbPorts, DWORD dwScope)
{
HANDLE hEnum;
LPNETRESOURCE lpBuffer;
if(NO_ERROR==WNetOpenEnum(dwScope,RESOURCETYPE_PRINT,RESOURCEUSAGE_ATTACHED,NULL,&hEnum))
{
if(NULL != (lpBuffer=(LPNETRESOURCE)(void*)LocalAlloc(LPTR, 4096)))
{
while (TRUE)
{
DWORD dwSize=4096;
DWORD dwEntries=1L;
DWORD dwResult;
dwResult=WNetEnumResource(hEnum,&dwEntries,lpBuffer,&dwSize);
if(NO_ERROR==dwResult && 1==dwEntries)
{
if((RESOURCETYPE_PRINT & lpBuffer->dwType) &&
(RESOURCEUSAGE_CONNECTABLE & lpBuffer->dwUsage)
&& lpBuffer->lpRemoteName
&& lpBuffer->lpLocalName)
{
TCHAR szLocalName[20];
WORD wStrLength;
// Make sure that the local name terminates with
// a colon (since this is how it appears from
// EnumPorts)
lstrcpyn(szLocalName,lpBuffer->lpLocalName,
ARRAYSIZE(szLocalName));
wStrLength=lstrlen(szLocalName);
if(TEXT(':') != szLocalName[wStrLength-1])
{
if((wStrLength + 2) <= ARRAYSIZE(szLocalName))
lstrcat(szLocalName,TEXT(":"));
else
continue; // Skip this entry
}
DebugMsg(DM_TRACE,TEXT("sh PRTPROP - Checking network port [%s]"), szLocalName);
AddPortToCombobox(hcbPorts, szLocalName, lpBuffer->lpRemoteName);
}
}
else
break;
}
LocalFree((HLOCAL)lpBuffer);
}
WNetCloseEnum(hEnum);
}
}
BOOL Printers_EnumPortsCB(LPVOID lpData, HANDLE hPrinter, DWORD dwLevel,
LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
{
return(g_pfnEnumPorts(NULL, dwLevel, pEnum, dwSize, lpdwNeeded, lpdwNum));
}
VOID EnumLocalPorts(HWND hcbPorts)
{
LPPORT_INFO_2 pPorts;
DWORD dwNum;
pPorts = Printer_EnumProps(NULL, 2, &dwNum, Printers_EnumPortsCB, NULL);
if (pPorts)
{
for ( ; dwNum > 0 ; )
{
--dwNum;
DebugMsg(DM_TRACE,TEXT("sh PRTPROP - Checking local port [%s]"), pPorts[dwNum].pPortName);
AddPortToCombobox(hcbPorts, pPorts[dwNum].pPortName, pPorts[dwNum].pDescription);
}
LocalFree((HLOCAL)pPorts);
}
}
// DetailDlg_FillPorts fills in all the ports and their descriptions into
// the combobox. We use connected network resources, remembered network
// resources, local ports, and an mru of the last 10 (unc) ports connected to.
void DetailDlg_FillPorts(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
HWND hTemp;
hTemp = GetDlgItem(hDlg, IDDC_PRINTTO);
#if 0 // there's no easy way to get the listbox any more; it's not a child
// window of the combobox! So we can't use tabs...
if (!(pppi->psPrinterStuff->uFlags & DETAIL_PORTS_INITIALIZED))
{
HWND hLB;
TCHAR szClassName[20];
int nTabStop;
WORD wXBaseUnit;
RECT rcListBox;
DebugMsg(DM_TRACE, TEXT("sh PRTPROP - Initializing port combobox"));
// find listbox of combobox
hLB = GetWindow(hTemp, GW_CHILD);
GetClassName(hLB, szClassName, ARRAYSIZE(szClassName));
while (lstrcmp(szClassName, c_szListViewClass))
{
hLB = GetWindow(hLB, GW_HWNDNEXT);
if (!hLB)
{
DebugMsg(DM_WARNING, TEXT("sh PRTPROP - Could not find child window"));
goto skip_setup;
}
}
// Set up the tabstop so the right hand column is 1/3 of the way
// across the listbox.
wXBaseUnit=LOWORD(GetDialogBaseUnits());
GetWindowRect(hLB,&rcListBox);
nTabStop=(rcListBox.right-rcListBox.left) * 4 / (3*wXBaseUnit);
ListBox_SetTabStops(hLB, 1, &nTabStop);
skip_setup:
pppi->psPrinterStuff->uFlags |= DETAIL_PORTS_INITIALIZED;
}
#endif
if (!(pppi->psPrinterStuff->uFlags & DETAIL_PORTS_FILLED))
{
TCHAR szOldPort[MAX_PATH];
int iSel;
if (ComboBox_GetText(hTemp, szOldPort, ARRAYSIZE(szOldPort)))
{
// extract the local name if we can
// try the exact name for unc paths, otherwise "\\net\hp4" may match to "\\net\hp4si"
iSel = ComboBox_FindStringExact(hTemp, 0, szOldPort);
if (iSel == CB_ERR)
{
iSel = ComboBox_FindString(hTemp, 0, szOldPort);
}
if (iSel != CB_ERR)
{
LPTSTR lpPortName = (LPTSTR)ComboBox_GetItemData(hTemp, iSel);
if (lpPortName)
{
lstrcpy(szOldPort, lpPortName);
}
}
}
else
{
// edit box is empty (!DETAIL_PORTS_INITIALIZED), go with given
lstrcpy(szOldPort, pppi->psPrinterStuff->sPrinter.pPortName);
}
NukePortsFromCombobox(hTemp);
EnumNetworkPorts(hTemp, RESOURCE_CONNECTED);
EnumNetworkPorts(hTemp, RESOURCE_REMEMBERED);
EnumLocalPorts(hTemp);
// REVIEW: This should probably be a FindStringExact
if (CB_ERR == ComboBox_FindString(hTemp, 0, pppi->psPrinterStuff->sPrinter.pPortName))
{
// Must be a UNC -- make sure it's in the MRU
if (!IntlStrEqNI(c_szLPT, pppi->psPrinterStuff->sPrinter.pPortName, 3))
AddMRUString(pppi->psPrinterStuff->hmru, pppi->psPrinterStuff->sPrinter.pPortName);
}
// Add MRU ports (unc paths)
if (pppi->psPrinterStuff->hmru)
{
TCHAR szPort[MAX_PATH];
int i;
for (i = EnumMRUList(pppi->psPrinterStuff->hmru, -1, NULL, 0) ;
i-- > 0 ; )
{
if (EnumMRUList(pppi->psPrinterStuff->hmru, i, szPort, ARRAYSIZE(szPort)))
{
int iSel = ComboBox_FindStringExact(hTemp, 0, szPort);
DebugMsg(DM_TRACE,TEXT("sh PRTPROP - Checking mru unc port [%s]"), szPort);
// Don't add an MRU port if it's already there --
// this may happen if someone enters "LPT3:"
// before redirecting the LPT3: port
if (CB_ERR == iSel)
{
ComboBox_AddString(hTemp, szPort);
}
else
{
// BUGBUG: Not implemented yet
//DelMRUString(pppi->psPrinterStuff->hmru, iSel);
}
}
}
}
// select the old port
iSel = ComboBox_FindStringExact(hTemp, 0, szOldPort);
if (iSel == CB_ERR)
{
iSel = ComboBox_FindString(hTemp, 0, szOldPort);
}
if (iSel != CB_ERR)
{
ComboBox_SetCurSel(hTemp, iSel);
}
else
{
ComboBox_SetText(hTemp, szOldPort);
}
pppi->psPrinterStuff->uFlags |= DETAIL_PORTS_FILLED;
}
}
BOOL Printers_EnumPrinterDriversCB(LPVOID lpData, HANDLE hPrinter, DWORD dwLevel,
LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
{
return(g_pfnEnumPrinterDrivers(NULL, NULL, dwLevel, pEnum, dwSize, lpdwNeeded, lpdwNum));
}
void DetailDlg_FillDrivers(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
HWND hTemp;
DWORD dwNum;
DRIVER_INFO_1 * pDrivers;
hTemp = GetDlgItem(hDlg, IDDC_DRIVER);
ComboBox_ResetContent(hTemp);
pDrivers = Printer_EnumProps(NULL, 1, &dwNum, Printers_EnumPrinterDriversCB, NULL);
if (pDrivers)
{
for ( ; dwNum>0; )
{
--dwNum;
ComboBox_AddString(hTemp, pDrivers[dwNum].pName);
}
if (!Printer_SelDlgComboEntry(hTemp, 0, pppi->psPrinterStuff->sPrinter.pDriverName, FALSE))
{
DebugMsg(DM_WARNING, TEXT("sh WN - Printer is using unenumerated driver! We'll try to force it."));
Assert(FALSE);
// BUGBUG: We probably want to select "LPT1:"
Printer_SelDlgComboEntry(hTemp, 0, pppi->psPrinterStuff->sPrinter.pDriverName, TRUE);
}
LocalFree((HLOCAL)pDrivers);
}
}
//---------------------------------------------------------------------
// Function: CreateUniqueName(lpDest,lpBaseName,wInstance)
//
// Action: Create a unique friendly name for this printer. If wInstance
// is 0, just copy the name over. Otherwise, play some games
// with truncating the name so it will fit.
//
// Return: TRUE if we created a name, FALSE if something went wrong
//
// NOTE: THIS CODE IS FROM MSPRINT2.DLL! We should match their naming scheme.
//
//---------------------------------------------------------------------
BOOL WINAPI CreateUniqueName(LPTSTR lpDest,
LPTSTR lpBaseName,
WORD wInstance)
{
BOOL bSuccess=FALSE;
if(wInstance)
{
// We want to provide a fully localizable way to create a
// unique friendly name for each instance. We start with
// a single string from the resource, and call wsprintf
// twice, getting something like this:
//
// "%%s (Copy %u)" From resource
// "%s (Copy 2)" After first wsprintf
// "Foobar Laser (Copy 2)" After second wsprintf
//
// We can't make a single wsprintf call, since it has no
// concept of limiting the string size. We truncate the
// model name (in a DBCS-aware fashion) to the appropriate
// size, so the whole string fits in MAXNAMELEN bytes. This
// may cause some name truncation, but only in cases where
// the model name is extremely long.
TCHAR szFormat1[MAXNAMELEN];
TCHAR szFormat2[MAXNAMELEN];
if(LoadString(HINST_THISDLL,IDS_PRTPROP_UNIQUE_FORMAT,szFormat1,ARRAYSIZE(szFormat1)))
{
WORD wFormatLength;
TCHAR szBaseName[MAXNAMELEN];
// wFormatLength is length of format string before inserting
// the model name. Subtract 2 to remove the "%s", and add
// 1 to compensate for the terminating NULL, which is
// counted in the total buffer length, but not the string length
wFormatLength=wsprintf(szFormat2,szFormat1,wInstance+1)-1;
lstrcpyn(szBaseName,lpBaseName,ARRAYSIZE(szBaseName)-wFormatLength);
wsprintf(lpDest,szFormat2,(LPTSTR)szBaseName);
bSuccess=TRUE;
}
}
else
{
lstrcpyn(lpDest,lpBaseName,MAXNAMELEN);
bSuccess=TRUE;
}
return bSuccess;
}
//-----------------------------------------------------------------------
// Function: NewFriendlyName(hDlg,lpBaseName,lpNewName)
//
// Action: Create a new (and unique) friendly name
//
// Return: TRUE if lpFriendlyName recevies new unique name, FALSE if not
//
// NOTE: THIS CODE IS FROM MSPRINT2.DLL! We should match their naming scheme.
//
//-----------------------------------------------------------------------
BOOL NewFriendlyName(LPTSTR lpBaseName,
LPTSTR lpNewName)
{
TCHAR szTestName[MAXNAMELEN];
WORD wCount;
// Set upper limit of 1000 tries, just to avoid hanging forever
for(wCount=0;wCount<1000;wCount++)
{
HANDLE hPrinter;
if(CreateUniqueName(szTestName,lpBaseName,wCount))
{
hPrinter = Printer_OpenPrinter(szTestName);
if(hPrinter)
{
// Name is in use--try another one
Printer_ClosePrinter(hPrinter);
}
else
{
lstrcpyn(lpNewName,szTestName,MAXNAMELEN);
return TRUE;
}
}
}
// Pretty unlikely to ever make it here, but just in case...
return FALSE;
}
void DetailDlg_HandleDriverChange(HWND hDlg, LPPRINTERPAGEINFO pppi, LPTSTR pOldDriver)
{
int len;
// if the current printer name is built from the old driver name,
// we want to rename this printer so nobody gets confused.
// BUGBUG: This driver change is busted when we change drivers to THE SAME
// DRIVER NAME... We rename "HP LaserJet 4L" to "HP LaserJet 4L (copy 2)"
// Don't change the name in this case.
len = lstrlen(pOldDriver);
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, 0,
pOldDriver, len,
pppi->psPrinterStuff->sPrinter.pPrinterName, len))
{
TCHAR szNewName[MAXNAMELEN];
if (NewFriendlyName(pppi->psPrinterStuff->sPrinter.pDriverName, szNewName))
{
if (NOERROR == Printer_SetNameOf(NULL, hDlg, pppi->psPrinterStuff->sPrinter.pPrinterName, szNewName, NULL))
{
lstrcpy(pppi->psPrinterStuff->sPrinter.pPrinterName, szNewName);
DetailDlg_SetFields(hDlg, pppi);
PostMessage(GetParent(hDlg), PSM_SETTITLE, PSH_PROPTITLE,
(LPARAM)(pppi->psPrinterStuff->sPrinter.pPrinterName));
}
}
}
}
void DetailDlg_DriverChange(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
TCHAR szDriver[MAXNAMELEN];
int i;
if (SHRestricted(REST_NOPRINTERADD))
{
ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_RESTRICTIONS),
MAKEINTRESOURCE(IDS_RESTRICTIONSTITLE), MB_OK|MB_ICONSTOP);
return;
}
Dlg_CB_GetSelText(hDlg, IDDC_DRIVER, szDriver, ARRAYSIZE(szDriver));
if (!lstrcmp(pppi->psPrinterStuff->sPrinter.pDriverName, szDriver))
{
return;
}
i = ShellMessageBox(HINST_THISDLL, hDlg,
MAKEINTRESOURCE(IDS_PRTPROP_DRIVER_WARN),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_YESNO|MB_ICONEXCLAMATION);
if (i != IDYES)
goto error_exit;
if (PropSheet_Apply(GetParent(hDlg)))
{
TCHAR szOldDriver[MAXNAMELEN];
BOOL fDriverChanged = TRUE;
DECLAREWAITCURSOR;
DebugMsg(DM_TRACE,TEXT("sh TR - saved print properties, changing driver"));
SetWaitCursor();
_RemovePropSheets(hDlg, pppi);
// Don't change the driver until everything else has been saved
// AND removed. A driver change could adversely affect
// the driver's pages.
lstrcpy(szOldDriver, pppi->psPrinterStuff->sPrinter.pDriverName);
lstrcpy(pppi->psPrinterStuff->sPrinter.pDriverName, szDriver);
if (GeneralDlg_SaveEverything(hDlg, pppi, GDSE_SAVE))
{
// we couldn't save the driver! (Bad net?) go back to old one.
lstrcpy(pppi->psPrinterStuff->sPrinter.pDriverName, szOldDriver);
Printer_SelDlgComboEntry(hDlg, IDDC_DRIVER, szOldDriver, FALSE);
fDriverChanged = FALSE;
}
_RebuildPropSheets(hDlg, pppi);
if (fDriverChanged)
{
DetailDlg_HandleDriverChange(hDlg, pppi, szOldDriver);
}
ResetWaitCursor();
}
else
{
error_exit:
// reselect the old driver in the combobox
Printer_SelDlgComboEntry(hDlg, IDDC_DRIVER,
pppi->psPrinterStuff->sPrinter.pDriverName, FALSE);
}
}
void DetailDlg_NewDriver(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
if (SHRestricted(REST_NOPRINTERADD))
{
ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_RESTRICTIONS),
MAKEINTRESOURCE(IDS_RESTRICTIONSTITLE), MB_OK|MB_ICONSTOP);
return;
}
if (ShellMessageBox(HINST_THISDLL, hDlg,
MAKEINTRESOURCE(IDS_PRTPROP_DRIVER_WARN),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_YESNO|MB_ICONEXCLAMATION) != IDYES)
{
return;
}
if (PropSheet_Apply(GetParent(hDlg)))
{
TCHAR szDriver[MAXNAMELEN];
DECLAREWAITCURSOR;
SetWaitCursor();
// Remove the pages before calling PrinterSetup. Even though this
// creates more work if the driver cannot be installed. This will
// give the appearance of a quicker return after the PrinterSetup
// dialogs go away.
_RemovePropSheets(hDlg, pppi);
szDriver[0] = TEXT('\0');
Printers_PrinterSetup(hDlg, MSP_NEWDRIVER, szDriver, NULL);
if (szDriver[0])
{
TCHAR szOldDriver[MAXNAMELEN];
lstrcpy(szOldDriver, pppi->psPrinterStuff->sPrinter.pDriverName);
lstrcpy(pppi->psPrinterStuff->sPrinter.pDriverName, szDriver);
if (GeneralDlg_SaveEverything(hDlg, pppi, GDSE_SAVE))
{
// we couldn't save the driver! go back to old one
lstrcpy(pppi->psPrinterStuff->sPrinter.pDriverName, szOldDriver);
}
else
{
// we saved the new driver, select it in the combobox
Printer_SelDlgComboEntry(hDlg, IDDC_DRIVER, szDriver, TRUE);
DetailDlg_HandleDriverChange(hDlg, pppi, szOldDriver);
}
}
_RebuildPropSheets(hDlg, pppi);
ResetWaitCursor();
// BUGBUG: we probably want to suggest a new friendly name if
// the current friendly name is the same as the old driver name
}
}
// This function puts pppi info into the dialog and
// hides/enables/disables controls as needed
void DetailDlg_SetFields(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
// turn of PSM_CHANGE messages
pppi->psPrinterStuff->fInitializing = TRUE;
SetDlgItemText(hDlg, IDC_PRINTER_NAME, pppi->psPrinterStuff->sPrinter.pPrinterName);
// Port "FILE:" cannot have spool settings
EnableWindow(GetDlgItem(hDlg, IDDB_SPOOL),
lstrcmp(pppi->psPrinterStuff->sPrinter.pPortName, c_szFileColon));
// 3.1 drivers show the Setup... button, 4.0 drivers do not.
if (!(pppi->psPrinterStuff->uFlags & PS_OLDSTYLE))
ShowWindow(GetDlgItem(hDlg, IDDB_SETUP), SW_HIDE);
else
ShowWindow(GetDlgItem(hDlg, IDDB_SETUP), SW_SHOWNA);
DetailDlg_FillPorts(hDlg, pppi);
DetailDlg_FillDrivers(hDlg, pppi);
SetDlgItemInt(hDlg, IDC_TIMEOUT_NOTSELECTED,
pppi->psPrinterStuff->sPrinter.DeviceNotSelectedTimeout/1000, FALSE);
SetDlgItemInt(hDlg, IDC_TIMEOUT_TRANSRETRY,
pppi->psPrinterStuff->sPrinter.TransmissionRetryTimeout/1000, FALSE);
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, 0,
pppi->psPrinterStuff->sPrinter.pPortName, 3,
c_szLPT, 3))
{
EnableWindow(GetDlgItem(hDlg, IDC_TIMEOUT_NOTSELECTED), TRUE);
goto enable_common;
}
else if (2 == CompareString(LOCALE_SYSTEM_DEFAULT, 0,
pppi->psPrinterStuff->sPrinter.pPortName, 3,
TEXT("COM"), 3))
{
EnableWindow(GetDlgItem(hDlg, IDC_TIMEOUT_NOTSELECTED), FALSE);
enable_common:
EnableWindow(GetDlgItem(hDlg, IDC_TIMEOUT_TRANSRETRY), TRUE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDC_TIMEOUT_NOTSELECTED), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TIMEOUT_TRANSRETRY), FALSE);
}
// BUGBUG 15512: disable the port settings button if:
// a) port is FILE:
// b) port is redirected local port
// c) port is not associated with a port monitor
// (a) is trivial to check, (b) less so, and (c) even less so.
// Do (a) for now and (b+c) if time.
if (!lstrcmp(pppi->psPrinterStuff->sPrinter.pPortName, c_szFileColon))
{
EnableWindow(GetDlgItem(hDlg, IDDB_PORT), FALSE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDDB_PORT), TRUE);
}
pppi->psPrinterStuff->fInitializing = FALSE;
}
// This function reads information from hDlg into pppi.
// returns TRUE iff an invalid state was detected
BOOL DetailDlg_GetFields(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
TCHAR szPortName[MAX_PATH];
BOOL b;
HWND hcbPorts = GetDlgItem(hDlg, IDDC_PRINTTO);
b = GetPortFromCombobox(hcbPorts, szPortName, ARRAYSIZE(szPortName));
PathRemoveBlanks(szPortName);
if (!szPortName[0])
{
SetDlgFocus(hDlg, hcbPorts);
ShellMessageBox(HINST_THISDLL, hDlg,
MAKEINTRESOURCE(IDS_PRTPROP_PORT_ERROR),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONINFORMATION);
return TRUE;
}
if (b)
{
if (!IntlStrEqNI(c_szLPT, szPortName, 3))
AddMRUString(pppi->psPrinterStuff->hmru, szPortName);
}
lstrcpy(pppi->psPrinterStuff->sPrinter.pPortName, szPortName);
// pDriverName is grabbed and verified as soon as it is changed
pppi->psPrinterStuff->sPrinter.DeviceNotSelectedTimeout = 1000 *
GetDlgItemInt(hDlg, IDC_TIMEOUT_NOTSELECTED, &b, FALSE);
pppi->psPrinterStuff->sPrinter.TransmissionRetryTimeout = 1000 *
GetDlgItemInt(hDlg, IDC_TIMEOUT_TRANSRETRY, &b, FALSE);
return FALSE;
}
//--------------------------------------------------------------------------
// Dialog procedure of "Detail" page
//
#pragma data_seg(DATASEG_READONLY)
static DWORD aDetailHelpIds[] = {
IDC_PRINTER_ICON, IDH_PRTPROPS_ICON,
IDC_PRINTER_NAME, IDH_PRTPROPS_NAME_STATIC,
IDD_LINE_1, NO_HELP,
IDDC_PRINTTO, IDH_PRTPROPS_PORT,
IDDB_ADD_PORT, IDH_PRTPROPS_NEW_PORT,
IDDB_DEL_PORT, IDH_PRTPROPS_DEL_PORT,
IDDC_DRIVER, IDH_PRTPROPS_DRIVER,
IDDB_NEWDRIVER, IDH_PRTPROPS_NEW_DRIVER,
IDC_TIMEOUTSETTING, IDH_COMM_GROUPBOX,
IDC_TIMEOUTTEXT_1, IDH_PRTPROPS_TIMEOUT_NOTSELECTED,
IDC_TIMEOUTTEXT_2, IDH_PRTPROPS_TIMEOUT_NOTSELECTED,
IDC_TIMEOUT_NOTSELECTED, IDH_PRTPROPS_TIMEOUT_NOTSELECTED,
IDC_TIMEOUTTEXT_3, IDH_PRTPROPS_TIMEOUT_TRANSRETRY,
IDC_TIMEOUTTEXT_4, IDH_PRTPROPS_TIMEOUT_TRANSRETRY,
IDC_TIMEOUT_TRANSRETRY, IDH_PRTPROPS_TIMEOUT_TRANSRETRY,
IDDB_SPOOL, IDH_PRTPROPS_SPOOL_SETTINGS,
IDDB_PORT, IDH_PRTPROPS_PORT_SETTINGS,
IDDB_SETUP, IDH_PRTPROPS_SETUP,
IDDB_CAPTURE_PORT, IDH_PRTPROPS_MAP_PRN_PORT,
IDDB_RELEASE_PORT, IDH_PRTPROPS_UNMAP_PRN_PORT,
0, 0
};
#pragma data_seg()
BOOL Printers_EnumMonitorsCB(LPVOID lpData, HANDLE hPrinter, DWORD dwLevel,
LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
{
return(g_pfnEnumMonitors(NULL, dwLevel, pEnum, dwSize, lpdwNeeded, lpdwNum));
}
BOOL CALLBACK Printer_DetailDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
LPPRINTERPAGEINFO pppi = (LPPRINTERPAGEINFO)GetWindowLong(hdlg, DWL_USER);
switch (uMessage)
{
case WM_INITDIALOG:
{
#if 0
LPMONITOR_INFO_1 pMonitors;
DWORD dwNum;
BOOL fShow = FALSE;
#endif
HICON hIcon;
pppi = (LPPRINTERPAGEINFO)lParam;
SetWindowLong(hdlg, DWL_USER, lParam);
// we have to destroy the icon returned
if (pppi->psPrinterStuff->hIcon)
if (NULL != (hIcon = (HICON)SendDlgItemMessage(hdlg, IDC_PRINTER_ICON, STM_SETICON, (WPARAM)pppi->psPrinterStuff->hIcon, 0L)))
DestroyIcon(hIcon);
#if 0 // Spec says to not show the button, but that doesn't make sense
// determine if we should show the "New" port button
pMonitors = Printer_EnumProps(NULL, 1, &dwNum, Printers_EnumMonitorsCB, NULL);
if (pMonitors)
{
LocalFree((HLOCAL)pMonitors);
fShow = dwNum > 1;
}
if (!fShow)
{
ShowWindow(GetDlgItem(hdlg, IDDB_ADD_PORT), SW_HIDE);
}
#endif
break;
}
case WM_DESTROY:
NukePortsFromCombobox(GetDlgItem(hdlg, IDDC_PRINTTO));
// since we're sharing our 1 hicon across 2 pages, set this to null
// so the dialog box procedure doesn't destroy it twice (we destroy it
// once after we return from the PropertySheet function).
if (pppi->psPrinterStuff->hIcon)
SendDlgItemMessage(hdlg, IDC_PRINTER_ICON, STM_SETICON, 0, 0L);
break;
case WM_HELP:
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP,
(DWORD) (LPTSTR) aDetailHelpIds);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD) (LPTSTR) aDetailHelpIds);
break;
case WM_COMMAND:
{
BOOL fApply = FALSE; // Do we want to turn on the Apply button?
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDDC_DRIVER:
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
{
DetailDlg_DriverChange(hdlg, pppi);
// don't need fApply -- _DriverChange saves everything
}
break;
case IDDC_PRINTTO:
// most of the time when we get a CBN_KILLFOCUS, nothing has
// happened... we only need to do any work after a CBN_EDITCHANGE
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_EDITCHANGE)
{
pppi->psPrinterStuff->fPortModified = TRUE;
fApply = TRUE;
}
if ((GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) ||
((GET_WM_COMMAND_CMD(wParam, lParam) == CBN_KILLFOCUS) &&
pppi->psPrinterStuff->fPortModified ) )
{
TCHAR szPortName[MAX_PATH];
pppi->psPrinterStuff->fPortModified = FALSE;
UpdatePrintTo:
// save old port name
lstrcpy(szPortName, pppi->psPrinterStuff->sPrinter.pPortName);
// The port may have changed. Update timeout settings and the
// spool settings button. Save code by calling _SetFields.
if (!DetailDlg_GetFields(hdlg, pppi))
DetailDlg_SetFields(hdlg, pppi);
fApply = lstrcmp(szPortName, pppi->psPrinterStuff->sPrinter.pPortName);
}
break;
case IDDB_NEWDRIVER:
DetailDlg_NewDriver(hdlg, pppi);
// don't need fApply -- _NewDriver saves everything
break;
case IDDB_ADD_PORT:
// This may update the contents/selection of the ports combobox
if (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_ADDPORT),
hdlg, Printer_AddPortDlgProc,
(LPARAM)GetDlgItem(hdlg, IDDC_PRINTTO)))
{
goto UpdatePrintTo; // turns on fApply
}
break;
case IDDB_DEL_PORT:
{
DELPORTDLG dpd;
dpd.pppi = pppi;
dpd.hwndCB = GetDlgItem(hdlg, IDDC_PRINTTO);
// This may update the contents/selection of the ports combobox
if (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_DELPORT),
hdlg, Printer_DelPortDlgProc,
(LPARAM)&dpd))
{
goto UpdatePrintTo; // turns on fApply
}
break;
}
case IDDB_PORT:
{
TCHAR szPrintTo[MAX_PATH];
GetPortFromCombobox(GetDlgItem(hdlg, IDDC_PRINTTO),
szPrintTo, ARRAYSIZE(szPrintTo));
g_pfnConfigurePort(NULL, hdlg, szPrintTo);
break;
}
case IDDB_CAPTURE_PORT:
SHNetConnectionDialog(hdlg, NULL, RESOURCETYPE_PRINT);
pppi->psPrinterStuff->uFlags &= ~DETAIL_PORTS_FILLED;
DetailDlg_FillPorts(hdlg, pppi);
break;
case IDDB_RELEASE_PORT:
WNetDisconnectDialog(hdlg, RESOURCETYPE_PRINT);
pppi->psPrinterStuff->uFlags &= ~DETAIL_PORTS_FILLED;
DetailDlg_FillPorts(hdlg, pppi);
break;
case IDDB_SPOOL:
fApply = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_SPOOLSETTINGS), hdlg,
Printer_SpoolSettingsDlgProc, (LPARAM)pppi) > 0;
break;
case IDDB_SETUP:
Assert(pppi->psPrinterStuff->uFlags & PS_OLDSTYLE);
if (!g_pfnPrinterProperties(hdlg, pppi->psPrinterStuff->hPrinter))
{
ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_CANTOPENDRIVERPROP),
MAKEINTRESOURCE(IDS_PRINTERS), MB_OK|MB_ICONSTOP);
}
break;
case IDC_TIMEOUT_NOTSELECTED:
case IDC_TIMEOUT_TRANSRETRY:
fApply = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
break;
default:
break;
}
if (fApply && !pppi->psPrinterStuff->fInitializing)
{
PostMessage(GetParent(hdlg), PSM_CHANGED, (WPARAM)hdlg, 0);
}
break;
}
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case PSN_KILLACTIVE:
// User is leaving this page.
SetWindowLong(hdlg, DWL_MSGRESULT, DetailDlg_GetFields(hdlg, pppi));
break;
case PSN_APPLY:
// save everything on OK or Apply Now
PrtProp_Apply(hdlg, pppi);
break;
case PSN_SETACTIVE:
// Update information that may have changed on the General page
pppi->psPrinterStuff->fSaveEverything = TRUE;
DetailDlg_SetFields(hdlg, pppi);
Assert(pppi->psPrinterStuff->fPortModified == FALSE);
pppi->psPrinterStuff->fPortModified = FALSE;
// We need this because _SetFields trashes DWL_MSGRESULT...
SetWindowLong(hdlg, DWL_MSGRESULT, 0);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
//==========================================================================
// General page
//==========================================================================
void GeneralDlg_FillSeparator(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
HWND hTemp;
TCHAR buf[128];
UINT id;
hTemp = GetDlgItem(hDlg, IDDC_SEPARATOR);
ComboBox_ResetContent(hTemp);
for (id = IDS_PRNSEP_FULL ; id >= IDS_PRNSEP_NONE ; id--)
{
LoadString(HINST_THISDLL, id, buf, ARRAYSIZE(buf));
ComboBox_AddString(hTemp, buf);
}
if (pppi->psPrinterStuff->sPrinter.pSepFile[0])
Printer_SelDlgComboEntry(hTemp, 0, pppi->psPrinterStuff->sPrinter.pSepFile, TRUE);
else
Printer_SelDlgComboEntry(hTemp, 0, buf, FALSE);
}
void GeneralDlg_SetFields(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
// turn off PSM_CHANGE messages
pppi->psPrinterStuff->fInitializing = TRUE;
SetDlgItemText(hDlg, IDC_PRINTER_NAME, pppi->psPrinterStuff->sPrinter.pPrinterName);
SetDlgItemText(hDlg, IDGE_COMMENT, pppi->psPrinterStuff->sPrinter.pComment);
GeneralDlg_FillSeparator(hDlg, pppi);
pppi->psPrinterStuff->fInitializing = FALSE;
}
// returns TRUE iff invalid information detected
BOOL GeneralDlg_GetFields(HWND hDlg, LPPRINTERPAGEINFO pppi)
{
GetDlgItemText(hDlg, IDGE_COMMENT, pppi->psPrinterStuff->sPrinter.pComment, ARRAYSIZE(pppi->psPrinterStuff->sPrinter.pComment));
Dlg_CB_GetSelText(hDlg, IDDC_SEPARATOR,
pppi->psPrinterStuff->sPrinter.pSepFile,
ARRAYSIZE(pppi->psPrinterStuff->sPrinter.pSepFile));
return FALSE;
}
// fSaveMe == GDSE_SAVE => save changes and
// return PSNRET_NOERROR, PSNRET_INVALID, or PSNRET_INVALID_NOCHANGEPAGE
// fSaveMe == GDSE_QUERY_TESTPAGE => don't save anything and
// return TRUE iff a "test page state change" has been entered
// fSaveMe == GDSE_QUERY_SAVE => don't save anything and
// return TRUE iff some change exists
LONG GeneralDlg_SaveEverything(HWND hDlg, LPPRINTERPAGEINFO pppi, int fSaveMe)
{
LPPRINTER_INFO_2 pPrinter;
LPPRINTER_INFO_5 pPrinter5;
LONG lRet = PSNRET_NOERROR;
BOOL fError = FALSE;
BOOL fTestPage = FALSE;
HWND hTempEditBox = NULL; // save some code
HWND hTempComboBox = NULL;
WPARAM wPage;
LPCTSTR lpError;
BOOL fSave = FALSE;
BOOL fPortChange = FALSE;
DWORD dwOldAttributes; // old info, valid iff fPortChange
TCHAR szOldPortName[MAX_PATH]; // old info, valid iff fPortChange
pPrinter = Printer_GetPrinterInfo(pppi->psPrinterStuff->hPrinter, 2);
if (pPrinter)
{
LPPRINTER_INFO_2_COPY pCopy = &(pppi->psPrinterStuff->sPrinter);
if (lstrcmp(pPrinter->pPortName, pCopy->pPortName)
&& pCopy->pPortName[0])
{
TCHAR newPrinterPort[ARRAYSIZE(pCopy->pPrinterName) +
ARRAYSIZE(pCopy->pPortName)];
TCHAR oldPrinterPort[ARRAYSIZE(pCopy->pPrinterName) +
ARRAYSIZE(pCopy->pPortName)];
LPTSTR pNewInfo;
LPTSTR pOldInfo;
int i;
// If there's a port change, call the copyhook right away.
// If we are going to proceed, we have to re-get the PRINTER_INFO_2,
// since the copyhook may have modified it. (Assume that the name
// and port won't change.)
// the copyhook receives a doubly-null
// terminated list of "printername\0port\0\0", so muck with
// the strings.
lstrcpy(newPrinterPort,pPrinter->pPrinterName);
i = lstrlen(newPrinterPort)+1;
lstrcpy(&newPrinterPort[i],pCopy->pPortName);
i = i+lstrlen(&newPrinterPort[i])+1;
newPrinterPort[i] = TEXT('\0');
lstrcpy(oldPrinterPort,pPrinter->pPrinterName);
i = lstrlen(oldPrinterPort)+1;
lstrcpy(&oldPrinterPort[i],pPrinter->pPortName);
i = i+lstrlen(&oldPrinterPort[i])+1;
oldPrinterPort[i] = TEXT('\0');
pNewInfo = newPrinterPort;
pOldInfo = oldPrinterPort;
if (fSaveMe == GDSE_SAVE)
{
if (CallPrinterCopyHooks(hDlg, PO_PORTCHANGE, 0,
pNewInfo, 0, pOldInfo, 0)
!= IDYES)
{
// user canceled a shared printer port change, bail.
return(PSNRET_INVALID_NOCHANGEPAGE);
}
// get the PRINTER_INFO_2 again, since the attributes/status may
// have been changed by the called CopyHook.
LocalFree((HLOCAL)pPrinter);
pPrinter = Printer_GetPrinterInfo(pppi->psPrinterStuff->hPrinter, 2);
if (!pPrinter)
goto handle_error;
}
// flag port changes so we can update links to printers!
// keep track of relevant info.
fPortChange = TRUE;
dwOldAttributes = pPrinter->Attributes;
lstrcpy(szOldPortName, pPrinter->pPortName);
// set the pPortName AFTER we get the new PRINTER_INFO_2. duh.
pPrinter->pPortName = pCopy->pPortName;
fSave = TRUE;
fTestPage = TRUE;
}
if (pPrinter->pComment == NULL)
{
if (pCopy->pComment[0])
goto save_comment;
}
else if (lstrcmp(pPrinter->pComment, pCopy->pComment))
{
save_comment:
pPrinter->pComment = pCopy->pComment;
fSave = TRUE;
}
if (lstrcmp(pPrinter->pDriverName, pCopy->pDriverName)
&& pCopy->pDriverName[0])
{
pPrinter->pDriverName = pCopy->pDriverName;
fSave = TRUE;
fTestPage = TRUE;
}
{
TCHAR buf[128];
buf[0]= TEXT('\0');
LoadString(HINST_THISDLL, IDS_PRNSEP_NONE, buf, ARRAYSIZE(buf));
if (pPrinter->pSepFile == NULL || *pPrinter->pSepFile == TEXT('\0'))
{
if (pCopy->pSepFile[0] && lstrcmp(pCopy->pSepFile, buf))
goto save_sepfile;
}
else if (lstrcmp(pPrinter->pSepFile, pCopy->pSepFile))
{
save_sepfile:
if (!lstrcmp(pCopy->pSepFile, buf))
{
pPrinter->pSepFile = (LPTSTR)c_szNULL;
}
else
{
pPrinter->pSepFile = pCopy->pSepFile;
fTestPage = TRUE;
}
fSave = TRUE;
}
}
if (pPrinter->pDatatype == NULL)
{
if (pCopy->pDatatype[0])
goto save_datatype;
}
else if (lstrcmp(pPrinter->pDatatype, pCopy->pDatatype))
{
save_datatype:
pPrinter->pDatatype = pCopy->pDatatype;
fSave = TRUE;
fTestPage = TRUE;
}
if ((pPrinter->Attributes & PS_ATTRIBUTE_MASK) !=
(pCopy->Attributes & PS_ATTRIBUTE_MASK))
{
pPrinter->Attributes = (pPrinter->Attributes & ~PS_ATTRIBUTE_MASK)
| (pCopy->Attributes & PS_ATTRIBUTE_MASK);
fSave = TRUE;
fTestPage = TRUE;
}
if (fSave && (fSaveMe == GDSE_SAVE))
{
DebugMsg(DM_TRACE,TEXT("sh TR - Saving printer property sheet info_2"));
fError = !g_pfnSetPrinter(pppi->psPrinterStuff->hPrinter, 2, (LPBYTE)pPrinter, 0);
} // if (fSave)
LocalFree((HLOCAL)pPrinter);
// don't save PRINTER_INFO_5 if PRINTER_INFO_2 failed
if (fError)
goto handle_error;
pPrinter5 = Printer_GetPrinterInfo(pppi->psPrinterStuff->hPrinter, 5);
if (pPrinter5)
{
if (fSaveMe == GDSE_SAVE)
{
// update our internal Attributes state, since it may have
// changed from the above SetPrinter(2) call.
pppi->psPrinterStuff->sPrinter.Attributes = pPrinter5->Attributes;
}
if (pPrinter5->DeviceNotSelectedTimeout != pCopy->DeviceNotSelectedTimeout
|| pPrinter5->TransmissionRetryTimeout != pCopy->TransmissionRetryTimeout)
{
pPrinter5->DeviceNotSelectedTimeout = pCopy->DeviceNotSelectedTimeout;
pPrinter5->TransmissionRetryTimeout = pCopy->TransmissionRetryTimeout;
fSave = TRUE;
fTestPage = TRUE;
if (fSaveMe == GDSE_SAVE)
{
DebugMsg(DM_TRACE,TEXT("sh TR - Saving printer property sheet info_5"));
fError = !g_pfnSetPrinter(pppi->psPrinterStuff->hPrinter, 5, (LPBYTE)pPrinter5, 0);
}
} // if PRINTER_INFO_5 change
LocalFree((HLOCAL)pPrinter5);
if (fError)
{
// we're in a mixed state, but there's not much we can do about
// it now...
goto handle_error;
}
}
else
{
// Assuming that if we got a PRINTER_INFO_2, then we'd be able
// to get a PRINTER_INFO_5 implies that we'd never get here.
DebugMsg(DM_TRACE,TEXT("sh TR - Couldn't get PRINTER_INFO_5, some info may not be saved (unlikely)"));
}
if (fPortChange && (fSaveMe == GDSE_SAVE))
{
// if the port change causes an icon change, update the correct icon images
if (((dwOldAttributes & PRINTER_ATTRIBUTE_NETWORK) !=
(pppi->psPrinterStuff->sPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK)) ||
(!lstrcmp(c_szFileColon, szOldPortName) ||
!lstrcmp(c_szFileColon, pCopy->pPortName)))
{
TCHAR szModule[MAX_PATH];
LPTSTR pszModule;
int iIcon1, iIcon2;
int iImage;
GetModuleFileName(HINST_THISDLL, szModule, ARRAYSIZE(szModule));
pszModule = PathFindFileName(szModule);
if (dwOldAttributes & PRINTER_ATTRIBUTE_NETWORK)
{
DebugMsg(DM_TRACE, TEXT("sh PRTPROP - sending icon change for network printer %s"), pppi->psPrinterStuff->sPrinter.pPrinterName);
iIcon1 = IDI_PRINTER_NET;
iIcon2 = IDI_DEF_PRINTER_NET;
}
else if (!lstrcmp(c_szFileColon, szOldPortName))
{
DebugMsg(DM_TRACE, TEXT("sh PRTPROP - sending icon change for file printer %s"), pppi->psPrinterStuff->sPrinter.pPrinterName);
iIcon1 = IDI_PRINTER_FILE;
iIcon2 = IDI_DEF_PRINTER_FILE;
}
else
{
DebugMsg(DM_TRACE, TEXT("sh PRTPROP - sending icon change for local printer %s"), pppi->psPrinterStuff->sPrinter.pPrinterName);
iIcon1 = IDI_PRINTER;
iIcon2 = IDI_DEF_PRINTER;
}
iImage = LookupIconIndex(pszModule, EIRESID(iIcon1), 0);
if (iImage != -1)
{
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)iImage, NULL);
}
iImage = LookupIconIndex(pszModule, EIRESID(iIcon2), 0);
if (iImage != -1)
{
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)iImage, NULL);
}
}
}
} // if (pPrinter)
else
{
DWORD dwLastError;
handle_error:
lRet = PSNRET_INVALID;
dwLastError = GetLastError();
switch (dwLastError)
{
case ERROR_UNKNOWN_PORT:
// The user tried to change to an invalid port
hTempComboBox = GetDlgItem(hDlg, IDDC_PRINTTO);
wPage = 1;
lpError = MAKEINTRESOURCE(IDS_PRTPROP_PORT_ERROR);
break;
case ERROR_INVALID_SEPARATOR_FILE:
// The user selected an invalid separator page
hTempComboBox = GetDlgItem(hDlg, IDDC_SEPARATOR);
wPage = 1;
lpError = MAKEINTRESOURCE(IDS_PRTPROP_SEP_ERROR);
break;
default:
{
TCHAR szTemplate[128];
TCHAR buf[MAXPATHLEN];
// Default message if FormatMessage doesn't recognize dwLastError
LoadString(HINST_THISDLL, IDS_PRTPROP_UNKNOWNERROR, szTemplate, ARRAYSIZE(szTemplate));
wsprintf(buf, szTemplate, dwLastError);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0L,
buf, ARRAYSIZE(buf), NULL);
ShellMessageBox(HINST_THISDLL, hDlg,
MAKEINTRESOURCE(IDS_PRTPROP_UNKNOWN_ERROR),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONEXCLAMATION, buf);
return(PSNRET_INVALID);
break;
}
} // switch (GetLastError())
SendMessage(GetParent(hDlg), PSM_SETCURSEL, wPage, 0L);
if (hTempEditBox)
{
SetDlgFocus(hDlg, hTempEditBox);
Edit_SetSel(hTempEditBox, 0, -1);
}
if (hTempComboBox)
{
SetDlgFocus(hDlg, hTempComboBox);
ComboBox_SetEditSel(hTempComboBox, 0, -1);
}
ShellMessageBox(HINST_THISDLL, hDlg, lpError,
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONEXCLAMATION);
return(PSNRET_INVALID_NOCHANGEPAGE);
}
switch (fSaveMe)
{
case GDSE_SAVE: return(lRet);
case GDSE_QUERY_TESTPAGE: return(fTestPage);
// not currently used, but it may be useful some day
// case GDSE_QUERY_SAVE: return(fSave);
default: Assert(FALSE);
}
}
//--------------------------------------------------------------------------
// Dialog procedure of "General" page
//
#pragma data_seg(DATASEG_READONLY)
static DWORD aGeneralHelpIds[] = {
IDD_LINE_1, NO_HELP,
IDD_LINE_2, NO_HELP,
IDD_LINE_3, NO_HELP,
IDC_PRINTER_ICON, IDH_PRTPROPS_ICON,
IDC_PRINTER_NAME, IDH_PRTPROPS_NAME_STATIC,
IDGS_TYPE_TXT, IDH_PRTPROPS_TYPE_LOCATION,
IDGS_TYPE, IDH_PRTPROPS_TYPE_LOCATION,
IDGS_LOCATION_TXT, IDH_PRTPROPS_TYPE_LOCATION,
IDGS_LOCATION, IDH_PRTPROPS_TYPE_LOCATION,
IDGE_COMMENT_TXT, IDH_PRTPROPS_COMMENT,
IDGE_COMMENT, IDH_PRTPROPS_COMMENT,
IDDB_TESTPAGE, IDH_PRTPROPS_TEST_PAGE,
IDDC_SEPARATOR_TXT, IDH_PRTPROPS_SEPARATOR,
IDDC_SEPARATOR, IDH_PRTPROPS_SEPARATOR,
IDDB_CHANGESEPARATOR, IDH_PRTPROPS_SEPARATOR_BROWSE,
0, 0
};
#pragma data_seg()
BOOL CALLBACK Printer_GeneralDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
LPPRINTERPAGEINFO pppi = (LPPRINTERPAGEINFO)GetWindowLong(hdlg, DWL_USER);
switch (uMessage)
{
case WM_INITDIALOG:
{
HICON hIcon;
pppi = (LPPRINTERPAGEINFO)lParam;
SetWindowLong(hdlg, DWL_USER, lParam);
SendDlgItemMessage(hdlg, IDDC_SEPARATOR, CB_LIMITTEXT,
SIZEOF(pppi->psPrinterStuff->sPrinter.pSepFile)-1, 0L);
if (pppi->psPrinterStuff->sPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK)
{
EnableWindow(GetDlgItem(hdlg, IDDC_SEPARATOR_TXT), FALSE);
EnableWindow(GetDlgItem(hdlg, IDDC_SEPARATOR), FALSE);
EnableWindow(GetDlgItem(hdlg, IDDB_CHANGESEPARATOR), FALSE);
}
if (pppi->psPrinterStuff->hIcon)
if (NULL != (hIcon = (HICON)SendDlgItemMessage(hdlg, IDC_PRINTER_ICON, STM_SETICON, (WPARAM)pppi->psPrinterStuff->hIcon, 0L)))
DestroyIcon(hIcon);
break;
}
case WM_CLOSE:
// MLE controls generate a WM_CLOSE message when the user hits
// the escape key, so post one up to our parent to let him
// process it...
PostMessage(GetParent(hdlg), WM_CLOSE, wParam, lParam);
break;
case WM_DESTROY:
if (pppi->psPrinterStuff->hIcon)
SendDlgItemMessage(hdlg, IDC_PRINTER_ICON, STM_SETICON, 0, 0L);
break;
case WM_HELP:
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP,
(DWORD) (LPTSTR) aGeneralHelpIds);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD) (LPTSTR) aGeneralHelpIds);
break;
case WM_COMMAND:
{
BOOL fApply = FALSE; // turn on Apply button?
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDDB_TESTPAGE:
if (GeneralDlg_SaveEverything(hdlg, pppi, GDSE_QUERY_TESTPAGE))
{
// State may have changed, so TestPage may not work
if (IDYES != ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_PRTPROP_TESTPAGE_WARN),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_YESNO|MB_ICONEXCLAMATION))
{
break;
}
}
Printers_DoCommand(hdlg, PRINTACTION_TESTPAGE,
pppi->psPrinterStuff->sPrinter.pPrinterName, NULL);
break;
case IDDB_CHANGESEPARATOR:
{
TCHAR buf[MAX_PATH];
buf[0] = TEXT('\0');
if (_GetFileNameFromBrowse(hdlg, buf, ARRAYSIZE(buf), NULL,
MAKEINTRESOURCE(IDS_CLP),
MAKEINTRESOURCE(IDS_SEPARATORFILTER),
MAKEINTRESOURCE(IDS_BROWSE),
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST))
{
HWND hcbSeparator = GetDlgItem(hdlg, IDDC_SEPARATOR);
ComboBox_SetCurSel(hcbSeparator,
ComboBox_AddString(hcbSeparator, buf));
fApply = TRUE;
}
break;
}
case IDGE_COMMENT:
fApply = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
break;
case IDDC_SEPARATOR:
fApply = GET_WM_COMMAND_CMD(wParam, lParam) == CBN_EDITCHANGE ||
GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE;
break;
}
if (fApply && !pppi->psPrinterStuff->fInitializing)
{
PostMessage(GetParent(hdlg), PSM_CHANGED, (WPARAM)hdlg, 0);
}
break;
}
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code)
{
case PSN_KILLACTIVE:
// validate entries when leaving this page
SetWindowLong(hdlg, DWL_MSGRESULT, GeneralDlg_GetFields(hdlg, pppi));
break;
case PSN_APPLY:
// save everything on OK or Apply Now
PrtProp_Apply(hdlg, pppi);
break;
case PSN_SETACTIVE:
pppi->psPrinterStuff->fSaveEverything = TRUE;
GeneralDlg_SetFields(hdlg, pppi);
// We need this because _SetFields trashes DWL_MSGRESULT...
SetWindowLong(hdlg, DWL_MSGRESULT, 0);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
//==========================================================================
// Spool Settings dialog
//==========================================================================
#define IDDC_DATATYPE cmb1
#define IDGRB_SPOOL rad1
#define IDGRB_DIRECT rad2
#define IDGRB_DESPOOL_LATER rad3
#define IDGRB_DESPOOL_NOW rad4
BOOL Printers_EnumPrintProcessorDatatypesCB(LPVOID lpData, HANDLE hPrinter,
DWORD dwLevel, LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
{
return(g_pfnEnumPrintProcessorDataTypes(NULL, lpData, dwLevel, pEnum,
dwSize, lpdwNeeded, lpdwNum));
}
// GDI hardcodes these strings
TCHAR const c_szEMF[] = TEXT("EMF");
TCHAR const c_szRAW[] = TEXT("RAW");
void DetailDlg_FillDatatypes(HWND hDlg, LPPRINTERSTUFF psPrinterStuff)
{
HWND hcbDatatypes;
DWORD dwNum;
DATATYPES_INFO_1 * pDataTypes;
int iSel;
int numDatatypes;
hcbDatatypes = GetDlgItem(hDlg, IDDC_DATATYPE);
ComboBox_ResetContent(hcbDatatypes);
// Get datatypes supported by print processor; set the ItemData to FALSE
pDataTypes = Printer_EnumProps(NULL, 1, &dwNum,
Printers_EnumPrintProcessorDatatypesCB,
(LPVOID)psPrinterStuff->sPrinter.pPrintProcessor);
if (pDataTypes)
{
for ( ; dwNum>0; )
{
--dwNum;
ComboBox_SetItemData(hcbDatatypes,
ComboBox_AddString(hcbDatatypes, pDataTypes[dwNum].pName),
FALSE);
DebugMsg(DM_TRACE, TEXT("sh FILLDATATYPE - adding %s"), pDataTypes[dwNum].pName);
}
LocalFree((HLOCAL)pDataTypes);
}
// make sure driver supports EMF. If not, make sure not in datatype list.
iSel = ComboBox_FindString(hcbDatatypes, 0, c_szEMF);
if (iSel != -1)
{
// BUGBUG: old MicroGrafx drivers have a bug in which they always
// dereference pDevMode. Is it too much effort to get a devmode?
// Or should we just blow off this old driver?
BOOL fEMF = g_pfnDeviceCapabilities(psPrinterStuff->sPrinter.pPrinterName,
psPrinterStuff->sPrinter.pPortName, DC_EMF_COMPLIANT, NULL, NULL) > 0;
if (!fEMF)
{
// remove EMF if driver doesn't support it
ComboBox_DeleteString(hcbDatatypes, iSel);
DebugMsg(DM_TRACE, TEXT("sh FILLDATATYPE - deleted EMF"));
}
else
{
// mark EMF as supported so it doesn't get removed later
ComboBox_SetItemData(hcbDatatypes, iSel, TRUE);
DebugMsg(DM_TRACE, TEXT("sh FILLDATATYPE - support EMF"));
}
}
numDatatypes = g_pfnDeviceCapabilities(psPrinterStuff->sPrinter.pPrinterName,
psPrinterStuff->sPrinter.pPortName, DC_DATATYPE_PRODUCED, NULL, NULL);
if (numDatatypes > 0)
{
LPTSTR pDatatypesGenerated = (void*)LocalAlloc(LPTR, numDatatypes * DATATYPE_NAMELEN);
if (pDatatypesGenerated)
{
if (-1 != g_pfnDeviceCapabilities(psPrinterStuff->sPrinter.pPrinterName,
psPrinterStuff->sPrinter.pPortName, DC_DATATYPE_PRODUCED,
pDatatypesGenerated, NULL))
{
LPTSTR pDatatype = pDatatypesGenerated;
while (numDatatypes--)
{
iSel = ComboBox_FindString(hcbDatatypes, 0, pDatatype);
if (iSel != -1)
{
// mark pDatatype as supported
ComboBox_SetItemData(hcbDatatypes, iSel, TRUE);
DebugMsg(DM_TRACE, TEXT("sh FILLDATATYPE - support %s"), pDatatype);
}
pDatatype += DATATYPE_NAMELEN;
}
// remove all unsupported datatypes
for (numDatatypes = ComboBox_GetCount(hcbDatatypes) ;
numDatatypes > 0 ;
numDatatypes -- )
{
if (!ComboBox_GetItemData(hcbDatatypes, numDatatypes))
{
ComboBox_DeleteString(hcbDatatypes, numDatatypes);
DebugMsg(DM_TRACE, TEXT("sh FILLDATATYPE - deleted %s"), pDatatype);
}
}
}
LocalFree((HLOCAL)pDatatypesGenerated);
}
}
// if pDatatype isn't in the combobox, put it in. it's an undefined state,
// but that's better than having no datatype selected.
Printer_SelDlgComboEntry(hcbDatatypes, 0, psPrinterStuff->sPrinter.pDatatype, TRUE);
}
//--------------------------------------------------------------------------
// Dialog procedure of "Add Port" dialog
//
#pragma data_seg(DATASEG_READONLY)
const static DWORD aAddPortHelpIDs[] = { // Context Help IDs
IDD_ADDPORT_NETWORK, IDH_ADDPORT_NETWORK,
IDD_ADDPORT_PORTMON, IDH_ADDPORT_PORTMON,
IDD_ADDPORT_NETPATH, IDH_ADDPORT_NETPATH,
IDD_ADDPORT_BROWSE, IDH_ADDPORT_BROWSE,
IDD_ADDPORT_LB, IDH_ADDPORT_LB,
0, 0
};
#pragma data_seg()
BOOL CALLBACK Printer_AddPortDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
HWND hwndLB;
switch (uMessage)
{
case WM_INITDIALOG:
{
LPMONITOR_INFO_1 pMonitors;
DWORD dwNum;
// store dest HWND away
SetWindowLong(hdlg, DWL_USER, lParam);
// select network radio button
CheckRadioButton(hdlg, IDD_ADDPORT_NETWORK, IDD_ADDPORT_PORTMON,
IDD_ADDPORT_NETWORK);
// fill portmon listbox with port monitors
hwndLB = GetDlgItem(hdlg, IDD_ADDPORT_LB);
pMonitors = Printer_EnumProps(NULL, 1, &dwNum, Printers_EnumMonitorsCB, NULL);
if (pMonitors)
{
int i;
for (i = 0 ; i < (int)dwNum ; i++)
{
ListBox_AddString(hwndLB, pMonitors[i].pName);
}
ListBox_SetCurSel(hwndLB, 0);
LocalFree((HLOCAL)pMonitors);
}
break;
}
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
HELP_WM_HELP, (DWORD)(LPTSTR) aAddPortHelpIDs);
break;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD)(LPVOID)aAddPortHelpIDs);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDD_ADDPORT_NETWORK:
CheckRadioButton(hdlg, IDD_ADDPORT_NETWORK, IDD_ADDPORT_PORTMON,
IDD_ADDPORT_NETWORK);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_NETPATH), TRUE);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_BROWSE), TRUE);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_LB), FALSE);
break;
case IDD_ADDPORT_PORTMON:
CheckRadioButton(hdlg, IDD_ADDPORT_NETWORK, IDD_ADDPORT_PORTMON,
IDD_ADDPORT_PORTMON);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_NETPATH), FALSE);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_BROWSE), FALSE);
EnableWindow(GetDlgItem(hdlg, IDD_ADDPORT_LB), TRUE);
break;
case IDD_ADDPORT_BROWSE:
{
LPITEMIDLIST pidlNetPrinter;
BROWSEINFO bi;
TCHAR szBuf[MAX_PATH];
LoadString(HINST_THISDLL,IDS_BROWSE,szBuf,ARRAYSIZE(szBuf));
ZeroMemory(&bi,SIZEOF(BROWSEINFO));
bi.hwndOwner=hdlg;
bi.pidlRoot=(LPITEMIDLIST)MAKEINTRESOURCE(CSIDL_NETWORK);
bi.lpszTitle=szBuf;
bi.ulFlags=BIF_BROWSEFORPRINTER;
pidlNetPrinter = SHBrowseForFolder(&bi);
if (pidlNetPrinter)
{
if (SHGetPathFromIDList(pidlNetPrinter,szBuf))
{
Edit_SetText(GetDlgItem(hdlg, IDD_ADDPORT_NETPATH), szBuf);
}
ILFree(pidlNetPrinter);
}
break;
}
case IDOK:
{
TCHAR szBuf[MAX_PATH];
HWND hwndCB;
int i;
if (IsDlgButtonChecked(hdlg, IDD_ADDPORT_NETWORK))
{
HANDLE hPrinter;
Edit_GetText(GetDlgItem(hdlg, IDD_ADDPORT_NETPATH),
szBuf, ARRAYSIZE(szBuf));
DebugMsg(DM_TRACE, TEXT("sh ADDPORT -- adding UNC port '%s'"), szBuf);
// validate port
hPrinter = Printer_OpenPrinter(szBuf);
if (hPrinter)
{
Printer_ClosePrinter(hPrinter);
}
else
{
ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_PRTPROP_PORT_ERROR),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONSTOP);
// stay in dialog -- break out of IDOK processing
break;
}
// Add port to port list combobox
hwndCB = (HWND)GetWindowLong(hdlg, DWL_USER);
AddPortToCombobox(hwndCB, szBuf, NULL);
ComboBox_SetCurSel(hwndCB,
ComboBox_FindString(hwndCB, 0, szBuf));
}
else
{
hwndLB = GetDlgItem(hdlg, IDD_ADDPORT_LB);
i = ListBox_GetCurSel(hwndLB);
if (i >= 0)
{
LPPORT_INFO_2 pPorts;
DWORD dwNumPorts;
BOOL fAddPort;
ListBox_GetText(hwndLB, i, szBuf);
DebugMsg(DM_TRACE, TEXT("sh ADDPORT - Adding a '%s' port"), szBuf);
// We want to add a port AND select the newly added port
// into the listbox, but there's no easy way to get this
// info... So we need to re-enumerate the ports and
// grab the new one...
pPorts = Printer_EnumProps(NULL, 2, &dwNumPorts, Printers_EnumPortsCB, NULL);
fAddPort = g_pfnAddPort(NULL, hdlg, szBuf);
if (fAddPort && pPorts)
{
LPPORT_INFO_2 pNewPorts;
DWORD dwNumNewPorts;
pNewPorts = Printer_EnumProps(NULL, 2, &dwNumNewPorts, Printers_EnumPortsCB, NULL);
if (pNewPorts)
{
DWORD i;
// I'm assuming no other thread called DeletePort
// during this operation. I'm worrying about the
// case where dwNumPorts == dwNumNewPorts just in
// case there's some way for AddPort to return
// success without actually adding a port.
Assert(dwNumNewPorts >= dwNumPorts);
// I'm also assuming that the ports (exluding the
// newly added one) will be enumerated in
// the same order
for (i = 0 ; i < dwNumPorts ; i++)
{
if (lstrcmp(pPorts[i].pPortName, pNewPorts[i].pPortName))
{
// we found the new port, select it
goto AddPort;
}
}
if (i == dwNumNewPorts - 1)
{
// the new port was added to the end of the list
AddPort:
hwndCB = (HWND)GetWindowLong(hdlg, DWL_USER);
AddPortToCombobox(
hwndCB,
pNewPorts[i].pPortName,
pNewPorts[i].pDescription);
ComboBox_SetCurSel(hwndCB,
ComboBox_FindString(hwndCB, 0,
pNewPorts[i].pPortName));
}
LocalFree((HLOCAL)pNewPorts);
} // if (pNewPorts)
} // if (g_pfnAddPort() && pPorts)
if (pPorts)
LocalFree((HLOCAL)pPorts);
if (!fAddPort)
{
// user cancelled AddPort, so stay in this dlg.
break;
}
}
else
{
DebugMsg(DM_TRACE, TEXT("sh ADDPORT - No portmon is selected!"));
Assert(0);
}
}
EndDialog (hdlg, TRUE);
return TRUE;
}
case IDCANCEL:
EndDialog (hdlg, FALSE);
return FALSE;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
//--------------------------------------------------------------------------
// Dialog procedure of "Del Port" dialog
//
#pragma data_seg(DATASEG_READONLY)
const static DWORD aDelPortHelpIDs[] = { // Context Help IDs
IDD_DELPORT_LB, IDH_DELPORT_LB,
IDD_DELPORT_TEXT_1, IDH_DELPORT_LB,
0, 0
};
#pragma data_seg()
BOOL CALLBACK Printer_DelPortDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
LPDELPORTDLG pdpd = (LPDELPORTDLG)GetWindowLong(hdlg, DWL_USER);
switch (uMessage)
{
case WM_INITDIALOG:
{
HWND hwndLB;
int i;
// store dest HWND away
pdpd = (LPDELPORTDLG)lParam;
SetWindowLong(hdlg, DWL_USER, lParam);
// move all entries in hwndCB into this listbox
hwndLB = GetDlgItem(hdlg, IDD_DELPORT_LB);
for (i = ComboBox_GetCount(pdpd->hwndCB)-1 ; i >= 0 ; i--)
{
TCHAR szBuf[MAX_PATH];
ComboBox_GetLBText(pdpd->hwndCB, i, szBuf);
ListBox_AddString(hwndLB, szBuf);
}
ListBox_SetCurSel(hwndLB, 0);
break;
}
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
HELP_WM_HELP, (DWORD)(LPTSTR) aDelPortHelpIDs);
break;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD)(LPVOID)aDelPortHelpIDs);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDOK:
{
HWND hwndLB;
TCHAR szBuf[MAX_PATH];
int iSel;
// get port to remove
hwndLB = GetDlgItem(hdlg, IDD_DELPORT_LB);
iSel = ListBox_GetCurSel(hwndLB);
if (LB_ERR != iSel &&
LB_ERR != ListBox_GetText(hwndLB, iSel, szBuf))
{
LPTSTR pPortName;
// find port NAME from combobox
iSel = ComboBox_FindStringExact(pdpd->hwndCB, 0, szBuf);
Assert(iSel != CB_ERR);
pPortName = (LPTSTR)ComboBox_GetItemData(pdpd->hwndCB, iSel);
// if this port is currently selected, don't delete it
if (iSel == ComboBox_GetCurSel(pdpd->hwndCB))
{
goto PortIsBusy;
}
if (pPortName)
{
// remove port from subsystem
if (!g_pfnDeletePort(NULL, hdlg, pPortName))
{
switch (GetLastError())
{
case ERROR_BUSY:
PortIsBusy:
ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_PRTPROP_ADDPORT_CANTDEL_BUSY),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONINFORMATION);
break;
default:
ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_PRTPROP_ADDPORT_CANTDEL_LOCAL),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_OK|MB_ICONINFORMATION);
break;
}
// stay in dlg
break;
}
}
else
{
// remove port from MRU
DelMRUString(pdpd->pppi->psPrinterStuff->hmru,
FindMRUString(pdpd->pppi->psPrinterStuff->hmru,
szBuf, NULL));
}
// remove port from combobox
ComboBox_DeleteString(pdpd->hwndCB, iSel);
Str_SetPtr(&pPortName, NULL);
// REVIEW: Do we need to select another port if
// this one becomes empty?
}
else
{
Assert(FALSE);
}
EndDialog (hdlg, TRUE);
return TRUE;
}
case IDCANCEL:
EndDialog (hdlg, FALSE);
return FALSE;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
//--------------------------------------------------------------------------
// Dialog procedure of "Spool Settings" dialog
//
#pragma data_seg(DATASEG_READONLY)
const static DWORD aSpoolSettingsHelpIDs[] = { // Context Help IDs
rad1, IDH_SPOOLSETTINGS_SPOOL,
rad2, IDH_SPOOLSETTINGS_NOSPOOL,
rad3, IDH_SPOOLSETTINGS_PRINT_FASTER,
rad4, IDH_SPOOLSETTINGS_LESS_SPACE,
cmb1, IDH_SPOOLSETTINGS_DATA_FORMAT,
IDD_SPOOL_TXT, IDH_SPOOLSETTINGS_DATA_FORMAT,
IDD_RESTORE, IDH_SPOOLSETTINGS_RESTORE,
IDD_ENABLE_BIDI, IDH_SPOOLSETTINGS_ENABLE_BIDI,
IDD_DISABLE_BIDI, IDH_SPOOLSETTINGS_DISABLE_BIDI,
0, 0
};
#pragma data_seg()
BOOL CALLBACK Printer_SpoolSettingsDlgProc(HWND hdlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
LPPRINTERPAGEINFO pppi = (LPPRINTERPAGEINFO)GetWindowLong(hdlg, DWL_USER);
switch (uMessage) {
case WM_INITDIALOG: {
pppi = (LPPRINTERPAGEINFO)lParam;
SetWindowLong(hdlg, DWL_USER, lParam);
DetailDlg_FillDatatypes(hdlg, pppi->psPrinterStuff);
if (pppi->psPrinterStuff->sPrinter.Attributes &
PRINTER_ATTRIBUTE_QUEUED)
{
CheckRadioButton(hdlg, IDGRB_DESPOOL_LATER,
IDGRB_DESPOOL_NOW, IDGRB_DESPOOL_LATER);
}
else
{
CheckRadioButton(hdlg, IDGRB_DESPOOL_LATER,
IDGRB_DESPOOL_NOW, IDGRB_DESPOOL_NOW);
}
if (pppi->psPrinterStuff->sPrinter.Attributes & PRINTER_ATTRIBUTE_DIRECT)
{
CheckRadioButton(hdlg, IDGRB_SPOOL, IDGRB_DIRECT, IDGRB_DIRECT);
EnableWindow(GetDlgItem(hdlg, IDDC_DATATYPE), FALSE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_LATER), FALSE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_NOW), FALSE);
}
else
{
CheckRadioButton(hdlg, IDGRB_SPOOL, IDGRB_DIRECT, IDGRB_SPOOL);
}
if (pppi->psPrinterStuff->sPrinter.Attributes & PRINTER_ATTRIBUTE_SHARED)
{
EnableWindow(GetDlgItem(hdlg, IDGRB_DIRECT), FALSE);
}
if (pppi->psPrinterStuff->sPrinter.Attributes &
PRINTER_ATTRIBUTE_NETWORK)
{
DisableBIDI:
EnableWindow(GetDlgItem(hdlg, IDD_ENABLE_BIDI), FALSE);
EnableWindow(GetDlgItem(hdlg, IDD_DISABLE_BIDI), FALSE);
}
else
{
LPDRIVER_INFO_3 pDriver;
BOOL fNoBIDI;
pDriver = Printer_GetPrinterDriver(pppi->psPrinterStuff->hPrinter, 3);
fNoBIDI = !pDriver || pDriver->pMonitorName == NULL || *(pDriver->pMonitorName) == TEXT('\0');
if (pDriver)
LocalFree(pDriver);
if (fNoBIDI)
goto DisableBIDI;
if (pppi->psPrinterStuff->sPrinter.Attributes &
PRINTER_ATTRIBUTE_ENABLE_BIDI)
{
CheckRadioButton(hdlg, IDD_ENABLE_BIDI,
IDD_DISABLE_BIDI, IDD_ENABLE_BIDI);
}
else
{
CheckRadioButton(hdlg, IDD_ENABLE_BIDI,
IDD_DISABLE_BIDI, IDD_DISABLE_BIDI);
}
}
break;
}
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
HELP_WM_HELP, (DWORD)(LPTSTR) aSpoolSettingsHelpIDs);
break;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
(DWORD)(LPVOID)aSpoolSettingsHelpIDs);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDGRB_SPOOL:
EnableWindow(GetDlgItem(hdlg, IDDC_DATATYPE), TRUE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_LATER), TRUE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_NOW), TRUE);
break;
case IDGRB_DIRECT:
{
HWND hTemp = GetDlgItem(hdlg, IDDC_DATATYPE);
// DIRECT only supports RAW printing
Printer_SelDlgComboEntry(hTemp, 0, c_szRAW, FALSE);
EnableWindow(hTemp, FALSE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_LATER), FALSE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_NOW), FALSE);
break;
}
#if 0 // just in case we decide we want this code sometime...
case IDDC_DATATYPE:
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
{
TCHAR szDataType[DATATYPE_NAMELEN];
LPDRIVER_INFO_3 pDriver;
// if the user selects a datatype other than RAW or
// their DEFAULT datatype, double check the change.
Dlg_CB_GetSelText(hdlg, IDDC_DATATYPE, szDataType, ARRAYSIZE(szDataType));
pDriver = Printer_GetPrinterDriver(pppi->psPrinterStuff->hPrinter, 3);
if (!lstrcmp(szDataType, c_szRAW) &&
(pDriver && !lstrcmp(szDataType, pDriver->pDefaultDataType)))
{
if (IDYES != ShellMessageBox(HINST_THISDLL, hdlg,
MAKEINTRESOURCE(IDS_PRTPROP_DRIVER_WARN),
MAKEINTRESOURCE(IDS_PRINTERS),
MB_YESNO|MB_ICONEXCLAMATION))
{
if (IsDlgButtonChecked(hdlg, IDGRB_SPOOL))
{
Printer_SelDlgComboEntry(hdlg, IDDC_DATATYPE,
pppi->psPrinterStuff->sPrinter.pDatatype, TRUE);
}
else
{
// if you're printing direct, we must force raw
Printer_SelDlgComboEntry(hdlg, IDDC_DATATYPE,
c_szRAW, TRUE);
}
}
}
if (pDriver)
LocalFree((HLOCAL)pDriver);
}
#endif
case IDD_RESTORE:
{
HWND hTemp = GetDlgItem(hdlg, IDDC_DATATYPE);
LPDRIVER_INFO_3 pDriver;
CheckRadioButton(hdlg, IDGRB_SPOOL, IDGRB_DIRECT, IDGRB_SPOOL);
EnableWindow(hTemp, TRUE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_LATER), TRUE);
EnableWindow(GetDlgItem(hdlg, IDGRB_DESPOOL_NOW), TRUE);
CheckRadioButton(hdlg, IDGRB_DESPOOL_LATER, IDGRB_DESPOOL_NOW, IDGRB_DESPOOL_NOW);
pDriver = Printer_GetPrinterDriver(pppi->psPrinterStuff->hPrinter, 3);
if (pDriver)
{
Printer_SelDlgComboEntry(hTemp, 0, pDriver->pDefaultDataType, TRUE);
LocalFree((HLOCAL)pDriver);
}
// BUGBUG: we have no default BIDI support
break;
}
case IDOK:
{
DWORD dwAttributes;
TCHAR szDatatype[128];
// store sPrinter info
dwAttributes = pppi->psPrinterStuff->sPrinter.Attributes;
lstrcpy(szDatatype, pppi->psPrinterStuff->sPrinter.pDatatype);
// update sPrinter
if (IsDlgButtonChecked(hdlg, IDGRB_DIRECT))
{
pppi->psPrinterStuff->sPrinter.Attributes |= PRINTER_ATTRIBUTE_DIRECT;
pppi->psPrinterStuff->sPrinter.Attributes &= ~PRINTER_ATTRIBUTE_QUEUED;
}
else
{
pppi->psPrinterStuff->sPrinter.Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
pppi->psPrinterStuff->sPrinter.Attributes &= ~PRINTER_ATTRIBUTE_QUEUED;
if (IsDlgButtonChecked(hdlg, IDGRB_DESPOOL_LATER))
pppi->psPrinterStuff->sPrinter.Attributes |= PRINTER_ATTRIBUTE_QUEUED;
}
Dlg_CB_GetSelText(hdlg, IDDC_DATATYPE,
pppi->psPrinterStuff->sPrinter.pDatatype,
ARRAYSIZE(pppi->psPrinterStuff->sPrinter.pDatatype));
if (IsDlgButtonChecked(hdlg, IDD_ENABLE_BIDI))
{
pppi->psPrinterStuff->sPrinter.Attributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
else
{
pppi->psPrinterStuff->sPrinter.Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
// return TRUE iff something changed
EndDialog (hdlg, dwAttributes != pppi->psPrinterStuff->sPrinter.Attributes ||
lstrcmp(szDatatype, pppi->psPrinterStuff->sPrinter.pDatatype));
return TRUE;
}
case IDCANCEL:
EndDialog (hdlg, FALSE);
return FALSE;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
return TRUE;
}
//--------------------------------------------------------------------------
// Add a "Setup" page for Win 3.1 driver
//
void _AddDlgPage(UINT idResource,
DLGPROC lpfnDlgProc,
PRINTERSTUFF *psPrinterStuff,
LPPROPSHEETHEADER lpsh)
{
PRINTERPAGEINFO ppi;
HPROPSHEETPAGE hpage;
ZeroMemory(&ppi, SIZEOF(PRINTERPAGEINFO));
// Fill common part
ppi.psp.dwSize = SIZEOF(ppi); // extra data
ppi.psp.dwFlags = PSP_DEFAULT;
ppi.psp.hInstance = HINST_THISDLL;
//ppi.psp.lParam = 0;
ppi.psp.pszTemplate = MAKEINTRESOURCE(idResource);
ppi.psp.pfnDlgProc = lpfnDlgProc;
// Fill extra parameter
ppi.psPrinterStuff = psPrinterStuff;
hpage = CreatePropertySheetPage(&ppi.psp);
if (hpage) {
_AddPropSheetPage(hpage, (LPARAM)lpsh);
}
}
extern IDataObjectVtbl c_CPrintersIDLDataVtbl;
UINT _AddPrinterPropPages(LPPRINTERSTUFF psPrinterStuff, HWND hWnd, LPPROPSHEETHEADER lpsh)
{
UINT cpageGeneric;
HKEY hkeyBaseProgID;
// First add our pages
if (!SHRestricted(REST_NOPRINTERTABS))
{
_AddDlgPage(DLG_PRN_GENERAL, Printer_GeneralDlgProc, psPrinterStuff, lpsh);
_AddDlgPage(DLG_PRN_DETAIL, Printer_DetailDlgProc, psPrinterStuff, lpsh);
}
// Then, add hooked pages if they exist in the registry
hkeyBaseProgID = NULL;
RegOpenKey(HKEY_CLASSES_ROOT, c_szPrinters, &hkeyBaseProgID);
if (hkeyBaseProgID)
{
// we need an IDataObject
LPCITEMIDLIST pidlParent = GetSpecialFolderIDList(NULL, CSIDL_PRINTERS, FALSE);
if (pidlParent)
{
HRESULT hres;
LPDATAOBJECT lpdtobj;
IDPRINTER idp;
LPITEMIDLIST pidp;
Printers_FillPidl(&idp, psPrinterStuff->sPrinter.pPrinterName);
pidp = (LPITEMIDLIST)&idp;
hres = CIDLData_CreateFromIDArray2(&c_CPrintersIDLDataVtbl, pidlParent, 1,
&pidp, &lpdtobj);
if (hres == NOERROR)
{
// add the hooked pages
HDCA hdca = DCA_Create();
if (hdca)
{
DCA_AddItemsFromKey(hdca, hkeyBaseProgID, c_szPropSheet);
DCA_AppendClassSheetInfo(hdca, hkeyBaseProgID, lpsh, lpdtobj);
DCA_Destroy(hdca);
}
lpdtobj->lpVtbl->Release(lpdtobj);
}
}
RegCloseKey(hkeyBaseProgID);
}
// Then, let the driver add pages
cpageGeneric = lpsh->nPages;
g_pfnEnumPrinterPropertySheets(psPrinterStuff->hPrinter, hWnd, _AddPropSheetPage, (LPARAM)lpsh);
// Check if the driver has append any pages.
if (cpageGeneric == lpsh->nPages)
psPrinterStuff->uFlags |= PS_OLDSTYLE;
else
psPrinterStuff->uFlags &= ~PS_OLDSTYLE; // to catch 3.1 -> 4.0 transition
return lpsh->nPages;
}
//
// This function opens the property sheet of specified printer
//
// Arguments:
// hWnd -- Specifies the parent window (optional)
// pszPrinter -- Specifies the printer (e.g., "HP LaserJet IIISi")
// lParam -- pszArgs -- may specify a sheet name to open to
//
void Printer_Properties(HWND hWnd, LPCTSTR lpszPrinterName, int nCmdShow, LPARAM lParam)
{
PRINTERSTUFF sPrinterStuff;
HPROPSHEETPAGE ahpage[MAX_FILE_PROP_PAGES]; // must use MAX_FILE_PROP_PAGES
PROPSHEETHEADER psh; // since we call _AppendClassSheetInfo
LPPRINTER_INFO_2 pPrinter;
LPPRINTER_INFO_5 pPrinter5;
BOOL fError = TRUE;
MRUINFO mi;
#ifdef COOLICON
// Send the window a message so it will have the correct title and icon
//
if (hWnd)
{
RUNDLL_NOTIFY sNotify;
sNotify.hIcon = LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_PRINTER), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
sNotify.lpszTitle = lpszPrinterName;
// HACK: It will look like the stub window is sending itself
// a WM_NOTIFY message. Oh well.
//
SendNotify(hWnd, hWnd, RDN_TASKINFO, (NMHDR FAR*)&sNotify);
}
#endif
ZeroMemory(&sPrinterStuff, SIZEOF(sPrinterStuff));
sPrinterStuff.hPrinter = Printer_OpenPrinter(lpszPrinterName);
if (!sPrinterStuff.hPrinter)
goto Error0;
pPrinter = Printer_GetPrinterInfo(sPrinterStuff.hPrinter, 2);
if (!pPrinter)
goto Error1;
// make a copy for us to party on
//
// be a bit paranoid and make sure we have all the strings. some of them
// can be null some of the time. we expect a few to never be null.
Assert(pPrinter->pPrinterName);
if (pPrinter->pPrinterName)
lstrcpyn(sPrinterStuff.sPrinter.pPrinterName, pPrinter->pPrinterName, MAXNAMELEN);
if (pPrinter->pComment)
lstrcpyn(sPrinterStuff.sPrinter.pComment, pPrinter->pComment, 256);
Assert(pPrinter->pPortName);
if (pPrinter->pPortName)
lstrcpyn(sPrinterStuff.sPrinter.pPortName, pPrinter->pPortName, MAX_PATH);
Assert(pPrinter->pDriverName);
if (pPrinter->pDriverName)
lstrcpyn(sPrinterStuff.sPrinter.pDriverName, pPrinter->pDriverName, MAXNAMELEN);
if (pPrinter->pSepFile)
lstrcpyn(sPrinterStuff.sPrinter.pSepFile, pPrinter->pSepFile, MAX_PATH);
if (pPrinter->pPrintProcessor)
lstrcpyn(sPrinterStuff.sPrinter.pPrintProcessor, pPrinter->pPrintProcessor, 128);
else
DebugMsg(DM_WARNING,TEXT("sh WN - pPrintProcessor is NULL."));
if (pPrinter->pDatatype)
lstrcpyn(sPrinterStuff.sPrinter.pDatatype, pPrinter->pDatatype, 128);
else
DebugMsg(DM_TRACE,TEXT("sh TR - bug 19753 is back: pDatatype is NULL."));
sPrinterStuff.sPrinter.Attributes = pPrinter->Attributes;
sPrinterStuff.sPrinter.StartTime = pPrinter->StartTime;
sPrinterStuff.sPrinter.UntilTime = pPrinter->UntilTime;
LocalFree((HLOCAL)pPrinter);
pPrinter5 = Printer_GetPrinterInfo(sPrinterStuff.hPrinter, 5);
if (!pPrinter5)
goto Error1;
sPrinterStuff.sPrinter.DeviceNotSelectedTimeout = pPrinter5->DeviceNotSelectedTimeout;
sPrinterStuff.sPrinter.TransmissionRetryTimeout = pPrinter5->TransmissionRetryTimeout;
LocalFree((HLOCAL)pPrinter5);
sPrinterStuff.fSaveEverything = FALSE;
mi.cbSize = SIZEOF(MRUINFO);
mi.uMax = 7;
mi.fFlags = MRU_CACHEWRITE;
mi.hKey = HKEY_CURRENT_USER;
mi.lpszSubKey = c_szPrnPortsMRU;
mi.lpfnCompare = NULL;
sPrinterStuff.hmru = CreateMRUList(&mi);
Printer_LoadIcons(lpszPrinterName, &(sPrinterStuff.hIcon), NULL);
//
// Initialize PROPSHEETHEADER
//
ZeroMemory(&psh, SIZEOF(psh));
psh.dwSize = SIZEOF(psh);
psh.dwFlags = PSH_PROPTITLE;
psh.hwndParent = hWnd;
psh.pszCaption = lpszPrinterName;
psh.phpage = ahpage;
if (lParam)
{
psh.dwFlags |= PSH_USEPSTARTPAGE;
psh.pStartPage = (LPCTSTR)lParam;
}
//
// Add property sheet pages
//
sPrinterStuff.nPages = _AddPrinterPropPages(&sPrinterStuff, hWnd, &psh);
if (sPrinterStuff.nPages)
{
// Successfuly done. Open the property sheet.
fError = PropertySheet(&psh) < 0;
}
if (sPrinterStuff.hIcon)
DestroyIcon(sPrinterStuff.hIcon);
if (sPrinterStuff.hmru)
FreeMRUList(sPrinterStuff.hmru);
Error1:
Printer_ClosePrinter(sPrinterStuff.hPrinter);
Error0:
if (fError)
{
ShellMessageBox(HINST_THISDLL, hWnd,
MAKEINTRESOURCE(IDS_PRTPROP_CANNOT_OPEN),
MAKEINTRESOURCE(IDS_PRINTERS), MB_OK|MB_ICONEXCLAMATION);
}
}
#ifdef DEBUG
//
// Type checking
//
static LPFNPRINTACTION lpfnPropAction=Printer_Properties;
#endif
#endif // ndef WINNT
// returns 0 if this is a legal name
// returns the IDS_ string id of the error string for an illegal name
int Printer_IllegalName(LPTSTR lpFriendlyName)
{
int fIllegal = 0;
if (*lpFriendlyName == TEXT('\0'))
{
fIllegal = IDS_PRTPROP_RENAME_NULL;
}
else if (lstrlen(lpFriendlyName) >= MAXNAMELEN)
{
fIllegal = IDS_PRTPROP_RENAME_TOO_LONG;
}
else
{
#ifdef DBCS
while (*lpFriendlyName)
{
if (IsDBCSLeadByte(*lpFriendlyName) && *(lpFriendlyName+1))
{
lpFriendlyName ++;
}
#ifdef WINNT
else if ( *lpFriendlyName == TEXT('!') ||
*lpFriendlyName == TEXT('\\') ||
*lpFriendlyName == TEXT(',') )
#else
else if ( *lpFriendlyName == TEXT('=') ||
*lpFriendlyName == TEXT('\\') ||
*lpFriendlyName == TEXT(';') ||
*lpFriendlyName == TEXT(',') )
#endif
break;
lpFriendlyName++;
}
#else
while (*lpFriendlyName &&
#ifdef WINNT
*lpFriendlyName != TEXT('!') &&
*lpFriendlyName != TEXT('\\') &&
*lpFriendlyName != TEXT(',') )
#else
*lpFriendlyName != TEXT('=') &&
*lpFriendlyName != TEXT('\\') &&
*lpFriendlyName != TEXT(';') &&
*lpFriendlyName != TEXT(',') )
#endif
{
lpFriendlyName++ ;
}
#endif
if (*lpFriendlyName)
{
fIllegal = IDS_PRTPROP_RENAME_BADCHARS;
}
}
return fIllegal;
}