Windows2000/private/shell/shell32/prqwnd.c
2020-09-30 17:12:32 +02:00

1624 lines
42 KiB
C

#include "shellprv.h"
#pragma hdrstop
#include "printer.h"
#ifndef WINNT
#define ICOL_DOCNAME 0
#define ICOL_STATUS 1
#define ICOL_OWNER 2
#define ICOL_PROGRESS 3
#define ICOL_TIME 4
#define ICOL_NUM 5
typedef struct _QueueInfo
{
JOB_INFO_2 *pJobs;
DWORD dwJobs;
IDPRINTER idp; // name of printer
HANDLE hPrinter; // handle to printer
HWND hDlg; // dialog handle
HWND hwndLV; // listview handle
HWND hwndSB; // status bar handle
BOOL fStatusBar; // TRUE iff status bar is shown
int cx, cy; // window extents for WM_SIZE
BOOL bDragSource;
BOOL bMinimized;
// POINT ptDragAnchor;
HICON hLargeIcon; // icons for the sysmenu / alt-tab list
HICON hSmallIcon; // these need to be freed on window destroy
} QUEUEINFO, *PQUEUEINFO;
typedef struct _PosInfo
{
WINDOWPLACEMENT wp;
int nWidths[ICOL_NUM];
BOOL fStatusBar;
} POSINFO;
typedef struct _InitInfo
{
LPCTSTR lpszPrinterName;
int nCmdShow;
} INITINFO;
extern TCHAR const c_szRAW[];
BOOL Printer_ModifyJob(HWND hDlg, DWORD dwCommand);
#endif // WINNT
// Helper functions
typedef struct _IDPRINTJOB
{
USHORT cb;
SHCNF_PRINTJOB_DATA data;
USHORT uTerm;
} IDPRINTJOB, *LPIDPRINTJOB;
typedef const IDPRINTJOB *LPCIDPRINTJOB;
void Printjob_FillPidl(LPIDPRINTJOB pidl, LPSHCNF_PRINTJOB_DATA pData)
{
pidl->cb = FIELD_OFFSET(IDPRINTJOB, uTerm);
if (pData)
{
pidl->data = *pData;
}
else
{
ZeroMemory(&(pidl->data), SIZEOF(SHCNF_PRINTJOB_DATA));
}
pidl->uTerm = 0;
}
LPITEMIDLIST Printjob_GetPidl(LPCTSTR szName, LPSHCNF_PRINTJOB_DATA pData)
{
LPITEMIDLIST pidl = NULL;
LPITEMIDLIST pidlParent = Printers_GetPidl(NULL, szName);
if (pidlParent)
{
IDPRINTJOB idj;
Printjob_FillPidl(&idj, pData);
pidl = ILCombine(pidlParent, (LPITEMIDLIST)&idj);
ILFree(pidlParent);
}
return pidl;
}
#ifndef WINNT
/* IDropTarget and IDataObject for drag & drop re-ordering of queue */
// print job descriptor
typedef struct
{
DWORD dwJobId;
int iItem;
} PRINTJOBDESC;
// data object for print job
typedef struct
{
IDataObject dtobj;
UINT cRef;
PRINTJOBDESC pj; // the data is here
} CPJData;
UINT g_cfPrintJob = 0;
extern const IDataObjectVtbl c_CPJDataVtbl; // forward
void RegisterPrintJobFormat()
{
if (!g_cfPrintJob)
g_cfPrintJob = RegisterClipboardFormat(TEXT("PrintJob"));
}
// print job data object for drag/drop
STDMETHODIMP CPJData_CreateInstance(const PRINTJOBDESC *ppj, IDataObject **ppdtobj)
{
CPJData *this = (void*)LocalAlloc(LPTR, SIZEOF(CPJData));
if (this)
{
this->dtobj.lpVtbl = &c_CPJDataVtbl;
this->cRef = 1;
*ppdtobj = &this->dtobj;
this->pj = *ppj;
RegisterPrintJobFormat();
return NOERROR;
}
else
{
*ppdtobj = NULL;
return E_OUTOFMEMORY;
}
}
STDMETHODIMP CPJData_QueryInterface(IDataObject *pdtobj, REFIID riid, LPVOID *ppvObj)
{
CPJData *this = IToClass(CPJData, dtobj, pdtobj);
if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown))
{
*ppvObj = this;
this->cRef++;
return NOERROR;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CPJData_AddRef(IDataObject *pdtobj)
{
CPJData *this = IToClass(CPJData, dtobj, pdtobj);
this->cRef++;
return this->cRef;
}
STDMETHODIMP_(ULONG) CPJData_Release(IDataObject *pdtobj)
{
CPJData *this = IToClass(CPJData, dtobj, pdtobj);
if (InterlockedDecrement(&this->cRef))
return this->cRef;
LocalFree((HLOCAL)this);
return 0;
}
STDMETHODIMP CPJData_GetData(IDataObject *pdtobj, LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
{
CPJData *this = IToClass(CPJData, dtobj, pdtobj);
HRESULT hres = E_INVALIDARG;
pmedium->hGlobal = NULL;
pmedium->pUnkForRelease = NULL;
pmedium->tymed = TYMED_HGLOBAL;
if ((g_cfPrintJob == pformatetcIn->cfFormat) && (TYMED_HGLOBAL & pformatetcIn->tymed))
{
pmedium->hGlobal = GlobalAlloc(GPTR, SIZEOF(PRINTJOBDESC));
if (pmedium->hGlobal)
{
*((PRINTJOBDESC *)pmedium->hGlobal) = this->pj;
hres = NOERROR; // success
}
else
hres = E_OUTOFMEMORY;
}
return hres;
}
STDMETHODIMP CPJData_GetDataHere(IDataObject *pdtobj, LPFORMATETC pformatetc, LPSTGMEDIUM pmedium )
{
return E_NOTIMPL;
}
STDMETHODIMP CPJData_QueryGetData(IDataObject *pdtobj, LPFORMATETC pformatetcIn)
{
// CPJData *this = IToClass(CPJData, dtobj, pdtobj);
if ((g_cfPrintJob == pformatetcIn->cfFormat) && (TYMED_HGLOBAL & pformatetcIn->tymed))
{
return NOERROR;
}
return S_FALSE;
}
STDMETHODIMP CPJData_GetCanonicalFormatEtc(IDataObject *pdtobj, LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
{
return DATA_S_SAMEFORMATETC;
}
STDMETHODIMP CPJData_SetData(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
return E_INVALIDARG;
}
STDMETHODIMP CPJData_EnumFormatEtc(IDataObject *pdtobj, DWORD dwDirection, LPENUMFORMATETC *ppenumFormatEtc)
{
return S_FALSE;
}
STDMETHODIMP CPJData_Advise(IDataObject *pdtobj, FORMATETC *pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP CPJData_Unadvise(IDataObject *pdtobj, DWORD dwConnection)
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHODIMP CPJData_EnumAdvise(IDataObject *pdtobj, LPENUMSTATDATA *ppenumAdvise)
{
return OLE_E_ADVISENOTSUPPORTED;
}
const IDataObjectVtbl c_CPJDataVtbl = {
CPJData_QueryInterface, CPJData_AddRef, CPJData_Release,
CPJData_GetData,
CPJData_GetDataHere,
CPJData_QueryGetData,
CPJData_GetCanonicalFormatEtc,
CPJData_SetData,
CPJData_EnumFormatEtc,
CPJData_Advise,
CPJData_Unadvise,
CPJData_EnumAdvise
};
// IDropTarget stuff
// CPQDropTarget : class definition
typedef struct { // dvdt
IDropTarget dt;
UINT cRef;
PQUEUEINFO pqi;
DWORD grfKeyStateLast;
DWORD dwEffect; // drop action set in DragEnter
AUTO_SCROLL_DATA asd; // for auto scrolling
} CPQDropTarget;
// CPQDropTarget : Constructor
extern const IDropTargetVtbl c_CPQDropTarget; // forward
STDMETHODIMP CPQDropTarget_CreateInstance(PQUEUEINFO pqi, IDropTarget **ppdtgt)
{
HRESULT hres = E_OUTOFMEMORY;
CPQDropTarget *pdvdt = (void*)LocalAlloc(LPTR, SIZEOF(CPQDropTarget));
if (pdvdt)
{
pdvdt->dt.lpVtbl = &c_CPQDropTarget;
pdvdt->cRef = 1;
pdvdt->pqi = pqi;
*ppdtgt = &pdvdt->dt;
hres = NOERROR;
}
return hres;
}
// CPQDropTarget : member
STDMETHODIMP CPQDropTarget_QueryInterface(IDropTarget *pdt, REFIID riid, LPVOID *ppvObj)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
// If we just want the same interface or an unknown one, return
// this guy
if (IsEqualIID(riid, &IID_IDropTarget) || IsEqualIID(riid, &IID_IUnknown))
{
*((IDropTarget **)ppvObj) = &this->dt;
this->cRef++;
return(NOERROR);
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CPQDropTarget_AddRef(IDropTarget *pdt)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
this->cRef++;
return(this->cRef);
}
STDMETHODIMP_(ULONG) CPQDropTarget_Release(IDropTarget *pdt)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
this->cRef--;
if (this->cRef > 0)
return this->cRef;
LocalFree((HLOCAL)this);
return 0;
}
STDMETHODIMP CPQDropTarget_DragEnter(IDropTarget *pdt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
FORMATETC fmte = {g_cfPrintJob, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
DebugMsg(DM_TRACE, TEXT("sh - TR CPQDropTarget::DragEnter"));
this->grfKeyStateLast = grfKeyState;
RegisterPrintJobFormat();
// default action
*pdwEffect = DROPEFFECT_NONE;
// We accept jobs from this queue:
// - the only "job" object that we accept is ours, so do a quick check
// (this also keeps us from supporting another datatype in idataobject!)
// - there's only one outstanding drag:
// if this pdt's queue was the source of the drag, we can accept it
if (this->pqi->bDragSource && (NOERROR == pdtobj->lpVtbl->QueryGetData(pdtobj, &fmte)))
{
// this is a print job from our window, accept this
*pdwEffect = DROPEFFECT_MOVE;
}
else
{
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
// We also accept files for printing
if (NOERROR == pdtobj->lpVtbl->QueryGetData(pdtobj, &fmte))
{
*pdwEffect = DROPEFFECT_COPY;
}
}
// store dwEffect for DragOver
this->dwEffect = *pdwEffect;
DAD_DragEnter(this->pqi->hwndLV);
DAD_InitScrollData(&this->asd);
return NOERROR;
}
int PQ_GetDropTarget(CPQDropTarget *this, long y)
{
LV_HITTESTINFO info;
int iItem;
info.pt.x = 0;
info.pt.y = y;
ScreenToClient(this->pqi->hwndLV, &info.pt);
// using 10 for x forces us into "document name" column, allowing us to
// get a "hit" even if we are on some other column.
info.pt.x = 10;
iItem = ListView_HitTest(this->pqi->hwndLV, &info);
if (iItem == -1)
{
// another hack: since 100 above forces us into column 1, we know that
// a -1 return is not from being too far to the left or to the right.
// And you can't go off the top (above item 0) without falling off the
// listview. So a -1 return means we're below the last item, so put
// us on the last item:
iItem = ListView_GetItemCount(this->pqi->hwndLV) - 1;
}
return iItem;
}
STDMETHODIMP CPQDropTarget_DragOver(IDropTarget *pdt, DWORD grfKeyState, POINTL ptl, LPDWORD pdwEffect)
{
HRESULT hres = NOERROR;
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
POINT pt = { ptl.x, ptl.y }; // in screen coords
ScreenToClient(this->pqi->hwndLV, &pt);
// assume coords of our window match listview
DAD_AutoScroll(this->pqi->hwndLV, &this->asd, &pt);
// effect was stored in DragEnter
*pdwEffect = this->dwEffect;
// If this->dwEffect is DROPACTION_MOVE, then
// it might be nice to show where the job will move to:
// v
// - Use a " - " cursor to show where this job will be inserted
// ^
DAD_DragMove(pt);
return hres;
}
STDMETHODIMP CPQDropTarget_DragLeave(IDropTarget *pdt)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
DebugMsg(DM_TRACE, TEXT("sh - TR CPQDropTarget::DragLeave"));
DAD_DragLeave();
LVUtil_DragSelectItem(this->pqi->hwndLV, -1);
return NOERROR;
}
STDMETHODIMP CPQDropTarget_Drop(IDropTarget *pdt, IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
CPQDropTarget *this = IToClass(CPQDropTarget, dt, pdt);
HRESULT hres = NOERROR;
DebugMsg(DM_TRACE, TEXT("sh - TR CPQDropTarget::Drop"));
if (this->grfKeyStateLast & MK_LBUTTON)
{
*pdwEffect = this->dwEffect;
}
else
{
HMENU hmenu;
// pop up a menu to choose from.
if (this->dwEffect == DROPEFFECT_MOVE)
{
// we're moving a job
hmenu = SHLoadPopupMenu(HINST_THISDLL, POPUP_MOVEONLYDD);
}
else // this->dwEffect == DROPEFFECT_COPY
{
// we're printing a file
ASSERT(this->dwEffect == DROPEFFECT_COPY);
// To use MENU_PRINTOBJ_DD we assume DDIDM_COPY == DROPEFFECT_COPY
hmenu = SHLoadPopupMenu(HINST_THISDLL, MENU_PRINTOBJ_DD);
}
if (hmenu)
{
SetMenuDefaultItem(hmenu, this->dwEffect, MF_BYCOMMAND);
*pdwEffect = TrackPopupMenu(
hmenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
ptl.x, ptl.y, 0, this->pqi->hwndLV, NULL);
DestroyMenu(hmenu);
DebugMsg(DM_TRACE, TEXT("CPQDropTarget_Drop *pdwEffect = %x, this->dwEffect=%x"), *pdwEffect, this->dwEffect);
}
}
// Do the drop!
if (*pdwEffect == DROPEFFECT_COPY)
{
// we're printing the file pdtobj to printer idp
hres = PrintObj_DropPrint(pdtobj, this->pqi->hDlg, *pdwEffect, (LPCITEMIDLIST)&(this->pqi->idp), CPrintObj_DropThreadProc);
}
else if (*pdwEffect == DROPEFFECT_MOVE)
{
STGMEDIUM medium;
FORMATETC fmte = {g_cfPrintJob, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj, &fmte, &medium)))
{
int iItem;
BOOL bRet;
PRINTJOBDESC *pidpj = (PRINTJOBDESC *)GlobalLock(medium.hGlobal);
ASSERT(pidpj->dwJobId == this->pqi->pJobs[pidpj->iItem].JobId);
iItem = PQ_GetDropTarget(this, ptl.y);
DebugMsg(DM_TRACE, TEXT("Drop %d on %d"), pidpj->iItem, iItem);
bRet = FALSE;
this->pqi->pJobs[pidpj->iItem].Position = iItem + 1;
bRet = SetJob(this->pqi->hPrinter, pidpj->dwJobId, 2,
(LPBYTE)&(this->pqi->pJobs[pidpj->iItem]), 0);
if (bRet)
{
PostMessage(this->pqi->hDlg, WM_TIMER, 1, 0L);
}
else
{
MessageBeep((UINT)-1);
}
GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium);
}
}
// Make sure to unlock the window for updating
CPQDropTarget_DragLeave(pdt);
return hres;
}
const IDropTargetVtbl c_CPQDropTarget = {
CPQDropTarget_QueryInterface, CPQDropTarget_AddRef, CPQDropTarget_Release,
CPQDropTarget_DragEnter,
CPQDropTarget_DragOver,
CPQDropTarget_DragLeave,
CPQDropTarget_Drop
};
// More D&D functions
LRESULT PRQ_BeginDrag(HWND hDlg, PQUEUEINFO pqi, NM_LISTVIEW *lpnm)
{
int iJob = ListView_GetNextItem(pqi->hwndLV, -1, LVNI_SELECTED);
LPITEMIDLIST pidlParent;
ASSERT(iJob >= 0);
pidlParent = Printers_GetPidl(NULL, pqi->idp.cName);
if (pidlParent)
{
POINT ptOffset = lpnm->ptAction; // hwndLV client coords
DWORD dwEffect = DROPEFFECT_MOVE;
PRINTJOBDESC pjd;
BOOL fPaused;
// set up relative pidl for job
pjd.dwJobId = pqi->pJobs[iJob].JobId;
pjd.iItem = iJob;
// pause the job so it won't start printing during drag operation
fPaused = !(pqi->pJobs[iJob].Status & JOB_STATUS_PAUSED) &&
Printer_ModifyJob(hDlg, JOB_CONTROL_PAUSE);
// Somebody began dragging in our window, so store that fact
// save away the anchor point
// pqi->ptDragAnchor = lpnm->ptAction;
// LVUtil_ClientToLV(pqi->hwndLV, &pqi->ptDragAnchor);
ClientToScreen(pqi->hwndLV, &ptOffset); // now in screen
if (DAD_SetDragImageFromListView(pqi->hwndLV, ptOffset))
{
IDataObject *pdtobj;
if (SUCCEEDED(CPJData_CreateInstance(&pjd, &pdtobj)))
{
pqi->bDragSource = TRUE;
SHDoDragDrop(hDlg, pdtobj, NULL, dwEffect, &dwEffect);
pdtobj->lpVtbl->Release(pdtobj);
pqi->bDragSource = FALSE;
}
DAD_SetDragImage(NULL, NULL);
}
// All done dragging
if (fPaused)
{
Printer_ModifyJob(hDlg, JOB_CONTROL_RESUME);
}
ILFree(pidlParent);
}
return 0L;
}
/* Printer Queue helper functions */
void SystemTimeString(LPTSTR pszText, SYSTEMTIME *pst)
{
FILETIME ftUTC, ftLocal;
SYSTEMTIME st;
TCHAR szTmp[64];
// Convert from UTC to Local time
SystemTimeToFileTime(pst, &ftUTC);
FileTimeToLocalFileTime(&ftUTC, &ftLocal);
FileTimeToSystemTime(&ftLocal, &st);
// Generate string
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, pszText, ARRAYSIZE(szTmp));
lstrcat(pszText, c_szSpace);
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szTmp, ARRAYSIZE(szTmp));
lstrcat(pszText, szTmp);
}
const struct
{
int iCol;
int ids; // Id of string for title
int iFmt; // The format of the column;
} c_PQCols[] = {
{ICOL_DOCNAME , IDS_PRQ_DOCNAME , LVCFMT_LEFT},
{ICOL_STATUS , IDS_PRQ_STATUS , LVCFMT_LEFT},
{ICOL_OWNER , IDS_PRQ_OWNER , LVCFMT_LEFT},
{ICOL_PROGRESS, IDS_PRQ_PROGRESS, LVCFMT_LEFT},
{ICOL_TIME , IDS_PRQ_TIME , LVCFMT_LEFT},
};
void PrinterQueue_AddColumns(HWND hLV, int *nPos)
{
LV_COLUMN col;
TCHAR szColName[258];
int i;
for (i=0; i<ARRAYSIZE(c_PQCols); ++i)
{
LoadString(HINST_THISDLL, c_PQCols[i].ids, szColName, ARRAYSIZE(szColName));
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
col.fmt = c_PQCols[i].iFmt;
col.pszText = (LPTSTR)szColName;
col.cchTextMax = 0;
col.cx = nPos[i];
col.iSubItem = c_PQCols[i].iCol;
ListView_InsertColumn(hLV, c_PQCols[i].iCol, &col);
}
}
const TCHAR szPrinterPositions[] = REGSTR_PATH_EXPLORER TEXT("\\Printers") ;
const POSINFO c_PQPos = {
SIZEOF(WINDOWPLACEMENT), 0, SW_SHOW, 0, 0, 0, 0, 50, 100, 612, 285,
185, 80, 80, 80, 125, TRUE
};
BOOL PrinterQueue_Init(HWND hDlg, INITINFO *pii)
{
POSINFO sPos;
HWND hLV;
PQUEUEINFO pqi;
IDropTarget *lpdt;
HKEY hkey;
HANDLE hPrinter;
HWND hSB;
HIMAGELIST himl;
int border[] = {0, -1, 2};
// Let the printer hwnd dpa point to this hDlg instead of stub parent.
PrintDef_UpdateHwnd(pii->lpszPrinterName, hDlg);
hLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, c_szNULL,
WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_CLIPSIBLINGS|LVS_REPORT,
0, 0, 100, 100, hDlg, NULL, HINST_THISDLL, NULL);
if (!hLV)
{
goto Error1;
}
hSB = CreateStatusWindow(
WS_CHILD | SBARS_SIZEGRIP | CCS_NOHILITE | WS_CLIPSIBLINGS,
NULL, hDlg, FCIDM_STATUS);
if (!hSB)
{
goto Error1;
}
SendMessage(hSB, SB_SETBORDERS, 0, (LPARAM)(LPINT)border);
himl = ImageList_Create(g_cxSmIcon, g_cySmIcon, ILC_MASK, 1, 4);
if (himl)
{
HICON hIcon;
int iIndex;
ImageList_SetBkColor(himl, GetSysColor(COLOR_WINDOW));
hIcon = LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_DOCUMENT),
IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
iIndex = ImageList_AddIcon(himl, hIcon);
ASSERT(iIndex == 0);
DestroyIcon(hIcon);
SendMessage(hLV, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL, (LPARAM)himl);
}
hPrinter = Printer_OpenPrinter(pii->lpszPrinterName);
if (!hPrinter)
{
goto Error1;
}
pqi = (PQUEUEINFO)LocalAlloc(LPTR, SIZEOF(QUEUEINFO));
if (!pqi)
{
Printer_ClosePrinter(hPrinter);
Error1:
PostQuitMessage(0);
return(TRUE);
}
pqi->hPrinter = hPrinter;
pqi->hDlg = hDlg;
pqi->hwndLV = hLV;
Printers_FillPidl(&pqi->idp, pii->lpszPrinterName);
SetWindowPtr(hDlg, DWLP_USER, pqi);
sPos = c_PQPos;
if (ERROR_SUCCESS ==
RegOpenKey(HKEY_CURRENT_USER, szPrinterPositions, &hkey))
{
DWORD dwSize = SIZEOF(sPos);
DWORD dwType;
if (ERROR_SUCCESS !=
SHQueryValueEx(hkey, (LPTSTR)(pii->lpszPrinterName), NULL, &dwType, (LPBYTE)&sPos, &dwSize)
|| dwSize != SIZEOF(sPos)
|| sPos.wp.length != SIZEOF(WINDOWPLACEMENT))
{
sPos = c_PQPos;
}
RegCloseKey(hkey);
}
pqi->hwndSB = hSB;
pqi->fStatusBar = sPos.fStatusBar;
ShowWindow(pqi->hwndSB, pqi->fStatusBar ? SW_SHOW : SW_HIDE);
PrinterQueue_AddColumns(hLV, sPos.nWidths);
Printer_LoadIcons(pqi->idp.cName, &(pqi->hLargeIcon), &(pqi->hSmallIcon));
SendMessage(pqi->hDlg, WM_SETICON, TRUE, (LPARAM)(pqi->hLargeIcon));
SendMessage(pqi->hDlg, WM_SETICON, FALSE, (LPARAM)(pqi->hSmallIcon));
PostMessage(hDlg, WM_TIMER, 1, 0L);
sPos.wp.showCmd = pii->nCmdShow;
SetWindowPlacement(hDlg, &sPos.wp);
if (SUCCEEDED(CPQDropTarget_CreateInstance(pqi, &lpdt)))
{
RegisterDragDrop(hLV, lpdt);
}
return(TRUE);
}
void PrinterQueue_Destroy(HWND hDlg)
{
PQUEUEINFO pqi;
POSINFO sPos;
int i;
HKEY hkey;
pqi = (PQUEUEINFO)GetWindowPtr(hDlg, DWLP_USER);
if (!pqi)
{
// Nothing was initialized, so nothing to clean up
return;
}
SendMessage(pqi->hDlg, WM_SETICON, TRUE, 0);
SendMessage(pqi->hDlg, WM_SETICON, FALSE, 0);
DestroyIcon(pqi->hLargeIcon);
DestroyIcon(pqi->hSmallIcon);
RevokeDragDrop(pqi->hwndLV);
sPos.wp.length = SIZEOF(WINDOWPLACEMENT);
GetWindowPlacement(hDlg, &sPos.wp);
// Get the column widths
for (i=0; i<ICOL_NUM; ++i)
{
sPos.nWidths[i] = ListView_GetColumnWidth(pqi->hwndLV, i);
}
sPos.fStatusBar = pqi->fStatusBar;
// Save the position info
if (ERROR_SUCCESS ==
RegCreateKey(HKEY_CURRENT_USER, szPrinterPositions, &hkey))
{
RegSetValueEx(hkey, pqi->idp.cName, 0, REG_BINARY,
(LPBYTE)&sPos, SIZEOF(sPos));
RegCloseKey(hkey);
}
if (pqi->hPrinter)
{
Printer_ClosePrinter(pqi->hPrinter);
}
if (pqi->pJobs)
{
LocalFree((HLOCAL)pqi->pJobs);
}
LocalFree(pqi);
SetWindowPtr(hDlg, DWLP_USER, 0L);
}
#endif
// Printer_BitsToString maps bits into a string representation, putting
// the string idsSep in between each found bit.
// Returns the size of the created string.
UINT Printer_BitsToString(
DWORD bits, // the bitfield we're looking at
UINT idsSep, // string id of separator
LPCSTATUSSTUFF pSS, // a 0 terminated mapping of bits to string ids
LPTSTR lpszBuf, // output buffer
UINT cchMax) // size of output buffer
{
UINT cchBuf = 0;
UINT i = 0;
UINT cchSep = 0;
TCHAR szSep[20];
if (LoadString(HINST_THISDLL, idsSep, szSep, ARRAYSIZE(szSep)))
cchSep = lstrlen(szSep);
for ( ; pSS->bit != 0 ; ++i, ++pSS)
{
if (bits & pSS->bit)
{
TCHAR szTmp[258];
if (LoadString(HINST_THISDLL, pSS->uStringID, szTmp, ARRAYSIZE(szTmp)))
{
UINT cchTmp = lstrlen(szTmp);
if (cchBuf + cchSep + cchTmp < cchMax)
{
if (cchBuf)
{
lstrcat(lpszBuf, szSep);
cchBuf += cchSep;
}
lstrcat(lpszBuf, szTmp);
cchBuf += cchTmp;
}
}
}
}
return(cchBuf);
}
#ifndef WINNT
extern const STATUSSTUFF ssPrinterStatus[]; // defined in printer.c
void Printer_PrinterStatus(PQUEUEINFO pqi)
{
LPPRINTER_INFO_2 pPrinter;
LPTSTR lpszPrinterName;
TCHAR szBuf[256];
// Default window title is the current printer name
lpszPrinterName = pqi->idp.cName;
pPrinter = Printer_GetPrinterInfo(pqi->hPrinter, 2);
if (pPrinter)
{
UINT bufLen;
UINT nameLen;
if (lstrcmp(pqi->idp.cName, pPrinter->pPrinterName))
{
// WHOA! The user renamed this printer
Printers_FillPidl(&pqi->idp, pPrinter->pPrinterName);
// BUGBUG: We don't update the hdsaPrintDef (which keeps track
// of which printers are open) with the new printer name. So
// the user can open another window for this printer OR rename a
// different printer to this one's old name and then get this
// window when trying to open the other printer.
}
if (pPrinter->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE)
{
// HACK: Use this free bit for "Work Offline"
pPrinter->Status |= PRINTER_HACK_WORK_OFFLINE;
}
if (pPrinter->Status)
{
lstrcpy(szBuf, lpszPrinterName);
nameLen = bufLen = lstrlen(szBuf);
LoadString(HINST_THISDLL, IDS_PRQSTATUS_SEPARATOR,
szBuf+bufLen, ARRAYSIZE(szBuf)-bufLen);
bufLen = lstrlen(szBuf);
Printer_BitsToString(pPrinter->Status, IDS_PRQSTATUS_SEPARATOR,
ssPrinterStatus, szBuf+bufLen, ARRAYSIZE(szBuf)-bufLen);
lpszPrinterName = szBuf;
}
LocalFree((HLOCAL)pPrinter);
}
SetWindowText(pqi->hDlg, lpszPrinterName);
}
// Printer_AddJobs sets the number of items in hLV to be iJobsWanted.
void Printer_AddJobs(HWND hLV, int iJobsWanted)
{
LV_ITEM item;
int iJobs;
// And to the listview
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE ;
item.iSubItem = 0;
item.pszText = LPSTR_TEXTCALLBACK;
item.state = 0;
item.iImage = -1;
iJobs = ListView_GetItemCount(hLV);
for ( ; iJobs<iJobsWanted; ++iJobs)
{
item.iItem = iJobs;
item.lParam = (LPARAM)iJobs;
if (ListView_InsertItem(hLV, &item) < 0)
{
break;
}
}
for ( ; iJobs>iJobsWanted; --iJobs)
{
ListView_DeleteItem(hLV, iJobs-1);
}
}
BOOL Printers_EnumJobsCB(LPVOID lpData, HANDLE hPrinter, DWORD dwLevel,
LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
{
#ifndef BUGBUG_BOBDAY
return(EnumJobs(hPrinter, 0, 0x7fffffffL, dwLevel, pEnum, dwSize, lpdwNeeded, lpdwNum));
#else
return(EnumJobs(hPrinter, 1, 0x7fffffffL, dwLevel, pEnum, dwSize, lpdwNeeded, lpdwNum));
#endif
}
void PrinterQueue_Check(HWND hDlg)
{
PQUEUEINFO pqi = (PQUEUEINFO)GetWindowPtr(hDlg, DWLP_USER);
DWORD dwJobs;
int iJob, iSel;
DWORD dwSelID;
LPTSTR pszJobsInQueue;
ASSERT(hDlg == pqi->hDlg);
if (pqi->bDragSource || pqi->bMinimized)
{
// If we are dragging from this window, don't update the queue info!
// If we did, we'd need to put semaphores around this function and
// all the drag&drop stuff. This is much easier.
// If we are minimized, we don't need to poll either
return;
}
// remember which job is selected
dwSelID = (DWORD)-1;
iSel = ListView_GetNextItem(pqi->hwndLV, -1, LVNI_SELECTED);
if (iSel >= 0)
{
dwSelID = pqi->pJobs[iSel].JobId;
}
// update title
Printer_PrinterStatus(pqi);
// get new job state
if (pqi->pJobs)
LocalFree((HLOCAL)pqi->pJobs);
pqi->pJobs = Printer_EnumProps(pqi->hPrinter, 2, &dwJobs, Printers_EnumJobsCB, NULL);
if (pqi->pJobs == NULL)
{
pqi->dwJobs = dwJobs = 0;
}
// Make sure we set pqi->dwJobs before we call anything that might
// recurse back into PrintQueue_DlgProc where we might fault!
pqi->dwJobs = dwJobs;
// Make sure we set pqi->dwJobs before we call anything that might
// recurse back into PrintQueue_DlgProc where we might fault!
pqi->dwJobs = dwJobs;
pszJobsInQueue = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_PRQ_JOBSINQUEUE), dwJobs);
if (pszJobsInQueue)
{
// a-msadek; needed only for BiDi Win95 loc
// Mirroring will take care of that over NT5 & BiDi Win98
if(g_bBiDiW95Loc)
{
SendMessage(pqi->hwndSB, SB_SETTEXT, (WPARAM)SBT_RTLREADING, (LPARAM)pszJobsInQueue);
}
else
{
SendMessage(pqi->hwndSB, SB_SETTEXT, (WPARAM)0, (LPARAM)pszJobsInQueue);
}
LocalFree(pszJobsInQueue);
}
Printer_AddJobs(pqi->hwndLV, (int)dwJobs);
// Find the previously selected job and select it again
iSel = -1;
for (iJob = 0; iJob < (int)dwJobs; iJob++)
{
if (pqi->pJobs[iJob].JobId == dwSelID)
{
iSel = iJob;
}
}
ListView_SetItemState(pqi->hwndLV, iSel, iSel == -1 ? 0 : LVIS_SELECTED, LVIS_SELECTED);
InvalidateRect(pqi->hwndLV, NULL, TRUE);
}
BOOL Printer_ModifyJob(HWND hDlg, DWORD dwCommand)
{
PQUEUEINFO pqi = (PQUEUEINFO)GetWindowPtr(hDlg, DWLP_USER);
int iJob = -1;
DWORD dwJobID;
BOOL bRet = TRUE;
while (bRet &&
(iJob = ListView_GetNextItem(pqi->hwndLV, iJob, LVNI_SELECTED)) >= 0)
{
dwJobID = pqi->pJobs[iJob].JobId;
bRet = SetJob(pqi->hPrinter, dwJobID, 0, NULL, dwCommand);
}
// Let the listbox refresh right now
PostMessage(hDlg, WM_TIMER, 1, 0L);
return(bRet);
}
#if 0 // not used
BOOL PrinterDlg_ModifyPrinter(PQUEUEINFO pqi, DWORD dwCommand)
{
BOOL fRet = SetPrinter(pqi->hPrinter, 0, NULL, dwCommand);
// Let the listbox refresh right now
PostMessage(pqi->hDlg, WM_TIMER, 1, 0L);
return fRet;
}
#endif
void PrinterQueue_InitPrinterMenu(HMENU hmPrinter, PQUEUEINFO pqi)
{
QCMINFO qcm = {hmPrinter, 0, ID_PRINTER_START, 0xffff};
int i;
// remove previously merged items
for (i = GetMenuItemCount(hmPrinter) ; i > 3 ; i--)
{
DeleteMenu(hmPrinter, 0, MF_BYPOSITION);
}
// merge in context menu
Printer_MergeMenu(NULL, &qcm, pqi->idp.cName, TRUE);
// remove Open
DeleteMenu(hmPrinter, 0, MF_BYPOSITION);
DeleteMenu(hmPrinter, 0, MF_BYPOSITION);
}
void PrinterQueue_InitDocMenu(HMENU hmDoc, PQUEUEINFO pqi, int iSel)
{
UINT i = (iSel >= 0 && pqi->pJobs[iSel].Status & JOB_STATUS_PAUSED) ?
MF_CHECKED : 0 ;
Printer_CheckMenuItem(hmDoc, i, ID_DOCUMENT_RESUME, ID_DOCUMENT_PAUSE);
Printer_EnableMenuItems(hmDoc, iSel >= 0);
}
void PrinterQueue_InitViewMenu(HMENU hmView, PQUEUEINFO pqi)
{
// This seems a bit bogus to me. We can simply un/check the menu item
// whenever the user makes the change. That won't work for the
// Printer and Document menu's, since they may change asynchronous to
// user input. To be consistent, let's follow the same model here.
CheckMenuItem(hmView, ID_VIEW_STATUSBAR,
pqi->fStatusBar ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
}
// load a popup from a main menu
HMENU _LoadSubPopupMenu(UINT id, UINT uSubOffset)
{
HMENU hmParent, hmPopup;
hmParent = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(id));
if (!hmParent)
return NULL;
hmPopup = GetSubMenu(hmParent, uSubOffset);
RemoveMenu(hmParent, uSubOffset, MF_BYPOSITION);
DestroyMenu(hmParent);
return hmPopup;
}
const STATUSSTUFF ssPRQStatus[] =
{
JOB_STATUS_DELETING, IDS_PRQSTATUS_PENDING_DELETION,
JOB_STATUS_ERROR , IDS_PRQSTATUS_ERROR ,
JOB_STATUS_OFFLINE , IDS_PRQSTATUS_OFFLINE ,
JOB_STATUS_PAPEROUT, IDS_PRQSTATUS_PAPER_OUT,
JOB_STATUS_PAUSED , IDS_PRQSTATUS_PAUSED ,
JOB_STATUS_PRINTED , IDS_PRQSTATUS_PRINTED ,
JOB_STATUS_PRINTING, IDS_PRQSTATUS_PRINTING,
JOB_STATUS_SPOOLING, IDS_PRQSTATUS_SPOOLING,
JOB_STATUS_USER_INTERVENTION, IDS_PRQSTATUS_USER_INTERVENTION,
0, 0
} ;
void PrintQueue_Notify(HWND hDlg, NMHDR *lphdr)
{
PQUEUEINFO pqi = (PQUEUEINFO)GetWindowPtr(hDlg, DWLP_USER);
if (!pqi)
{
return;
}
switch (lphdr->code)
{
case NM_RCLICK:
{
int iSel;
HMENU hmContext;
POINT pt;
iSel = ListView_GetNextItem(pqi->hwndLV, -1, LVNI_SELECTED);
hmContext = _LoadSubPopupMenu(MENU_PRINTERQUEUE, iSel >= 0 ? 1 : 0);
if (!hmContext)
{
break;
}
if (iSel < 0)
{
// We need to remove the "Close" menu item
// (and separator)
iSel = GetMenuItemCount(hmContext) - 2;
DeleteMenu(hmContext, iSel, MF_BYPOSITION);
DeleteMenu(hmContext, iSel, MF_BYPOSITION);
PrinterQueue_InitPrinterMenu(hmContext, pqi);
}
else
{
PrinterQueue_InitDocMenu(hmContext, pqi, iSel);
}
GetMsgPos(&pt);
// The command will just get stuck in the regular queue and
// handled at that time
TrackPopupMenu(hmContext, TPM_LEFTALIGN|TPM_RIGHTBUTTON, pt.x, pt.y,
0, hDlg, NULL);
DestroyMenu(hmContext);
// Tell the listview that we handled the context menu
// so don't try to display some generic ctx menu for us
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
break;
}
case LVN_GETDISPINFO:
{
LV_DISPINFO *lpdi = (LV_DISPINFO *)lphdr;
JOB_INFO_2 *pJob;
if (lpdi->item.mask & LVIF_IMAGE)
{
lpdi->item.iImage = 0;
}
if (!(lpdi->item.mask & LVIF_TEXT))
{
// we only have info for LVIF_TEXT
break;
}
// Why is this using lParam? iItem tells us the selection...
// Stress page faulted referencing pJob+lpdi->item.lParam.
// Shouldn't have happened, so put these asserts here and
// bail if lParam is bad.
ASSERT(lpdi->item.lParam == lpdi->item.iItem);
pJob = pqi->pJobs;
if (!pJob || (DWORD)lpdi->item.lParam >= pqi->dwJobs)
{
return;
}
pJob += lpdi->item.lParam;
switch (lpdi->item.iSubItem)
{
case ICOL_DOCNAME:
if (pJob->pDocument)
lpdi->item.pszText = pJob->pDocument;
break;
case ICOL_STATUS:
if (pJob->pStatus && *(pJob->pStatus))
{
lstrcpyn(lpdi->item.pszText, pJob->pStatus, lpdi->item.cchTextMax);
}
else
{
Printer_BitsToString(pJob->Status, IDS_PRQSTATUS_SEPARATOR,
ssPRQStatus, lpdi->item.pszText, lpdi->item.cchTextMax);
}
break;
case ICOL_OWNER:
if (pJob->pUserName)
lpdi->item.pszText = pJob->pUserName;
break;
case ICOL_PROGRESS:
{
LPTSTR pszFormat = NULL;
// If TotalPages == 0 and Size != 0, PagesPrinted is SizePrinted
if (pJob->Status&JOB_STATUS_PRINTING)
{
if (pJob->TotalPages == 0)
{
TCHAR szSize[32];
TCHAR szPrinted[32];
ShortSizeFormat(pJob->Size, szSize);
ShortSizeFormat(pJob->PagesPrinted, szPrinted);
pszFormat = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_PRQ_BYTESPRINTED),
szPrinted, szSize);
}
else
{
pszFormat = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_PRQ_PAGESPRINTED),
pJob->PagesPrinted, pJob->TotalPages);
}
}
else
{
if (pJob->TotalPages == 0)
{
ShortSizeFormat(pJob->Size, lpdi->item.pszText);
}
else
{
pszFormat = ShellConstructMessageString(HINST_THISDLL,
MAKEINTRESOURCE(IDS_PRQ_PAGES),
pJob->TotalPages);
}
}
if (pszFormat)
{
lstrcpyn(lpdi->item.pszText, pszFormat, lpdi->item.cchTextMax);
LocalFree(pszFormat);
}
break;
}
case ICOL_TIME:
SystemTimeString(lpdi->item.pszText, &pJob->Submitted);
break;
default:
break;
}
break;
}
case LVN_BEGINDRAG:
case LVN_BEGINRDRAG:
PRQ_BeginDrag(hDlg, pqi, (NM_LISTVIEW *)lphdr);
break;
default:
break;
}
}
void PrinterQueue_OnSize(PQUEUEINFO pqi)
{
int dyList;
int dyStatus = 0;
if (pqi->fStatusBar)
{
RECT rc;
// REVIEW: Is this the right way to do this?
GetWindowRect(pqi->hwndSB, &rc);
dyStatus = min(pqi->cy, rc.bottom - rc.top - 2);
}
dyList = pqi->cy - dyStatus;
SetWindowPos(pqi->hwndLV, NULL, 0, 0, pqi->cx, dyList, SWP_NOZORDER);
SetWindowPos(pqi->hwndSB, NULL, dyList, 0, pqi->cx, dyStatus, SWP_NOZORDER);
}
extern TCHAR const c_szWindowsHlp[];
BOOL CALLBACK PrinterQueue_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PQUEUEINFO pqi = (PQUEUEINFO)GetWindowPtr(hDlg, DWLP_USER);
INSTRUMENT_WNDPROC(SHCNFI_PRINTERQUEUE_DLGPROC, hDlg, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_INITDIALOG:
return(PrinterQueue_Init(hDlg, (INITINFO *)lParam));
case WM_DESTROY:
PrinterQueue_Destroy(hDlg);
break;
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
pqi->bMinimized = TRUE;
}
else
{
if (pqi->bMinimized)
{
pqi->bMinimized = FALSE;
// Restoring from a minimized state -- update queue
PostMessage(hDlg, WM_TIMER, 1, 0L);
}
pqi->cx = GET_X_LPARAM(lParam);
pqi->cy = GET_Y_LPARAM(lParam);
PrinterQueue_OnSize(pqi);
}
break;
case WM_CONTEXTMENU:
if (hDlg == (HWND)wParam &&
SendMessage(hDlg, WM_NCHITTEST, 0, lParam) == HTSYSMENU)
{
HMENU hmContext = _LoadSubPopupMenu(MENU_PRINTERQUEUE, 0);
if (hmContext)
{
int idCmd;
PrinterQueue_InitPrinterMenu(hmContext, pqi);
idCmd = TrackPopupMenu(hmContext,
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hDlg, NULL);
switch(idCmd)
{
case 0:
break;
case IDCANCEL:
PostQuitMessage(0);
break;
default:
Printer_InvokeCommand(hDlg, NULL, &(pqi->idp), idCmd-ID_PRINTER_START, 0, NULL);
break;
}
DestroyMenu(hmContext);
return TRUE;
}
}
return FALSE;
case WM_TIMER:
PrinterQueue_Check(hDlg);
// Check the queue every 10 seconds
SetTimer(hDlg, 1, 10000, NULL);
break;
case WM_INITMENU:
if ((HMENU)wParam != GetMenu(hDlg))
{
break;
}
PrinterQueue_InitPrinterMenu(GetSubMenu((HMENU)wParam, 0), pqi);
PrinterQueue_InitDocMenu(GetSubMenu((HMENU)wParam, 1), pqi, ListView_GetNextItem(pqi->hwndLV, -1, LVNI_SELECTED));
PrinterQueue_InitViewMenu(GetSubMenu((HMENU)wParam, 2), pqi);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDCANCEL:
PostQuitMessage(0);
break;
case ID_DOCUMENT_PAUSE:
if (!Printer_ModifyJob(hDlg, JOB_CONTROL_PAUSE))
goto WarnOnError;
break;
case ID_DOCUMENT_RESUME:
if (!Printer_ModifyJob(hDlg, JOB_CONTROL_RESUME))
goto WarnOnError;
break;
case ID_DOCUMENT_DELETE:
if (!Printer_ModifyJob(hDlg, JOB_CONTROL_CANCEL))
{
WarnOnError:;
#ifndef WINNT
Printer_WarnOnError(hDlg, pqi->idp.cName, IDS_SECURITYDENIED_JOB);
#endif
}
break;
// case ID_VIEW_TOOLBAR:
// break;
case ID_VIEW_STATUSBAR:
pqi->fStatusBar = 1-pqi->fStatusBar;
ShowWindow(pqi->hwndSB, pqi->fStatusBar ? SW_SHOW : SW_HIDE);
PrinterQueue_OnSize(pqi);
break;
// even though this isn't on the menu any more, printobj.c sends it:
// we also have an accelerator for it:
case ID_VIEW_REFRESH:
PostMessage(hDlg, WM_TIMER, 1, 0L);
break;
// from cabinet\command.c: DoAboutChicago
case ID_HELP_ABOUT:
{
TCHAR szChicago[64];
LoadString(HINST_THISDLL, IDS_WINDOWS, szChicago, ARRAYSIZE(szChicago));
ShellAbout(hDlg, szChicago, NULL, NULL);
break;
}
// from defviewx.c: SFVIDM_HELP_TOPIC
case ID_HELP_CONTENTS:
// REVIEW: Should we jump to a topic which describes current
// viewed folder?
WinHelp(hDlg, c_szWindowsHlp, HELP_FINDER, 0);
break;
default:
// Must have been merged in from the printer's context menu
Printer_InvokeCommand(hDlg, NULL, &(pqi->idp), wParam-ID_PRINTER_START, 0, NULL);
break;
}
break;
case WM_NOTIFY:
PrintQueue_Notify(hDlg, (NMHDR *)lParam);
break;
default:
return(FALSE);
}
return(TRUE);
}
void Printer_ViewQueue(HWND hwndStub, LPCTSTR lpszCmdLine, int nCmdShow, LPARAM lParam)
{
LPPRINTER_INFO_5 pPrinter;
BOOL fFile = FALSE;
pPrinter = Printer_GetPrinterInfoStr(lpszCmdLine, 5);
if (pPrinter)
{
fFile = !lstrcmp(pPrinter->pPortName, c_szFileColon);
LocalFree((HLOCAL)pPrinter);
}
if (fFile)
{
ShellMessageBox(HINST_THISDLL, hwndStub,
MAKEINTRESOURCE(IDS_CANTVIEW_FILEPRN), lpszCmdLine,
MB_OK|MB_ICONINFORMATION);
}
else if (pPrinter)
{
INITINFO ii;
HWND hwndDlg;
ii.lpszPrinterName = lpszCmdLine;
ii.nCmdShow = nCmdShow;
// Call CreateDialog and do our own message loop w/ TranslateAccelerator
hwndDlg = CreateDialogParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_PRN_QUEUE), hwndStub,
PrinterQueue_DlgProc, (LPARAM)(LPTSTR)&ii);
if (hwndDlg)
{
HACCEL hAccel;
MSG msg;
hAccel = LoadAccelerators(HINST_THISDLL, MAKEINTRESOURCE(ACCEL_PRN_QUEUE));
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwndDlg, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DestroyWindow(hwndDlg);
}
}
else
{
// If you rename a printer and then try to open a link to that
// printer, we hit this case. An error message is appropriate?
ShellMessageBox(HINST_THISDLL, hwndStub,
MAKEINTRESOURCE(IDS_PRINTERNAME_CHANGED), lpszCmdLine,
MB_OK|MB_ICONINFORMATION);
}
}
#endif