320 lines
13 KiB
C++
320 lines
13 KiB
C++
// this is really private data to CPrinterFolder
|
|
typedef struct
|
|
{
|
|
USHORT cb;
|
|
USHORT uFlags;
|
|
|
|
#define PRINTER_MAGIC 0xBEBADB00
|
|
|
|
DWORD dwMagic;
|
|
DWORD dwType;
|
|
WCHAR cName[MAXNAMELENBUFFER];
|
|
USHORT uTerm;
|
|
} IDPRINTER;
|
|
typedef UNALIGNED IDPRINTER *LPIDPRINTER;
|
|
typedef const UNALIGNED IDPRINTER *LPCIDPRINTER;
|
|
|
|
// W95 IDPrinter structure
|
|
typedef struct
|
|
{
|
|
USHORT cb;
|
|
char cName[32]; // Win9x limitation
|
|
USHORT uTerm;
|
|
} W95IDPRINTER;
|
|
typedef const UNALIGNED W95IDPRINTER *LPW95IDPRINTER;
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
const UINT kDNSMax = INTERNET_MAX_HOST_NAME_LENGTH;
|
|
const UINT kServerBufMax = kDNSMax + 2 + 1;
|
|
|
|
//
|
|
// Max printer name should really be MAX_PATH, but if you create
|
|
// a max path printer and connect to it remotely, win32spl prepends
|
|
// "\\server\" to it, causing it to exceed max path. The new UI
|
|
// therefore makes the max path MAX_PATH-kServerLenMax, but we still
|
|
// allow the old case to work.
|
|
//
|
|
const UINT kPrinterBufMax = MAX_PATH + kServerBufMax + 1;
|
|
|
|
|
|
class CPrinterFolder : public IRemoteComputer,
|
|
public IPrinterFolder,
|
|
public IFolderNotify,
|
|
public IShellFolder2,
|
|
public IPersistFolder2,
|
|
public IContextMenuCB,
|
|
public IShellIconOverlay
|
|
{
|
|
friend class CPrintersEnum;
|
|
friend class CPrinterFolderViewCB;
|
|
public:
|
|
CPrinterFolder();
|
|
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
// IShellFolder
|
|
STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut);
|
|
STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut);
|
|
STDMETHODIMP CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
|
STDMETHODIMP CreateViewObject(HWND hwnd, REFIID riid, void** ppvOut);
|
|
STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD grfFlags, IEnumIDList** ppenum);
|
|
STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* prgfInOut);
|
|
STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
|
|
STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void** ppvOut);
|
|
STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
|
|
STDMETHODIMP SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST* ppidlOut);
|
|
|
|
// IShellFolder2
|
|
STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum);
|
|
STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay);
|
|
STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pdwState);
|
|
STDMETHODIMP GetDefaultSearchGUID(LPGUID pGuid);
|
|
STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv);
|
|
STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails);
|
|
STDMETHODIMP MapColumnToSCID(UINT iCol, SHCOLUMNID* pscid);
|
|
|
|
// IPersistFolder2
|
|
STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
|
|
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
|
|
STDMETHODIMP GetClassID(LPCLSID lpClassID);
|
|
|
|
// IShellIconOverlay
|
|
STDMETHODIMP GetOverlayIndex(LPCITEMIDLIST pidl, int* pIndex);
|
|
STDMETHODIMP GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIndex);
|
|
|
|
// IRemoteComputer
|
|
STDMETHODIMP Initialize(const WCHAR *pszMachine, BOOL bEnumerating);
|
|
|
|
// IPrinterFolder
|
|
STDMETHODIMP_(BOOL) IsPrinter(LPCITEMIDLIST pidl);
|
|
|
|
// IFolderNotify
|
|
STDMETHODIMP_(BOOL) ProcessNotify(FOLDER_NOTIFY_TYPE NotifyType, LPCWSTR pszName, LPCWSTR pszNewName);
|
|
|
|
// IContextMenuCB
|
|
STDMETHODIMP CallBack(IShellFolder *psf, HWND hwnd,IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// DUI webview impl.
|
|
HRESULT GetWebViewLayout(IUnknown *pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData);
|
|
HRESULT GetWebViewContent(IUnknown *pv, SFVM_WEBVIEW_CONTENT_DATA* pData);
|
|
HRESULT GetWebViewTasks(IUnknown *pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks);
|
|
|
|
// mask passsed to _IsContextMenuVerbEnabled to determine the selection type in which
|
|
// this command is applicable
|
|
enum
|
|
{
|
|
// nothing is selected
|
|
SEL_NONE = 0x0000, // nothing is selected
|
|
|
|
// single selection types
|
|
SEL_SINGLE_ADDPRN = 0x0001, // the add printer wizard object is selected
|
|
SEL_SINGLE_PRINTER = 0x0002, // 1 printer is selected
|
|
SEL_SINGLE_LINK = 0x0004, // 1 link is selected
|
|
|
|
// any single selection type
|
|
SEL_SINGLE_ANY = SEL_SINGLE_ADDPRN | SEL_SINGLE_PRINTER | SEL_SINGLE_LINK,
|
|
|
|
// multi selection types
|
|
SEL_MULTI_PRINTER = 0x0010, // 2+ printers are selected
|
|
SEL_MULTI_LINK = 0x0020, // 2+ links are selected
|
|
SEL_MULTI_MIXED = 0x0040, // 2+ objects of any type are selected
|
|
|
|
// any link in the selection
|
|
SEL_LINK_ANY = SEL_SINGLE_LINK | SEL_MULTI_LINK | SEL_MULTI_MIXED,
|
|
|
|
// any printer in the selection
|
|
SEL_PRINTER_ANY = SEL_SINGLE_ADDPRN | SEL_SINGLE_ADDPRN |
|
|
SEL_MULTI_PRINTER | SEL_MULTI_MIXED,
|
|
|
|
// any multi selection type
|
|
SEL_MULTI_ANY = SEL_MULTI_PRINTER | SEL_MULTI_LINK | SEL_MULTI_MIXED,
|
|
|
|
// any selection type
|
|
SEL_ANY = SEL_SINGLE_ANY | SEL_MULTI_ANY,
|
|
};
|
|
|
|
// split the selection into its parts (printers and links) and determine the
|
|
// selection type (see the enum above)
|
|
HRESULT SplitSelection(IDataObject *pdo, UINT *puSelType, IDataObject **ppdoPrinters, IDataObject **ppdoLinks);
|
|
|
|
// webview verbs
|
|
enum WV_VERB
|
|
{
|
|
// standard verbs
|
|
WVIDM_DELETE,
|
|
WVIDM_RENAME,
|
|
WVIDM_PROPERTIES,
|
|
|
|
// common verbs
|
|
WVIDM_ADDPRINTERWIZARD,
|
|
WVIDM_SERVERPROPERTIES,
|
|
WVIDM_SETUPFAXING,
|
|
WVIDM_CREATELOCALFAX,
|
|
WVIDM_SENDFAXWIZARD,
|
|
|
|
// special common verbs
|
|
WVIDM_TROUBLESHOOTER,
|
|
WVIDM_GOTOSUPPORT,
|
|
|
|
// printer verbs
|
|
WVIDM_OPENPRN,
|
|
WVIDM_NETPRN_INSTALL,
|
|
WVIDM_SETDEFAULTPRN,
|
|
WVIDM_DOCUMENTDEFAULTS,
|
|
WVIDM_PAUSEPRN,
|
|
WVIDM_RESUMEPRN,
|
|
WVIDM_PURGEPRN,
|
|
WVIDM_SHARING,
|
|
WVIDM_WORKOFFLINE,
|
|
WVIDM_WORKONLINE,
|
|
|
|
// special commands
|
|
WVIDM_VENDORURL,
|
|
WVIDM_PRINTERURL,
|
|
|
|
WVIDM_COUNT,
|
|
};
|
|
|
|
// webview support - core APIs
|
|
HRESULT _WebviewVerbIsEnabled(WV_VERB eVerbID, UINT uSelMask, BOOL *pbEnabled);
|
|
HRESULT _WebviewVerbInvoke(WV_VERB eVerbID, IUnknown* pv, IShellItemArray *psiItemArray);
|
|
HRESULT _WebviewCheckToUpdateDataObjectCache(IDataObject *pdo);
|
|
|
|
private:
|
|
virtual ~CPrinterFolder();
|
|
|
|
// data access
|
|
LPCTSTR GetServer() { return _pszServer; }
|
|
HANDLE GetFolder() { CheckToRegisterNotify(); return _hFolder; }
|
|
BOOL GetAdminAccess() { CheckToRegisterNotify(); return _bAdminAccess; }
|
|
|
|
static LPCTSTR GetStatusString(PFOLDER_PRINTER_DATA pData, LPTSTR pBuff, UINT uSize);
|
|
static INT GetCompareDisplayName(LPCTSTR pName1, LPCTSTR pName2);
|
|
INT CompareData(LPCIDPRINTER pidp1, LPCIDPRINTER pidp2, LPARAM iCol);
|
|
static ReduceToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fPrintObjects);
|
|
DWORD SpoolerVersion();
|
|
void CheckToRegisterNotify();
|
|
void CheckToRefresh();
|
|
void RequestRefresh();
|
|
HRESULT _GetFullIDList(LPCWSTR pszPrinter, LPITEMIDLIST *ppidl);
|
|
static HRESULT _Parse(LPCWSTR pszPrinter, LPITEMIDLIST *ppidl, DWORD dwType = 0, USHORT uFlags = 0);
|
|
static void _FillPidl(LPIDPRINTER pidl, LPCTSTR szName, DWORD dwType = 0, USHORT uFlags = 0);
|
|
LPCTSTR _BuildPrinterName(LPTSTR pszFullPrinter, LPCIDPRINTER pidp, LPCTSTR pszPrinter);
|
|
void _MergeMenu(LPQCMINFO pqcm, LPCTSTR pszPrinter);
|
|
HRESULT _InvokeCommand(HWND hwnd, LPCIDPRINTER pidp, WPARAM wParam, LPARAM lParam, LPBOOL pfChooseNewDefault);
|
|
HRESULT _InvokeCommandRunAs(HWND hwnd, LPCIDPRINTER pidp, WPARAM wParam, LPARAM lParam, LPBOOL pfChooseNewDefault);
|
|
BOOL _PurgePrinter(HWND hwnd, LPCTSTR pszFullPrinter, UINT uAction, BOOL bQuietMode);
|
|
LPTSTR _FindIcon(LPCTSTR pszPrinterName, LPTSTR pszModule, ULONG cbModule, int *piIcon, int *piShortcutIcon);
|
|
static HRESULT CALLBACK _DFMCallBack(IShellFolder *psf, HWND hwnd,
|
|
IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
HRESULT _PrinterObjectsCallBack(HWND hwnd, UINT uSelType,
|
|
IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static LPTSTR _ItemName(LPCIDPRINTER pidp, LPTSTR pszName, UINT cch);
|
|
static BOOL _IsAddPrinter(LPCIDPRINTER pidp);
|
|
|
|
HRESULT _UpdateDataObjectCache();
|
|
HRESULT _AssocCreate(REFIID riid, void **ppv);
|
|
HRESULT _OnRefresh(BOOL bPriorRefresh);
|
|
|
|
LONG _cRef; // ref count
|
|
LPITEMIDLIST _pidl; // the PIDL of this folder
|
|
LPTSTR _pszServer; // the print server this folder is browsing (NULL means local PF)
|
|
DWORD _dwSpoolerVersion; // the spooler version
|
|
HANDLE _hFolder; // handle to the printer folder cache (in printui)
|
|
BOOL _bAdminAccess; // TRUE if you have admin access to this print server
|
|
BOOL _bReqRefresh; // whether we should request a full refresh during the next enum
|
|
|
|
|
|
// our webview get command state cache. we have 35+ commands and unpacking
|
|
// the same data object each time we need to verify the state of a command
|
|
// can be very expensive! we are going to maintain a cache with each command
|
|
// state and update the cache each time the data object gets changed, so
|
|
// the get state callbacks will finish very quickly just by consulting
|
|
// the cache.
|
|
|
|
IDataObject *_pdoCache; // current data object
|
|
UINT _uSelCurrent; // current selection type
|
|
BOOL _aWVCommandStates[WVIDM_COUNT]; // commands state cache
|
|
|
|
// the folder has to be MT safe
|
|
CCSLock _csLock;
|
|
|
|
// slow data. this members below should refresh every time the selection changes,
|
|
// but we should do this in a separate thread since updating them can take a while
|
|
|
|
enum ESlowWebviewDataType
|
|
{
|
|
WV_SLOW_DATA_OEM_SUPPORT_URL,
|
|
WV_SLOW_DATA_PRINTER_WEB_URL,
|
|
|
|
WV_SLOW_DATA_COUNT,
|
|
};
|
|
|
|
enum
|
|
{
|
|
// in miliseconds
|
|
WV_SLOW_DATA_CACHE_TIMEOUT = 5000,
|
|
};
|
|
|
|
class CSlowWVDataCacheEntry
|
|
{
|
|
public:
|
|
CSlowWVDataCacheEntry(CPrinterFolder *ppf):
|
|
_ppf(ppf),
|
|
_bDataPending(TRUE),
|
|
_nLastTimeUpdated(0)
|
|
{}
|
|
|
|
HRESULT Initialize(LPCTSTR pszPrinterName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (pszPrinterName)
|
|
{
|
|
_bstrPrinterName = pszPrinterName;
|
|
hr = _bstrPrinterName ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
CPrinterFolder *_ppf;
|
|
BOOL _bDataPending;
|
|
DWORD _nLastTimeUpdated;
|
|
CComBSTR _bstrPrinterName;
|
|
CComBSTR _arrData[WV_SLOW_DATA_COUNT];
|
|
};
|
|
|
|
static DWORD WINAPI _SlowWebviewData_WorkerProc(LPVOID lpParameter);
|
|
static HRESULT _SlowWVDataRetrieve(LPCTSTR pszPrinterName, BSTR *pbstrSupportUrl, BSTR *pbstrPrinterWebUrl);
|
|
static int _CompareSlowWVDataCacheEntries(CSlowWVDataCacheEntry *p1,
|
|
CSlowWVDataCacheEntry *p2, LPARAM lParam);
|
|
|
|
HRESULT _GetSelectedPrinter(BSTR *pbstrVal);
|
|
HRESULT _GetSlowWVDataForCurrentPrinter(ESlowWebviewDataType eType, BSTR *pbstrVal);
|
|
HRESULT _GetSlowWVData(LPCTSTR pszPrinterName, ESlowWebviewDataType eType, BSTR *pbstrVal);
|
|
HRESULT _UpdateSlowWVDataCacheEntry(CSlowWVDataCacheEntry *pCacheEntry);
|
|
HRESULT _SlowWVDataUpdateWebviewPane();
|
|
HRESULT _SlowWVDataCacheResetUnsafe();
|
|
HRESULT _GetCustomSupportURL(BSTR *pbstrVal);
|
|
|
|
CComBSTR _bstrSelectedPrinter;
|
|
CDPA<CSlowWVDataCacheEntry> _dpaSlowWVDataCache;
|
|
|
|
// fax support...
|
|
static HRESULT _GetFaxControl(IDispatch **ppDisp);
|
|
static HRESULT _GetFaxCommand(UINT_PTR *puCmd);
|
|
static HRESULT _InvokeFaxControlMethod(LPCTSTR pszMethodName);
|
|
static DWORD WINAPI _ThreadProc_InstallFaxService(LPVOID lpParameter);
|
|
static DWORD WINAPI _ThreadProc_InstallLocalFaxPrinter(LPVOID lpParameter);
|
|
};
|
|
|
|
STDAPI CPrinterFolderDropTarget_CreateInstance(HWND hwnd, IDropTarget **ppdropt);
|