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

6853 lines
228 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <initguid.h>
  4. #include <winprtp.h> // IID_IPrinterFolder & IID_IFolderNotify interfaces declared in windows\inc\winprtp.h
  5. #include <guids.h> // IID_IPrintersBindInfo
  6. #include "w32utils.h"
  7. #include "dpa.h"
  8. #include "idlcomm.h"
  9. #include "idldrop.h"
  10. #include "printer.h"
  11. #include "copy.h"
  12. #include "fstreex.h"
  13. #include "datautil.h"
  14. #include "infotip.h"
  15. #include "idldata.h"
  16. #include "ovrlaymn.h"
  17. #include "netview.h"
  18. #include "ids.h"
  19. #include "views.h"
  20. #include "basefvcb.h"
  21. #include "prnfldr.h"
  22. #include "shstr.h"
  23. #include "views.h"
  24. #include "defview.h"
  25. #include "prop.h"
  26. #undef PATH_SEPARATOR_STR
  27. #include "faxreg.h"
  28. #include "filetbl.h"
  29. #include "msprintx.h"
  30. #include "defcm.h"
  31. #include "enumidlist.h"
  32. #include "ole2dup.h"
  33. // FMTID_GroupByDetails - {FE9E4C12-AACB-4aa3-966D-91A29E6128B5}
  34. #define STR_FMTID_GroupByDetails TEXT("{FE9E4C12-AACB-4aa3-966D-91A29E6128B5}")
  35. DEFINE_GUID(FMTID_GroupByDetails, 0xfe9e4c12, 0xaacb, 0x4aa3, 0x96, 0x6d, 0x91, 0xa2, 0x9e, 0x61, 0x28, 0xb5);
  36. #define PSCID_GroupByDetails {0xfe9e4c12, 0xaacb, 0x4aa3, 0x96, 0x6d, 0x91, 0xa2, 0x9e, 0x61, 0x28, 0xb5}
  37. #define PID_PRN_NAME 0
  38. #define PID_PRN_QUEUESIZE 1
  39. #define PID_PRN_STATUS 2
  40. #define PID_PRN_COMMENT 3
  41. #define PID_PRN_LOCATION 4
  42. #define PID_PRN_MODEL 5
  43. DEFINE_SCID(SCID_PRN_QUEUESIZE, PSCID_GroupByDetails, PID_PRN_QUEUESIZE);
  44. DEFINE_SCID(SCID_PRN_STATUS, PSCID_GroupByDetails, PID_PRN_STATUS);
  45. DEFINE_SCID(SCID_PRN_LOCATION, PSCID_GroupByDetails, PID_PRN_LOCATION);
  46. DEFINE_SCID(SCID_PRN_MODEL, PSCID_GroupByDetails, PID_PRN_MODEL);
  47. // file system folder, CSIDL_PRINTHOOD for printer shortcuts
  48. IShellFolder2 *g_psfPrintHood = NULL;
  49. enum
  50. {
  51. PRINTERS_ICOL_NAME = 0,
  52. PRINTERS_ICOL_QUEUESIZE,
  53. PRINTERS_ICOL_STATUS,
  54. PRINTERS_ICOL_COMMENT,
  55. PRINTERS_ICOL_LOCATION,
  56. PRINTERS_ICOL_MODEL,
  57. };
  58. const COLUMN_INFO c_printers_cols[] =
  59. {
  60. DEFINE_COL_STR_ENTRY(SCID_NAME, 20, IDS_NAME_COL),
  61. DEFINE_COL_INT_ENTRY(SCID_PRN_QUEUESIZE, 12, IDS_PSD_QUEUESIZE),
  62. DEFINE_COL_STR_ENTRY(SCID_PRN_STATUS, 12, IDS_PRQ_STATUS),
  63. DEFINE_COL_STR_ENTRY(SCID_Comment, 30, IDS_EXCOL_COMMENT),
  64. DEFINE_COL_STR_ENTRY(SCID_PRN_LOCATION, 20, IDS_PSD_LOCATION),
  65. DEFINE_COL_STR_ENTRY(SCID_PRN_MODEL, 20, IDS_PSD_MODEL),
  66. };
  67. // converts ProgID or string representation of a GUID to a GUID.
  68. static HRESULT _GetClassIDFromString(LPCTSTR psz, LPCLSID pClsID)
  69. {
  70. HRESULT hr = E_FAIL;
  71. if (psz[0] == TEXT('{'))
  72. {
  73. hr = CLSIDFromString((LPOLESTR)T2COLE(psz), pClsID);
  74. }
  75. else
  76. {
  77. hr = CLSIDFromProgID(T2COLE(psz), pClsID);
  78. }
  79. return hr;
  80. }
  81. class CPrintersBindInfo: public IPrintersBindInfo
  82. {
  83. public:
  84. // construction/destruction
  85. CPrintersBindInfo();
  86. CPrintersBindInfo(DWORD dwType, BOOL bValidated, LPVOID pCookie = NULL);
  87. ~CPrintersBindInfo();
  88. //////////////////
  89. // IUnknown
  90. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  91. STDMETHODIMP_(ULONG) AddRef();
  92. STDMETHODIMP_(ULONG) Release();
  93. ///////////////////////
  94. // IPrintersBindInfo
  95. STDMETHODIMP SetPIDLType(DWORD dwType);
  96. STDMETHODIMP GetPIDLType(LPDWORD pdwType);
  97. STDMETHODIMP IsValidated();
  98. STDMETHODIMP SetCookie(LPVOID pCookie);
  99. STDMETHODIMP GetCookie(LPVOID *ppCookie);
  100. private:
  101. LONG m_cRef;
  102. DWORD m_dwType;
  103. BOOL m_bValidated;
  104. LPVOID m_pCookie;
  105. };
  106. // construction/destruction
  107. CPrintersBindInfo::CPrintersBindInfo()
  108. : m_cRef(1),
  109. m_dwType(0),
  110. m_bValidated(FALSE),
  111. m_pCookie(NULL)
  112. {
  113. }
  114. CPrintersBindInfo::CPrintersBindInfo(DWORD dwType, BOOL bValidated, LPVOID pCookie)
  115. : m_cRef(1),
  116. m_dwType(dwType),
  117. m_bValidated(bValidated),
  118. m_pCookie(pCookie)
  119. {
  120. }
  121. CPrintersBindInfo::~CPrintersBindInfo()
  122. {
  123. // nothing special to do here
  124. }
  125. /////////////////////////////////
  126. // IUnknown - standard impl.
  127. STDMETHODIMP CPrintersBindInfo::QueryInterface(REFIID riid, void **ppv)
  128. {
  129. static const QITAB qit[] =
  130. {
  131. QITABENT(CPrintersBindInfo, IPrintersBindInfo),
  132. { 0 },
  133. };
  134. return QISearch(this, qit, riid, ppv);
  135. }
  136. STDMETHODIMP_(ULONG) CPrintersBindInfo::AddRef()
  137. {
  138. return InterlockedIncrement(&m_cRef);
  139. }
  140. STDMETHODIMP_(ULONG) CPrintersBindInfo::Release()
  141. {
  142. ULONG cRefs = InterlockedDecrement(&m_cRef);
  143. if (0 == cRefs)
  144. {
  145. delete this;
  146. }
  147. return cRefs;
  148. }
  149. ///////////////////////
  150. // IPrintersBindInfo
  151. STDMETHODIMP CPrintersBindInfo::SetPIDLType(DWORD dwType)
  152. {
  153. m_dwType = dwType;
  154. return S_OK;
  155. }
  156. STDMETHODIMP CPrintersBindInfo::GetPIDLType(LPDWORD pdwType)
  157. {
  158. HRESULT hr = E_INVALIDARG;
  159. if (pdwType)
  160. {
  161. *pdwType = m_dwType;
  162. hr = S_OK;
  163. }
  164. return hr;
  165. }
  166. STDMETHODIMP CPrintersBindInfo::IsValidated()
  167. {
  168. return m_bValidated ? S_OK : S_FALSE;
  169. }
  170. STDMETHODIMP CPrintersBindInfo::SetCookie(LPVOID pCookie)
  171. {
  172. m_pCookie = pCookie;
  173. return S_OK;
  174. }
  175. STDMETHODIMP CPrintersBindInfo::GetCookie(LPVOID *ppCookie)
  176. {
  177. HRESULT hr = E_INVALIDARG;
  178. if (ppCookie)
  179. {
  180. *ppCookie = m_pCookie;
  181. hr = S_OK;
  182. }
  183. return hr;
  184. }
  185. STDAPI Printers_CreateBindInfo(LPCTSTR pszPrinter, DWORD dwType, BOOL bValidated, LPVOID pCookie, IPrintersBindInfo **ppbc)
  186. {
  187. HRESULT hr = E_INVALIDARG;
  188. if (ppbc)
  189. {
  190. *ppbc = NULL;
  191. CPrintersBindInfo *pObj = new CPrintersBindInfo(dwType, bValidated, pCookie);
  192. hr = pObj ? pObj->QueryInterface(IID_PPV_ARG(IPrintersBindInfo, ppbc)) : E_OUTOFMEMORY;
  193. if (pObj)
  194. {
  195. pObj->Release();
  196. }
  197. }
  198. return hr;
  199. }
  200. #define PRINTER_HACK_WORK_OFFLINE 0x80000000
  201. // {EAE0A5E1-CE32-4296-9A44-9F0C069F73D4}
  202. DEFINE_GUID(SID_SAuxDataObject, 0xeae0a5e1, 0xce32, 0x4296, 0x9a, 0x44, 0x9f, 0xc, 0x6, 0x9f, 0x73, 0xd4);
  203. class CPrintersData: public CIDLDataObj,
  204. public IServiceProvider
  205. {
  206. public:
  207. CPrintersData(IDataObject *pdoAux, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[]):
  208. _pdoAux(pdoAux), CIDLDataObj(pidlFolder, cidl, apidl)
  209. {
  210. if (_pdoAux)
  211. _pdoAux->AddRef();
  212. }
  213. ~CPrintersData()
  214. {
  215. IUnknown_SafeReleaseAndNullPtr(_pdoAux);
  216. }
  217. // IUnknown
  218. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  219. STDMETHODIMP_(ULONG) AddRef(void) { return CIDLDataObj::AddRef(); }
  220. STDMETHODIMP_(ULONG) Release(void) { return CIDLDataObj::Release(); }
  221. // IDataObject
  222. STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  223. STDMETHODIMP QueryGetData(FORMATETC *pFmtEtc);
  224. // IServiceProvider
  225. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
  226. private:
  227. // auxiliary data object. we are going to use this data object to store the
  228. // selected printhood objects since they are in a different folder which is
  229. // a file system folder and their PIDLs don't have the printers folder as
  230. // parent. This is a limitation of the IDL array clipboard format -- it can
  231. // hold only PIDLs that have the same parent folder. the zero PIDL is the
  232. // PIDL of the parent folder and then we have the array of relative PIDLs
  233. // of the selected objects (childs).
  234. IDataObject *_pdoAux;
  235. };
  236. UINT Printer_BitsToString(DWORD bits, UINT idsSep, LPTSTR lpszBuf, UINT cchMax);
  237. #define PRINTERS_EVENTS \
  238. SHCNE_UPDATEITEM | \
  239. SHCNE_DELETE | \
  240. SHCNE_RENAMEITEM | \
  241. SHCNE_ATTRIBUTES | \
  242. SHCNE_CREATE
  243. class CPrinterFolderViewCB : public CBaseShellFolderViewCB
  244. {
  245. public:
  246. CPrinterFolderViewCB(CPrinterFolder *ppf, LPCITEMIDLIST pidl)
  247. : CBaseShellFolderViewCB(pidl, PRINTERS_EVENTS), _ppf(ppf)
  248. {
  249. _ppf->AddRef();
  250. }
  251. // IShellFolderViewCB
  252. STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  253. // IServiceProvider
  254. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
  255. private:
  256. ~CPrinterFolderViewCB()
  257. {
  258. _ppf->Release();
  259. }
  260. HRESULT OnINVOKECOMMAND(DWORD pv, UINT wP)
  261. {
  262. return _ppf->CallBack(_ppf, _hwndMain, NULL, DFM_INVOKECOMMAND, wP, 0);
  263. }
  264. HRESULT OnGETHELPTEXT(DWORD pv, UINT id, UINT cch, LPTSTR lP)
  265. {
  266. #ifdef UNICODE
  267. return _ppf->CallBack(_ppf, _hwndMain, NULL, DFM_GETHELPTEXTW, MAKEWPARAM(id, cch), (LPARAM)lP);
  268. #else
  269. return _ppf->CallBack(_ppf, _hwndMain, NULL, DFM_GETHELPTEXT, MAKEWPARAM(id, cch), (LPARAM)lP);
  270. #endif
  271. }
  272. HRESULT OnBACKGROUNDENUM(DWORD pv)
  273. {
  274. return _ppf->GetServer() ? S_OK : E_FAIL;
  275. }
  276. HRESULT OnREFRESH(DWORD pv, UINT wP)
  277. {
  278. HRESULT hr = S_OK;
  279. if (wP)
  280. {
  281. // start the net crawler
  282. RefreshNetCrawler();
  283. }
  284. if (_ppf)
  285. {
  286. // delegate to the folder
  287. hr = _ppf->_OnRefresh(static_cast<BOOL>(wP));
  288. }
  289. else
  290. {
  291. hr = E_UNEXPECTED;
  292. }
  293. return hr;
  294. }
  295. HRESULT OnGETHELPTOPIC(DWORD pv, SFVM_HELPTOPIC_DATA * phtd)
  296. {
  297. lstrcpynW(phtd->wszHelpTopic,
  298. L"hcp://services/layout/xml?definition=MS-ITS%3A%25HELP_LOCATION%25%5Cntdef.chm%3A%3A/Printers_and_Faxes.xml",
  299. ARRAYSIZE(phtd->wszHelpTopic));
  300. return S_OK;
  301. }
  302. HRESULT OnDELAYWINDOWCREATE(DWORD pv, HWND hwnd)
  303. {
  304. RefreshNetCrawler(); // start the net crawler
  305. return S_OK;
  306. }
  307. // by default we want tiles, grouped by location
  308. HRESULT OnDEFERRED_VIEW_SETTING(DWORD pv, SFVM_DEFERRED_VIEW_SETTINGS *pdvs)
  309. {
  310. pdvs->fvm = FVM_TILE;
  311. pdvs->fGroupView = FALSE;
  312. pdvs->uSortCol = PRINTERS_ICOL_NAME;
  313. pdvs->iSortDirection = 1; // ascending
  314. return S_OK;
  315. }
  316. // DUI webview commands
  317. HRESULT OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  318. {
  319. return _ppf ? _ppf->GetWebViewLayout(
  320. static_cast<IServiceProvider*>(this), uViewMode, pData) : E_UNEXPECTED;
  321. }
  322. HRESULT OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData)
  323. {
  324. return _ppf ? _ppf->GetWebViewContent(
  325. static_cast<IServiceProvider*>(this), pData) : E_UNEXPECTED;
  326. }
  327. HRESULT OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks)
  328. {
  329. return _ppf ? _ppf->GetWebViewTasks(
  330. static_cast<IServiceProvider*>(this), pTasks) : E_UNEXPECTED;
  331. }
  332. CPrinterFolder *_ppf;
  333. };
  334. class CPrinterDropTarget : public CIDLDropTarget
  335. {
  336. friend HRESULT CPrinterDropTarget_CreateInstance(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt);
  337. public:
  338. CPrinterDropTarget(HWND hwnd) : CIDLDropTarget(hwnd) { };
  339. // IDropTarget methods overwirte
  340. STDMETHODIMP DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  341. STDMETHODIMP Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  342. private:
  343. STDMETHODIMP _DropCallback(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect, LPTHREAD_START_ROUTINE pfn);
  344. };
  345. LPCTSTR GetPrinterName(PFOLDER_PRINTER_DATA pPrinter, UINT Index)
  346. {
  347. return ((PFOLDER_PRINTER_DATA)(((PBYTE)pPrinter)+pPrinter->cbSize*Index))->pName;
  348. }
  349. IShellFolder2* CPrintRoot_GetPSF()
  350. {
  351. SHCacheTrackingFolder(MAKEINTIDLIST(CSIDL_PRINTERS), CSIDL_PRINTHOOD | CSIDL_FLAG_CREATE, &g_psfPrintHood);
  352. return g_psfPrintHood;
  353. }
  354. typedef enum
  355. {
  356. HOOD_COL_PRINTER = 0,
  357. HOOD_COL_FILE = 1
  358. } PIDLTYPE ;
  359. PIDLTYPE _IDListType(LPCITEMIDLIST pidl)
  360. {
  361. LPCIDPRINTER pidlprint = (LPCIDPRINTER) pidl;
  362. if (pidlprint->cb >= sizeof(DWORD) + FIELD_OFFSET(IDPRINTER, dwMagic) &&
  363. pidlprint->dwMagic == PRINTER_MAGIC)
  364. {
  365. return HOOD_COL_PRINTER;
  366. }
  367. else
  368. {
  369. // This HACK is a little ugly but have to do it, in order to support
  370. // the legacy Win9x printer shortcuts under Win2k.
  371. //
  372. // Details: If the PRINTER_MAGIC field check fails it might still
  373. // be a valid Win9x PIDL. The only reliable way I can think of
  374. // to determine whether this is the case is to check if pidlprint->cb
  375. // points inside a W95IDPRINTER structure and also to check whether
  376. // the name is tighten up to the PIDL size.
  377. LPW95IDPRINTER pidlprint95 = (LPW95IDPRINTER)pidl;
  378. int nPIDLSize = sizeof(pidlprint95->cb) + lstrlenA(pidlprint95->cName) + 1;
  379. if (nPIDLSize < sizeof(W95IDPRINTER) && // Must be inside W95IDPRINTER
  380. pidlprint95->cb == nPIDLSize) // The PIDL size must match the ANSI name
  381. {
  382. // Well it might be a Win95 printer PIDL.
  383. return HOOD_COL_PRINTER;
  384. }
  385. else
  386. {
  387. // This PIDL is not a valid printer PIDL.
  388. return HOOD_COL_FILE;
  389. }
  390. }
  391. }
  392. /*++
  393. Inserts a backslash before each double quote in a string and saves the new string in a pre-allocated memory.
  394. For all the backslash immediately before the double, we will insert additional backslashes.
  395. This is mostly used by passing a command line between processes.
  396. The rule is the same as rundll32.
  397. Rules: each double quote ==> backslash + double quote
  398. N backslashes + double quote ==> 2N + 1 backslashes + double quote
  399. N backslashes ==> N backslashes
  400. Arguments:
  401. pszSrc -- [IN] source string
  402. pszDest -- [IN] destination string
  403. cbBuf -- [IN] size of the buffer for the destination string.
  404. pcbNeeded -- [OUT] the size of the buffer needed for destination string. If cbBuf is less than this value,
  405. this function will return E_OUTOFMEMORY.
  406. Return:
  407. standard HRESULT value.
  408. --*/
  409. HRESULT CheckAndVerboseQuote(LPTSTR pszSrc, LPTSTR pszDest, DWORD cbBuf, LPDWORD pcbNeeded)
  410. {
  411. LPTSTR pBegin;
  412. LPTSTR pBack; // for back tracing '\\' when we meet a '\"'
  413. UINT cAdd = 0;
  414. TCHAR const cchQuote = TEXT('\"');
  415. TCHAR const cchSlash = TEXT('\\');
  416. HRESULT hr = E_INVALIDARG;
  417. if (pszSrc && pcbNeeded)
  418. {
  419. hr = S_OK;
  420. pBegin = pszSrc;
  421. while (*pBegin)
  422. {
  423. // check whether the buffer is large enough
  424. if (*pBegin == cchQuote)
  425. {
  426. // check if the case is N backslashes + double quote
  427. // for each backslash before double quote, we add an additional backslash
  428. pBack = pBegin - 1;
  429. // make sure pBack will not be out of bound
  430. while (pBack >= pszSrc && *pBack-- == cchSlash)
  431. {
  432. cAdd++;
  433. }
  434. // for each double quote, we change it to backslash + double quote
  435. cAdd++;
  436. }
  437. pBegin++;
  438. }
  439. *pcbNeeded = (lstrlen(pszSrc) + cAdd + 1) * sizeof(TCHAR);
  440. if (*pcbNeeded > cbBuf)
  441. {
  442. hr = E_OUTOFMEMORY;
  443. }
  444. if (SUCCEEDED(hr))
  445. {
  446. // do the copy and verbose work
  447. pBegin = pszSrc;
  448. while (*pBegin)
  449. {
  450. if (*pBegin == cchQuote)
  451. {
  452. pBack = pBegin - 1;
  453. while (pBack >= pszSrc && *pBack-- == cchSlash)
  454. {
  455. *pszDest++ = cchSlash;
  456. }
  457. *pszDest++ = cchSlash;
  458. }
  459. *pszDest++ = *pBegin++;
  460. }
  461. *pszDest = 0;
  462. }
  463. }
  464. return hr;
  465. }
  466. /*++
  467. Inserts a backslash before each double quote in a string and allocates memory to save the new string.
  468. For all the backslash immediately before the double, we will insert additional backslashes.
  469. This is mostly used by passing a command line between processes.
  470. Arguments:
  471. pszSrc -- [IN] source string
  472. ppszDest -- [OUT] destination string
  473. Return:
  474. standard HRESULT value.
  475. Note: CheckAndVerboseQuote() does the real work.
  476. --*/
  477. HRESULT InsertBackSlash(LPTSTR pszSrc, LPTSTR *ppszDest)
  478. {
  479. LPTSTR pszDest;
  480. DWORD cbNeeded = 0;
  481. HRESULT hr = E_INVALIDARG;
  482. if (pszSrc && ppszDest)
  483. {
  484. hr = CheckAndVerboseQuote(pszSrc, NULL, 0, &cbNeeded);
  485. if (hr == E_OUTOFMEMORY && cbNeeded)
  486. {
  487. pszDest = (LPTSTR)SHAlloc(cbNeeded);
  488. if (pszDest)
  489. {
  490. hr = CheckAndVerboseQuote(pszSrc, pszDest, cbNeeded, &cbNeeded);
  491. if (SUCCEEDED(hr))
  492. {
  493. *ppszDest = pszDest;
  494. }
  495. else
  496. {
  497. SHFree(pszDest);
  498. }
  499. }
  500. else
  501. {
  502. hr = E_OUTOFMEMORY;
  503. }
  504. }
  505. }
  506. return hr;
  507. }
  508. /* Registers a modeless, non-top level window with the shell. When
  509. the user requests a window, we search for other instances of that
  510. window. If we find one, we switch to it rather than creating
  511. a new window.
  512. This function is used by PRINTUI.DLL
  513. pszPrinter - Name of the printer resource. Generally a fully
  514. qualified printer name (\\server\printer for remote print
  515. folders) or a server name for the folder itself.
  516. dwType - Type of property window. May refer to properties, document
  517. defaults, or job details. Should use the PRINTER_PIDL_TYPE_*
  518. flags.
  519. ph - Receives the newly created handle to the registered
  520. object. NULL if window already exists.
  521. phwnd - Receives the newly created hwndStub. The property sheet
  522. should use this as the parent, since subsequent calls to
  523. this function will set focus to the last active popup of
  524. hwndStub. phwnd will be set to NULL if the window already
  525. exists.
  526. TRUE - Success, either the printer was registered, or a window
  527. already exists.
  528. */
  529. STDAPI_(BOOL) Printers_RegisterWindow(LPCTSTR pszPrinter, DWORD dwType, HANDLE *ph, HWND *phwnd)
  530. {
  531. BOOL bReturn = FALSE;
  532. *ph = NULL;
  533. *phwnd = NULL;
  534. LPITEMIDLIST pidl = NULL;
  535. if (NULL == pszPrinter || 0 == pszPrinter[0])
  536. {
  537. // they ask us to register the local print server - i.e. server properties dialog
  538. pidl = SHCloneSpecialIDList(NULL, CSIDL_PRINTERS, FALSE);
  539. bReturn = (pidl != NULL);
  540. }
  541. else
  542. {
  543. bReturn = SUCCEEDED(ParsePrinterNameEx(pszPrinter, &pidl, TRUE, dwType, 0));
  544. }
  545. if (bReturn && pidl)
  546. {
  547. UNIQUESTUBINFO *pusi = (UNIQUESTUBINFO *)LocalAlloc(LPTR, sizeof(*pusi));
  548. if (pusi)
  549. {
  550. // Create a new stub window if necessary.
  551. if (EnsureUniqueStub(pidl, STUBCLASS_PROPSHEET, NULL, pusi))
  552. {
  553. *phwnd = pusi->hwndStub;
  554. *ph = pusi; // it's just a cookie
  555. }
  556. else
  557. {
  558. LocalFree(pusi);
  559. }
  560. }
  561. ILFree(pidl);
  562. }
  563. return bReturn;
  564. }
  565. /* Unregister a window handle.
  566. hClassPidl - Registration handle returned from Printers_RegisterWindow.
  567. It's really a pointer to a UNIQUESTUBINFO structure.
  568. */
  569. void Printers_UnregisterWindow(HANDLE hClassPidl, HWND hwnd)
  570. {
  571. UNIQUESTUBINFO* pusi = (UNIQUESTUBINFO*)hClassPidl;
  572. if (pusi)
  573. {
  574. ASSERT(pusi->hwndStub == hwnd);
  575. FreeUniqueStub(pusi);
  576. LocalFree(pusi);
  577. }
  578. }
  579. void CPrinterFolder::_FillPidl(LPIDPRINTER pidl, LPCTSTR pszName, DWORD dwType, USHORT uFlags)
  580. {
  581. ualstrcpyn(pidl->cName, pszName, ARRAYSIZE(pidl->cName));
  582. pidl->cb = (USHORT)(FIELD_OFFSET(IDPRINTER, cName) + (ualstrlen(pidl->cName) + 1) * sizeof(pidl->cName[0]));
  583. *(UNALIGNED USHORT *)((LPBYTE)(pidl) + pidl->cb) = 0;
  584. pidl->uFlags = uFlags;
  585. pidl->dwType = dwType;
  586. pidl->dwMagic = PRINTER_MAGIC;
  587. }
  588. // creates a relative PIDL to a printer.
  589. HRESULT CPrinterFolder::_Parse(LPCTSTR pszPrinterName, LPITEMIDLIST *ppidl, DWORD dwType, USHORT uFlags)
  590. {
  591. HRESULT hr = E_INVALIDARG;
  592. if (pszPrinterName && ppidl)
  593. {
  594. IDPRINTER idp;
  595. _FillPidl(&idp, pszPrinterName, dwType, uFlags);
  596. *ppidl = ILClone((LPCITEMIDLIST)&idp);
  597. hr = (*ppidl) ? S_OK : E_OUTOFMEMORY;
  598. }
  599. return hr;
  600. }
  601. TCHAR const c_szNewObject[] = TEXT("WinUtils_NewObject");
  602. TCHAR const c_szFileColon[] = TEXT("FILE:");
  603. TCHAR const c_szTwoSlashes[] = TEXT("\\\\");
  604. TCHAR const c_szPrinters[] = TEXT("Printers");
  605. TCHAR const c_szPrintersDefIcon[] = TEXT("Printers\\%s\\DefaultIcon");
  606. TCHAR const c_szNewLine[] = TEXT("\r\n");
  607. BOOL IsAvoidAutoDefaultPrinter(LPCTSTR pszPrinter)
  608. {
  609. return lstrcmp(pszPrinter, TEXT("Fax")) == 0;
  610. }
  611. //---------------------------------------------------------------------------
  612. //
  613. // this implements IContextMenu via defcm.c for a printer object
  614. //
  615. BOOL Printer_WorkOnLine(LPCTSTR pszPrinter, BOOL fWorkOnLine)
  616. {
  617. LPPRINTER_INFO_5 ppi5;
  618. BOOL bRet = FALSE;
  619. HANDLE hPrinter = Printer_OpenPrinterAdmin(pszPrinter);
  620. if (hPrinter)
  621. {
  622. ppi5 = (LPPRINTER_INFO_5)Printer_GetPrinterInfo(hPrinter, 5);
  623. if (ppi5)
  624. {
  625. if (fWorkOnLine)
  626. ppi5->Attributes &= ~PRINTER_ATTRIBUTE_WORK_OFFLINE;
  627. else
  628. ppi5->Attributes |= PRINTER_ATTRIBUTE_WORK_OFFLINE;
  629. bRet = SetPrinter(hPrinter, 5, (LPBYTE)ppi5, 0);
  630. LocalFree((HLOCAL)ppi5);
  631. }
  632. Printer_ClosePrinter(hPrinter);
  633. }
  634. return bRet;
  635. }
  636. TCHAR const c_szConfig[] = TEXT("Config");
  637. BOOL IsWinIniDefaultPrinter(LPCTSTR pszPrinter)
  638. {
  639. BOOL bRet = FALSE;
  640. TCHAR szPrinterDefault[kPrinterBufMax];
  641. DWORD dwSize = ARRAYSIZE(szPrinterDefault);
  642. if(GetDefaultPrinter(szPrinterDefault, &dwSize))
  643. {
  644. bRet = lstrcmpi(szPrinterDefault, pszPrinter) == 0;
  645. }
  646. return bRet;
  647. }
  648. BOOL IsDefaultPrinter(LPCTSTR pszPrinter, DWORD dwAttributesHint)
  649. {
  650. return (dwAttributesHint & PRINTER_ATTRIBUTE_DEFAULT) ||
  651. IsWinIniDefaultPrinter(pszPrinter);
  652. }
  653. // more win.ini uglyness
  654. BOOL IsPrinterInstalled(LPCTSTR pszPrinter)
  655. {
  656. TCHAR szScratch[2];
  657. return GetProfileString(TEXT("Devices"), pszPrinter, TEXT(""), szScratch, ARRAYSIZE(szScratch));
  658. }
  659. BOOL IsRedirectedPort(LPCTSTR pszPortName)
  660. {
  661. if (!pszPortName || lstrlen(pszPortName) < 2)
  662. {
  663. return FALSE;
  664. }
  665. else
  666. {
  667. return (*(pszPortName+0) == TEXT('\\')) && (*(pszPortName+1) == TEXT('\\'));
  668. }
  669. }
  670. void CPrinterFolder::_MergeMenu(LPQCMINFO pqcm, LPCTSTR pszPrinter)
  671. {
  672. INT idCmdFirst = pqcm->idCmdFirst;
  673. //
  674. // pszPrinter may be the share name of a printer rather than
  675. // the "real" printer name. Use the real printer name instead,
  676. // which is returned from GetPrinter().
  677. //
  678. // These three only valid if pData != NULL.
  679. //
  680. LPCTSTR pszRealPrinterName;
  681. DWORD dwAttributes;
  682. DWORD dwStatus;
  683. PFOLDER_PRINTER_DATA pData = NULL;
  684. HMENU hmenuRunAs = NULL;
  685. BOOL bRemoveOffline = FALSE;
  686. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  687. TCHAR szMenuText[255];
  688. // Insert verbs
  689. CDefFolderMenu_MergeMenu(HINST_THISDLL, MENU_PRINTOBJ_VERBS, 0, pqcm);
  690. // find the "Run as..." menu (if there is one) and update it in sync
  691. // with the main menu.
  692. MENUITEMINFO mii = {0};
  693. mii.cbSize = sizeof(mii);
  694. mii.fMask = MIIM_SUBMENU;
  695. if (GetMenuItemInfo(pqcm->hmenu, idCmdFirst + FSIDM_RUNAS, MF_BYCOMMAND, &mii))
  696. {
  697. hmenuRunAs = mii.hSubMenu;
  698. }
  699. if (pszPrinter && GetFolder())
  700. {
  701. pData = (PFOLDER_PRINTER_DATA)Printer_FolderGetPrinter(GetFolder(), pszPrinter);
  702. if (pData)
  703. {
  704. _BuildPrinterName(szFullPrinter, NULL, ((PFOLDER_PRINTER_DATA)pData)->pName);
  705. pszRealPrinterName = szFullPrinter;
  706. dwStatus = ((PFOLDER_PRINTER_DATA)pData)->Status;
  707. dwAttributes = ((PFOLDER_PRINTER_DATA)pData)->Attributes;
  708. }
  709. }
  710. // Remove document defaults if it's a remote print folder.
  711. // This command should be removed from the context menu independently
  712. // on whether we have mutiple selection or not - i.e. pData.
  713. if (GetServer())
  714. {
  715. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_DOCUMENTDEFAULTS, MF_BYCOMMAND);
  716. }
  717. // disable/remove/rename verbs
  718. if (pData)
  719. {
  720. if (dwStatus & PRINTER_STATUS_PAUSED)
  721. {
  722. MENUITEMINFO mii;
  723. // we need to change the menu text to "Resume Printer" anc change the command ID
  724. LoadString(HINST_THISDLL, IDS_RESUMEPRINTER, szMenuText, ARRAYSIZE(szMenuText));
  725. mii.cbSize = sizeof(MENUITEMINFO);
  726. mii.fMask = MIIM_STRING | MIIM_ID;
  727. mii.dwTypeData = szMenuText;
  728. mii.wID = idCmdFirst + FSIDM_RESUMEPRN;
  729. SetMenuItemInfo(pqcm->hmenu, idCmdFirst + FSIDM_PAUSEPRN, MF_BYCOMMAND, &mii);
  730. if (hmenuRunAs)
  731. {
  732. mii.wID = idCmdFirst + FSIDM_RUNAS_RESUMEPRN;
  733. SetMenuItemInfo(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_PAUSEPRN, MF_BYCOMMAND, &mii);
  734. }
  735. }
  736. if (0 == pData->cJobs)
  737. {
  738. // delete "Cancel All Documents" command if there are no any jobs in the queue
  739. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_PURGEPRN, MF_BYCOMMAND);
  740. if (hmenuRunAs)
  741. {
  742. DeleteMenu(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_PURGEPRN, MF_BYCOMMAND);
  743. }
  744. }
  745. // Remove default printer if it's a remote print folder.
  746. if (GetServer() || IsDefaultPrinter(pszRealPrinterName, dwAttributes))
  747. {
  748. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_SETDEFAULTPRN, MF_BYCOMMAND);
  749. }
  750. // Check whether the printer is already installed. If it
  751. // is, remove the option to install it.
  752. if (IsPrinterInstalled(pszRealPrinterName))
  753. {
  754. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_NETPRN_INSTALL, MF_BYCOMMAND);
  755. }
  756. // Remove Delete if it is a network printer but not a masq printer
  757. // or a down level print server (SMB connection)
  758. //
  759. // can't delete printer connections as another user (they are per user)
  760. DWORD dwSpoolerVersion = SpoolerVersion();
  761. if ((dwAttributes & PRINTER_ATTRIBUTE_NETWORK) || (dwSpoolerVersion <= 2))
  762. {
  763. if (hmenuRunAs && !(dwAttributes & PRINTER_ATTRIBUTE_LOCAL))
  764. {
  765. DeleteMenu(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_DELETE, MF_BYCOMMAND);
  766. }
  767. }
  768. // Remove work on/off-line if any of the following is met
  769. // - remote print folder
  770. // - network printer (including masq printer)
  771. // - down level print server
  772. // Remove work offline if it's a redirected port printer
  773. // But we may show online command if a the printer is currently offline
  774. if (IsRedirectedPort(pData->pPortName))
  775. {
  776. bRemoveOffline = TRUE;
  777. }
  778. if (GetServer() ||
  779. (dwAttributes & PRINTER_ATTRIBUTE_NETWORK) ||
  780. (dwSpoolerVersion <= 2))
  781. {
  782. bRemoveOffline = TRUE;
  783. }
  784. else if (dwAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE)
  785. {
  786. MENUITEMINFO mii;
  787. // we need to change the menu text to "Use Printer Online" anc change the command ID
  788. LoadString(HINST_THISDLL, IDS_WORKONLINE, szMenuText, ARRAYSIZE(szMenuText));
  789. mii.cbSize = sizeof(MENUITEMINFO);
  790. mii.fMask = MIIM_STRING | MIIM_ID;
  791. mii.dwTypeData = szMenuText;
  792. mii.wID = idCmdFirst + FSIDM_WORKONLINE;
  793. SetMenuItemInfo(pqcm->hmenu, idCmdFirst + FSIDM_WORKOFFLINE, MF_BYCOMMAND, &mii);
  794. if (hmenuRunAs)
  795. {
  796. mii.wID = idCmdFirst + FSIDM_RUNAS_WORKONLINE;
  797. SetMenuItemInfo(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_WORKOFFLINE, MF_BYCOMMAND, &mii);
  798. }
  799. bRemoveOffline = FALSE;
  800. }
  801. }
  802. else
  803. {
  804. // we have multiple printers selected
  805. if (!GetServer())
  806. {
  807. // if we are in the local printer's folder, do not display the "Connect..."
  808. // verb for the multiple selection case...
  809. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_NETPRN_INSTALL, MF_BYCOMMAND);
  810. }
  811. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_SETDEFAULTPRN, MF_BYCOMMAND);
  812. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_PAUSEPRN, MF_BYCOMMAND);
  813. if (hmenuRunAs)
  814. {
  815. DeleteMenu(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_PAUSEPRN, MF_BYCOMMAND);
  816. }
  817. bRemoveOffline = TRUE;
  818. }
  819. if (bRemoveOffline)
  820. {
  821. DeleteMenu(pqcm->hmenu, idCmdFirst + FSIDM_WORKOFFLINE, MF_BYCOMMAND);
  822. if (hmenuRunAs)
  823. {
  824. DeleteMenu(hmenuRunAs, idCmdFirst + FSIDM_RUNAS_WORKOFFLINE, MF_BYCOMMAND);
  825. }
  826. }
  827. if (hmenuRunAs)
  828. {
  829. _SHPrettyMenu(hmenuRunAs);
  830. }
  831. if (pData)
  832. {
  833. LocalFree((HLOCAL)pData);
  834. }
  835. }
  836. //
  837. // All string parsing functions should be localized here.
  838. //
  839. void Printer_SplitFullName(LPTSTR pszScratch, LPCTSTR pszFullName, LPCTSTR *ppszServer, LPCTSTR *ppszPrinter)
  840. /*++
  841. Splits a fully qualified printer connection name into server and
  842. printer name parts.
  843. Arguments:
  844. pszScratch - Scratch buffer used to store output strings. Must
  845. be MAXNAMELENBUFFER in size.
  846. pszFullName - Input name of a printer. If it is a printer
  847. connection (\\server\printer), then we will split it. If
  848. it is a true local printer (not a masq) then the server is
  849. szNULL.
  850. ppszServer - Receives pointer to the server string. If it is a
  851. local printer, szNULL is returned.
  852. ppszPrinter - Receives a pointer to the printer string. OPTIONAL
  853. Return Value:
  854. --*/
  855. {
  856. LPTSTR pszPrinter;
  857. lstrcpyn(pszScratch, pszFullName, MAXNAMELENBUFFER);
  858. if (pszFullName[0] != TEXT('\\') || pszFullName[1] != TEXT('\\'))
  859. {
  860. //
  861. // Set *ppszServer to szNULL since it's the local machine.
  862. //
  863. *ppszServer = szNULL;
  864. pszPrinter = pszScratch;
  865. }
  866. else
  867. {
  868. *ppszServer = pszScratch;
  869. pszPrinter = StrChr(*ppszServer + 2, TEXT('\\'));
  870. if (!pszPrinter)
  871. {
  872. //
  873. // We've encountered a printer called "\\server"
  874. // (only two backslashes in the string). We'll treat
  875. // it as a local printer. We should never hit this,
  876. // but the spooler doesn't enforce this. We won't
  877. // format the string. Server is local, so set to szNULL.
  878. //
  879. pszPrinter = pszScratch;
  880. *ppszServer = szNULL;
  881. }
  882. else
  883. {
  884. //
  885. // We found the third backslash; null terminate our
  886. // copy and set bRemote TRUE to format the string.
  887. //
  888. *pszPrinter++ = 0;
  889. }
  890. }
  891. if (ppszPrinter)
  892. {
  893. *ppszPrinter = pszPrinter;
  894. }
  895. }
  896. BOOL Printer_CheckShowFolder(LPCTSTR pszMachine)
  897. {
  898. HANDLE hServer = Printer_OpenPrinter(pszMachine);
  899. if (hServer)
  900. {
  901. Printer_ClosePrinter(hServer);
  902. return TRUE;
  903. }
  904. return FALSE;
  905. }
  906. //
  907. // Routine to tack on the specified string with some formating
  908. // to the existing infotip string. If there was a previous string,
  909. // then we also insert a newline.
  910. //
  911. HRESULT _FormatInfoTip(LPTSTR *ppszText, UINT idFmt, LPCTSTR pszBuf)
  912. {
  913. // If no string was returned, then nothing to do, and we should
  914. // return success
  915. if (*pszBuf)
  916. {
  917. TCHAR szFmt[MAX_PATH];
  918. LoadString(HINST_THISDLL, idFmt, szFmt, ARRAYSIZE(szFmt));
  919. // Note: This calculation only works because we assume
  920. // all the format strings will contain string specifiers.
  921. UINT uLen = (*ppszText ? lstrlen(*ppszText) : 0) +
  922. lstrlen(szFmt) + lstrlen(pszBuf) +
  923. (*ppszText ? lstrlen(c_szNewLine) : 0) + 1;
  924. LPTSTR pszText = (TCHAR *)SHAlloc(uLen * sizeof(*pszText));
  925. if (pszText)
  926. {
  927. *pszText = 0;
  928. if (*ppszText)
  929. {
  930. lstrcat(pszText, *ppszText);
  931. lstrcat(pszText, c_szNewLine);
  932. }
  933. uLen = lstrlen(pszText);
  934. wsprintf(pszText+uLen, szFmt, pszBuf);
  935. if (*ppszText)
  936. SHFree(*ppszText);
  937. *ppszText = pszText;
  938. }
  939. }
  940. return S_OK;
  941. }
  942. LPTSTR CPrinterFolder::_ItemName(LPCIDPRINTER pidp, LPTSTR pszName, UINT cch)
  943. {
  944. ualstrcpyn(pszName, pidp->cName, cch);
  945. return pszName;
  946. }
  947. BOOL CPrinterFolder::_IsAddPrinter(LPCIDPRINTER pidp)
  948. {
  949. TCHAR szPrinter[MAXNAMELENBUFFER];
  950. return 0 == lstrcmp(c_szNewObject, _ItemName(pidp, szPrinter, ARRAYSIZE(szPrinter)));
  951. }
  952. /*++
  953. Parses an unaligned partial printer name and printer shell folder
  954. into a fullly qualified printer name, and pointer to aligned printer
  955. name.
  956. Arguments:
  957. pszFullPrinter - Buffer to receive fully qualified printer name
  958. Must be MAXNAMELENBUFFER is size.
  959. pidp - Optional pass in the pidl to allow us to try to handle cases where maybe an
  960. old style printer pidl was passed in.
  961. pszPrinter - Unaligned partial (local) printer name.
  962. Return Value:
  963. LPCTSTR pointer to aligned partal (local) printer name.
  964. --*/
  965. LPCTSTR CPrinterFolder::_BuildPrinterName(LPTSTR pszFullPrinter, LPCIDPRINTER pidp, LPCTSTR pszPrinter)
  966. {
  967. UINT cchLen = 0;
  968. if (GetServer())
  969. {
  970. ASSERT(!pszPrinter || (lstrlen(pszPrinter) < MAXNAMELEN));
  971. cchLen = wsprintf(pszFullPrinter, TEXT("%s\\"), GetServer());
  972. }
  973. if (pidp)
  974. {
  975. LPCIDPRINTER pidlprint = (LPCIDPRINTER) pidp;
  976. if (pidlprint->cb >= sizeof(DWORD) + FIELD_OFFSET(IDPRINTER, dwMagic) &&
  977. (pidlprint->dwMagic == PRINTER_MAGIC))
  978. {
  979. _ItemName(pidlprint, &pszFullPrinter[cchLen], MAXNAMELEN);
  980. }
  981. else
  982. {
  983. // Win95 form...
  984. SHAnsiToTChar(((LPW95IDPRINTER)pidp)->cName, &pszFullPrinter[cchLen], MAXNAMELEN);
  985. }
  986. }
  987. else
  988. lstrcpyn(&pszFullPrinter[cchLen], pszPrinter, MAXNAMELEN);
  989. ASSERT(lstrlen(pszFullPrinter) < MAXNAMELENBUFFER);
  990. return pszFullPrinter + cchLen;
  991. }
  992. /*++
  993. Check whether the printer is a local printer by looking at
  994. the name for the "\\localmachine\" prefix or no server prefix.
  995. This is a HACK: we should check by printer attributes, but when
  996. it's too costly or impossible (e.g., if the printer connection
  997. no longer exists), then we use this routine.
  998. Note: this only works for WINNT since the WINNT spooler forces
  999. printer connections to be prefixed with "\\server\." Win9x
  1000. allows the user to rename the printer connection to any arbitrary
  1001. name.
  1002. We determine if it's a masq printer by looking for the
  1003. weird format "\\localserver\\\remoteserver\printer."
  1004. Arguments:
  1005. pszPrinter - Printer name.
  1006. ppszLocal - Returns local name only if the printer is a local printer.
  1007. (May be network and local if it's a masq printer.)
  1008. Return Value:
  1009. TRUE: it's a network printer (true or masq).
  1010. FALSE: it's a local printer.
  1011. --*/
  1012. BOOL Printer_CheckNetworkPrinterByName(LPCTSTR pszPrinter, LPCTSTR* ppszLocal)
  1013. {
  1014. BOOL bNetwork = FALSE;
  1015. LPCTSTR pszLocal = NULL;
  1016. if (pszPrinter[0] == TEXT('\\') && pszPrinter[1] == TEXT('\\'))
  1017. {
  1018. TCHAR szComputer[MAX_COMPUTERNAME_LENGTH+1];
  1019. DWORD cchComputer = ARRAYSIZE(szComputer);
  1020. bNetwork = TRUE;
  1021. pszLocal = NULL;
  1022. //
  1023. // Check if it's a masq printer. If it has the format
  1024. // \\localserver\\\server\printer then it's a masq case.
  1025. //
  1026. if (GetComputerName(szComputer, &cchComputer))
  1027. {
  1028. if (IntlStrEqNI(&pszPrinter[2], szComputer, cchComputer) &&
  1029. pszPrinter[cchComputer] == TEXT('\\'))
  1030. {
  1031. if (pszPrinter[cchComputer+1] == TEXT('\\') &&
  1032. pszPrinter[cchComputer+2] == TEXT('\\'))
  1033. {
  1034. //
  1035. // It's a masq printer.
  1036. //
  1037. pszLocal = &pszPrinter[cchComputer+1];
  1038. }
  1039. }
  1040. }
  1041. }
  1042. else
  1043. {
  1044. // It's a local printer.
  1045. pszLocal = pszPrinter;
  1046. }
  1047. if (ppszLocal)
  1048. {
  1049. *ppszLocal = pszLocal;
  1050. }
  1051. return bNetwork;
  1052. }
  1053. /*++
  1054. Purges the specified printer, and prompting the user if
  1055. they are really sure they want to purge the deviece. It is
  1056. kind of an extreme action to cancel all the documents on
  1057. the printer.
  1058. psf - pointer to shell folder
  1059. hwnd - handle to view window
  1060. pszFullPrinter - Fully qualified printer name.
  1061. uAction - action to execute.
  1062. Return Value:
  1063. TRUE: printer was purged successfully or the user choose to cancel
  1064. the action, FALSE: an error occurred attempting to purge the device.
  1065. --*/
  1066. BOOL CPrinterFolder::_PurgePrinter(HWND hwnd, LPCTSTR pszFullPrinter, UINT uAction, BOOL bQuietMode)
  1067. {
  1068. BOOL bRetval = FALSE;
  1069. LPTSTR pszRet = NULL;
  1070. LPCTSTR pszPrinter = NULL;
  1071. LPCTSTR pszServer = NULL;
  1072. TCHAR szTemp[MAXNAMELENBUFFER] = {0};
  1073. BOOL bPurge = TRUE;
  1074. if (!bQuietMode)
  1075. {
  1076. // We need to break up the full printer name in its components.
  1077. // in order to construct the display name string.
  1078. Printer_SplitFullName(szTemp, pszFullPrinter, &pszServer, &pszPrinter);
  1079. // If there is a server name then construct a friendly printer name.
  1080. if (pszServer && *pszServer)
  1081. {
  1082. pszRet = ShellConstructMessageString(HINST_THISDLL,
  1083. MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON),
  1084. &pszServer[2],
  1085. pszPrinter);
  1086. pszPrinter = pszRet;
  1087. }
  1088. // If we are referring to a local printer or shell construct message
  1089. // sting failed then just use the full printer name in the warning
  1090. // message.
  1091. if (!pszRet)
  1092. {
  1093. pszPrinter = pszFullPrinter;
  1094. }
  1095. // Ask the user if they are sure they want to cancel all documents.
  1096. if (IDYES == ShellMessageBox(HINST_THISDLL, hwnd,
  1097. MAKEINTRESOURCE(IDS_SUREPURGE), MAKEINTRESOURCE(IDS_PRINTERS),
  1098. MB_YESNO | MB_ICONQUESTION, pszPrinter))
  1099. {
  1100. bPurge = TRUE;
  1101. }
  1102. else
  1103. {
  1104. bPurge = FALSE;
  1105. }
  1106. }
  1107. // invoke the purge command
  1108. bRetval = bPurge ? Printer_ModifyPrinter(pszFullPrinter, uAction) : TRUE;
  1109. if (pszRet)
  1110. {
  1111. LocalFree(pszRet);
  1112. }
  1113. return bRetval;
  1114. }
  1115. HRESULT CPrinterFolder::_InvokeCommand(HWND hwnd, LPCIDPRINTER pidp, WPARAM wParam, LPARAM lParam,
  1116. BOOL *pfChooseNewDefault)
  1117. {
  1118. HRESULT hr = S_OK;
  1119. BOOL bNewObject = _IsAddPrinter(pidp);
  1120. LPCTSTR pszPrinter;
  1121. LPCTSTR pszFullPrinter;
  1122. //
  1123. // If it's a remote machine, prepend server name.
  1124. //
  1125. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  1126. if (bNewObject)
  1127. {
  1128. pszFullPrinter = pszPrinter = c_szNewObject;
  1129. }
  1130. else
  1131. {
  1132. pszPrinter = _BuildPrinterName(szFullPrinter, pidp, NULL);
  1133. pszFullPrinter = szFullPrinter;
  1134. }
  1135. switch(wParam)
  1136. {
  1137. case FSIDM_RUNAS_SHARING:
  1138. case FSIDM_RUNAS_OPENPRN:
  1139. case FSIDM_RUNAS_RESUMEPRN:
  1140. case FSIDM_RUNAS_PAUSEPRN:
  1141. case FSIDM_RUNAS_WORKONLINE:
  1142. case FSIDM_RUNAS_WORKOFFLINE:
  1143. case FSIDM_RUNAS_PURGEPRN:
  1144. case FSIDM_RUNAS_DELETE:
  1145. case FSIDM_RUNAS_PROPERTIES:
  1146. {
  1147. // handle all "Run As..." commands here
  1148. hr = _InvokeCommandRunAs(hwnd, pidp, wParam, lParam, pfChooseNewDefault);
  1149. }
  1150. break;
  1151. case FSIDM_OPENPRN:
  1152. SHInvokePrinterCommand(hwnd, PRINTACTION_OPEN, pszFullPrinter, GetServer(), FALSE);
  1153. break;
  1154. case FSIDM_ADDPRINTERWIZARD:
  1155. if (NULL == GetServer() || GetAdminAccess())
  1156. {
  1157. // This is the local printers folder or it is the remote printers folder, but you have
  1158. // admin access to to the remote machine - go ahead.
  1159. SHInvokePrinterCommand(hwnd, PRINTACTION_OPEN, pszFullPrinter, GetServer(), FALSE);
  1160. }
  1161. else
  1162. {
  1163. // This is the remote printers folder and the user don't have the necessary access to install
  1164. // a printer - then ask to run as different user.
  1165. if (IDYES == ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_ADDPRINTERTRYRUNAS),
  1166. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION, GetServer()))
  1167. {
  1168. _InvokeCommandRunAs(hwnd, pidp, FSIDM_RUNAS_ADDPRN, lParam, pfChooseNewDefault);
  1169. }
  1170. }
  1171. break;
  1172. case FSIDM_RUNAS_ADDPRN:
  1173. if (bNewObject)
  1174. {
  1175. _InvokeCommandRunAs(hwnd, pidp, FSIDM_RUNAS_ADDPRN, lParam, pfChooseNewDefault);
  1176. }
  1177. break;
  1178. case FSIDM_DOCUMENTDEFAULTS:
  1179. if (!bNewObject)
  1180. {
  1181. SHInvokePrinterCommand(hwnd, PRINTACTION_DOCUMENTDEFAULTS, pszFullPrinter, NULL, 0);
  1182. }
  1183. break;
  1184. case FSIDM_SHARING:
  1185. case DFM_CMD_PROPERTIES:
  1186. if (!bNewObject)
  1187. {
  1188. SHInvokePrinterCommand(hwnd, PRINTACTION_PROPERTIES, pszFullPrinter,
  1189. wParam == FSIDM_SHARING ?
  1190. (LPCTSTR)PRINTER_SHARING_PAGE :
  1191. (LPCTSTR)lParam, FALSE);
  1192. }
  1193. break;
  1194. case DFM_CMD_DELETE:
  1195. if (!bNewObject &&
  1196. IDYES == CallPrinterCopyHooks(hwnd, PO_DELETE,
  1197. 0, pszFullPrinter, 0, NULL, 0))
  1198. {
  1199. BOOL bNukedDefault = FALSE;
  1200. DWORD dwAttributes = 0;
  1201. LPCTSTR pszPrinterCheck = pszFullPrinter;
  1202. PFOLDER_PRINTER_DATA pData = (PFOLDER_PRINTER_DATA)Printer_FolderGetPrinter(GetFolder(), pszFullPrinter);
  1203. if (pData)
  1204. {
  1205. dwAttributes = pData->Attributes;
  1206. pszPrinterCheck = pData->pName;
  1207. }
  1208. if (GetServer() == NULL)
  1209. {
  1210. // this is a local print folder then
  1211. // we need to check if we're deleting the default printer.
  1212. bNukedDefault = IsDefaultPrinter(pszPrinterCheck, dwAttributes);
  1213. }
  1214. if (pData)
  1215. LocalFree((HLOCAL)pData);
  1216. BOOL fSuccess = Printers_DeletePrinter(hwnd, pszPrinter, dwAttributes, GetServer(), (BOOL)lParam);
  1217. // if so, make another one the default
  1218. if (bNukedDefault && fSuccess && pfChooseNewDefault)
  1219. {
  1220. // don't choose in the middle of deletion,
  1221. // or we might delete the "default" again.
  1222. *pfChooseNewDefault = TRUE;
  1223. }
  1224. }
  1225. break;
  1226. case FSIDM_SETDEFAULTPRN:
  1227. Printer_SetAsDefault(pszFullPrinter);
  1228. break;
  1229. case FSIDM_PAUSEPRN:
  1230. if (!Printer_ModifyPrinter(pszFullPrinter, PRINTER_CONTROL_PAUSE))
  1231. goto WarnOnError;
  1232. break;
  1233. case FSIDM_RESUMEPRN:
  1234. if (!Printer_ModifyPrinter(pszFullPrinter, PRINTER_CONTROL_RESUME))
  1235. goto WarnOnError;
  1236. break;
  1237. case FSIDM_PURGEPRN:
  1238. if (!bNewObject)
  1239. {
  1240. if (!_PurgePrinter(hwnd, pszFullPrinter, PRINTER_CONTROL_PURGE, (BOOL)lParam))
  1241. {
  1242. WarnOnError:
  1243. // show an appropriate error message based on the last error
  1244. ShowErrorMessageSC(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, GetLastError());
  1245. }
  1246. }
  1247. break;
  1248. case FSIDM_NETPRN_INSTALL:
  1249. {
  1250. SHInvokePrinterCommand(hwnd, PRINTACTION_NETINSTALL, pszFullPrinter, NULL, FALSE);
  1251. }
  1252. break;
  1253. case FSIDM_WORKONLINE:
  1254. if (!Printer_WorkOnLine(pszFullPrinter, TRUE))
  1255. {
  1256. // show an appropriate error message based on the last error
  1257. ShowErrorMessageSC(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, GetLastError());
  1258. }
  1259. break;
  1260. case FSIDM_WORKOFFLINE:
  1261. if (!Printer_WorkOnLine(pszFullPrinter, FALSE))
  1262. {
  1263. // show an appropriate error message based on the last error
  1264. ShowErrorMessageSC(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, GetLastError());
  1265. }
  1266. break;
  1267. case DFM_CMD_LINK:
  1268. case DFM_CMD_RENAME:
  1269. case DFM_CMD_PASTE:
  1270. // let defcm handle this too
  1271. hr = S_FALSE;
  1272. break;
  1273. default:
  1274. // GetAttributesOf doesn't set other SFGAO_ bits,
  1275. // BUT accelerator keys will get unavailable menu items,
  1276. // so we need to return failure here.
  1277. hr = E_NOTIMPL;
  1278. break;
  1279. } // switch(wParam)
  1280. return hr;
  1281. }
  1282. // implements a bunch of admin related "Run as..." command using printui.dll rundll32 interface.
  1283. HRESULT CPrinterFolder::_InvokeCommandRunAs(HWND hwnd, LPCIDPRINTER pidp, WPARAM wParam, LPARAM lParam,
  1284. LPBOOL pfChooseNewDefault)
  1285. {
  1286. HRESULT hr = S_OK; // assume success
  1287. TCHAR szCmdLine[2048]; // the command line buffer - 2K should be enough.
  1288. BOOL bNewObject = FALSE; // TRUE if "Add Printer" icon is selected
  1289. TCHAR szFullPrinter[MAXNAMELENBUFFER]; // buffer to expand the full printer name i.e. \\server\printer
  1290. LPCTSTR pszPrinter = NULL; // only the printer name is here
  1291. LPTSTR pszFullPrinter = NULL; // the fully qulified printer name i.e. \\server\printer
  1292. if (pidp)
  1293. {
  1294. bNewObject = _IsAddPrinter(pidp);
  1295. if (!bNewObject)
  1296. {
  1297. pszPrinter = _BuildPrinterName(szFullPrinter, pidp, NULL);
  1298. // insert backslashes for command parsing
  1299. hr = InsertBackSlash(szFullPrinter, &pszFullPrinter);
  1300. if (FAILED(hr))
  1301. {
  1302. goto Done;
  1303. }
  1304. }
  1305. }
  1306. // build the command line here
  1307. szCmdLine[0] = 0;
  1308. int iResult = -1;
  1309. switch(wParam)
  1310. {
  1311. case FSIDM_RUNAS_SHARING:
  1312. // bring up the properties dialog for this printer, positioned on the sharing page
  1313. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /p /t1 /n\"%s\""), pszFullPrinter);
  1314. break;
  1315. case FSIDM_RUNAS_ADDPRN:
  1316. {
  1317. // invoke the add printer wizard here
  1318. iResult = (NULL == GetServer()) ?
  1319. // local server - simply format the command
  1320. wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("%s"), TEXT("printui.dll,PrintUIEntry /il")):
  1321. // remote server case - specify the machine name
  1322. wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /il /c\"%s\""), GetServer());
  1323. }
  1324. break;
  1325. case FSIDM_RUNAS_SVRPROP:
  1326. {
  1327. // bring up the server properties dialog for this print server
  1328. iResult = (NULL == GetServer()) ?
  1329. // local server - simply format the command
  1330. wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("%s"), TEXT("printui.dll,PrintUIEntry /s /t0")):
  1331. // remote server case - specify the machine name
  1332. wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /s /t0 /n\"%s\""), GetServer());
  1333. }
  1334. break;
  1335. case FSIDM_RUNAS_OPENPRN:
  1336. // bring up the print queue for this printer
  1337. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /o /n\"%s\""), pszFullPrinter);
  1338. break;
  1339. case FSIDM_RUNAS_RESUMEPRN:
  1340. // pause the printer (assume ready)
  1341. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Xs /n\"%s\" Status Resume"), pszFullPrinter);
  1342. break;
  1343. case FSIDM_RUNAS_PAUSEPRN:
  1344. // resume a paused printer back to ready mode
  1345. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Xs /n\"%s\" Status Pause"), pszFullPrinter);
  1346. break;
  1347. case FSIDM_RUNAS_WORKONLINE:
  1348. // resume an offline printer back to online mode
  1349. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Xs /n\"%s\" Attributes -WorkOffline"), pszFullPrinter);
  1350. break;
  1351. case FSIDM_RUNAS_WORKOFFLINE:
  1352. // make the printer available offline (assume online mode)
  1353. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Xs /n\"%s\" Attributes +WorkOffline"), pszFullPrinter);
  1354. break;
  1355. case FSIDM_RUNAS_PURGEPRN:
  1356. {
  1357. // cancel all documents pending to print on this printer
  1358. LPTSTR pszMsg = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_SUREPURGE), szFullPrinter);
  1359. if (pszMsg)
  1360. {
  1361. LPTSTR pszNewMsg = NULL;
  1362. if (SUCCEEDED(hr = InsertBackSlash(pszMsg, &pszNewMsg)))
  1363. {
  1364. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Mq\"%s\" /Xs /n\"%s\" Status Purge"), pszNewMsg, pszFullPrinter);
  1365. SHFree(pszNewMsg);
  1366. }
  1367. SHFree(pszMsg);
  1368. }
  1369. else
  1370. {
  1371. hr = E_OUTOFMEMORY;
  1372. }
  1373. }
  1374. break;
  1375. case FSIDM_RUNAS_DELETE:
  1376. {
  1377. LPTSTR pszMsg = NULL;
  1378. LPCTSTR pszP = NULL, pszS = NULL;
  1379. TCHAR szBuffer[MAXNAMELENBUFFER] = {0};
  1380. Printer_SplitFullName(szBuffer, pszPrinter, &pszS, &pszP);
  1381. if (pszS && *pszS)
  1382. {
  1383. // this can be a masq printer - use the connection template in this case
  1384. pszMsg = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_SUREDELETECONNECTION),
  1385. pszP, SkipServerSlashes(pszS));
  1386. }
  1387. else
  1388. {
  1389. if (GetServer())
  1390. {
  1391. // this is a local printer in the remote PF - use the remote PF template
  1392. pszMsg = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_SUREDELETEREMOTE),
  1393. pszPrinter, SkipServerSlashes(GetServer()));
  1394. }
  1395. else
  1396. {
  1397. // this is a local printer in the local PF - use the local PF template
  1398. pszMsg = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_SUREDELETE), pszPrinter);
  1399. }
  1400. }
  1401. hr = pszMsg ? S_OK : E_OUTOFMEMORY;
  1402. if (SUCCEEDED(hr))
  1403. {
  1404. LPTSTR pszNewMsg = NULL;
  1405. if (SUCCEEDED(hr = InsertBackSlash(pszMsg, &pszNewMsg)))
  1406. {
  1407. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /Mq\"%s\" /dl /n\"%s\""), pszNewMsg, pszFullPrinter);
  1408. SHFree(pszNewMsg);
  1409. }
  1410. SHFree(pszMsg);
  1411. }
  1412. }
  1413. break;
  1414. case FSIDM_RUNAS_PROPERTIES:
  1415. // bring up the properties dialog for this printer
  1416. iResult = wnsprintf(szCmdLine, ARRAYSIZE(szCmdLine), TEXT("printui.dll,PrintUIEntry /p /t0 /n\"%s\""), pszFullPrinter);
  1417. break;
  1418. default:
  1419. hr = E_NOTIMPL;
  1420. break;
  1421. }
  1422. if (SUCCEEDED(hr) && -1 == iResult)
  1423. {
  1424. hr = E_NOTIMPL;
  1425. }
  1426. if (SUCCEEDED(hr))
  1427. {
  1428. // invokes the command as different user (run as) through rundll process...
  1429. SHRunDLLProcess(hwnd, szCmdLine, SW_SHOWNORMAL, IDS_PRINTERS, TRUE);
  1430. }
  1431. Done:
  1432. // clean up
  1433. SHFree(pszFullPrinter);
  1434. return hr;
  1435. }
  1436. //
  1437. // The printer name specified in the _SHARE_INFO_502 structure in a call
  1438. // to NetShareAdd() which is in localspl.dll, contains a printer name that
  1439. // is expressed as \\server_name\printer_name,LocalsplOnly. (',LocalsplOnly'
  1440. // post fix string was recently added for clustering support) The server
  1441. // name prefix and the post fix string prevent the maximum printer name from
  1442. // being a valid size in a call to NetShareAdd(), because NetShareAdd() will
  1443. // only accept a maximum share name path of 256 characters, therefore the
  1444. // maximum printer name calculation has been changed to. This change only
  1445. // applies to the windows nt spooler. Because the remote printers folder can
  1446. // view non shared printers on downlevel print servers we cannot change the
  1447. // maxnamelen define to 220 this would break long printer name printers on
  1448. // downlevel print servers.
  1449. //
  1450. // max local printer name = max shared net path - (wack + wack + max server name + wack + comma + 'LocalsplOnly' + null)
  1451. // max local printer name = 256 - (1 + 1 + 13 + 1 + 1 + 12 + 1)
  1452. // max local printer name = 256 - 30
  1453. // max local printer name = 226 - 5 to round to some reasonable number
  1454. // max local printer name = 221
  1455. //
  1456. #define MAXLOCALNAMELEN 221
  1457. // returns 0 if this is a legal name
  1458. // returns the IDS_ string id of the error string for an illegal name
  1459. int _IllegalPrinterName(LPTSTR pszName)
  1460. {
  1461. int fIllegal = 0;
  1462. if (*pszName == 0)
  1463. {
  1464. fIllegal = IDS_PRTPROP_RENAME_NULL;
  1465. }
  1466. else if (lstrlen(pszName) >= MAXLOCALNAMELEN)
  1467. {
  1468. fIllegal = IDS_PRTPROP_RENAME_TOO_LONG;
  1469. }
  1470. else
  1471. {
  1472. while (*pszName &&
  1473. *pszName != TEXT('!') &&
  1474. *pszName != TEXT('\\') &&
  1475. *pszName != TEXT(',') )
  1476. {
  1477. pszName++ ;
  1478. }
  1479. if (*pszName)
  1480. {
  1481. fIllegal = IDS_PRTPROP_RENAME_BADCHARS;
  1482. }
  1483. }
  1484. return fIllegal;
  1485. }
  1486. const struct
  1487. {
  1488. UINT_PTR uVerbID;
  1489. LPCSTR pszCanonicalName;
  1490. }
  1491. g_CanonicalVerbNames[] =
  1492. {
  1493. {DFM_CMD_DELETE, "delete" },
  1494. {DFM_CMD_MOVE, "cut" },
  1495. {DFM_CMD_COPY, "copy" },
  1496. {DFM_CMD_PASTE, "paste" },
  1497. {DFM_CMD_LINK, "link" },
  1498. {DFM_CMD_PROPERTIES, "properties" },
  1499. {DFM_CMD_PASTELINK, "pastelink" },
  1500. {DFM_CMD_RENAME, "rename" },
  1501. };
  1502. static LPCSTR _GetStandardCommandCanonicalName(UINT_PTR uVerbID)
  1503. {
  1504. LPCSTR pszCmd = NULL;
  1505. for (int i=0; i<ARRAYSIZE(g_CanonicalVerbNames); i++)
  1506. {
  1507. if (uVerbID == g_CanonicalVerbNames[i].uVerbID)
  1508. {
  1509. pszCmd = g_CanonicalVerbNames[i].pszCanonicalName;
  1510. break;
  1511. }
  1512. }
  1513. return pszCmd;
  1514. }
  1515. HRESULT CALLBACK CPrinterFolder::_DFMCallBack(IShellFolder *psf, HWND hwnd,
  1516. IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1517. {
  1518. CPrinterFolder* This;
  1519. HRESULT hr = psf->QueryInterface(CLSID_Printers, (void**)&This);
  1520. if (FAILED(hr))
  1521. return hr;
  1522. hr = E_INVALIDARG;
  1523. if (pdo)
  1524. {
  1525. // let't split the selection into its components (printers and links)
  1526. IDataObject *pdoP = NULL;
  1527. IDataObject *pdoL = NULL;
  1528. UINT uSelType = SEL_NONE;
  1529. if (SUCCEEDED(hr = This->SplitSelection(pdo, &uSelType, &pdoP, &pdoL)))
  1530. {
  1531. if (pdoP)
  1532. {
  1533. // we have printer objects in the selection delegate the call to
  1534. // _PrinterObjectsCallBack
  1535. hr = This->_PrinterObjectsCallBack(hwnd, uSelType, pdoP, uMsg, wParam, lParam);
  1536. }
  1537. if (SUCCEEDED(hr) && pdoL && DFM_INVOKECOMMAND == uMsg)
  1538. {
  1539. // we have link objects. this can only happen if we have mixed selection
  1540. // of print and link objects. we need to handle some of the commands through
  1541. // printhood
  1542. IShellFolder2* psfPrinthood = CPrintRoot_GetPSF();
  1543. if (psfPrinthood)
  1544. {
  1545. LPCSTR pszCmd = _GetStandardCommandCanonicalName(wParam);
  1546. hr = pszCmd ? SHInvokeCommandOnDataObject(hwnd, psfPrinthood, pdoL, 0, pszCmd) : E_NOTIMPL;
  1547. }
  1548. }
  1549. }
  1550. if (pdoP)
  1551. pdoP->Release();
  1552. if (pdoL)
  1553. pdoL->Release();
  1554. }
  1555. This->Release();
  1556. return hr;
  1557. }
  1558. HRESULT CPrinterFolder::_PrinterObjectsCallBack(HWND hwnd, UINT uSelType,
  1559. IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1560. {
  1561. HRESULT hr = E_INVALIDARG;
  1562. if (pdo)
  1563. {
  1564. STGMEDIUM medium;
  1565. LPIDA pida = DataObj_GetHIDA(pdo, &medium);
  1566. hr = E_OUTOFMEMORY;
  1567. if (pida)
  1568. {
  1569. hr = S_OK;
  1570. switch (uMsg)
  1571. {
  1572. case DFM_MERGECONTEXTMENU:
  1573. // returning S_FALSE indicates no need to use default verbs
  1574. hr = S_FALSE;
  1575. break;
  1576. case DFM_MERGECONTEXTMENU_TOP:
  1577. {
  1578. // merge the printer commands in the context menu only if
  1579. // there are no link objects in the selection
  1580. if (0 == (SEL_LINK_ANY & uSelType))
  1581. {
  1582. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  1583. UINT idCmdBase = pqcm->idCmdFirst; // must be called before merge
  1584. UINT idRunAs = FSIDM_RUNAS;
  1585. if (pida->cidl == 1 && _IsAddPrinter((LPCIDPRINTER)IDA_GetIDListPtr(pida, 0)))
  1586. {
  1587. // The only selected object is the "New Printer" thing
  1588. // insert verbs
  1589. CDefFolderMenu_MergeMenu(HINST_THISDLL, MENU_ADDPRINTER_OPEN_VERBS, 0, pqcm);
  1590. idRunAs = FSIDM_RUNAS_ADDPRN;
  1591. }
  1592. else
  1593. {
  1594. LPCTSTR pszFullPrinter = NULL;
  1595. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  1596. // We're dealing with printer objects
  1597. if (!(wParam & CMF_DEFAULTONLY))
  1598. {
  1599. if (pida->cidl == 1)
  1600. {
  1601. LPIDPRINTER pidp = (LPIDPRINTER)IDA_GetIDListPtr(pida, 0);
  1602. if (pidp)
  1603. {
  1604. _BuildPrinterName(szFullPrinter, pidp, NULL);
  1605. pszFullPrinter = szFullPrinter;
  1606. }
  1607. }
  1608. }
  1609. _MergeMenu(pqcm, pszFullPrinter);
  1610. }
  1611. if (!(wParam & CMF_EXTENDEDVERBS) || (pida->cidl > 1))
  1612. {
  1613. // if the extended verbs are not enabled (shift key is not down) then
  1614. // delete the "Run as..." command(s).
  1615. DeleteMenu(pqcm->hmenu, idCmdBase + idRunAs, MF_BYCOMMAND);
  1616. }
  1617. SetMenuDefaultItem(pqcm->hmenu, 0, MF_BYPOSITION);
  1618. }
  1619. break;
  1620. }
  1621. case DFM_GETHELPTEXT:
  1622. case DFM_GETHELPTEXTW:
  1623. {
  1624. // this is applicale only for our printer commands
  1625. if (0 == (SEL_LINK_ANY & uSelType))
  1626. {
  1627. int idCmd = LOWORD(wParam);
  1628. int cchMax = HIWORD(wParam);
  1629. LPBYTE pBuf = (LPBYTE)lParam;
  1630. if (FSIDM_RUNAS_FIRST < idCmd && idCmd < FSIDM_RUNAS_LAST)
  1631. {
  1632. // all runas commands have the same help text (FSIDM_RUNAS)
  1633. idCmd = FSIDM_RUNAS;
  1634. }
  1635. if (uMsg == DFM_GETHELPTEXTW)
  1636. LoadStringW(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST,
  1637. (LPWSTR)pBuf, cchMax);
  1638. else
  1639. LoadStringA(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST,
  1640. (LPSTR)pBuf, cchMax);
  1641. break;
  1642. }
  1643. }
  1644. case DFM_INVOKECOMMAND:
  1645. {
  1646. BOOL fChooseNewDefault = FALSE;
  1647. // Assume not quiet mode
  1648. lParam = 0;
  1649. switch (wParam)
  1650. {
  1651. case (DFM_CMD_DELETE):
  1652. case (FSIDM_PURGEPRN):
  1653. {
  1654. UINT uMsgID = DFM_CMD_DELETE == wParam ? IDS_SUREDELETEMULTIPLE :
  1655. FSIDM_PURGEPRN == wParam ? IDS_SUREPURGEMULTIPLE : 0;
  1656. if (uMsgID && pida->cidl > 1)
  1657. {
  1658. // delete multiple printers. ask the user once for confirmation and then delete
  1659. // all the selected printers quietly
  1660. if (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(uMsgID),
  1661. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION)
  1662. != IDYES)
  1663. {
  1664. goto Bail;
  1665. }
  1666. // Turn on the quiet mode
  1667. lParam = 1;
  1668. }
  1669. }
  1670. break;
  1671. }
  1672. for (int i = pida->cidl - 1; i >= 0; i--)
  1673. {
  1674. LPIDPRINTER pidp = (LPIDPRINTER)IDA_GetIDListPtr(pida, i);
  1675. hr = _InvokeCommand(hwnd, pidp, wParam, lParam, &fChooseNewDefault);
  1676. if (hr != S_OK)
  1677. goto Bail;
  1678. }
  1679. if (fChooseNewDefault)
  1680. Printers_ChooseNewDefault(hwnd);
  1681. break;
  1682. } // case DFM_INVOKECOMMAND
  1683. default:
  1684. hr = E_NOTIMPL;
  1685. break;
  1686. } // switch (uMsg)
  1687. Bail:
  1688. HIDA_ReleaseStgMedium(pida, &medium);
  1689. }
  1690. }
  1691. return hr;
  1692. }
  1693. //
  1694. // IContextMenuCB::Callback entry for the background menu (right click backgrond of folder)
  1695. //
  1696. HRESULT CPrinterFolder::CallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdo,
  1697. UINT uMsg, WPARAM wParam, LPARAM lParam)
  1698. {
  1699. HRESULT hr = S_OK;
  1700. LPQCMINFO pqcm;
  1701. UINT idCmdBase;
  1702. switch(uMsg)
  1703. {
  1704. case DFM_MERGECONTEXTMENU:
  1705. // returning S_FALSE indicates no need to use default verbs
  1706. hr = S_FALSE;
  1707. break;
  1708. case DFM_MERGECONTEXTMENU_TOP:
  1709. {
  1710. pqcm = (LPQCMINFO)lParam;
  1711. idCmdBase = pqcm->idCmdFirst; // must be called before merge
  1712. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_DRIVES_PRINTERS, 0, pqcm);
  1713. if (!(wParam & CMF_EXTENDEDVERBS))
  1714. {
  1715. // if the extended verbs are not enabled (shift key is not down) then
  1716. // delete the "Run as..." command(s).
  1717. DeleteMenu(pqcm->hmenu, idCmdBase + FSIDM_RUNAS, MF_BYCOMMAND);
  1718. }
  1719. // fax related commands are applicable only for the local printers folder
  1720. UINT_PTR uCmd;
  1721. if (GetServer() || FAILED(_GetFaxCommand(&uCmd)))
  1722. {
  1723. uCmd = 0;
  1724. }
  1725. UINT_PTR arrFaxCmds[] =
  1726. {
  1727. FSIDM_SETUPFAXING,
  1728. FSIDM_CREATELOCALFAX,
  1729. FSIDM_SENDFAXWIZARD
  1730. };
  1731. // all fax commands are mutually exclusive - only the one returned from
  1732. // _GetFaxCommand is applicable.
  1733. for (INT_PTR i = 0; i < ARRAYSIZE(arrFaxCmds); i++)
  1734. {
  1735. if (uCmd != arrFaxCmds[i])
  1736. {
  1737. DeleteMenu(pqcm->hmenu, idCmdBase + arrFaxCmds[i], MF_BYCOMMAND);
  1738. }
  1739. }
  1740. }
  1741. break;
  1742. case DFM_GETHELPTEXT:
  1743. case DFM_GETHELPTEXTW:
  1744. {
  1745. int idCmd = LOWORD(wParam);
  1746. int cchMax = HIWORD(wParam);
  1747. if (FSIDM_RUNAS_FIRST < idCmd && idCmd < FSIDM_RUNAS_LAST)
  1748. {
  1749. // all runas commands have the same help text (FSIDM_RUNAS)
  1750. idCmd = FSIDM_RUNAS;
  1751. }
  1752. if (DFM_GETHELPTEXT == uMsg)
  1753. {
  1754. LoadStringA(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, cchMax);
  1755. }
  1756. else
  1757. {
  1758. LoadStringW(HINST_THISDLL, idCmd + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, cchMax);
  1759. }
  1760. }
  1761. break;
  1762. case DFM_INVOKECOMMAND:
  1763. switch (wParam)
  1764. {
  1765. case FSIDM_CONNECT_PRN:
  1766. SHNetConnectionDialog(hwnd, NULL, RESOURCETYPE_PRINT);
  1767. break;
  1768. case FSIDM_DISCONNECT_PRN:
  1769. WNetDisconnectDialog(hwnd, RESOURCETYPE_PRINT);
  1770. break;
  1771. case FSIDM_ADDPRINTERWIZARD:
  1772. if (NULL == GetServer() || GetAdminAccess())
  1773. {
  1774. // This is the local printers folder or it is the remote printers folder, but you have
  1775. // admin access to to the remote machine - go ahead.
  1776. SHInvokePrinterCommand(hwnd, PRINTACTION_OPEN, c_szNewObject, GetServer(), FALSE);
  1777. }
  1778. else
  1779. {
  1780. // This is the remote printers folder and the user don't have the necessary access to install
  1781. // a printer - then ask to run as different user.
  1782. if (IDYES == ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_ADDPRINTERTRYRUNAS),
  1783. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION, GetServer()))
  1784. {
  1785. _InvokeCommandRunAs(hwnd, NULL, FSIDM_RUNAS_ADDPRN, lParam, NULL);
  1786. }
  1787. }
  1788. break;
  1789. case FSIDM_SERVERPROPERTIES:
  1790. SHInvokePrinterCommand(hwnd, PRINTACTION_SERVERPROPERTIES,
  1791. GetServer() ? GetServer() : TEXT(""), NULL, FALSE);
  1792. break;
  1793. case FSIDM_SENDFAXWIZARD:
  1794. // just invoke faxsend.exe here
  1795. ShellExecute(hwnd, TEXT("open"), FAX_SEND_IMAGE_NAME, TEXT(""), NULL, SW_SHOWNORMAL);
  1796. break;
  1797. case FSIDM_SETUPFAXING:
  1798. // push the command in background
  1799. SHQueueUserWorkItem(reinterpret_cast<LPTHREAD_START_ROUTINE>(_ThreadProc_InstallFaxService),
  1800. NULL, 0, 0, NULL, "shell32.dll", 0);
  1801. break;
  1802. case FSIDM_CREATELOCALFAX:
  1803. // push the command in background
  1804. SHQueueUserWorkItem(reinterpret_cast<LPTHREAD_START_ROUTINE>(_ThreadProc_InstallLocalFaxPrinter),
  1805. NULL, 0, 0, NULL, "shell32.dll", 0);
  1806. break;
  1807. case FSIDM_RUNAS_ADDPRN:
  1808. case FSIDM_RUNAS_SVRPROP:
  1809. {
  1810. // handle all "Run As..." commands here
  1811. hr = _InvokeCommandRunAs(hwnd, NULL, wParam, lParam, NULL);
  1812. }
  1813. break;
  1814. default:
  1815. // one of view menu items, use the default code.
  1816. hr = S_FALSE;
  1817. break;
  1818. }
  1819. break;
  1820. default:
  1821. hr = E_NOTIMPL;
  1822. break;
  1823. }
  1824. return hr;
  1825. }
  1826. ////////////////////////
  1827. // CPrintersEnum
  1828. ////////////////////////
  1829. class CPrintersEnum: public CEnumIDListBase
  1830. {
  1831. public:
  1832. // IEnumIDList
  1833. STDMETHODIMP Next(ULONG celt, LPITEMIDLIST* ppidl, ULONG* pceltFetched);
  1834. // CreateInstance
  1835. static HRESULT CreateInstance(DWORD grfFlags, DWORD dwRemote, IEnumIDList* peunk, CPrinterFolder* ppsf, IEnumIDList **ppenum);
  1836. private:
  1837. CPrintersEnum(DWORD grfFlags, DWORD dwRemote, IEnumIDList* peunk, CPrinterFolder* ppsf);
  1838. virtual ~CPrintersEnum();
  1839. DWORD _grfFlags;
  1840. int _nLastFound;
  1841. CPrinterFolder* _ppsf;
  1842. PFOLDER_PRINTER_DATA _pPrinters;
  1843. DWORD _dwNumPrinters;
  1844. DWORD _dwRemote;
  1845. IEnumIDList* _peunk; // file system enumerator
  1846. };
  1847. // Flags for the dwRemote field
  1848. //
  1849. #define RMF_SHOWLINKS 0x00000001 // Hoodlinks need to be shown
  1850. CPrintersEnum::CPrintersEnum(DWORD grfFlags, DWORD dwRemote, IEnumIDList* peunk, CPrinterFolder* ppsf)
  1851. {
  1852. _nLastFound = -1;
  1853. _pPrinters = NULL;
  1854. _grfFlags = grfFlags;
  1855. _dwRemote = dwRemote;
  1856. _peunk = peunk;
  1857. _ppsf = ppsf;
  1858. }
  1859. CPrintersEnum::~CPrintersEnum()
  1860. {
  1861. if (_pPrinters)
  1862. LocalFree((HLOCAL)_pPrinters);
  1863. // Release the link (filesystem) enumerator.
  1864. if (_peunk)
  1865. _peunk->Release();
  1866. }
  1867. //
  1868. // IEnumIDList
  1869. //
  1870. STDMETHODIMP CPrintersEnum::Next(ULONG celt, LPITEMIDLIST* ppidl, ULONG* pceltFetched)
  1871. {
  1872. HRESULT hr = S_OK;
  1873. if (pceltFetched)
  1874. *pceltFetched = 0;
  1875. // We don't do any form of folder
  1876. if (!(_grfFlags & SHCONTF_NONFOLDERS))
  1877. {
  1878. return S_FALSE;
  1879. }
  1880. // Are we looking for the links right now?
  1881. if (_dwRemote & RMF_SHOWLINKS)
  1882. {
  1883. // Yes, use the link (PrintHood folder) enumerator
  1884. if (_peunk)
  1885. {
  1886. hr = _peunk->Next(1, ppidl, pceltFetched);
  1887. if (hr == S_OK)
  1888. {
  1889. // Added link
  1890. return S_OK;
  1891. }
  1892. }
  1893. _dwRemote &= ~RMF_SHOWLINKS; // Done enumerating links
  1894. }
  1895. // Carry on with enumerating printers now
  1896. ASSERT(_nLastFound >= 0 || _nLastFound == -1);
  1897. if (_nLastFound == -1)
  1898. {
  1899. // check if refresh has been requested
  1900. _ppsf->CheckToRefresh();
  1901. // free up the memory if _pPrinters is not NULL
  1902. if (_pPrinters)
  1903. {
  1904. LocalFree((HLOCAL)_pPrinters);
  1905. _pPrinters = NULL;
  1906. }
  1907. // note that _pPrinters may be NULL if no printers are installed.
  1908. _dwNumPrinters = _ppsf->GetFolder() ? Printers_FolderEnumPrinters(
  1909. _ppsf->GetFolder(), (void**)&_pPrinters) : 0;
  1910. if (S_FALSE != SHShouldShowWizards(_punkSite) && !SHRestricted(REST_NOPRINTERADD))
  1911. {
  1912. // special case the Add Printer Wizard.
  1913. hr = _ppsf->_Parse(c_szNewObject, ppidl);
  1914. goto Done;
  1915. }
  1916. // Not an admin, skip the add printer wizard and return the
  1917. // first item.
  1918. _nLastFound = 0;
  1919. }
  1920. if (_nLastFound >= (int)_dwNumPrinters)
  1921. return S_FALSE;
  1922. hr = _ppsf->_Parse(GetPrinterName(_pPrinters, _nLastFound), ppidl);
  1923. Done:
  1924. if (SUCCEEDED(hr))
  1925. {
  1926. ++_nLastFound;
  1927. if (pceltFetched)
  1928. *pceltFetched = 1;
  1929. }
  1930. return hr;
  1931. }
  1932. // CreateInstance
  1933. HRESULT CPrintersEnum::CreateInstance(DWORD grfFlags, DWORD dwRemote, IEnumIDList *peunk, CPrinterFolder *ppsf, IEnumIDList **ppenum)
  1934. {
  1935. HRESULT hr = E_INVALIDARG;
  1936. if (ppenum && ppsf)
  1937. {
  1938. *ppenum = NULL;
  1939. hr = E_OUTOFMEMORY;
  1940. CPrintersEnum *pObj = new CPrintersEnum(grfFlags, dwRemote, peunk, ppsf);
  1941. if (pObj)
  1942. {
  1943. hr = pObj->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  1944. pObj->Release();
  1945. }
  1946. }
  1947. return hr;
  1948. }
  1949. //
  1950. // CPrinterFolder
  1951. //
  1952. CPrinterFolder::CPrinterFolder()
  1953. {
  1954. _cRef = 1;
  1955. _pszServer = NULL;
  1956. _dwSpoolerVersion = -1;
  1957. _pidl = NULL;
  1958. _hFolder = NULL;
  1959. _bAdminAccess = FALSE;
  1960. _bReqRefresh = FALSE;
  1961. }
  1962. CPrinterFolder::~CPrinterFolder()
  1963. {
  1964. if (_hFolder)
  1965. {
  1966. // unregister from the folder cache
  1967. UnregisterPrintNotify(_pszServer, this, &_hFolder);
  1968. }
  1969. //
  1970. // The pidl must be freed here!! (after unregister from PRUNTUI.DLL),
  1971. // because if you move this code before the call to PRINTUI
  1972. // serious race condition occurs. Have in mind that the interface which
  1973. // is used for communication with PRINTUI is part this class and
  1974. // and uses the pidl in its ProcessNotify(...) member
  1975. //
  1976. if (_pidl)
  1977. {
  1978. ILFree(_pidl);
  1979. }
  1980. if (_pszServer)
  1981. {
  1982. LocalFree(_pszServer);
  1983. }
  1984. // clear the PDO cache
  1985. _WebviewCheckToUpdateDataObjectCache(NULL);
  1986. // cleanup the slow webview data cache
  1987. if (_dpaSlowWVDataCache)
  1988. {
  1989. _SlowWVDataCacheResetUnsafe();
  1990. ASSERT(0 == _dpaSlowWVDataCache.GetPtrCount());
  1991. _dpaSlowWVDataCache.Destroy();
  1992. }
  1993. }
  1994. /*++
  1995. Returns the printer status string in the privided
  1996. buffer.
  1997. Arguments:
  1998. pData - pointer to printer data, i.e. cache data
  1999. pBuff - pointer to buffer where to return status string.
  2000. uSize - size in characters of status buffer.
  2001. Return Value:
  2002. pointer to printer status string.
  2003. --*/
  2004. LPCTSTR CPrinterFolder::GetStatusString(PFOLDER_PRINTER_DATA pData, LPTSTR pBuff, UINT uSize)
  2005. {
  2006. LPCTSTR pszReturn = pBuff;
  2007. DWORD dwStatus = pData->Status;
  2008. *pBuff = 0;
  2009. // HACK: Use this free bit for "Work Offline"
  2010. // 99/03/30 #308785 vtan: compare the strings displayed. Adjust
  2011. // for this hack from GetDetailsOf().
  2012. if (pData->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE)
  2013. dwStatus |= PRINTER_HACK_WORK_OFFLINE;
  2014. // If there is queue status value then convert the status id to a
  2015. // readable status string.
  2016. if (dwStatus)
  2017. {
  2018. Printer_BitsToString(dwStatus, IDS_PRQSTATUS_SEPARATOR, pBuff, uSize);
  2019. }
  2020. else
  2021. {
  2022. // If we do not have queue status string then the status of the queue
  2023. // is 0 and assumed ready, display ready rather than an empty string.
  2024. if (!pData->pStatus)
  2025. {
  2026. LoadString(HINST_THISDLL, IDS_PRN_INFOTIP_READY, pBuff, uSize);
  2027. }
  2028. else
  2029. {
  2030. // If we do not have a queue status value then we assume we
  2031. // must have a queue status string. Queue status strings
  2032. // are cooked up string from printui to indicate pending
  2033. // connection status. i.e. opening|retrying|unable to connect|etc.
  2034. pszReturn = pData->pStatus;
  2035. }
  2036. }
  2037. return pszReturn;
  2038. }
  2039. /*++
  2040. Compares the printers display name for column sorting
  2041. support.
  2042. Arguments:
  2043. pName1 - pointer to unalligned printer name.
  2044. pName2 - pointer to unalligned printer name.
  2045. Return Value:
  2046. -1 = pName1 less than pName2
  2047. 0 = pName1 equal to pName2
  2048. 1 = pName1 greather than pName2
  2049. --*/
  2050. INT CPrinterFolder::GetCompareDisplayName(LPCTSTR pName1, LPCTSTR pName2)
  2051. {
  2052. LPCTSTR pszServer = NULL;
  2053. LPCTSTR pszPrinter = NULL;
  2054. LPTSTR pszRet2 = NULL;
  2055. TCHAR szTemp[MAXNAMELENBUFFER] = {0};
  2056. //
  2057. // We need to break up the full printer name in its components.
  2058. // in order to construct the display name string.
  2059. //
  2060. Printer_SplitFullName(szTemp, pName1, &pszServer, &pszPrinter);
  2061. LPTSTR pszRet1 = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON),
  2062. &pszServer[2], pszPrinter);
  2063. if (pszRet1)
  2064. {
  2065. Printer_SplitFullName(szTemp, pName2, &pszServer, &pszPrinter);
  2066. pszRet2 = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON),
  2067. &pszServer[2], pszPrinter);
  2068. if (pszRet2)
  2069. {
  2070. pName1 = pszRet1;
  2071. pName2 = pszRet2;
  2072. }
  2073. }
  2074. int iResult = lstrcmpi(pName1, pName2);
  2075. if (pszRet1)
  2076. LocalFree(pszRet1);
  2077. if (pszRet2)
  2078. LocalFree(pszRet2);
  2079. return iResult;
  2080. }
  2081. /*++
  2082. Compares printer column data using the
  2083. column index as a guide indicating which data to compare.
  2084. Arguments:
  2085. psf - pointer to the containter shell folder.
  2086. pidp1 - pointer to unalligned printer name.
  2087. pidp1 - pointer to unalligned printer name.
  2088. iCol - column index shich to sort on.
  2089. Return Value:
  2090. -1 = pName1 less than pName2
  2091. 0 = pName1 equal to pName2
  2092. 1 = pName1 greather than pName2
  2093. --*/
  2094. INT CPrinterFolder::CompareData(LPCIDPRINTER pidp1, LPCIDPRINTER pidp2, LPARAM iCol)
  2095. {
  2096. LPCTSTR pName1 = NULL;
  2097. LPCTSTR pName2 = NULL;
  2098. INT iResult = 0;
  2099. TCHAR szTemp1[MAX_PATH] = {0};
  2100. TCHAR szTemp2[MAX_PATH] = {0};
  2101. BOOL bDoStringCompare = TRUE;
  2102. // since the pidp's are UNALIGNED we need to copy the strings out.
  2103. TCHAR szName1[MAX_PATH];
  2104. _ItemName(pidp1, szName1, ARRAYSIZE(szName1));
  2105. TCHAR szName2[MAX_PATH];
  2106. _ItemName(pidp2, szName2, ARRAYSIZE(szName2));
  2107. // There is no reason to hit the cache for the printer name.
  2108. if ((iCol & SHCIDS_COLUMNMASK) == PRINTERS_ICOL_NAME)
  2109. {
  2110. return GetCompareDisplayName(szName1, szName2);
  2111. }
  2112. PFOLDER_PRINTER_DATA pData1 = (PFOLDER_PRINTER_DATA)Printer_FolderGetPrinter(GetFolder(), szName1);
  2113. PFOLDER_PRINTER_DATA pData2 = (PFOLDER_PRINTER_DATA)Printer_FolderGetPrinter(GetFolder(), szName2);
  2114. if (pData1 && pData2)
  2115. {
  2116. switch (iCol & SHCIDS_COLUMNMASK)
  2117. {
  2118. case PRINTERS_ICOL_QUEUESIZE:
  2119. iResult = pData1->cJobs - pData2->cJobs;
  2120. bDoStringCompare = FALSE;
  2121. break;
  2122. case PRINTERS_ICOL_STATUS:
  2123. pName1 = GetStatusString(pData1, szTemp1, ARRAYSIZE(szTemp1));
  2124. pName2 = GetStatusString(pData2, szTemp2, ARRAYSIZE(szTemp1));
  2125. break;
  2126. case PRINTERS_ICOL_COMMENT:
  2127. pName1 = pData1->pComment;
  2128. pName2 = pData2->pComment;
  2129. break;
  2130. case PRINTERS_ICOL_LOCATION:
  2131. pName1 = pData1->pLocation;
  2132. pName2 = pData2->pLocation;
  2133. break;
  2134. case PRINTERS_ICOL_MODEL:
  2135. pName1 = pData1->pDriverName;
  2136. pName2 = pData2->pDriverName;
  2137. break;
  2138. default:
  2139. bDoStringCompare = FALSE;
  2140. break;
  2141. }
  2142. if (bDoStringCompare)
  2143. {
  2144. if (!pName1)
  2145. pName1 = TEXT("");
  2146. if (!pName2)
  2147. pName2 = TEXT("");
  2148. TraceMsg(TF_GENERAL, "CPrinters_SF_CompareData %ws %ws", pName1, pName2);
  2149. iResult = lstrcmpi(pName1, pName2);
  2150. }
  2151. }
  2152. if (pData1)
  2153. LocalFree((HLOCAL)pData1);
  2154. if (pData2)
  2155. LocalFree((HLOCAL)pData2);
  2156. return iResult;
  2157. }
  2158. //
  2159. // Stolen almost verbatim from netviewx.c's CNetRoot_MakeStripToLikeKinds
  2160. //
  2161. // Takes a possibly-heterogenous pidl array, and strips out the pidls that
  2162. // don't match the requested type. (If fPrinterObjects is TRUE, we're asking
  2163. // for printers pidls, otherwise we're asking for the filesystem/link
  2164. // objects.) The return value is TRUE if we had to allocate a new array
  2165. // in which to return the reduced set of pidls (in which case the caller
  2166. // should free the array with LocalFree()), FALSE if we are returning the
  2167. // original array of pidls (in which case no cleanup is required).
  2168. //
  2169. BOOL CPrinterFolder::ReduceToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fPrintObjects)
  2170. {
  2171. LPITEMIDLIST *apidl = (LPITEMIDLIST*)*papidl;
  2172. int cidl = *pcidl;
  2173. int iidl;
  2174. LPITEMIDLIST *apidlHomo;
  2175. int cpidlHomo;
  2176. for (iidl = 0; iidl < cidl; iidl++)
  2177. {
  2178. if ((HOOD_COL_PRINTER == _IDListType(apidl[iidl])) != fPrintObjects)
  2179. {
  2180. apidlHomo = (LPITEMIDLIST *)LocalAlloc(LPTR, sizeof(LPITEMIDLIST) * cidl);
  2181. if (!apidlHomo)
  2182. return FALSE;
  2183. cpidlHomo = 0;
  2184. for (iidl = 0; iidl < cidl; iidl++)
  2185. {
  2186. if ((HOOD_COL_PRINTER == _IDListType(apidl[iidl])) == fPrintObjects)
  2187. apidlHomo[cpidlHomo++] = apidl[iidl];
  2188. }
  2189. // Setup to use the stripped version of the pidl array...
  2190. *pcidl = cpidlHomo;
  2191. *papidl = (LPCITEMIDLIST*)apidlHomo;
  2192. return TRUE;
  2193. }
  2194. }
  2195. return FALSE;
  2196. }
  2197. DWORD CPrinterFolder::SpoolerVersion()
  2198. {
  2199. CCSLock::Locker lock(_csLock);
  2200. if (lock)
  2201. {
  2202. if (_dwSpoolerVersion == -1)
  2203. {
  2204. _dwSpoolerVersion = 0;
  2205. HANDLE hServer = Printer_OpenPrinter(_pszServer);
  2206. if (hServer)
  2207. {
  2208. DWORD dwNeeded = 0, dwType = REG_DWORD;
  2209. GetPrinterData(hServer, TEXT("MajorVersion"), &dwType, (PBYTE)&_dwSpoolerVersion,
  2210. sizeof(_dwSpoolerVersion), &dwNeeded);
  2211. Printer_ClosePrinter(hServer);
  2212. }
  2213. }
  2214. }
  2215. else
  2216. {
  2217. // unable to enter the CS -- this can happen only in extremely low memory conditions!
  2218. SetLastError(ERROR_OUTOFMEMORY);
  2219. }
  2220. return _dwSpoolerVersion;
  2221. }
  2222. void CPrinterFolder::CheckToRegisterNotify()
  2223. {
  2224. CCSLock::Locker lock(_csLock);
  2225. if (lock)
  2226. {
  2227. if (NULL == _hFolder && FAILED(RegisterPrintNotify(_pszServer, this, &_hFolder, &_bAdminAccess)))
  2228. {
  2229. // paranoia...
  2230. ASSERT(NULL == _hFolder);
  2231. _hFolder = NULL;
  2232. }
  2233. }
  2234. else
  2235. {
  2236. // unable to enter the CS -- this can happen only in extremely low memory conditions!
  2237. SetLastError(ERROR_OUTOFMEMORY);
  2238. }
  2239. }
  2240. void CPrinterFolder::CheckToRefresh()
  2241. {
  2242. if (_bReqRefresh)
  2243. {
  2244. // kick off a full refresh...
  2245. _bReqRefresh = FALSE;
  2246. bFolderRefresh(_hFolder, &_bAdminAccess);
  2247. }
  2248. }
  2249. void CPrinterFolder::RequestRefresh()
  2250. {
  2251. _bReqRefresh = TRUE;
  2252. }
  2253. HRESULT CPrinterFolder::QueryInterface(REFIID riid, void **ppv)
  2254. {
  2255. static const QITAB qit[] =
  2256. {
  2257. QITABENT(CPrinterFolder, IShellFolder),
  2258. QITABENTMULTI(CPrinterFolder, IShellFolder2, IShellFolder),
  2259. QITABENT(CPrinterFolder, IPersist),
  2260. QITABENTMULTI(CPrinterFolder, IPersistFolder, IPersist),
  2261. QITABENTMULTI(CPrinterFolder, IPersistFolder2, IPersistFolder),
  2262. QITABENT(CPrinterFolder, IShellIconOverlay),
  2263. QITABENT(CPrinterFolder, IRemoteComputer),
  2264. QITABENT(CPrinterFolder, IPrinterFolder),
  2265. QITABENT(CPrinterFolder, IFolderNotify),
  2266. QITABENT(CPrinterFolder, IContextMenuCB),
  2267. { 0 },
  2268. };
  2269. HRESULT hr = QISearch(this, qit, riid, ppv);
  2270. if (FAILED(hr))
  2271. {
  2272. // Internal only
  2273. if (IsEqualGUID(riid, CLSID_Printers))
  2274. {
  2275. *ppv = (CPrinterFolder*)this;
  2276. AddRef();
  2277. hr = S_OK;
  2278. }
  2279. }
  2280. return hr;
  2281. }
  2282. ULONG CPrinterFolder::AddRef()
  2283. {
  2284. return InterlockedIncrement(&_cRef);
  2285. }
  2286. ULONG CPrinterFolder::Release()
  2287. {
  2288. if (InterlockedDecrement(&_cRef))
  2289. return _cRef;
  2290. delete this;
  2291. return 0;
  2292. }
  2293. // IShellFolder2
  2294. STDMETHODIMP CPrinterFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  2295. {
  2296. *ppv = NULL;
  2297. return E_NOTIMPL;
  2298. }
  2299. STDMETHODIMP CPrinterFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  2300. {
  2301. return BindToObject(pidl, pbc, riid, ppv);
  2302. }
  2303. STDMETHODIMP CPrinterFolder::CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  2304. {
  2305. UNALIGNED IDPRINTER *pidp1 = (UNALIGNED IDPRINTER*)pidl1;
  2306. UNALIGNED IDPRINTER *pidp2 = (UNALIGNED IDPRINTER*)pidl2;
  2307. PIDLTYPE ColateType1 = _IDListType(pidl1);
  2308. PIDLTYPE ColateType2 = _IDListType(pidl2);
  2309. if (ColateType1 == ColateType2)
  2310. {
  2311. // pidls are of same type.
  2312. if (ColateType1 == HOOD_COL_FILE)
  2313. {
  2314. // pidls are both of type file, so pass on to the IShellFolder
  2315. // interface for the hoods custom directory.
  2316. IShellFolder2* psf = CPrintRoot_GetPSF();
  2317. if (psf)
  2318. return psf->CompareIDs(iCol, pidl1, pidl2);
  2319. }
  2320. else
  2321. {
  2322. // pidls are same and not files, so must be printers
  2323. if (pidp1->dwType != pidp2->dwType)
  2324. {
  2325. return (pidp1->dwType < pidp2->dwType) ?
  2326. ResultFromShort(-1) :
  2327. ResultFromShort(1);
  2328. }
  2329. int i = ualstrcmpi(pidp1->cName, pidp2->cName);
  2330. if (i != 0)
  2331. {
  2332. // add printer wizard is "less" than everything else
  2333. // This implies that when the list is sorted
  2334. // either accending or decending the add printer
  2335. // wizard object will always appear at the extream
  2336. // ends of the list, i.e. the top or bottom.
  2337. //
  2338. if (_IsAddPrinter(pidp1))
  2339. i = -1;
  2340. else if (_IsAddPrinter(pidp2))
  2341. i = 1;
  2342. else
  2343. {
  2344. // Both of the names are not the add printer wizard
  2345. // object then compare further i.e. using the cached
  2346. // column data.
  2347. // 99/03/24 #308785 vtan: Make the compare data call.
  2348. // If that fails use the name compare result which is
  2349. // known to be non-zero.
  2350. int iDataCompareResult = CompareData(pidp1, pidp2, iCol);
  2351. if (iDataCompareResult != 0)
  2352. i = iDataCompareResult;
  2353. }
  2354. }
  2355. return ResultFromShort(i);
  2356. }
  2357. }
  2358. else
  2359. {
  2360. // pidls are not of same type, so have already been correctly
  2361. // collated (consequently, sorting is first by type and
  2362. // then by subfield).
  2363. return ResultFromShort((((INT)(ColateType2 - ColateType1)) > 0) ? -1 : 1);
  2364. }
  2365. return E_FAIL;
  2366. }
  2367. STDMETHODIMP CPrinterFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  2368. {
  2369. HRESULT hr;
  2370. if (IsEqualIID(riid, IID_IShellView))
  2371. {
  2372. SFV_CREATE sSFV;
  2373. sSFV.cbSize = sizeof(sSFV);
  2374. sSFV.pshf = this;
  2375. sSFV.psvOuter = NULL;
  2376. sSFV.psfvcb = new CPrinterFolderViewCB(this, _pidl);
  2377. hr = SHCreateShellFolderView(&sSFV, (IShellView**)ppv);
  2378. if (sSFV.psfvcb)
  2379. sSFV.psfvcb->Release();
  2380. }
  2381. else if (IsEqualIID(riid, IID_IDropTarget))
  2382. {
  2383. hr = CPrinterFolderDropTarget_CreateInstance(hwnd, (IDropTarget **)ppv);
  2384. }
  2385. else if (IsEqualIID(riid, IID_IContextMenu))
  2386. {
  2387. hr = CDefFolderMenu_Create2Ex(NULL, hwnd,
  2388. 0, NULL, this, this,
  2389. 0, NULL, (IContextMenu **)ppv);
  2390. }
  2391. else
  2392. {
  2393. *ppv = NULL;
  2394. hr = E_NOINTERFACE;
  2395. }
  2396. return hr;
  2397. }
  2398. STDMETHODIMP CPrinterFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList** ppenum)
  2399. {
  2400. // By default we always do standard (printer) enumeration
  2401. DWORD dwRemote = 0;
  2402. // Only add links (from the PrintHood directory) to the enumeration
  2403. // if this is the local print folder
  2404. IEnumIDList* peunk = NULL;
  2405. if (_pszServer == NULL)
  2406. {
  2407. // Always try to enum links.
  2408. IShellFolder2 *psfPrintHood = CPrintRoot_GetPSF();
  2409. if (psfPrintHood)
  2410. psfPrintHood->EnumObjects(NULL, grfFlags, &peunk);
  2411. if (peunk)
  2412. {
  2413. // If this went OK, we will also enumerate links
  2414. dwRemote |= RMF_SHOWLINKS;
  2415. }
  2416. }
  2417. return CPrintersEnum::CreateInstance(grfFlags, dwRemote, peunk, this, ppenum);
  2418. }
  2419. STDMETHODIMP CPrinterFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* prgf)
  2420. {
  2421. HRESULT hr = S_OK;
  2422. ULONG rgfOut = SFGAO_CANLINK | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET;
  2423. ULONG rgfIn = *prgf;
  2424. if (cidl && (HOOD_COL_FILE == _IDListType(apidl[0])))
  2425. {
  2426. IShellFolder2 *psf = CPrintRoot_GetPSF();
  2427. if (psf)
  2428. return psf->GetAttributesOf(cidl, apidl, prgf);
  2429. return E_INVALIDARG;
  2430. }
  2431. // if new printer wizard is selected, we support CANLINK *only*
  2432. for (UINT i = 0 ; i < cidl ; i++)
  2433. {
  2434. LPIDPRINTER pidp = (LPIDPRINTER)apidl[i];
  2435. TCHAR szPrinter[MAXNAMELENBUFFER];
  2436. _ItemName(pidp, szPrinter, ARRAYSIZE(szPrinter));
  2437. if (_IsAddPrinter(pidp))
  2438. {
  2439. // add printer wiz, we support CANLINK *only*
  2440. rgfOut &= SFGAO_CANLINK;
  2441. // added SFGAO_CANDELETE if multiple printers are selected
  2442. // otherwise it's hard to tell why the del key doesn't work.
  2443. if (cidl > 1)
  2444. {
  2445. rgfOut |= SFGAO_CANDELETE;
  2446. }
  2447. }
  2448. else if (Printer_CheckNetworkPrinterByName(szPrinter, NULL))
  2449. {
  2450. // Don't allow renaming of printer connections on WINNT.
  2451. // This is disallowed becase on WINNT, the printer connection
  2452. // name _must_ be the in the format \\server\printer. On
  2453. // win9x, the user can rename printer connections.
  2454. rgfOut &= ~SFGAO_CANRENAME;
  2455. }
  2456. }
  2457. *prgf &= rgfOut;
  2458. if (cidl == 1 && (rgfIn & (SFGAO_SHARE | SFGAO_GHOSTED)))
  2459. {
  2460. LPIDPRINTER pidp = (LPIDPRINTER)apidl[0];
  2461. void *pData = NULL;
  2462. DWORD dwAttributes = 0;
  2463. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  2464. LPCTSTR pszPrinter = _BuildPrinterName(szFullPrinter, pidp, NULL);
  2465. // If we have notification code, use the hFolder to get
  2466. // printer data instead of querying the printer directly.
  2467. if (GetFolder())
  2468. {
  2469. pData = Printer_FolderGetPrinter(GetFolder(), pszPrinter);
  2470. if (pData)
  2471. dwAttributes = ((PFOLDER_PRINTER_DATA)pData)->Attributes;
  2472. }
  2473. else
  2474. {
  2475. pData = Printer_GetPrinterInfoStr(szFullPrinter, 5);
  2476. if (pData)
  2477. dwAttributes = ((PPRINTER_INFO_5)pData)->Attributes;
  2478. }
  2479. if (pData)
  2480. {
  2481. if (dwAttributes & PRINTER_ATTRIBUTE_SHARED
  2482. // NT appears to return all network printers with their
  2483. // share bit on. I think this is intentional.
  2484. //
  2485. && (dwAttributes & PRINTER_ATTRIBUTE_NETWORK) == 0
  2486. )
  2487. {
  2488. *prgf |= SFGAO_SHARE;
  2489. }
  2490. if (dwAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE)
  2491. *prgf |= SFGAO_GHOSTED;
  2492. else
  2493. *prgf &= ~SFGAO_GHOSTED;
  2494. LocalFree((HLOCAL)pData);
  2495. }
  2496. else
  2497. {
  2498. // This fct used to always return E_OUTOFMEMORY if pData was NULL. pData can be
  2499. // NULL for other reasons than out of memory. So this failure is not really valid.
  2500. // However the Shell handle this failure (which is bad in the first place).
  2501. // If we fail, we just set the attributes to 0 and go on as if nothing happenned.
  2502. // Star Office 5.0, does not handle the E_OUTOFMEMORY properly, they handle it as
  2503. // a failure (which is exactly what we report to them) and they stop their
  2504. // processing to show the Add Printer icon. But they're bad on one point, they
  2505. // check for S_OK directly so I cannot return S_FALSE. (stephstm, 07/30/99)
  2506. if (SHGetAppCompatFlags(ACF_STAROFFICE5PRINTER) &&
  2507. (ERROR_INVALID_PRINTER_NAME == GetLastError()))
  2508. {
  2509. hr = S_OK;
  2510. }
  2511. else
  2512. {
  2513. hr = E_OUTOFMEMORY;
  2514. }
  2515. }
  2516. }
  2517. return hr;
  2518. }
  2519. STDMETHODIMP CPrinterFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *psr)
  2520. {
  2521. LPIDPRINTER pidc = (LPIDPRINTER)pidl;
  2522. BOOL bPrinterOnServerFormat = FALSE;
  2523. LPCTSTR pszServer;
  2524. TCHAR szBuffer[MAXNAMELENBUFFER];
  2525. TCHAR szTemp[MAXNAMELENBUFFER];
  2526. LPCTSTR pszTemp;
  2527. LPCTSTR pszPrinter = szBuffer;
  2528. if (pidl && HOOD_COL_FILE == _IDListType(pidl))
  2529. {
  2530. IShellFolder2 *psf = CPrintRoot_GetPSF();
  2531. if (psf)
  2532. return psf->GetDisplayNameOf(pidl, uFlags, psr);
  2533. return E_INVALIDARG;
  2534. }
  2535. if (!_IsAddPrinter(pidc))
  2536. {
  2537. pszPrinter = _ItemName(pidc, szBuffer, ARRAYSIZE(szBuffer));
  2538. if (uFlags & SHGDN_INFOLDER)
  2539. {
  2540. // relative name (to the folder)
  2541. if (!(SHGDN_FORPARSING & uFlags))
  2542. {
  2543. // If it's a connection then format as "printer on server."
  2544. Printer_SplitFullName(szTemp, pszPrinter, &pszServer, &pszTemp);
  2545. if (pszServer[0])
  2546. {
  2547. bPrinterOnServerFormat = TRUE;
  2548. pszPrinter = pszTemp;
  2549. }
  2550. }
  2551. }
  2552. else // SHGDN_NORMAL
  2553. {
  2554. if (!(SHGDN_FORPARSING & uFlags))
  2555. {
  2556. // If it's a RPF then extract the server name from psf.
  2557. // Note in the case of masq connections, we still do this
  2558. // (for gateway services: sharing a masq printer).
  2559. if (_pszServer)
  2560. {
  2561. pszServer = _pszServer;
  2562. bPrinterOnServerFormat = TRUE;
  2563. }
  2564. else
  2565. {
  2566. // If it's a connection then format as "printer on server."
  2567. Printer_SplitFullName(szTemp, pszPrinter, &pszServer, &pszTemp);
  2568. if (pszServer[0])
  2569. {
  2570. bPrinterOnServerFormat = TRUE;
  2571. pszPrinter = pszTemp;
  2572. }
  2573. }
  2574. }
  2575. else // SHGDN_NORMAL | SHGDN_FORPARSING
  2576. {
  2577. // Fully qualify the printer name if it's not
  2578. // the add printer wizard.
  2579. if (!_IsAddPrinter(pidc))
  2580. {
  2581. _BuildPrinterName(szTemp, pidc, NULL);
  2582. pszPrinter = szTemp;
  2583. }
  2584. }
  2585. }
  2586. }
  2587. else
  2588. {
  2589. LoadString(HINST_THISDLL, IDS_NEWPRN, szBuffer, ARRAYSIZE(szBuffer));
  2590. // Use "Add Printer Wizard on \\server" description only if not
  2591. // remote and if not in folder view (e.g., on the desktop).
  2592. if (_pszServer && (uFlags == SHGDN_NORMAL))
  2593. {
  2594. bPrinterOnServerFormat = TRUE;
  2595. pszServer = _pszServer;
  2596. pszPrinter = szBuffer;
  2597. }
  2598. else if (uFlags & SHGDN_FORPARSING)
  2599. {
  2600. // Return the raw add printer wizard object.
  2601. pszPrinter = (LPTSTR)c_szNewObject;
  2602. }
  2603. }
  2604. HRESULT hr;
  2605. if (bPrinterOnServerFormat)
  2606. {
  2607. // When bRemote is set, we want to translate the name to
  2608. // "printer on server." Note: we should not have a rename problem
  2609. // since renaming connections is disallowed.
  2610. //
  2611. // pszServer and pszPrinter must be initialize if bRemote is TRUE.
  2612. // Also skip the leading backslashes for the server name.
  2613. ASSERT(pszServer[0] == TEXT('\\') && pszServer[1] == TEXT('\\'));
  2614. LPTSTR pszRet = ShellConstructMessageString(HINST_THISDLL,
  2615. MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON),
  2616. &pszServer[2], pszPrinter);
  2617. if (pszRet)
  2618. {
  2619. hr = StringToStrRet(pszRet, psr);
  2620. LocalFree(pszRet);
  2621. }
  2622. else
  2623. hr = E_FAIL;
  2624. }
  2625. else
  2626. {
  2627. hr = StringToStrRet(pszPrinter, psr);
  2628. }
  2629. return hr;
  2630. }
  2631. STDMETHODIMP CPrinterFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT *prgf, void **ppv)
  2632. {
  2633. HRESULT hr = E_INVALIDARG;
  2634. UINT cidlPrinters = cidl;
  2635. LPCITEMIDLIST *apidlPrinters = apidl;
  2636. BOOL bStrippedLinks = FALSE;
  2637. if (cidl)
  2638. {
  2639. // strip out the link PIDLs and leave only the printer ones
  2640. bStrippedLinks = ReduceToLikeKinds(&cidlPrinters, &apidlPrinters, TRUE);
  2641. }
  2642. if (cidl && 0 == cidlPrinters)
  2643. {
  2644. // if we don't have any printer PIDLs then just defer the operation
  2645. // to the printhood folder.
  2646. IShellFolder2* psfPrintRoot = CPrintRoot_GetPSF();
  2647. hr = psfPrintRoot ? psfPrintRoot->GetUIObjectOf(hwnd, cidl, apidl, riid, prgf, ppv) : E_INVALIDARG;
  2648. }
  2649. else
  2650. {
  2651. //
  2652. // we have some printer PIDLs selected, but it could be a mixed selection
  2653. // of printer PIDLs and file system link objects. we will handle the data
  2654. // object explicitly not to loose information about the selection type.
  2655. // the IDL array format doesn't support different type of PIDLs so we have
  2656. // to create two data objects and combine them into one data object which
  2657. // supports IServiceProvider and then the caller can query our compound data
  2658. // object for SID_SAuxDataObject service to get IDataObject interface of our
  2659. // auxiliary data object (in case it needs access to the link PIDLs).
  2660. //
  2661. if (cidl && IsEqualIID(riid, IID_IDataObject))
  2662. {
  2663. // strip out the printer PIDLs and leave only the link ones
  2664. // we are going to use those PIDLs to create our auxiliary data object
  2665. UINT cidlLinks = cidl;
  2666. LPCITEMIDLIST *apidlLinks = apidl;
  2667. BOOL bStrippedPrinters = FALSE;
  2668. if (cidl)
  2669. {
  2670. // strip out the printer PIDLs and leave only the link ones
  2671. bStrippedPrinters = ReduceToLikeKinds(&cidlLinks, &apidlLinks, FALSE);
  2672. }
  2673. hr = S_OK;
  2674. IDataObject *pdoLinks = NULL;
  2675. if (cidlLinks && apidlLinks)
  2676. {
  2677. // we have some link PIDLs. let's ask the printhood folder to create
  2678. // data object for us to embedd into our data object.
  2679. IShellFolder2* psfPrintRoot = CPrintRoot_GetPSF();
  2680. hr = psfPrintRoot ?
  2681. psfPrintRoot->GetUIObjectOf(hwnd, cidlLinks, apidlLinks, riid, prgf, (void **)&pdoLinks) :
  2682. E_INVALIDARG;
  2683. // just out of paranoia...
  2684. if (FAILED(hr))
  2685. pdoLinks = NULL;
  2686. }
  2687. if (SUCCEEDED(hr))
  2688. {
  2689. // create our compund printers data object and pass in the private
  2690. // auxiliary data object which will contain the link PIDLs
  2691. CPrintersData *ppd = new CPrintersData(pdoLinks, _pidl, cidlPrinters, apidlPrinters);
  2692. if (ppd)
  2693. {
  2694. hr = ppd->QueryInterface(riid, ppv);
  2695. ppd->Release();
  2696. }
  2697. else
  2698. hr = E_OUTOFMEMORY;
  2699. }
  2700. // release allocated objects/memory
  2701. if (pdoLinks)
  2702. pdoLinks->Release();
  2703. if (bStrippedPrinters)
  2704. LocalFree((HLOCAL)apidlLinks);
  2705. }
  2706. else
  2707. {
  2708. // operate only on the printer PIDLs selection (the current behaviour)
  2709. // and ignore the links selection. this may be wrong in some cases, but
  2710. // this code has been busted either way (so far), so we'll fix those on
  2711. // per case basis. the best solution will be to cut of the printhood
  2712. // functionality, but alas...
  2713. LPCIDPRINTER pidp = cidlPrinters > 0 ? (LPIDPRINTER)apidlPrinters[0] : NULL;
  2714. if (pidp && (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)))
  2715. {
  2716. int iIcon;
  2717. int iShortcutIcon;
  2718. TCHAR szBuf[MAX_PATH+20];
  2719. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  2720. LPTSTR pszModule = NULL;
  2721. _BuildPrinterName(szFullPrinter, pidp, NULL);
  2722. if (_IsAddPrinter(pidp))
  2723. iIcon = iShortcutIcon = IDI_NEWPRN;
  2724. else
  2725. {
  2726. pszModule = _FindIcon(szFullPrinter, szBuf, ARRAYSIZE(szBuf), &iIcon, &iShortcutIcon);
  2727. }
  2728. hr = SHCreateDefExtIconKey(NULL, pszModule, EIRESID(iIcon), -1, -1, EIRESID(iShortcutIcon), GIL_PERINSTANCE, riid, ppv);
  2729. }
  2730. else if (pidp && IsEqualIID(riid, IID_IContextMenu))
  2731. {
  2732. HKEY hkeyBaseProgID = NULL;
  2733. int nCount = 0;
  2734. if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, c_szPrinters, &hkeyBaseProgID))
  2735. nCount++;
  2736. hr = CDefFolderMenu_Create2(_pidl, hwnd,
  2737. cidl, apidl, SAFECAST(this, IShellFolder*), _DFMCallBack,
  2738. nCount, &hkeyBaseProgID, (IContextMenu **)ppv);
  2739. if (hkeyBaseProgID)
  2740. RegCloseKey(hkeyBaseProgID);
  2741. }
  2742. else if (pidp && IsEqualIID(riid, IID_IDropTarget))
  2743. {
  2744. if (_IsAddPrinter(pidp))
  2745. {
  2746. // "NewPrinter" accepts network printer shares
  2747. hr = CreateViewObject(hwnd, riid, ppv); // folder drop target
  2748. }
  2749. else
  2750. {
  2751. LPITEMIDLIST pidl;
  2752. hr = SHILCombine(_pidl, apidl[0], &pidl);
  2753. if (SUCCEEDED(hr))
  2754. {
  2755. hr = CPrinterDropTarget_CreateInstance(hwnd, pidl, (IDropTarget**)ppv);
  2756. ILFree(pidl);
  2757. }
  2758. }
  2759. }
  2760. else if (pidp && IsEqualIID(riid, IID_IQueryInfo))
  2761. {
  2762. // get the infotip from IQA
  2763. IQueryAssociations *pqa;
  2764. hr = _AssocCreate(IID_PPV_ARG(IQueryAssociations, &pqa));
  2765. if (SUCCEEDED(hr))
  2766. {
  2767. WCHAR szText[INFOTIPSIZE];
  2768. DWORD cch = ARRAYSIZE(szText);
  2769. hr = pqa->GetString(0, ASSOCSTR_INFOTIP, NULL, szText, &cch);
  2770. if (SUCCEEDED(hr))
  2771. {
  2772. hr = CreateInfoTipFromItem(SAFECAST(this, IShellFolder2*),
  2773. (LPCITEMIDLIST)pidp, szText, riid, ppv);
  2774. }
  2775. pqa->Release();
  2776. }
  2777. }
  2778. else if (pidp && IsEqualIID(riid, IID_IQueryAssociations))
  2779. {
  2780. // return our IQA
  2781. hr = _AssocCreate(riid, ppv);
  2782. }
  2783. }
  2784. }
  2785. // release the memory allocated from ReduceToLikeKinds
  2786. if (bStrippedLinks)
  2787. LocalFree((HLOCAL)apidlPrinters);
  2788. return hr;
  2789. }
  2790. STDMETHODIMP CPrinterFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes)
  2791. {
  2792. HRESULT hr = E_INVALIDARG;
  2793. // check if this is not a PrintHood object first
  2794. IShellFolder2 *psfPrintHood = CPrintRoot_GetPSF();
  2795. if (psfPrintHood)
  2796. {
  2797. hr = psfPrintHood->ParseDisplayName(hwnd, pbc, pszName, pchEaten, ppidl, pdwAttributes);
  2798. }
  2799. if (FAILED(hr))
  2800. {
  2801. // not a printhood object - try the folder cache
  2802. hr = E_INVALIDARG;
  2803. if (ppidl)
  2804. *ppidl = NULL;
  2805. if (pszName && ppidl)
  2806. {
  2807. hr = S_OK;
  2808. DWORD dwType = 0;
  2809. BOOL bValidated = FALSE;
  2810. void *pData = NULL;
  2811. // check the bind info first
  2812. if (pbc)
  2813. {
  2814. IUnknown *pUnk;
  2815. hr = pbc->GetObjectParam(PRINTER_BIND_INFO, &pUnk);
  2816. if (SUCCEEDED(hr))
  2817. {
  2818. IPrintersBindInfo *pInfo;
  2819. hr = pUnk->QueryInterface(IID_PPV_ARG(IPrintersBindInfo, &pInfo));
  2820. if (SUCCEEDED(hr))
  2821. {
  2822. // update dwType & bValidated from the bind info
  2823. pInfo->GetPIDLType(&dwType);
  2824. bValidated = (S_OK == pInfo->IsValidated());
  2825. pInfo->Release();
  2826. }
  2827. pUnk->Release();
  2828. }
  2829. }
  2830. if (SUCCEEDED(hr))
  2831. {
  2832. // the "add printer" icon doesn't need validation
  2833. if (StrStrIW(pszName, c_szNewObject))
  2834. {
  2835. bValidated = TRUE;
  2836. }
  2837. // hit the folder cache to see if this printer belongs to this folder.
  2838. if (bValidated || (pData = (GetFolder() ? Printer_FolderGetPrinter(GetFolder(), pszName) : NULL)))
  2839. {
  2840. // well, looks like this printer belongs to our folder -
  2841. // create a printer PIDL (relative to this folder).
  2842. hr = _Parse(pszName, ppidl, dwType);
  2843. }
  2844. else
  2845. {
  2846. // the printer doesn't belong to this folder - cook up correct HRESULT.
  2847. // usually the last error here is ERROR_INVALID_PRINTER_NAME
  2848. DWORD dwLastErr = GetLastError();
  2849. hr = ERROR_SUCCESS == dwLastErr ? HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME)
  2850. : HRESULT_FROM_WIN32(dwLastErr);
  2851. }
  2852. }
  2853. if (pData)
  2854. LocalFree((HLOCAL)pData);
  2855. }
  2856. // check to return pchEaten
  2857. if (SUCCEEDED(hr) && pchEaten)
  2858. {
  2859. *pchEaten = lstrlen(pszName);
  2860. }
  2861. // check to return pdwAttributes
  2862. if (SUCCEEDED(hr) && pdwAttributes)
  2863. {
  2864. hr = GetAttributesOf(1, (LPCITEMIDLIST *)ppidl, pdwAttributes);
  2865. }
  2866. }
  2867. return hr;
  2868. }
  2869. STDMETHODIMP CPrinterFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszNewName, DWORD dwRes, LPITEMIDLIST* ppidlOut)
  2870. {
  2871. HRESULT hr = S_OK;
  2872. HANDLE hPrinter = NULL;
  2873. LPPRINTER_INFO_2 pPrinter = NULL;
  2874. if (HOOD_COL_FILE == _IDListType(pidl))
  2875. {
  2876. IShellFolder2 *psf = CPrintRoot_GetPSF();
  2877. hr = psf ? psf->SetNameOf(hwnd, pidl, pszNewName, dwRes, ppidlOut) : E_INVALIDARG;
  2878. goto Exit;
  2879. }
  2880. else
  2881. {
  2882. LPIDPRINTER pidc = (LPIDPRINTER)pidl;
  2883. ASSERT(!_IsAddPrinter(pidc)); // does not have _CANRENAME bit
  2884. TCHAR szNewName[MAX_PATH];
  2885. SHUnicodeToTChar(pszNewName, szNewName, ARRAYSIZE(szNewName));
  2886. PathRemoveBlanks(szNewName);
  2887. TCHAR szOldName[MAXNAMELENBUFFER];
  2888. _ItemName(pidc, szOldName, ARRAYSIZE(szOldName));
  2889. if (0 == lstrcmp(szOldName, szNewName))
  2890. goto Exit;
  2891. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  2892. _BuildPrinterName(szFullPrinter, NULL, szOldName);
  2893. LPCTSTR pszFullOldName = szFullPrinter;
  2894. hPrinter = Printer_OpenPrinterAdmin(pszFullOldName);
  2895. if (NULL == hPrinter)
  2896. goto Error;
  2897. pPrinter = (LPPRINTER_INFO_2)Printer_GetPrinterInfo(hPrinter, 2);
  2898. if (NULL == pPrinter)
  2899. goto Error;
  2900. int nTmp = _IllegalPrinterName(szNewName);
  2901. if (0 != nTmp)
  2902. {
  2903. // NTRAID95214-2000-03-17:
  2904. // We need to impl ::SetSite() and pass it to UI APIs
  2905. // to go modal if we display UI.
  2906. if (hwnd)
  2907. {
  2908. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(nTmp),
  2909. MAKEINTRESOURCE(IDS_PRINTERS),
  2910. MB_OK|MB_ICONEXCLAMATION);
  2911. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2912. goto Exit;
  2913. }
  2914. }
  2915. else if (IDYES != CallPrinterCopyHooks(hwnd, PO_RENAME, 0, szNewName, 0, pszFullOldName, 0))
  2916. {
  2917. // user canceled a shared printer name change, bail.
  2918. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2919. goto Exit;
  2920. }
  2921. else
  2922. {
  2923. pPrinter->pPrinterName = szNewName;
  2924. if (FALSE == SetPrinter(hPrinter, 2, (LPBYTE)pPrinter, 0))
  2925. goto Error;
  2926. // return the new pidl if requested
  2927. hr = ppidlOut ? _Parse(szNewName, ppidlOut) : S_OK;
  2928. if (SUCCEEDED(hr))
  2929. goto Exit;
  2930. }
  2931. }
  2932. Error:
  2933. if (SUCCEEDED(hr))
  2934. {
  2935. // get the correct error from win32
  2936. hr = HRESULT_FROM_WIN32(GetLastError());
  2937. }
  2938. // show an appropriate error message based on the HRESULT
  2939. ShowErrorMessageHR(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, hr);
  2940. Exit:
  2941. if( pPrinter )
  2942. {
  2943. LocalFree((HLOCAL)pPrinter);
  2944. }
  2945. if( hPrinter )
  2946. {
  2947. Printer_ClosePrinter(hPrinter);
  2948. }
  2949. return hr;
  2950. }
  2951. STDMETHODIMP CPrinterFolder::EnumSearches(IEnumExtraSearch **ppenum)
  2952. {
  2953. *ppenum = NULL;
  2954. return E_NOTIMPL;
  2955. }
  2956. STDMETHODIMP CPrinterFolder::GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  2957. {
  2958. return E_NOTIMPL;
  2959. }
  2960. STDMETHODIMP CPrinterFolder::GetDefaultColumnState(UINT iColumn, DWORD* pdwState)
  2961. {
  2962. HRESULT hr;
  2963. if (iColumn < ARRAYSIZE(c_printers_cols))
  2964. {
  2965. *pdwState = c_printers_cols[iColumn].csFlags;
  2966. hr = S_OK;
  2967. }
  2968. else
  2969. {
  2970. *pdwState = 0;
  2971. hr = E_NOTIMPL;
  2972. }
  2973. return hr;
  2974. }
  2975. STDMETHODIMP CPrinterFolder::GetDefaultSearchGUID(LPGUID pGuid)
  2976. {
  2977. *pGuid = SRCID_SFindPrinter;
  2978. return S_OK;
  2979. }
  2980. STDMETHODIMP CPrinterFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  2981. {
  2982. BOOL fFound;
  2983. HRESULT hr = AssocGetDetailsOfSCID(this, pidl, pscid, pv, &fFound);
  2984. if (FAILED(hr) && !fFound)
  2985. {
  2986. int iCol = FindSCID(c_printers_cols, ARRAYSIZE(c_printers_cols), pscid);
  2987. if (iCol >= 0)
  2988. {
  2989. SHELLDETAILS sd;
  2990. hr = GetDetailsOf(pidl, iCol, &sd);
  2991. if (SUCCEEDED(hr))
  2992. {
  2993. if (PRINTERS_ICOL_LOCATION == iCol)
  2994. {
  2995. // widen the scope of the location by 1, so it does make more sense
  2996. WCHAR szTemp[MAX_PATH];
  2997. hr = StrRetToBufW(&sd.str, pidl, szTemp, ARRAYSIZE(szTemp));
  2998. if (SUCCEEDED(hr))
  2999. {
  3000. WCHAR *p = szTemp + lstrlen(szTemp);
  3001. // cut the last slash if any
  3002. if (p > szTemp && L'/' == *p)
  3003. {
  3004. p--;
  3005. }
  3006. // search for a slash from the end
  3007. while(p > szTemp && L'/' != *p)
  3008. {
  3009. p--;
  3010. }
  3011. // if found, cut the text here, so the scope gets wider
  3012. if (p > szTemp)
  3013. {
  3014. *p = 0;
  3015. }
  3016. hr = InitVariantFromStr(pv, szTemp);
  3017. }
  3018. }
  3019. else
  3020. {
  3021. hr = InitVariantFromStrRet(&sd.str, pidl, pv);
  3022. }
  3023. }
  3024. }
  3025. }
  3026. return hr;
  3027. }
  3028. STDMETHODIMP CPrinterFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
  3029. {
  3030. LPIDPRINTER pidp = (LPIDPRINTER)pidl;
  3031. HRESULT hr = S_OK;
  3032. TCHAR szTemp[MAX_PATH];
  3033. TCHAR szPrinter[MAXNAMELENBUFFER];
  3034. if (pidl && (HOOD_COL_FILE == _IDListType(pidl)))
  3035. {
  3036. IShellFolder2 *psf = CPrintRoot_GetPSF();
  3037. if (psf)
  3038. {
  3039. if (iColumn >= 1)
  3040. return E_NOTIMPL;
  3041. return psf->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &(psd->str));
  3042. }
  3043. return E_INVALIDARG;
  3044. }
  3045. psd->str.uType = STRRET_CSTR;
  3046. psd->str.cStr[0] = 0;
  3047. if (!pidp)
  3048. {
  3049. return GetDetailsOfInfo(c_printers_cols, ARRAYSIZE(c_printers_cols), iColumn, psd);
  3050. }
  3051. _ItemName(pidp, szPrinter, ARRAYSIZE(szPrinter));
  3052. if (iColumn == PRINTERS_ICOL_NAME)
  3053. {
  3054. #ifdef UNICODE
  3055. LPCTSTR pszPrinterName = szPrinter;
  3056. TCHAR szPrinterName[MAXNAMELENBUFFER];
  3057. //
  3058. // If we have a valid server name and the printer is not
  3059. // the add printer wizard object then return a fully qualified
  3060. // printer name in the remote printers folder.
  3061. //
  3062. if (GetServer() && !_IsAddPrinter(pidp))
  3063. {
  3064. //
  3065. // Build the name which consists of the
  3066. // server name plus slash plus the printer name.
  3067. //
  3068. lstrcpyn(szPrinterName, GetServer(), ARRAYSIZE(szPrinterName));
  3069. UINT len = lstrlen(szPrinterName);
  3070. lstrcpyn(&szPrinterName[len++], TEXT("\\"), ARRAYSIZE(szPrinterName) - len);
  3071. lstrcpyn(&szPrinterName[len], pszPrinterName, ARRAYSIZE(szPrinterName) - len);
  3072. pszPrinterName = szPrinterName;
  3073. }
  3074. hr = StringToStrRet(pszPrinterName, &psd->str);
  3075. #else
  3076. hr = StringToStrRet(szPrinter, &psd->str);
  3077. #endif
  3078. }
  3079. else if (!_IsAddPrinter(pidp))
  3080. {
  3081. PFOLDER_PRINTER_DATA pData = (PFOLDER_PRINTER_DATA)Printer_FolderGetPrinter(GetFolder(), szPrinter);
  3082. if (pData)
  3083. {
  3084. switch (iColumn)
  3085. {
  3086. case PRINTERS_ICOL_QUEUESIZE:
  3087. wsprintf(szTemp, TEXT("%ld"), pData->cJobs);
  3088. hr = StringToStrRet(szTemp, &psd->str);
  3089. break;
  3090. case PRINTERS_ICOL_STATUS:
  3091. {
  3092. DWORD dwStatus = pData->Status;
  3093. // HACK: Use this free bit for "Work Offline"
  3094. if (pData->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE)
  3095. dwStatus |= PRINTER_HACK_WORK_OFFLINE;
  3096. szTemp[0] = 0;
  3097. Printer_BitsToString(dwStatus, IDS_PRQSTATUS_SEPARATOR, szTemp, ARRAYSIZE(szTemp));
  3098. hr = StringToStrRet(szTemp, &psd->str);
  3099. // If the status word is null and we have a connection status string
  3100. // display the status string. This only works on NT because printui.dll
  3101. // in will generate printer connection status i.e. <opening> | <access denied> etc.
  3102. if (!dwStatus)
  3103. {
  3104. LPCTSTR pStr = pData->pStatus;
  3105. // Discard the previous status StrRet if any.
  3106. StrRetToBuf(&psd->str, NULL, szTemp, ARRAYSIZE(szTemp));
  3107. //
  3108. // If we do not have a connection status string and the status
  3109. // is 0 then the printer is ready, display ready rather than an empty string.
  3110. //
  3111. if (!pStr)
  3112. {
  3113. LoadString(HINST_THISDLL, IDS_PRN_INFOTIP_READY, szTemp, ARRAYSIZE(szTemp));
  3114. pStr = szTemp;
  3115. }
  3116. hr = StringToStrRet(pStr, &psd->str);
  3117. }
  3118. break;
  3119. }
  3120. case PRINTERS_ICOL_COMMENT:
  3121. if (pData->pComment)
  3122. {
  3123. // pComment can have newlines in it because it comes from
  3124. // a multi-line edit box. BUT we display it here in a
  3125. // single line edit box. Strip out the newlines
  3126. // to avoid the ugly characters.
  3127. lstrcpyn(szTemp, pData->pComment, ARRAYSIZE(szTemp));
  3128. LPTSTR pStr = szTemp;
  3129. while (*pStr)
  3130. {
  3131. if (*pStr == TEXT('\r') || *pStr == TEXT('\n'))
  3132. *pStr = TEXT(' ');
  3133. pStr = CharNext(pStr);
  3134. }
  3135. hr = StringToStrRet(szTemp, &psd->str);
  3136. }
  3137. break;
  3138. case PRINTERS_ICOL_LOCATION:
  3139. if (pData->pLocation)
  3140. hr = StringToStrRet(pData->pLocation, &psd->str);
  3141. break;
  3142. case PRINTERS_ICOL_MODEL:
  3143. if (pData->pDriverName)
  3144. hr = StringToStrRet(pData->pDriverName, &psd->str);
  3145. break;
  3146. }
  3147. LocalFree((HLOCAL)pData);
  3148. }
  3149. }
  3150. return hr;
  3151. }
  3152. STDMETHODIMP CPrinterFolder::MapColumnToSCID(UINT iCol, SHCOLUMNID* pscid)
  3153. {
  3154. return MapColumnToSCIDImpl(c_printers_cols, ARRAYSIZE(c_printers_cols), iCol, pscid);
  3155. }
  3156. // IPersistFolder2
  3157. STDMETHODIMP CPrinterFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  3158. {
  3159. return GetCurFolderImpl(_pidl, ppidl);
  3160. }
  3161. STDMETHODIMP CPrinterFolder::Initialize(LPCITEMIDLIST pidl)
  3162. {
  3163. ASSERT(_pidl == NULL);
  3164. // if _csLock is false then InitializeCriticalSection has thrown exception.
  3165. // this can happen only in extremely low memory conditions!
  3166. HRESULT hr = _csLock ? S_OK : E_OUTOFMEMORY;
  3167. if (SUCCEEDED(hr))
  3168. {
  3169. hr = SHILClone(pidl, &_pidl);
  3170. }
  3171. if (!_dpaSlowWVDataCache.Create(16))
  3172. {
  3173. hr = E_OUTOFMEMORY;
  3174. }
  3175. return hr;
  3176. }
  3177. STDMETHODIMP CPrinterFolder::GetClassID(LPCLSID lpClassID)
  3178. {
  3179. *lpClassID = CLSID_Printers;
  3180. return S_OK;
  3181. }
  3182. // IShellIconOverlay
  3183. STDMETHODIMP CPrinterFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int* pIndex)
  3184. {
  3185. HRESULT hr = E_INVALIDARG;
  3186. if (pidl)
  3187. {
  3188. ULONG uAttrib = SFGAO_SHARE;
  3189. hr = E_FAIL; // Until proven otherwise...
  3190. GetAttributesOf(1, &pidl, &uAttrib);
  3191. if (uAttrib & SFGAO_SHARE)
  3192. {
  3193. IShellIconOverlayManager* psiom;
  3194. hr = GetIconOverlayManager(&psiom);
  3195. if (SUCCEEDED(hr))
  3196. {
  3197. hr = psiom->GetReservedOverlayInfo(L"0", 0, pIndex, SIOM_OVERLAYINDEX, SIOM_RESERVED_SHARED);
  3198. psiom->Release();
  3199. }
  3200. }
  3201. }
  3202. return hr;
  3203. }
  3204. STDMETHODIMP CPrinterFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIndex)
  3205. {
  3206. return E_NOTIMPL;
  3207. }
  3208. // this function is assuming the printer name is valid. it is for private use.
  3209. // if you need a printer PIDL call CPrinterFolder::ParseDisplayName instead.
  3210. // we don't use CPrinterFolder::ParseDisplayName because it's heavy to use.
  3211. // it's hitting the folder cache (and potentionally creating it!).
  3212. HRESULT CPrinterFolder::_GetFullIDList(LPCWSTR pszPrinter, LPITEMIDLIST *ppidl)
  3213. {
  3214. HRESULT hr = E_INVALIDARG;
  3215. if (ppidl)
  3216. {
  3217. *ppidl = NULL;
  3218. if (pszPrinter)
  3219. {
  3220. // if pszPrinter isn't NULL this means a printer PIDL is requested.
  3221. LPITEMIDLIST pidl;
  3222. hr = _Parse(pszPrinter, &pidl, 0, 0);
  3223. if (SUCCEEDED(hr))
  3224. {
  3225. hr = SHILCombine(_pidl, pidl, ppidl);
  3226. ILFree(pidl);
  3227. }
  3228. }
  3229. else
  3230. {
  3231. // if pszPrinter is NULL this means the printers folder PIDL is requested.
  3232. hr = SHILClone(_pidl, ppidl);
  3233. }
  3234. }
  3235. return hr;
  3236. }
  3237. // IRemoteComputer
  3238. STDMETHODIMP CPrinterFolder::Initialize(const WCHAR *pszMachine, BOOL bEnumerating)
  3239. {
  3240. // if _csLock is false then InitializeCriticalSection has thrown exception.
  3241. // this can happen only in extremely low memory conditions!
  3242. HRESULT hr = _csLock ? S_OK : E_OUTOFMEMORY;
  3243. if (SUCCEEDED(hr))
  3244. {
  3245. // for servers, we want to show the remote printer folder. only check during enumeration
  3246. hr = (bEnumerating && !Printer_CheckShowFolder(pszMachine)) ? E_FAIL : S_OK;
  3247. if (SUCCEEDED(hr))
  3248. {
  3249. TCHAR szBuf[MAXCOMPUTERNAME];
  3250. SHUnicodeToTChar(pszMachine, szBuf, ARRAYSIZE(szBuf));
  3251. _pszServer = StrDup(szBuf);
  3252. hr = _pszServer ? S_OK : E_OUTOFMEMORY;
  3253. }
  3254. }
  3255. return hr;
  3256. }
  3257. // IPrinterFolder
  3258. BOOL CPrinterFolder::IsPrinter(LPCITEMIDLIST pidl)
  3259. {
  3260. return _IDListType(pidl) == HOOD_COL_PRINTER;
  3261. }
  3262. // IFolderNotify
  3263. STDMETHODIMP_(BOOL) CPrinterFolder::ProcessNotify(FOLDER_NOTIFY_TYPE NotifyType, LPCWSTR pszName, LPCWSTR pszNewName)
  3264. {
  3265. static const DWORD aNotifyTypes[] = {
  3266. kFolderUpdate, SHCNE_UPDATEITEM,
  3267. kFolderCreate, SHCNE_CREATE,
  3268. kFolderDelete, SHCNE_DELETE,
  3269. kFolderRename, SHCNE_RENAMEITEM,
  3270. kFolderAttributes, SHCNE_ATTRIBUTES };
  3271. BOOL bReturn = FALSE;
  3272. UINT uFlags = SHCNF_IDLIST | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT;
  3273. if (kFolderUpdateAll == NotifyType)
  3274. {
  3275. //
  3276. // Clear the this->bRefreshed flag, which will force invalidating the folder cache
  3277. // during the next print folder enumeration, and then request the defview to update
  3278. // the entire printers folder content (i.e. to re-enumerate the folder).
  3279. //
  3280. RequestRefresh();
  3281. NotifyType = kFolderUpdate;
  3282. pszName = NULL;
  3283. }
  3284. for (int i = 0; i < ARRAYSIZE(aNotifyTypes); i += 2)
  3285. {
  3286. if (aNotifyTypes[i] == (DWORD)NotifyType)
  3287. {
  3288. LPITEMIDLIST pidl = NULL;
  3289. LPITEMIDLIST pidlNew = NULL;
  3290. HRESULT hr = _GetFullIDList(pszName, &pidl);
  3291. if (SUCCEEDED(hr) && pszNewName)
  3292. hr = _GetFullIDList(pszNewName, &pidlNew);
  3293. // We can get a null pidl if the printer receives a refresh,
  3294. // and before we call Printers_GetPidl the printer is gone.
  3295. if (SUCCEEDED(hr))
  3296. SHChangeNotify(aNotifyTypes[i+1], uFlags, pidl, pidlNew);
  3297. ILFree(pidl);
  3298. ILFree(pidlNew);
  3299. bReturn = SUCCEEDED(hr);
  3300. break;
  3301. }
  3302. }
  3303. return bReturn;
  3304. }
  3305. // The IClassFactory callback for CLSID_Printers
  3306. STDAPI CPrinters_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
  3307. {
  3308. HRESULT hr;
  3309. CPrinterFolder* ppf = new CPrinterFolder();
  3310. if (!ppf)
  3311. {
  3312. *ppv = NULL;
  3313. hr = E_OUTOFMEMORY;
  3314. }
  3315. else
  3316. {
  3317. hr = ppf->QueryInterface(riid, ppv);
  3318. ppf->Release(); // Already have a ref count from new
  3319. }
  3320. return hr;
  3321. }
  3322. ////////////////////////////////////////////////////////////////////////////////
  3323. // CPrintersData
  3324. //
  3325. // IUnknown
  3326. STDMETHODIMP CPrintersData::QueryInterface(REFIID riid, void **ppv)
  3327. {
  3328. HRESULT hr = E_INVALIDARG;
  3329. if (ppv)
  3330. {
  3331. if (IsEqualIID(riid, IID_IServiceProvider))
  3332. {
  3333. // we implement IServiceProvider
  3334. *ppv = reinterpret_cast<void*>(static_cast<IServiceProvider*>(this));
  3335. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  3336. hr = S_OK;
  3337. }
  3338. else
  3339. {
  3340. // delegate to CIDLDataObj
  3341. hr = CIDLDataObj::QueryInterface(riid, ppv);
  3342. }
  3343. }
  3344. return hr;
  3345. }
  3346. STDMETHODIMP CPrintersData::QueryGetData(FORMATETC *pformatetc)
  3347. {
  3348. if ((pformatetc->cfFormat == g_cfPrinterFriendlyName) &&
  3349. (pformatetc->tymed & TYMED_HGLOBAL))
  3350. {
  3351. return S_OK;
  3352. }
  3353. return CIDLDataObj::QueryGetData(pformatetc);
  3354. }
  3355. STDMETHODIMP CPrintersData::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  3356. {
  3357. HRESULT hr = E_INVALIDARG;
  3358. // g_cfPrinterFriendlyName creates an HDROP-like structure that contains
  3359. // friendly printer names (instead of absolute paths) for the objects
  3360. // in pdo. The handle returned from this can be used by the HDROP
  3361. // functions DragQueryFile, DragQueryInfo, ...
  3362. //
  3363. if ((pformatetcIn->cfFormat == g_cfPrinterFriendlyName) &&
  3364. (pformatetcIn->tymed & TYMED_HGLOBAL))
  3365. {
  3366. STGMEDIUM medium;
  3367. UINT cbRequired = sizeof(DROPFILES) + sizeof(TCHAR); // dbl null terminated
  3368. LPIDA pida = DataObj_GetHIDA(this, &medium);
  3369. for (UINT i = 0; i < pida->cidl; i++)
  3370. {
  3371. LPIDPRINTER pidp = (LPIDPRINTER)IDA_GetIDListPtr(pida, i);
  3372. cbRequired += ualstrlen(pidp->cName) * sizeof(pidp->cName[0]) + sizeof(pidp->cName[0]);
  3373. }
  3374. pmedium->pUnkForRelease = NULL; // caller should release hmem
  3375. pmedium->tymed = TYMED_HGLOBAL;
  3376. pmedium->hGlobal = GlobalAlloc(GPTR, cbRequired);
  3377. if (pmedium->hGlobal)
  3378. {
  3379. LPDROPFILES pdf = (LPDROPFILES)pmedium->hGlobal;
  3380. pdf->pFiles = sizeof(DROPFILES);
  3381. pdf->fWide = (sizeof(TCHAR) == sizeof(WCHAR));
  3382. LPTSTR lps = (LPTSTR)((LPBYTE)pdf + pdf->pFiles);
  3383. for (i = 0; i < pida->cidl; i++)
  3384. {
  3385. LPIDPRINTER pidp = (LPIDPRINTER)IDA_GetIDListPtr(pida, i);
  3386. ualstrcpy(lps, pidp->cName);
  3387. lps += lstrlen(lps) + 1;
  3388. }
  3389. ASSERT(*lps == 0);
  3390. hr = S_OK;
  3391. }
  3392. else
  3393. hr = E_OUTOFMEMORY;
  3394. HIDA_ReleaseStgMedium(pida, &medium);
  3395. }
  3396. else
  3397. {
  3398. hr = CIDLDataObj::GetData(pformatetcIn, pmedium);
  3399. }
  3400. return hr;
  3401. }
  3402. // IServiceProvider
  3403. STDMETHODIMP CPrintersData::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  3404. {
  3405. HRESULT hr = E_NOINTERFACE;
  3406. if (_pdoAux && IsEqualIID(guidService, SID_SAuxDataObject))
  3407. {
  3408. hr = _pdoAux->QueryInterface(riid, ppv);
  3409. }
  3410. return hr;
  3411. }
  3412. ////////////////////////////////////////////////////////////////////////////////
  3413. // CPrinterDropTarget
  3414. //
  3415. STDAPI CPrinterDropTarget_CreateInstance(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt)
  3416. {
  3417. *ppdropt = NULL;
  3418. HRESULT hr;
  3419. CPrinterDropTarget *ppdt = new CPrinterDropTarget(hwnd);
  3420. if (ppdt)
  3421. {
  3422. hr = ppdt->_Init(pidl);
  3423. if (SUCCEEDED(hr))
  3424. ppdt->QueryInterface(IID_PPV_ARG(IDropTarget, ppdropt));
  3425. ppdt->Release();
  3426. }
  3427. else
  3428. hr = E_OUTOFMEMORY;
  3429. return hr;
  3430. }
  3431. STDMETHODIMP CPrinterDropTarget::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  3432. {
  3433. // let the base-class process it now to save away pdwEffect
  3434. CIDLDropTarget::DragEnter(pDataObj, grfKeyState, pt, pdwEffect);
  3435. // We allow files to be dropped for printing
  3436. // if it is from the bitbucket only DROEFFECT_MOVE will be set in *pdwEffect
  3437. // so this will keep us from printing wastbasket items.
  3438. if (m_dwData & DTID_HDROP)
  3439. *pdwEffect &= DROPEFFECT_COPY;
  3440. else
  3441. *pdwEffect = DROPEFFECT_NONE; // Default action is nothing
  3442. m_dwEffectLastReturned = *pdwEffect;
  3443. return S_OK;
  3444. }
  3445. void _PrintHDROPFiles(HWND hwnd, HDROP hdrop, LPCITEMIDLIST pidlPrinter)
  3446. {
  3447. DRAGINFO di;
  3448. di.uSize = sizeof(di);
  3449. if (DragQueryInfo(hdrop, &di))
  3450. {
  3451. BOOL bInstalled = FALSE;
  3452. TCHAR szPrinter[MAXNAMELENBUFFER];
  3453. //
  3454. // first check if the printer is already installed (in the local printer's folder)
  3455. // and if not installed asks the user if he wants to install it. you can't print
  3456. // to a printer which isn't installed locally.
  3457. //
  3458. if (SUCCEEDED(SHGetNameAndFlags(pidlPrinter, SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL)))
  3459. {
  3460. //
  3461. // let's see if this printer is accessible and get the real printer name
  3462. // (since szPrinter could be a share name - \\machine\share)
  3463. //
  3464. DWORD dwError = ERROR_SUCCESS;
  3465. BOOL bPrinterOK = FALSE;
  3466. HANDLE hPrinter = Printer_OpenPrinter(szPrinter);
  3467. if (hPrinter)
  3468. {
  3469. PRINTER_INFO_5 *pPrinter = (PRINTER_INFO_5 *)Printer_GetPrinterInfo(hPrinter, 5);
  3470. if (pPrinter)
  3471. {
  3472. // the printer looks accessible, get the real printer name
  3473. bPrinterOK = TRUE;
  3474. lstrcpyn(szPrinter, pPrinter->pPrinterName, ARRAYSIZE(szPrinter));
  3475. LocalFree((HLOCAL)pPrinter);
  3476. }
  3477. else
  3478. {
  3479. // save the last error
  3480. dwError = GetLastError();
  3481. }
  3482. Printer_ClosePrinter(hPrinter);
  3483. }
  3484. else
  3485. {
  3486. // save the last error
  3487. dwError = GetLastError();
  3488. }
  3489. if (bPrinterOK)
  3490. {
  3491. LPITEMIDLIST pidl = NULL;
  3492. if (SUCCEEDED(ParsePrinterName(szPrinter, &pidl)))
  3493. {
  3494. // the printer is installed in the local printer's folder
  3495. bInstalled = TRUE;
  3496. ILFree(pidl);
  3497. }
  3498. else
  3499. {
  3500. //
  3501. // tell the user this printer isn't installed and ask if he wants to install the printer
  3502. // before printing the files(s).
  3503. //
  3504. if (IDYES == ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_PRINTER_NOTCONNECTED),
  3505. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION))
  3506. {
  3507. pidl = Printers_PrinterSetup(hwnd, MSP_NETPRINTER, szPrinter, NULL);
  3508. if (pidl)
  3509. {
  3510. bInstalled = TRUE;
  3511. ILFree(pidl);
  3512. }
  3513. }
  3514. }
  3515. }
  3516. else
  3517. {
  3518. if( ERROR_SUCCESS == dwError )
  3519. {
  3520. //
  3521. // the printer is unreachable for some reason or some other weird error occured -
  3522. // just show up an appropriate error message and continue.
  3523. //
  3524. // since all the above APIs are poorly designed it's very hard to tell what
  3525. // exactly has failed. it isn't possible to use the last error, since it's already
  3526. // stomped and probably totally wrong.
  3527. //
  3528. ShellMessageBox(HINST_THISDLL, hwnd,
  3529. MAKEINTRESOURCE(IDS_CANTPRINT),
  3530. MAKEINTRESOURCE(IDS_PRINTERS),
  3531. MB_OK|MB_ICONEXCLAMATION);
  3532. }
  3533. else
  3534. {
  3535. // if ERROR_SUCCESS != dwError then we have meaningfull error to show up to
  3536. // the user. just do it.
  3537. ShowErrorMessageSC(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, dwError);
  3538. }
  3539. }
  3540. }
  3541. if (bInstalled)
  3542. {
  3543. //
  3544. // at this point the printer we are trying to print to should be installed
  3545. // locally, so we can safely proceed with printing the selected files(s).
  3546. //
  3547. LPTSTR pszFile = di.lpFileList;
  3548. int i = IDYES;
  3549. // Printing more than one file at a time can easily fail.
  3550. // Ask the user to confirm this operation.
  3551. if (*pszFile && *(pszFile + lstrlen(pszFile) + 1))
  3552. {
  3553. i = ShellMessageBox(HINST_THISDLL,
  3554. NULL,
  3555. MAKEINTRESOURCE(IDS_MULTIPLEPRINTFILE),
  3556. MAKEINTRESOURCE(IDS_PRINTERS),
  3557. MB_YESNO|MB_ICONINFORMATION);
  3558. }
  3559. if (i == IDYES)
  3560. {
  3561. // FEATURE: It would be really nice to have a progress bar when
  3562. // printing multiple files. And there should definitely be a way
  3563. // to cancel this operation. Oh well, we warned them...
  3564. while (*pszFile)
  3565. {
  3566. Printer_PrintFile(hwnd, pszFile, pidlPrinter);
  3567. pszFile += lstrlen(pszFile) + 1;
  3568. }
  3569. }
  3570. }
  3571. SHFree(di.lpFileList);
  3572. }
  3573. }
  3574. typedef struct {
  3575. HWND hwnd;
  3576. IDataObject *pDataObj;
  3577. IStream *pstmDataObj; // to marshall the data object
  3578. DWORD dwEffect;
  3579. POINT ptDrop;
  3580. LPITEMIDLIST pidl; // relative pidl of printer printing to
  3581. } PRNTHREADPARAM;
  3582. void FreePrinterThreadParam(PRNTHREADPARAM *pthp)
  3583. {
  3584. if (pthp->pDataObj)
  3585. pthp->pDataObj->Release();
  3586. if (pthp->pstmDataObj)
  3587. pthp->pstmDataObj->Release();
  3588. ILFree(pthp->pidl);
  3589. LocalFree((HLOCAL)pthp);
  3590. }
  3591. //
  3592. // This is the entry of "drop thread"
  3593. //
  3594. DWORD CALLBACK CPrintObj_DropThreadProc(void *pv)
  3595. {
  3596. PRNTHREADPARAM *pthp = (PRNTHREADPARAM *)pv;
  3597. STGMEDIUM medium;
  3598. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  3599. CoGetInterfaceAndReleaseStream(pthp->pstmDataObj, IID_PPV_ARG(IDataObject, &pthp->pDataObj));
  3600. pthp->pstmDataObj = NULL;
  3601. if (pthp->pDataObj && SUCCEEDED(pthp->pDataObj->GetData(&fmte, &medium)))
  3602. {
  3603. _PrintHDROPFiles(pthp->hwnd, (HDROP)medium.hGlobal, pthp->pidl);
  3604. ReleaseStgMedium(&medium);
  3605. }
  3606. FreePrinterThreadParam(pthp);
  3607. return 0;
  3608. }
  3609. HRESULT PrintObj_DropPrint(IDataObject *pDataObj, HWND hwnd, DWORD dwEffect, LPCITEMIDLIST pidl, LPTHREAD_START_ROUTINE pfn)
  3610. {
  3611. HRESULT hr = E_OUTOFMEMORY; // assume the worst
  3612. PRNTHREADPARAM *pthp = (PRNTHREADPARAM *)LocalAlloc(LPTR, sizeof(*pthp));
  3613. if (pthp)
  3614. {
  3615. hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, (IUnknown *)pDataObj, &pthp->pstmDataObj);
  3616. if (SUCCEEDED(hr))
  3617. {
  3618. if (hwnd)
  3619. ShellFolderView_GetAnchorPoint(hwnd, FALSE, &pthp->ptDrop);
  3620. pthp->hwnd = hwnd;
  3621. pthp->dwEffect = dwEffect;
  3622. hr = SHILClone(pidl, &pthp->pidl);
  3623. if (SUCCEEDED(hr))
  3624. {
  3625. if (!SHCreateThread(pfn, pthp, CTF_COINIT, NULL))
  3626. {
  3627. hr = E_OUTOFMEMORY;
  3628. }
  3629. }
  3630. }
  3631. if (FAILED(hr))
  3632. FreePrinterThreadParam(pthp);
  3633. }
  3634. return hr;
  3635. }
  3636. STDMETHODIMP CPrinterDropTarget::_DropCallback(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect, LPTHREAD_START_ROUTINE pfn)
  3637. {
  3638. *pdwEffect = m_dwEffectLastReturned;
  3639. HRESULT hr;
  3640. if (*pdwEffect)
  3641. hr = DragDropMenu(DROPEFFECT_COPY, pDataObj, pt, pdwEffect, NULL, NULL, MENU_PRINTOBJ_DD, grfKeyState);
  3642. else
  3643. hr = S_FALSE;
  3644. if (*pdwEffect)
  3645. hr = PrintObj_DropPrint(pDataObj, _GetWindow(), *pdwEffect, m_pidl, pfn);
  3646. CIDLDropTarget::DragLeave();
  3647. return hr;
  3648. }
  3649. STDMETHODIMP CPrinterDropTarget::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  3650. {
  3651. return _DropCallback(pDataObj, grfKeyState, pt, pdwEffect, CPrintObj_DropThreadProc);
  3652. }
  3653. // cbModule = sizeof(*pszModule) and cbModule ~== MAX_PATH+slop
  3654. // returns NULL and sets *pid to the icon id in HINST_THISDLL or
  3655. // returns pszModule and sets *pid to the icon id for module pszModule
  3656. LPTSTR CPrinterFolder::_FindIcon(LPCTSTR pszPrinterName, LPTSTR pszModule, ULONG cbModule, int *piIcon, int *piShortcutIcon)
  3657. {
  3658. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  3659. LPTSTR pszRet = NULL;
  3660. TCHAR szKeyName[256];
  3661. int iStandardIcon;
  3662. int iDefaultIcon;
  3663. // Sanitize the printer name so it doesn't have backslashes.
  3664. // We're about to use the string as a registry key name, where
  3665. // backslashes are illegal.
  3666. lstrcpyn(szFullPrinter, pszPrinterName, ARRAYSIZE(szFullPrinter));
  3667. LPTSTR psz = szFullPrinter;
  3668. while ((psz = StrChr(psz, TEXT('\\'))) != NULL)
  3669. {
  3670. *psz = TEXT('/');
  3671. }
  3672. // registry override of the icon
  3673. wnsprintf(szKeyName, ARRAYSIZE(szKeyName), c_szPrintersDefIcon, szFullPrinter);
  3674. if (SHGetValue(HKEY_CLASSES_ROOT, szKeyName, NULL, NULL, pszModule, &cbModule) && cbModule)
  3675. {
  3676. *piIcon = *piShortcutIcon = PathParseIconLocation(pszModule);
  3677. pszRet = pszModule;
  3678. }
  3679. else
  3680. {
  3681. void *pData = NULL;
  3682. DWORD dwAttributes = 0;
  3683. LPTSTR pszPort = NULL;
  3684. BOOL fDef;
  3685. BOOL bIsFax = FALSE;
  3686. // Try retrieving the information from hFolder if it's remote
  3687. // to avoid hitting the net.
  3688. //
  3689. if (GetServer() && (pData = Printer_FolderGetPrinter(GetFolder(), pszPrinterName)))
  3690. {
  3691. dwAttributes = ((PFOLDER_PRINTER_DATA)pData)->Attributes;
  3692. bIsFax = dwAttributes & PRINTER_ATTRIBUTE_FAX;
  3693. LocalFree((HLOCAL)pData);
  3694. pData = NULL;
  3695. }
  3696. else if (Printer_CheckNetworkPrinterByName(pszPrinterName, NULL))
  3697. {
  3698. // no remote fax icon if we have to resort to this
  3699. // avoid hitting the network.
  3700. dwAttributes = PRINTER_ATTRIBUTE_NETWORK;
  3701. }
  3702. else
  3703. {
  3704. pData = Printer_GetPrinterInfoStr(pszPrinterName, 5);
  3705. if (pData)
  3706. {
  3707. dwAttributes = ((LPPRINTER_INFO_5)pData)->Attributes;
  3708. pszPort = ((LPPRINTER_INFO_5)pData)->pPortName;
  3709. bIsFax = dwAttributes & PRINTER_ATTRIBUTE_FAX;
  3710. if (!bIsFax)
  3711. {
  3712. // the last resort -- check by port name
  3713. bIsFax = !lstrcmp(pszPort, FAX_MONITOR_PORT_NAME);
  3714. }
  3715. }
  3716. }
  3717. // check if the delected printer is default
  3718. fDef = IsDefaultPrinter(pszPrinterName, dwAttributes);
  3719. if (dwAttributes & PRINTER_ATTRIBUTE_NETWORK)
  3720. {
  3721. if (bIsFax)
  3722. {
  3723. iStandardIcon = IDI_FAX_PRINTER_NET;
  3724. iDefaultIcon = IDI_FAX_PRINTER_DEF_NET;
  3725. }
  3726. else
  3727. {
  3728. iStandardIcon = IDI_PRINTER_NET;
  3729. iDefaultIcon = IDI_DEF_PRINTER_NET;
  3730. }
  3731. }
  3732. else if (pszPort && !lstrcmp(pszPort, c_szFileColon))
  3733. {
  3734. iStandardIcon = IDI_PRINTER_FILE;
  3735. iDefaultIcon = IDI_DEF_PRINTER_FILE;
  3736. }
  3737. else if (pszPort && !StrCmpNI(pszPort, c_szTwoSlashes, lstrlen(c_szTwoSlashes)))
  3738. {
  3739. iStandardIcon = IDI_PRINTER_NET;
  3740. iDefaultIcon = IDI_DEF_PRINTER_NET;
  3741. }
  3742. else if (bIsFax)
  3743. {
  3744. iStandardIcon = IDI_FAX_PRINTER;
  3745. iDefaultIcon = IDI_FAX_PRINTER_DEF;
  3746. }
  3747. else
  3748. {
  3749. iStandardIcon = IDI_PRINTER;
  3750. iDefaultIcon = IDI_DEF_PRINTER;
  3751. }
  3752. // Shortcut icon never shows "default" checkmark...
  3753. *piShortcutIcon = iStandardIcon;
  3754. if (fDef)
  3755. *piIcon = iDefaultIcon;
  3756. else
  3757. *piIcon = iStandardIcon;
  3758. if (pData)
  3759. LocalFree((HLOCAL)pData);
  3760. }
  3761. return pszRet;
  3762. }
  3763. ////////////////////////////////////////////////////////
  3764. ////////////////////////////////////////////////////////
  3765. //
  3766. // DUI WebView
  3767. //
  3768. // path to the scanners & cameras folder
  3769. const TCHAR g_szScanAndCam_Path[] =
  3770. TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\")
  3771. TEXT("::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\")
  3772. TEXT("::{E211B736-43FD-11D1-9EFB-0000F8757FCD}");
  3773. // printer's folder webview callbacks namespace
  3774. namespace PF_WV_CB
  3775. {
  3776. HRESULT WebviewVerbIsEnabled(CPrinterFolder::WV_VERB eVerbID, UINT uSelMask,
  3777. IUnknown* pv, IShellItemArray *psiItemArray, BOOL *pbEnabled)
  3778. {
  3779. HRESULT hr = E_FAIL;
  3780. CPrinterFolder *ppf;
  3781. hr = IUnknown_QueryService(pv, CLSID_Printers, CLSID_Printers, (void**)&ppf);
  3782. if (SUCCEEDED(hr))
  3783. {
  3784. IDataObject *pdo = NULL;
  3785. if (psiItemArray)
  3786. {
  3787. hr = psiItemArray->BindToHandler(NULL,BHID_DataObject,IID_PPV_ARG(IDataObject,&pdo));
  3788. }
  3789. if (SUCCEEDED(hr))
  3790. {
  3791. hr = ppf->_WebviewCheckToUpdateDataObjectCache(pdo);
  3792. if (SUCCEEDED(hr))
  3793. {
  3794. hr = ppf->_WebviewVerbIsEnabled(eVerbID, uSelMask, pbEnabled);
  3795. }
  3796. ATOMICRELEASE(pdo);
  3797. }
  3798. ppf->Release();
  3799. }
  3800. return hr;
  3801. }
  3802. HRESULT WebviewVerbInvoke(CPrinterFolder::WV_VERB eVerbID, IUnknown* pv,IShellItemArray *psiItemArray)
  3803. {
  3804. CPrinterFolder *ppf;
  3805. HRESULT hr = E_NOINTERFACE;
  3806. if (SUCCEEDED(hr = IUnknown_QueryService(pv, CLSID_Printers, CLSID_Printers, (void**)&ppf)))
  3807. {
  3808. // just delegate the call to the printer's folder
  3809. ULONG_PTR ulCookie = 0;
  3810. if (SHActivateContext(&ulCookie))
  3811. {
  3812. hr = ppf->_WebviewVerbInvoke(eVerbID, pv, psiItemArray);
  3813. SHDeactivateContext(ulCookie);
  3814. }
  3815. ppf->Release();
  3816. }
  3817. return hr;
  3818. }
  3819. // get state handler
  3820. #define DEFINE_WEBVIEW_STATE_HANDLER(verb, eSelType) \
  3821. { \
  3822. BOOL bEnabled = FALSE; \
  3823. HRESULT hr = WebviewVerbIsEnabled( \
  3824. CPrinterFolder::##verb, \
  3825. CPrinterFolder::##eSelType, \
  3826. pv, psiItemArray, &bEnabled); \
  3827. *puisState = (SUCCEEDED(hr) ? \
  3828. (bEnabled ? UIS_ENABLED : UIS_HIDDEN) : UIS_HIDDEN); \
  3829. return hr; \
  3830. } \
  3831. // invoke handler
  3832. #define DEFINE_WEBVIEW_INVOKE_HANDLER(verb) \
  3833. { \
  3834. return WebviewVerbInvoke(CPrinterFolder::##verb, pv, psiItemArray); \
  3835. } \
  3836. ////////////////////////////////////////////////////////////////////////////////////
  3837. // getState callbacks
  3838. HRESULT CanADDPRINTER (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3839. {
  3840. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_ADDPRINTERWIZARD, SEL_ANY)
  3841. }
  3842. HRESULT CanSRVPROPS (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3843. {
  3844. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_SERVERPROPERTIES, SEL_ANY)
  3845. }
  3846. HRESULT CanSENDFAX (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3847. {
  3848. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_SENDFAXWIZARD, SEL_ANY)
  3849. }
  3850. HRESULT CanTROUBLESHOOTER (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3851. {
  3852. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_TROUBLESHOOTER, SEL_ANY)
  3853. }
  3854. HRESULT CanGOTOSUPPORT (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3855. {
  3856. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_GOTOSUPPORT, SEL_ANY)
  3857. }
  3858. HRESULT CanSETUPFAXING (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3859. {
  3860. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_SETUPFAXING, SEL_ANY)
  3861. }
  3862. HRESULT CanCREATELOCALFAX (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3863. {
  3864. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_CREATELOCALFAX, SEL_ANY)
  3865. }
  3866. HRESULT CanFLD_RENAME (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3867. {
  3868. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_RENAME, SEL_SINGLE_LINK)
  3869. }
  3870. HRESULT CanFLD_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3871. {
  3872. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DELETE, SEL_SINGLE_LINK)
  3873. }
  3874. HRESULT CanFLD_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3875. {
  3876. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PROPERTIES, SEL_SINGLE_LINK)
  3877. }
  3878. HRESULT CanPRN_RENAME (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3879. {
  3880. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_RENAME, SEL_SINGLE_PRINTER)
  3881. }
  3882. HRESULT CanPRN_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3883. {
  3884. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DELETE, SEL_SINGLE_PRINTER)
  3885. }
  3886. HRESULT CanPRN_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3887. {
  3888. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PROPERTIES, SEL_SINGLE_PRINTER)
  3889. }
  3890. HRESULT CanPRN_OPENQUEUE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3891. {
  3892. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_OPENPRN, SEL_SINGLE_PRINTER)
  3893. }
  3894. HRESULT CanPRN_PREFERENCES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3895. {
  3896. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DOCUMENTDEFAULTS, SEL_SINGLE_PRINTER)
  3897. }
  3898. HRESULT CanPRN_PAUSE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3899. {
  3900. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PAUSEPRN, SEL_SINGLE_PRINTER)
  3901. }
  3902. HRESULT CanPRN_RESUME (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3903. {
  3904. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_RESUMEPRN, SEL_SINGLE_PRINTER)
  3905. }
  3906. HRESULT CanPRN_SHARE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3907. {
  3908. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_SHARING, SEL_SINGLE_PRINTER)
  3909. }
  3910. HRESULT CanPRN_VENDORURL (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3911. {
  3912. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_VENDORURL, SEL_SINGLE_PRINTER)
  3913. }
  3914. HRESULT CanPRN_PRINTERURL (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3915. {
  3916. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PRINTERURL, SEL_SINGLE_PRINTER)
  3917. }
  3918. HRESULT CanMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3919. {
  3920. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DELETE, SEL_MULTI_PRINTER)
  3921. }
  3922. HRESULT CanMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3923. {
  3924. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PROPERTIES, SEL_MULTI_PRINTER)
  3925. }
  3926. HRESULT CanFLDMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3927. {
  3928. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DELETE, SEL_MULTI_LINK)
  3929. }
  3930. HRESULT CanFLDMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3931. {
  3932. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PROPERTIES, SEL_MULTI_LINK)
  3933. }
  3934. HRESULT CanANYMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3935. {
  3936. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_DELETE, SEL_MULTI_MIXED)
  3937. }
  3938. HRESULT CanANYMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  3939. {
  3940. DEFINE_WEBVIEW_STATE_HANDLER(WVIDM_PROPERTIES, SEL_MULTI_MIXED)
  3941. }
  3942. ////////////////////////////////////////////////////////////////////////////////////
  3943. // Invoke callbacks
  3944. //
  3945. HRESULT OnADDPRINTER (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3946. {
  3947. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_ADDPRINTERWIZARD)
  3948. }
  3949. HRESULT OnSRVPROPS (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3950. {
  3951. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_SERVERPROPERTIES)
  3952. }
  3953. HRESULT OnSENDFAX (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3954. {
  3955. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_SENDFAXWIZARD)
  3956. }
  3957. HRESULT OnTROUBLESHOOTER (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3958. {
  3959. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_TROUBLESHOOTER)
  3960. }
  3961. HRESULT OnGOTOSUPPORT (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3962. {
  3963. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_GOTOSUPPORT)
  3964. }
  3965. HRESULT OnSETUPFAXING (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3966. {
  3967. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_SETUPFAXING)
  3968. }
  3969. HRESULT OnCREATELOCALFAX (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3970. {
  3971. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_CREATELOCALFAX)
  3972. }
  3973. HRESULT OnFLD_RENAME (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3974. {
  3975. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_RENAME)
  3976. }
  3977. HRESULT OnFLD_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3978. {
  3979. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DELETE)
  3980. }
  3981. HRESULT OnFLD_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3982. {
  3983. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PROPERTIES)
  3984. }
  3985. HRESULT OnPRN_RENAME (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3986. {
  3987. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_RENAME)
  3988. }
  3989. HRESULT OnPRN_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3990. {
  3991. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DELETE)
  3992. }
  3993. HRESULT OnPRN_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3994. {
  3995. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PROPERTIES)
  3996. }
  3997. HRESULT OnPRN_OPENQUEUE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  3998. {
  3999. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_OPENPRN)
  4000. }
  4001. HRESULT OnPRN_PREFERENCES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4002. {
  4003. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DOCUMENTDEFAULTS)
  4004. }
  4005. HRESULT OnPRN_PAUSE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4006. {
  4007. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PAUSEPRN)
  4008. }
  4009. HRESULT OnPRN_RESUME (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4010. {
  4011. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_RESUMEPRN)
  4012. }
  4013. HRESULT OnPRN_SHARE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4014. {
  4015. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_SHARING)
  4016. }
  4017. HRESULT OnPRN_VENDORURL (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4018. {
  4019. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_VENDORURL)
  4020. }
  4021. HRESULT OnPRN_PRINTERURL (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4022. {
  4023. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PRINTERURL)
  4024. }
  4025. HRESULT OnMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4026. {
  4027. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DELETE)
  4028. }
  4029. HRESULT OnMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4030. {
  4031. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PROPERTIES)
  4032. }
  4033. HRESULT OnFLDMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4034. {
  4035. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DELETE)
  4036. }
  4037. HRESULT OnFLDMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4038. {
  4039. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PROPERTIES)
  4040. }
  4041. HRESULT OnANYMUL_DELETE (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4042. {
  4043. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_DELETE)
  4044. }
  4045. HRESULT OnANYMUL_PROPERTIES (IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  4046. {
  4047. DEFINE_WEBVIEW_INVOKE_HANDLER(WVIDM_PROPERTIES)
  4048. }
  4049. }; // namespace PFWV_CALLBACKS
  4050. ///////////////////////////////////////////////////////////////////
  4051. // GUIDS for the printer's folder webview commands
  4052. //
  4053. // *************************************** PRINTER COMMANDS ***************************************
  4054. // {D351FCED-C179-41ae-AD50-CAAC892DF24A}
  4055. DEFINE_GUID(UICID_Printers_OpenQueue, 0xd351fced, 0xc179, 0x41ae, 0xad, 0x50, 0xca, 0xac, 0x89, 0x2d, 0xf2, 0x4a);
  4056. // {A263A9D6-F1BA-4607-B7AA-CF471DEA17FF}
  4057. DEFINE_GUID(UICID_Printers_Preferences, 0xa263a9d6, 0xf1ba, 0x4607, 0xb7, 0xaa, 0xcf, 0x47, 0x1d, 0xea, 0x17, 0xff);
  4058. // {73149B3F-1E6D-4b00-9047-4576BC853A41}
  4059. DEFINE_GUID(UICID_Printers_Pause, 0x73149b3f, 0x1e6d, 0x4b00, 0x90, 0x47, 0x45, 0x76, 0xbc, 0x85, 0x3a, 0x41);
  4060. // {A7920561-FAAD-44a0-8C4C-FD769587F807}
  4061. DEFINE_GUID(UICID_Printers_Resume, 0xa7920561, 0xfaad, 0x44a0, 0x8c, 0x4c, 0xfd, 0x76, 0x95, 0x87, 0xf8, 0x7);
  4062. // {538536A1-5BC3-4b9c-8287-7562D53BE380}
  4063. DEFINE_GUID(UICID_Printers_Share, 0x538536a1, 0x5bc3, 0x4b9c, 0x82, 0x87, 0x75, 0x62, 0xd5, 0x3b, 0xe3, 0x80);
  4064. // {1461CC4A-308E-4ae5-B03A-F9682E3232B0}
  4065. DEFINE_GUID(UICID_Printers_Properties, 0x1461cc4a, 0x308e, 0x4ae5, 0xb0, 0x3a, 0xf9, 0x68, 0x2e, 0x32, 0x32, 0xb0);
  4066. // {A1F67BA0-5DEF-4e12-9E64-EA77670BFF26}
  4067. DEFINE_GUID(UICID_Printers_VendorURL, 0xa1f67ba0, 0x5def, 0x4e12, 0x9e, 0x64, 0xea, 0x77, 0x67, 0xb, 0xff, 0x26);
  4068. // {8D4D326C-30A4-47dc-BF51-4BC5863883E3}
  4069. DEFINE_GUID(UICID_Printers_PrinterURL, 0x8d4d326c, 0x30a4, 0x47dc, 0xbf, 0x51, 0x4b, 0xc5, 0x86, 0x38, 0x83, 0xe3);
  4070. // *************************************** STANDARD COMMANDS ***************************************
  4071. // those are defined in shlguidp.h
  4072. //
  4073. // UICID_Rename
  4074. // UICID_Delete
  4075. // *************************************** COMMON COMMANDS ***************************************
  4076. // {6D9778A5-C27D-464a-8511-36F7243BD0ED}
  4077. DEFINE_GUID(UICID_Printers_AddPrinter, 0x6d9778a5, 0xc27d, 0x464a, 0x85, 0x11, 0x36, 0xf7, 0x24, 0x3b, 0xd0, 0xed);
  4078. // {E1391312-2DAC-48db-994B-0BF22DB7576D}
  4079. DEFINE_GUID(UICID_Printers_SrvProps, 0xe1391312, 0x2dac, 0x48db, 0x99, 0x4b, 0xb, 0xf2, 0x2d, 0xb7, 0x57, 0x6d);
  4080. // {27DC81DF-73DB-406a-9A86-5EF38BA67CA8}
  4081. DEFINE_GUID(UICID_Printers_SendFax, 0x27dc81df, 0x73db, 0x406a, 0x9a, 0x86, 0x5e, 0xf3, 0x8b, 0xa6, 0x7c, 0xa8);
  4082. // {A21E3CCF-68D4-49cd-99A2-A272E9FF3A20}
  4083. DEFINE_GUID(UICID_Printers_GotoSupport, 0xa21e3ccf, 0x68d4, 0x49cd, 0x99, 0xa2, 0xa2, 0x72, 0xe9, 0xff, 0x3a, 0x20);
  4084. // {793542CF-5720-49f3-9A09-CAA3079508B9}
  4085. DEFINE_GUID(UICID_Printers_Troubleshooter, 0x793542cf, 0x5720, 0x49f3, 0x9a, 0x9, 0xca, 0xa3, 0x7, 0x95, 0x8, 0xb9);
  4086. // {EED61EFC-6A20-48dd-82FD-958DFDB96F1E}
  4087. DEFINE_GUID(UICID_Printers_SetupFaxing, 0xeed61efc, 0x6a20, 0x48dd, 0x82, 0xfd, 0x95, 0x8d, 0xfd, 0xb9, 0x6f, 0x1e);
  4088. // {224ACF1D-BB4E-4979-A8B8-D078E2154BCC}
  4089. DEFINE_GUID(UICID_Printers_CreateFax, 0x224acf1d, 0xbb4e, 0x4979, 0xa8, 0xb8, 0xd0, 0x78, 0xe2, 0x15, 0x4b, 0xcc);
  4090. ///////////////////////////////////////////////////////////////////
  4091. // Header items
  4092. //
  4093. const WVTASKITEM
  4094. g_cPrintersVW_HeaderTasks =
  4095. WVTI_HEADER(
  4096. L"shell32.dll", // module where the resources are
  4097. IDS_PRINTERS_WV_HEADER_TASKS, // statis header for all cases
  4098. IDS_PRINTERS_WV_HEADER_TASKS_TT // tooltip
  4099. );
  4100. const WVTASKITEM
  4101. g_cPrintersVW_HeaderSeeAlso =
  4102. WVTI_HEADER(
  4103. L"shell32.dll", // module where the resources are
  4104. IDS_PRINTERS_WV_HEADER_SEEALSO, // statis header for all cases
  4105. IDS_PRINTERS_WV_HEADER_SEEALSO_TT // tooltip
  4106. );
  4107. // **************************************************************************************
  4108. // ****************************** sample command definition *****************************
  4109. //
  4110. // WVTI_ENTRY_ALL_TITLE(
  4111. // UICID_MyCmd, // command GUID
  4112. // L"shell32.dll", // module
  4113. // IDS_PRINTERS_WV_MYCMD, // no selection
  4114. // IDS_PRINTERS_WV_MYCMD, // 1 file
  4115. // IDS_PRINTERS_WV_MYCMD, // 1 folder selected
  4116. // IDS_PRINTERS_WV_MYCMD, // multiple selection
  4117. // IDS_PRINTERS_WV_MYCMD_TT, // tooltip
  4118. // IDI_PRINTERS_WV_MYCMD, // icon
  4119. // PF_WV_CB::CanMYCMD, // get UI state callback
  4120. // PF_WV_CB::OnMYCMD // OnVerb callback
  4121. // ),
  4122. //
  4123. const WVTASKITEM g_cPrintersTasks[] =
  4124. {
  4125. ////////////////////////////////////////////////////////////////////////////////////
  4126. // commands in the 'Tasks' section when there is no selection
  4127. ////////////////////////////////////////////////////////////////////////////////////
  4128. // add printer command - always enabled regardless of the selection type!
  4129. WVTI_ENTRY_ALL_TITLE(
  4130. UICID_Printers_AddPrinter, // command GUID
  4131. L"shell32.dll", // module
  4132. IDS_PRINTERS_WV_ADDPRINTER, // no selection
  4133. IDS_PRINTERS_WV_ADDPRINTER, // 1 file
  4134. IDS_PRINTERS_WV_ADDPRINTER, // 1 folder selected
  4135. IDS_PRINTERS_WV_ADDPRINTER, // multiple selection
  4136. IDS_PRINTERS_WV_ADDPRINTER_TT, // tooltip
  4137. IDI_PRINTERS_WV_ADDPRINTER, // icon
  4138. PF_WV_CB::CanADDPRINTER, // get UI state callback
  4139. PF_WV_CB::OnADDPRINTER // OnVerb callback
  4140. ),
  4141. // server properties command
  4142. WVTI_ENTRY_ALL_TITLE(
  4143. UICID_Printers_SrvProps, // command GUID
  4144. L"shell32.dll", // module
  4145. IDS_PRINTERS_WV_SRVPROPS, // no selection
  4146. 0, // 1 file
  4147. 0, // 1 folder selected
  4148. 0, // multiple selection
  4149. IDS_PRINTERS_WV_SRVPROPS_TT, // tooltip
  4150. IDI_PRINTERS_WV_SRVPROPS, // icon
  4151. PF_WV_CB::CanSRVPROPS, // get UI state callback
  4152. PF_WV_CB::OnSRVPROPS // OnVerb callback
  4153. ),
  4154. // send fax command
  4155. WVTI_ENTRY_ALL_TITLE(
  4156. UICID_Printers_SendFax, // command GUID
  4157. L"shell32.dll", // module
  4158. IDS_PRINTERS_WV_SENDFAX, // no selection
  4159. 0, // 1 file
  4160. 0, // 1 folder selected
  4161. 0, // multiple selection
  4162. IDS_PRINTERS_WV_SENDFAX_TT, // tooltip
  4163. IDI_PRINTERS_WV_SENDFAX, // icon
  4164. PF_WV_CB::CanSENDFAX, // get UI state callback
  4165. PF_WV_CB::OnSENDFAX // OnVerb callback
  4166. ),
  4167. // setup faxing
  4168. WVTI_ENTRY_ALL_TITLE(
  4169. UICID_Printers_SetupFaxing, // command GUID
  4170. L"shell32.dll", // module
  4171. IDS_PRINTERS_WV_SETUPFAXING, // no selection
  4172. 0, // 1 file
  4173. 0, // 1 folder selected
  4174. 0, // multiple selection
  4175. IDS_PRINTERS_WV_SETUPFAXING_TT, // tooltip
  4176. IDI_PRINTERS_WV_FAXING, // icon
  4177. PF_WV_CB::CanSETUPFAXING, // get UI state callback
  4178. PF_WV_CB::OnSETUPFAXING // OnVerb callback
  4179. ),
  4180. // create fax printer
  4181. WVTI_ENTRY_ALL_TITLE(
  4182. UICID_Printers_CreateFax, // command GUID
  4183. L"shell32.dll", // module
  4184. IDS_PRINTERS_WV_CREATEFAXPRN, // no selection
  4185. 0, // 1 file
  4186. 0, // 1 folder selected
  4187. 0, // multiple selection
  4188. IDS_PRINTERS_WV_CREATEFAXPRN_TT, // tooltip
  4189. IDI_PRINTERS_WV_FAXING, // icon
  4190. PF_WV_CB::CanCREATELOCALFAX, // get UI state callback
  4191. PF_WV_CB::OnCREATELOCALFAX // OnVerb callback
  4192. ),
  4193. // open printer queue command
  4194. WVTI_ENTRY_ALL_TITLE(
  4195. UICID_Printers_OpenQueue, // command GUID
  4196. L"shell32.dll", // module
  4197. 0, // no selection
  4198. IDS_PRINTERS_WV_PRN_OPENQUEUE, // 1 file
  4199. 0, // 1 folder selected
  4200. 0, // multiple selection
  4201. IDS_PRINTERS_WV_PRN_OPENQUEUE_TT, // tooltip
  4202. IDI_PRINTERS_WV_OPENQUEUE, // icon
  4203. PF_WV_CB::CanPRN_OPENQUEUE, // get UI state callback
  4204. PF_WV_CB::OnPRN_OPENQUEUE // OnVerb callback
  4205. ),
  4206. // single selection printer preferences
  4207. WVTI_ENTRY_ALL_TITLE(
  4208. UICID_Printers_Preferences, // command GUID
  4209. L"shell32.dll", // module
  4210. 0, // no selection
  4211. IDS_PRINTERS_WV_PRN_PREFERENCES, // 1 file
  4212. 0, // 1 folder selected
  4213. 0, // multiple selection
  4214. IDS_PRINTERS_WV_PRN_PREFERENCES_TT, // tooltip
  4215. IDI_PRINTERS_WV_PREFERENCES, // icon
  4216. PF_WV_CB::CanPRN_PREFERENCES, // get UI state callback
  4217. PF_WV_CB::OnPRN_PREFERENCES // OnVerb callback
  4218. ),
  4219. // pause printer
  4220. WVTI_ENTRY_ALL_TITLE(
  4221. UICID_Printers_Pause, // command GUID
  4222. L"shell32.dll", // module
  4223. 0, // no selection
  4224. IDS_PRINTERS_WV_PRN_PAUSE, // 1 file
  4225. 0, // 1 folder selected
  4226. 0, // multiple selection
  4227. IDS_PRINTERS_WV_PRN_PAUSE_TT, // tooltip
  4228. IDI_PRINTERS_WV_PAUSE, // icon
  4229. PF_WV_CB::CanPRN_PAUSE, // get UI state callback
  4230. PF_WV_CB::OnPRN_PAUSE // OnVerb callback
  4231. ),
  4232. // resume printer
  4233. WVTI_ENTRY_ALL_TITLE(
  4234. UICID_Printers_Resume, // command GUID
  4235. L"shell32.dll", // module
  4236. 0, // no selection
  4237. IDS_PRINTERS_WV_PRN_RESUME, // 1 file
  4238. 0, // 1 folder selected
  4239. 0, // multiple selection
  4240. IDS_PRINTERS_WV_PRN_RESUME_TT, // tooltip
  4241. IDI_PRINTERS_WV_RESUME, // icon
  4242. PF_WV_CB::CanPRN_RESUME, // get UI state callback
  4243. PF_WV_CB::OnPRN_RESUME // OnVerb callback
  4244. ),
  4245. // single selection share printer
  4246. WVTI_ENTRY_ALL_TITLE(
  4247. UICID_Printers_Share, // command GUID
  4248. L"shell32.dll", // module
  4249. 0, // no selection
  4250. IDS_PRINTERS_WV_PRN_SHARE, // 1 file
  4251. 0, // 1 folder selected
  4252. 0, // multiple selection
  4253. IDS_PRINTERS_WV_PRN_SHARE_TT, // tooltip
  4254. IDI_PRINTERS_WV_SHARE, // icon
  4255. PF_WV_CB::CanPRN_SHARE, // get UI state callback
  4256. PF_WV_CB::OnPRN_SHARE // OnVerb callback
  4257. ),
  4258. // single sel. rename for printer
  4259. WVTI_ENTRY_ALL_TITLE(
  4260. UICID_Rename, // command GUID
  4261. L"shell32.dll", // module
  4262. 0, // no selection
  4263. IDS_PRINTERS_WV_PRN_RENAME, // 1 file
  4264. 0, // 1 folder selected
  4265. 0, // multiple selection
  4266. IDS_PRINTERS_WV_PRN_RENAME_TT, // tooltip
  4267. IDI_PRINTERS_WV_RENAME, // icon
  4268. PF_WV_CB::CanPRN_RENAME, // get UI state callback
  4269. PF_WV_CB::OnPRN_RENAME // OnVerb callback
  4270. ),
  4271. // single sel. rename for link
  4272. WVTI_ENTRY_ALL_TITLE(
  4273. UICID_Rename, // command GUID
  4274. L"shell32.dll", // module
  4275. 0, // no selection
  4276. IDS_PRINTERS_WV_FLD_RENAME, // 1 file
  4277. 0, // 1 folder selected
  4278. 0, // multiple selection
  4279. IDS_PRINTERS_WV_FLD_RENAME_TT, // tooltip
  4280. IDI_PRINTERS_WV_RENAME, // icon
  4281. PF_WV_CB::CanFLD_RENAME, // get UI state callback
  4282. PF_WV_CB::OnFLD_RENAME // OnVerb callback
  4283. ),
  4284. // single sel. delete for printer
  4285. WVTI_ENTRY_ALL_TITLE(
  4286. UICID_Delete, // command GUID
  4287. L"shell32.dll", // module
  4288. 0, // no selection
  4289. IDS_PRINTERS_WV_PRN_DELETE, // 1 file
  4290. 0, // 1 folder selected
  4291. 0, // multiple selection
  4292. IDS_PRINTERS_WV_PRN_DELETE_TT, // tooltip
  4293. IDI_PRINTERS_WV_DELETE, // icon
  4294. PF_WV_CB::CanPRN_DELETE, // get UI state callback
  4295. PF_WV_CB::OnPRN_DELETE // OnVerb callback
  4296. ),
  4297. // single sel. delete for link
  4298. WVTI_ENTRY_ALL_TITLE(
  4299. UICID_Delete, // command GUID
  4300. L"shell32.dll", // module
  4301. 0, // no selection
  4302. IDS_PRINTERS_WV_FLD_DELETE, // 1 file
  4303. 0, // 1 folder selected
  4304. 0, // multiple selection
  4305. IDS_PRINTERS_WV_FLD_DELETE_TT, // tooltip
  4306. IDI_PRINTERS_WV_DELETE, // icon
  4307. PF_WV_CB::CanFLD_DELETE, // get UI state callback
  4308. PF_WV_CB::OnFLD_DELETE // OnVerb callback
  4309. ),
  4310. // multi sel. delete for printers
  4311. WVTI_ENTRY_ALL_TITLE(
  4312. UICID_Delete, // command GUID
  4313. L"shell32.dll", // module
  4314. 0, // no selection
  4315. 0, // 1 file
  4316. 0, // 1 folder selected
  4317. IDS_PRINTERS_WV_MUL_DELETE, // multiple selection
  4318. IDS_PRINTERS_WV_MUL_DELETE_TT, // tooltip
  4319. IDI_PRINTERS_WV_DELETE, // icon
  4320. PF_WV_CB::CanMUL_DELETE, // get UI state callback
  4321. PF_WV_CB::OnMUL_DELETE // OnVerb callback
  4322. ),
  4323. // multi sel. delete for links
  4324. //
  4325. // NOTE: note that this command will be enabled for
  4326. // the single selection as well because we don't really know
  4327. // what has been selected until we verify the selection type
  4328. WVTI_ENTRY_ALL_TITLE(
  4329. UICID_Delete, // command GUID
  4330. L"shell32.dll", // module
  4331. 0, // no selection
  4332. IDS_PRINTERS_WV_FLDMUL_DELETE, // 1 file
  4333. 0, // 1 folder selected
  4334. IDS_PRINTERS_WV_FLDMUL_DELETE, // multiple selection
  4335. IDS_PRINTERS_WV_FLDMUL_DELETE_TT, // tooltip
  4336. IDI_PRINTERS_WV_DELETE, // icon
  4337. PF_WV_CB::CanFLDMUL_DELETE, // get UI state callback
  4338. PF_WV_CB::OnFLDMUL_DELETE // OnVerb callback
  4339. ),
  4340. // multi sel. delete for mixed objects...
  4341. //
  4342. // NOTE: note that this command will be enabled for
  4343. // the single selection as well because we don't really know
  4344. // what has been selected until we verify the selection type
  4345. WVTI_ENTRY_ALL_TITLE(
  4346. UICID_Delete, // command GUID
  4347. L"shell32.dll", // module
  4348. 0, // no selection
  4349. IDS_PRINTERS_WV_ANYMUL_DELETE, // 1 file
  4350. 0, // 1 folder selected
  4351. IDS_PRINTERS_WV_ANYMUL_DELETE, // multiple selection
  4352. IDS_PRINTERS_WV_ANYMUL_DELETE_TT, // tooltip
  4353. IDI_PRINTERS_WV_DELETE, // icon
  4354. PF_WV_CB::CanANYMUL_DELETE, // get UI state callback
  4355. PF_WV_CB::OnANYMUL_DELETE // OnVerb callback
  4356. ),
  4357. // single sel. properties for printer
  4358. WVTI_ENTRY_ALL_TITLE(
  4359. UICID_Printers_Properties, // command GUID
  4360. L"shell32.dll", // module
  4361. 0, // no selection
  4362. IDS_PRINTERS_WV_PRN_PROPERTIES, // 1 file
  4363. 0, // 1 folder selected
  4364. 0, // multiple selection
  4365. IDS_PRINTERS_WV_PRN_PROPERTIES_TT, // tooltip
  4366. IDI_PRINTERS_WV_PROPERTIES, // icon
  4367. PF_WV_CB::CanPRN_PROPERTIES, // get UI state callback
  4368. PF_WV_CB::OnPRN_PROPERTIES // OnVerb callback
  4369. ),
  4370. // single sel. properties for link
  4371. WVTI_ENTRY_ALL_TITLE(
  4372. UICID_Printers_Properties, // command GUID
  4373. L"shell32.dll", // module
  4374. 0, // no selection
  4375. IDS_PRINTERS_WV_FLD_PROPERTIES, // 1 file
  4376. 0, // 1 folder selected
  4377. 0, // multiple selection
  4378. IDS_PRINTERS_WV_FLD_PROPERTIES_TT, // tooltip
  4379. IDI_PRINTERS_WV_PROPERTIES, // icon
  4380. PF_WV_CB::CanFLD_PROPERTIES, // get UI state callback
  4381. PF_WV_CB::OnFLD_PROPERTIES // OnVerb callback
  4382. ),
  4383. // multi sel. properties of printers
  4384. WVTI_ENTRY_ALL_TITLE(
  4385. UICID_Printers_Properties, // command GUID
  4386. L"shell32.dll", // module
  4387. 0, // no selection
  4388. 0, // 1 file
  4389. 0, // 1 folder selected
  4390. IDS_PRINTERS_WV_MUL_PROPERTIES, // multiple selection
  4391. IDS_PRINTERS_WV_MUL_PROPERTIES_TT, // tooltip
  4392. IDI_PRINTERS_WV_PROPERTIES, // icon
  4393. PF_WV_CB::CanMUL_PROPERTIES, // get UI state callback
  4394. PF_WV_CB::OnMUL_PROPERTIES // OnVerb callback
  4395. ),
  4396. // multi sel. properties of links
  4397. //
  4398. // NOTE: note that this command will be enabled for
  4399. // the single selection as well because we don't really know
  4400. // what has been selected until we verify the selection type
  4401. WVTI_ENTRY_ALL_TITLE(
  4402. UICID_Printers_Properties, // command GUID
  4403. L"shell32.dll", // module
  4404. 0, // no selection
  4405. IDS_PRINTERS_WV_FLDMUL_PROPERTIES, // 1 file
  4406. 0, // 1 folder selected
  4407. IDS_PRINTERS_WV_FLDMUL_PROPERTIES, // multiple selection
  4408. IDS_PRINTERS_WV_FLDMUL_PROPERTIES_TT, // tooltip
  4409. IDI_PRINTERS_WV_PROPERTIES, // icon
  4410. PF_WV_CB::CanFLDMUL_PROPERTIES, // get UI state callback
  4411. PF_WV_CB::OnFLDMUL_PROPERTIES // OnVerb callback
  4412. ),
  4413. // multi sel. properties of mixed objects
  4414. //
  4415. // NOTE: note that this command will be enabled for
  4416. // the single selection as well because we don't really know
  4417. // what has been selected until we verify the selection type
  4418. WVTI_ENTRY_ALL_TITLE(
  4419. UICID_Printers_Properties, // command GUID
  4420. L"shell32.dll", // module
  4421. 0, // no selection
  4422. IDS_PRINTERS_WV_ANYMUL_PROPERTIES, // 1 file
  4423. 0, // 1 folder selected
  4424. IDS_PRINTERS_WV_ANYMUL_PROPERTIES, // multiple selection
  4425. IDS_PRINTERS_WV_ANYMUL_PROPERTIES_TT, // tooltip
  4426. IDI_PRINTERS_WV_PROPERTIES, // icon
  4427. PF_WV_CB::CanANYMUL_PROPERTIES, // get UI state callback
  4428. PF_WV_CB::OnANYMUL_PROPERTIES // OnVerb callback
  4429. ),
  4430. };
  4431. const WVTASKITEM g_cPrintersSeeAlso[] =
  4432. {
  4433. ////////////////////////////////////////////////////////////////////////////////////
  4434. // commands in the 'See Also' section when there is no selection
  4435. ////////////////////////////////////////////////////////////////////////////////////
  4436. // open print troubleshooter
  4437. WVTI_ENTRY_ALL_TITLE(
  4438. UICID_Printers_Troubleshooter, // command GUID
  4439. L"shell32.dll", // module
  4440. IDS_PRINTERS_WV_TROUBLESHOOTER, // no selection
  4441. 0, // 1 file
  4442. 0, // 1 folder selected
  4443. 0, // multiple selection
  4444. IDS_PRINTERS_WV_TROUBLESHOOTER_TT, // tooltip
  4445. IDI_PRINTERS_WV_TROUBLESHOOTER, // icon
  4446. PF_WV_CB::CanTROUBLESHOOTER, // get UI state callback
  4447. PF_WV_CB::OnTROUBLESHOOTER // OnVerb callback
  4448. ),
  4449. // goto support
  4450. WVTI_ENTRY_ALL_TITLE(
  4451. UICID_Printers_GotoSupport, // command GUID
  4452. L"shell32.dll", // module
  4453. IDS_PRINTERS_WV_GOTOSUPPORT, // no selection
  4454. 0, // 1 file
  4455. 0, // 1 folder selected
  4456. 0, // multiple selection
  4457. IDS_PRINTERS_WV_GOTOSUPPORT_TT, // tooltip
  4458. IDI_PRINTERS_WV_GOTOSUPPORT, // icon
  4459. PF_WV_CB::CanGOTOSUPPORT, // get UI state callback
  4460. PF_WV_CB::OnGOTOSUPPORT // OnVerb callback
  4461. ),
  4462. ////////////////////////////////////////////////////////////////////////////////////
  4463. // commands in the 'See Also' section when there is 1 printer selected
  4464. ////////////////////////////////////////////////////////////////////////////////////
  4465. // goto vendor URL command
  4466. WVTI_ENTRY_ALL_TITLE(
  4467. UICID_Printers_VendorURL, // command GUID
  4468. L"shell32.dll", // module
  4469. 0, // no selection
  4470. IDS_PRINTERS_WV_PRN_VENDORURL, // 1 file
  4471. 0, // 1 folder selected
  4472. 0, // multiple selection
  4473. IDS_PRINTERS_WV_PRN_VENDORURL_TT, // tooltip
  4474. IDI_PRINTERS_WV_VENDORURL, // icon
  4475. PF_WV_CB::CanPRN_VENDORURL, // get UI state callback
  4476. PF_WV_CB::OnPRN_VENDORURL // OnVerb callback
  4477. ),
  4478. // goto printer URL command
  4479. WVTI_ENTRY_ALL_TITLE(
  4480. UICID_Printers_PrinterURL, // command GUID
  4481. L"shell32.dll", // module
  4482. 0, // no selection
  4483. IDS_PRINTERS_WV_PRN_PRINTERURL, // 1 file
  4484. 0, // 1 folder selected
  4485. 0, // multiple selection
  4486. IDS_PRINTERS_WV_PRN_PRINTERURL_TT, // tooltip
  4487. IDI_PRINTERS_WV_PRINTERURL, // icon
  4488. PF_WV_CB::CanPRN_PRINTERURL, // get UI state callback
  4489. PF_WV_CB::OnPRN_PRINTERURL // OnVerb callback
  4490. ),
  4491. };
  4492. // DUI webview impl.
  4493. HRESULT CPrinterFolder::GetWebViewLayout(IUnknown *pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  4494. {
  4495. pData->dwLayout = SFVMWVL_NORMAL;
  4496. return S_OK;
  4497. }
  4498. HRESULT CPrinterFolder::GetWebViewContent(IUnknown *pv, SFVM_WEBVIEW_CONTENT_DATA* pData)
  4499. {
  4500. // those must be NULL when called
  4501. ASSERT(NULL == pData->pIntroText);
  4502. ASSERT(NULL == pData->pSpecialTaskHeader);
  4503. ASSERT(NULL == pData->pFolderTaskHeader);
  4504. ASSERT(NULL == pData->penumOtherPlaces);
  4505. LPCTSTR rgCsidls[] = { g_szScanAndCam_Path, MAKEINTRESOURCE(CSIDL_PERSONAL), MAKEINTRESOURCE(CSIDL_MYPICTURES), MAKEINTRESOURCE(CSIDL_DRIVES) };
  4506. HRESULT hr = CreateIEnumIDListOnCSIDLs(_pidl, rgCsidls, ARRAYSIZE(rgCsidls), &pData->penumOtherPlaces);
  4507. if (FAILED(hr) ||
  4508. FAILED(hr = Create_IUIElement(&g_cPrintersVW_HeaderTasks, &pData->pSpecialTaskHeader)) ||
  4509. FAILED(hr = Create_IUIElement(&g_cPrintersVW_HeaderSeeAlso, &pData->pFolderTaskHeader)))
  4510. {
  4511. // something has failed - cleanup
  4512. IUnknown_SafeReleaseAndNullPtr(pData->pIntroText);
  4513. IUnknown_SafeReleaseAndNullPtr(pData->pSpecialTaskHeader);
  4514. IUnknown_SafeReleaseAndNullPtr(pData->pFolderTaskHeader);
  4515. IUnknown_SafeReleaseAndNullPtr(pData->penumOtherPlaces);
  4516. }
  4517. return hr;
  4518. }
  4519. HRESULT CPrinterFolder::GetWebViewTasks(IUnknown *pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks)
  4520. {
  4521. ZeroMemory(pTasks, sizeof(*pTasks));
  4522. HRESULT hr = S_OK;
  4523. if (FAILED(hr = Create_IEnumUICommand(pv, g_cPrintersTasks,
  4524. ARRAYSIZE(g_cPrintersTasks), &pTasks->penumSpecialTasks)) ||
  4525. FAILED(hr = Create_IEnumUICommand(pv, g_cPrintersSeeAlso,
  4526. ARRAYSIZE(g_cPrintersSeeAlso), &pTasks->penumFolderTasks)))
  4527. {
  4528. // something has failed - cleanup.
  4529. IUnknown_SafeReleaseAndNullPtr(pTasks->penumSpecialTasks);
  4530. IUnknown_SafeReleaseAndNullPtr(pTasks->penumFolderTasks);
  4531. }
  4532. else
  4533. {
  4534. // request to update webview each time the contents change
  4535. pTasks->dwUpdateFlags = SFVMWVTSDF_CONTENTSCHANGE;
  4536. }
  4537. return hr;
  4538. }
  4539. HRESULT CPrinterFolder::SplitSelection(IDataObject *pdo,
  4540. UINT *puSelType, IDataObject **ppdoPrinters, IDataObject **ppdoLinks)
  4541. {
  4542. HRESULT hr = E_INVALIDARG;
  4543. if (pdo)
  4544. {
  4545. hr = S_OK;
  4546. UINT uSel = SEL_NONE;
  4547. IDataObject *pdoPrinters = NULL;
  4548. IDataObject *pdoLinks = NULL;
  4549. // create a PIDL array from the passed in data object
  4550. STGMEDIUM medium, mediumAux;
  4551. LPIDA pida = NULL, pidaAux = NULL;
  4552. pida = DataObj_GetHIDA(pdo, &medium);
  4553. // now we'll query this data object for SID_SAuxDataObject to see if we have such
  4554. IDataObject *pdoAux;
  4555. if (SUCCEEDED(IUnknown_QueryService(pdo, SID_SAuxDataObject, IID_PPV_ARG(IDataObject, &pdoAux))))
  4556. {
  4557. pidaAux = DataObj_GetHIDA(pdoAux, &mediumAux);
  4558. }
  4559. else
  4560. {
  4561. pdoAux = NULL;
  4562. }
  4563. // check to see if PIDL array is created
  4564. if (pida && pida->cidl)
  4565. {
  4566. PIDLTYPE pidlType;
  4567. LPCITEMIDLIST pidl;
  4568. UINT uPrinters = 0, uLinks = 0, uAddPrn = 0;
  4569. // walk through the PIDLs array to count the number of PIDLs of each type
  4570. for (UINT i = 0; i < pida->cidl; i++)
  4571. {
  4572. pidl = (LPCITEMIDLIST)IDA_GetIDListPtr(pida, i);
  4573. pidlType = _IDListType(pidl);
  4574. if (HOOD_COL_PRINTER == pidlType)
  4575. {
  4576. // this is a printer PIDL - it could be a printer object
  4577. // or the add printer wizard special PIDL
  4578. if (_IsAddPrinter((LPCIDPRINTER)pidl))
  4579. {
  4580. // this is the wizard object
  4581. uAddPrn++;
  4582. }
  4583. else
  4584. {
  4585. // this is a regular printer object
  4586. uPrinters++;
  4587. }
  4588. }
  4589. else
  4590. {
  4591. // not a printer PIDL - link is the only other possiblity
  4592. uLinks++;
  4593. }
  4594. }
  4595. if (pidaAux)
  4596. {
  4597. // the auxiliary data object (if any) can contain only links
  4598. uLinks += pidaAux->cidl;
  4599. }
  4600. // determine the selection type
  4601. UINT uTotal = uPrinters + uLinks + uAddPrn;
  4602. if (uTotal)
  4603. {
  4604. if (1 == uTotal)
  4605. {
  4606. // single selection case
  4607. if (uPrinters)
  4608. {
  4609. pdoPrinters = pdo;
  4610. uSel = SEL_SINGLE_PRINTER;
  4611. }
  4612. else if (uLinks)
  4613. {
  4614. pdoLinks = pdo;
  4615. uSel = SEL_SINGLE_LINK;
  4616. }
  4617. else
  4618. {
  4619. pdoPrinters = pdo;
  4620. uSel = SEL_SINGLE_ADDPRN;
  4621. }
  4622. }
  4623. else
  4624. {
  4625. // multiple selection case
  4626. if (0 == uLinks)
  4627. {
  4628. // only printers are selected
  4629. pdoPrinters = pdo;
  4630. uSel = SEL_MULTI_PRINTER;
  4631. }
  4632. else if (0 == uPrinters)
  4633. {
  4634. if (uAddPrn)
  4635. {
  4636. // only add printer wizard and links are selected
  4637. pdoPrinters = pdo;
  4638. pdoLinks = pdoAux;
  4639. }
  4640. else
  4641. {
  4642. // only links are selected
  4643. pdoLinks = pdo;
  4644. }
  4645. uSel = SEL_MULTI_LINK;
  4646. }
  4647. else
  4648. {
  4649. // mixed selection case
  4650. pdoPrinters = pdo;
  4651. pdoLinks = pdoAux;
  4652. uSel = SEL_MULTI_MIXED;
  4653. }
  4654. }
  4655. }
  4656. }
  4657. // addref and return the out parameters
  4658. if (ppdoPrinters)
  4659. {
  4660. if (pdoPrinters)
  4661. pdoPrinters->AddRef();
  4662. *ppdoPrinters = pdoPrinters;
  4663. }
  4664. if (ppdoLinks)
  4665. {
  4666. if (pdoLinks)
  4667. pdoLinks->AddRef();
  4668. *ppdoLinks = pdoLinks;
  4669. }
  4670. if (puSelType)
  4671. {
  4672. *puSelType = uSel;
  4673. }
  4674. // check to release the PIDL array
  4675. if (pida)
  4676. HIDA_ReleaseStgMedium(pida, &medium);
  4677. // check to release the auxiliary data object and storage medium
  4678. if (pidaAux)
  4679. HIDA_ReleaseStgMedium(pidaAux, &mediumAux);
  4680. if (pdoAux)
  4681. pdoAux->Release();
  4682. }
  4683. return hr;
  4684. }
  4685. HRESULT CPrinterFolder::_UpdateDataObjectCache()
  4686. {
  4687. HRESULT hr = S_OK;
  4688. CCSLock::Locker lock(_csLock);
  4689. if (lock)
  4690. {
  4691. _bstrSelectedPrinter.Empty();
  4692. // clear the cache -- zero can mean disabled or undefined --
  4693. // we don't really care about the difference
  4694. _uSelCurrent = SEL_NONE;
  4695. ZeroMemory(&_aWVCommandStates, sizeof(_aWVCommandStates));
  4696. if (_pdoCache)
  4697. {
  4698. IDataObject *pdoP = NULL;
  4699. // collect state information relevant to the selection
  4700. if (SUCCEEDED(hr = SplitSelection(_pdoCache, &_uSelCurrent, &pdoP, NULL)) &&
  4701. SEL_SINGLE_PRINTER == _uSelCurrent)
  4702. {
  4703. STGMEDIUM medium;
  4704. LPIDA pida = DataObj_GetHIDA(pdoP, &medium);
  4705. if (pida)
  4706. {
  4707. // this is pretty much the same type of logic we do in _MergeMenu()
  4708. TCHAR szFullPrinter[MAXNAMELENBUFFER];
  4709. LPCTSTR pszPrinter = _BuildPrinterName(szFullPrinter,
  4710. (LPIDPRINTER)IDA_GetIDListPtr(pida, 0), NULL);
  4711. PFOLDER_PRINTER_DATA pData = (PFOLDER_PRINTER_DATA)
  4712. Printer_FolderGetPrinter(GetFolder(), szFullPrinter);
  4713. if (pData)
  4714. {
  4715. ULONG ulAttributes;
  4716. LPCITEMIDLIST pidl = IDA_GetIDListPtr(pida, 0);
  4717. ulAttributes = SFGAO_CANDELETE;
  4718. _aWVCommandStates[WVIDM_DELETE] =
  4719. SUCCEEDED(GetAttributesOf(1, &pidl, &ulAttributes)) ? !!ulAttributes : FALSE;
  4720. ulAttributes = SFGAO_CANRENAME;
  4721. _aWVCommandStates[WVIDM_RENAME] =
  4722. SUCCEEDED(GetAttributesOf(1, &pidl, &ulAttributes)) ? !!ulAttributes : FALSE;
  4723. // enabled only for the local PF and if not default already
  4724. _aWVCommandStates[WVIDM_SETDEFAULTPRN] =
  4725. (NULL == GetServer() && FALSE == IsDefaultPrinter(szFullPrinter, pData->Attributes));
  4726. // enabled only for the local PF
  4727. _aWVCommandStates[WVIDM_DOCUMENTDEFAULTS] = (NULL == GetServer());
  4728. // enabled only if not paused already
  4729. _aWVCommandStates[WVIDM_PAUSEPRN] = !(pData->Status & PRINTER_STATUS_PAUSED);
  4730. // enabled only if paused
  4731. _aWVCommandStates[WVIDM_RESUMEPRN] = !!(pData->Status & PRINTER_STATUS_PAUSED);
  4732. // enabled only if the printer has jobs in the queue
  4733. _aWVCommandStates[WVIDM_PURGEPRN] = (0 != pData->cJobs);
  4734. if ((pData->Attributes & PRINTER_ATTRIBUTE_NETWORK) || (SpoolerVersion() <= 2))
  4735. {
  4736. // not enabled for network, masq and downlevel printers
  4737. _aWVCommandStates[WVIDM_WORKOFFLINE] = FALSE;
  4738. }
  4739. else
  4740. {
  4741. // enabled only if not offline already
  4742. _aWVCommandStates[WVIDM_WORKOFFLINE] =
  4743. !(pData->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE);
  4744. }
  4745. if ((pData->Attributes & PRINTER_ATTRIBUTE_NETWORK) || (SpoolerVersion() <= 2))
  4746. {
  4747. // not enabled for network, masq and downlevel printers
  4748. _aWVCommandStates[WVIDM_WORKONLINE] = FALSE;
  4749. }
  4750. else
  4751. {
  4752. // enabled only if offline
  4753. _aWVCommandStates[WVIDM_WORKONLINE] =
  4754. !!(pData->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE);
  4755. }
  4756. // remember the name of the selected printer
  4757. _bstrSelectedPrinter = szFullPrinter;
  4758. if (!_bstrSelectedPrinter)
  4759. {
  4760. hr = E_OUTOFMEMORY;
  4761. }
  4762. // free up the memory allocated from Printer_FolderGetPrinter
  4763. LocalFree((HLOCAL)pData);
  4764. }
  4765. else
  4766. {
  4767. // Printer_FolderGetPrinter failed
  4768. hr = E_OUTOFMEMORY;
  4769. }
  4770. // release the PIDL array
  4771. HIDA_ReleaseStgMedium(pida, &medium);
  4772. }
  4773. else
  4774. {
  4775. // DataObj_GetHIDA failed
  4776. hr = E_OUTOFMEMORY;
  4777. }
  4778. }
  4779. if (pdoP)
  4780. pdoP->Release();
  4781. }
  4782. }
  4783. else
  4784. {
  4785. // unable to enter the CS -- this can happen only in extremely low memory conditions!
  4786. hr = E_OUTOFMEMORY;
  4787. }
  4788. return hr;
  4789. }
  4790. HRESULT CPrinterFolder::_AssocCreate(REFIID riid, void **ppv)
  4791. {
  4792. HRESULT hr = E_FAIL;
  4793. IQueryAssociations *pqa;
  4794. hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  4795. if (SUCCEEDED(hr))
  4796. {
  4797. hr = pqa->Init(0, c_szPrinters, NULL, NULL);
  4798. if (SUCCEEDED(hr))
  4799. {
  4800. hr = pqa->QueryInterface(riid, ppv);
  4801. }
  4802. pqa->Release();
  4803. }
  4804. return hr;
  4805. }
  4806. HRESULT CPrinterFolder::_OnRefresh(BOOL bPriorRefresh)
  4807. {
  4808. HRESULT hr = S_OK;
  4809. if (bPriorRefresh)
  4810. {
  4811. CCSLock::Locker lock(_csLock);
  4812. if (lock)
  4813. {
  4814. // reset the slow webview data cache
  4815. _SlowWVDataCacheResetUnsafe();
  4816. // request a full refresh during the next enum
  4817. RequestRefresh();
  4818. }
  4819. else
  4820. {
  4821. hr = E_OUTOFMEMORY;
  4822. }
  4823. }
  4824. return hr;
  4825. }
  4826. // thread proc for obtaining the slow webview data
  4827. DWORD WINAPI CPrinterFolder::_SlowWebviewData_WorkerProc(LPVOID lpParameter)
  4828. {
  4829. HRESULT hr = S_OK;
  4830. CSlowWVDataCacheEntry *pCacheEntry = reinterpret_cast<CSlowWVDataCacheEntry*>(lpParameter);
  4831. if (pCacheEntry && pCacheEntry->_ppf && pCacheEntry->_bDataPending)
  4832. {
  4833. CPrinterFolder *ppf = pCacheEntry->_ppf;
  4834. CComBSTR bstrOemSupportUrl;
  4835. CComBSTR bstrPrinterWebUrl;
  4836. // retreive the slow webview data...
  4837. HRESULT hrCOMInit = SHCoInitialize();
  4838. if (SUCCEEDED(hr = hrCOMInit))
  4839. {
  4840. ASSERT(pCacheEntry->_bstrPrinterName);
  4841. hr = _SlowWVDataRetrieve(pCacheEntry->_bstrPrinterName, &bstrOemSupportUrl, &bstrPrinterWebUrl);
  4842. }
  4843. // update the cache...
  4844. do
  4845. {
  4846. CCSLock::Locker lock(pCacheEntry->_ppf->_csLock);
  4847. if (lock)
  4848. {
  4849. pCacheEntry->_arrData[WV_SLOW_DATA_OEM_SUPPORT_URL].Empty();
  4850. pCacheEntry->_arrData[WV_SLOW_DATA_PRINTER_WEB_URL].Empty();
  4851. if (SUCCEEDED(hr))
  4852. {
  4853. if (bstrOemSupportUrl)
  4854. {
  4855. pCacheEntry->_arrData[WV_SLOW_DATA_OEM_SUPPORT_URL] = bstrOemSupportUrl;
  4856. }
  4857. if (bstrPrinterWebUrl)
  4858. {
  4859. pCacheEntry->_arrData[WV_SLOW_DATA_PRINTER_WEB_URL] = bstrPrinterWebUrl;
  4860. }
  4861. }
  4862. // mark the data as ready...
  4863. pCacheEntry->_nLastTimeUpdated = GetTickCount();
  4864. pCacheEntry->_bDataPending = FALSE;
  4865. hr = S_OK;
  4866. }
  4867. else
  4868. {
  4869. // even if we fail to enter the CS then we still should update
  4870. // those fields to prevent further leaks.
  4871. pCacheEntry->_nLastTimeUpdated = GetTickCount();
  4872. pCacheEntry->_bDataPending = FALSE;
  4873. hr = E_OUTOFMEMORY;
  4874. }
  4875. // pCacheEntry shouldn't be accessed beyond this point!
  4876. pCacheEntry = NULL;
  4877. }
  4878. while (false);
  4879. // update the webview pane...
  4880. hr = ppf->_SlowWVDataUpdateWebviewPane();
  4881. // shutdown...
  4882. ppf->Release();
  4883. SHCoUninitialize(hrCOMInit);
  4884. }
  4885. else
  4886. {
  4887. hr = E_INVALIDARG;
  4888. }
  4889. return SUCCEEDED(hr) ? EXIT_SUCCESS : EXIT_FAILURE;
  4890. }
  4891. HRESULT CPrinterFolder::_SlowWVDataRetrieve(LPCTSTR pszPrinterName, BSTR *pbstrOemSupportUrl, BSTR *pbstrPrinterWebUrl)
  4892. {
  4893. HRESULT hr = S_OK;
  4894. // pszPrinterName can be NULL. if pszPrinterName is NULL that means that the
  4895. // custom support URL is requested (if any)
  4896. if (pbstrOemSupportUrl && pbstrPrinterWebUrl)
  4897. {
  4898. *pbstrOemSupportUrl = NULL;
  4899. *pbstrPrinterWebUrl = NULL;
  4900. CLSID clsID = GUID_NULL;
  4901. hr = _GetClassIDFromString(TEXT("OlePrn.PrinterURL"), &clsID);
  4902. if (SUCCEEDED(hr))
  4903. {
  4904. IDispatch *pDisp = NULL;
  4905. // SHExtCoCreateInstance to go through approval/app compat layer
  4906. hr = SHExtCoCreateInstance(NULL, &clsID, NULL, IID_PPV_ARG(IDispatch, &pDisp));
  4907. if (SUCCEEDED(hr))
  4908. {
  4909. CComVariant varOemSupportURL;
  4910. CComVariant varPrinterWebURL;
  4911. CComDispatchDriver drvDispatch(pDisp);
  4912. // if pszPrinterName isn't NULL then on return pbstrOemSupportUrl will be the OEM
  4913. // support URL. if it is NULL then it will be the custom support URL (if any)
  4914. if (pszPrinterName)
  4915. {
  4916. CComVariant varPrinterName(pszPrinterName);
  4917. if (varPrinterName.vt && varPrinterName.bstrVal)
  4918. {
  4919. hr = drvDispatch.PutPropertyByName(TEXT("PrinterName"), &varPrinterName);
  4920. if (SUCCEEDED(hr))
  4921. {
  4922. if (SUCCEEDED(drvDispatch.GetPropertyByName(TEXT("PrinterOemURL"), &varOemSupportURL)) &&
  4923. VT_BSTR == varOemSupportURL.vt && varOemSupportURL.bstrVal && varOemSupportURL.bstrVal[0])
  4924. {
  4925. *pbstrOemSupportUrl = SysAllocString(varOemSupportURL.bstrVal);
  4926. }
  4927. if (SUCCEEDED(drvDispatch.GetPropertyByName(TEXT("PrinterWebURL"), &varPrinterWebURL)) &&
  4928. VT_BSTR == varPrinterWebURL.vt && varPrinterWebURL.bstrVal && varPrinterWebURL.bstrVal[0])
  4929. {
  4930. *pbstrPrinterWebUrl = SysAllocString(varPrinterWebURL.bstrVal);
  4931. }
  4932. hr = S_OK;
  4933. }
  4934. }
  4935. else
  4936. {
  4937. hr = E_OUTOFMEMORY;
  4938. }
  4939. }
  4940. else
  4941. {
  4942. hr = drvDispatch.GetPropertyByName(TEXT("SupportLink"), &varOemSupportURL);
  4943. if (SUCCEEDED(hr))
  4944. {
  4945. if (VT_BSTR == varOemSupportURL.vt && varOemSupportURL.bstrVal && varOemSupportURL.bstrVal[0])
  4946. {
  4947. *pbstrOemSupportUrl = SysAllocString(varOemSupportURL.bstrVal);
  4948. hr = S_OK;
  4949. }
  4950. else
  4951. {
  4952. hr = E_UNEXPECTED;
  4953. }
  4954. }
  4955. }
  4956. pDisp->Release();
  4957. }
  4958. }
  4959. }
  4960. else
  4961. {
  4962. hr = E_INVALIDARG;
  4963. }
  4964. return hr;
  4965. }
  4966. int CPrinterFolder::_CompareSlowWVDataCacheEntries(CSlowWVDataCacheEntry *p1,
  4967. CSlowWVDataCacheEntry *p2, LPARAM lParam)
  4968. {
  4969. ASSERT(p1 && p1->_bstrPrinterName);
  4970. ASSERT(p2 && p2->_bstrPrinterName);
  4971. return lstrcmpi(p1->_bstrPrinterName, p2->_bstrPrinterName);
  4972. }
  4973. HRESULT CPrinterFolder::_GetSelectedPrinter(BSTR *pbstrVal)
  4974. {
  4975. HRESULT hr = S_OK;
  4976. if (pbstrVal)
  4977. {
  4978. CCSLock::Locker lock(_csLock);
  4979. if (lock)
  4980. {
  4981. if (_bstrSelectedPrinter)
  4982. {
  4983. *pbstrVal = _bstrSelectedPrinter.Copy();
  4984. hr = (*pbstrVal) ? S_OK : E_OUTOFMEMORY;
  4985. }
  4986. else
  4987. {
  4988. hr = E_UNEXPECTED;
  4989. }
  4990. }
  4991. else
  4992. {
  4993. hr = E_OUTOFMEMORY;
  4994. }
  4995. }
  4996. else
  4997. {
  4998. hr = E_INVALIDARG;
  4999. }
  5000. return hr;
  5001. }
  5002. HRESULT CPrinterFolder::_GetSlowWVDataForCurrentPrinter(ESlowWebviewDataType eType, BSTR *pbstrVal)
  5003. {
  5004. HRESULT hr = S_OK;
  5005. CComBSTR bstrSelectedPrinter;
  5006. if (SUCCEEDED(hr = _GetSelectedPrinter(&bstrSelectedPrinter)) &&
  5007. SUCCEEDED(hr = _GetSlowWVData(bstrSelectedPrinter, eType, pbstrVal)))
  5008. {
  5009. hr = S_OK;
  5010. }
  5011. return hr;
  5012. }
  5013. HRESULT CPrinterFolder::_GetSlowWVData(LPCTSTR pszPrinterName, ESlowWebviewDataType eType, BSTR *pbstrVal)
  5014. {
  5015. HRESULT hr = S_OK;
  5016. if (pszPrinterName && pbstrVal && eType >= 0 && eType < WV_SLOW_DATA_COUNT)
  5017. {
  5018. *pbstrVal = NULL;
  5019. CCSLock::Locker lock(_csLock);
  5020. if (lock)
  5021. {
  5022. CSlowWVDataCacheEntry entry(this);
  5023. hr = entry.Initialize(pszPrinterName);
  5024. if (SUCCEEDED(hr))
  5025. {
  5026. CSlowWVDataCacheEntry *pCacheEntry = NULL;
  5027. // search the cache...
  5028. INT iPos = _dpaSlowWVDataCache.Search(&entry, 0,
  5029. _CompareSlowWVDataCacheEntries, 0L, DPAS_SORTED);
  5030. if (iPos >= 0)
  5031. {
  5032. // this item in the cache, check if it hasn't expired
  5033. pCacheEntry = _dpaSlowWVDataCache.GetPtr(iPos);
  5034. ASSERT(pCacheEntry);
  5035. // let's see if the requested data is available...
  5036. if (pCacheEntry->_arrData[eType])
  5037. {
  5038. *pbstrVal = pCacheEntry->_arrData[eType].Copy();
  5039. hr = (*pbstrVal) ? S_OK : E_OUTOFMEMORY;
  5040. }
  5041. else
  5042. {
  5043. hr = E_PENDING;
  5044. }
  5045. if (!pCacheEntry->_bDataPending)
  5046. {
  5047. // let's see if this entry hasn't expired...
  5048. DWORD dwTicks = GetTickCount();
  5049. // this can happen if the cache entry hasn't been touched for more than 49 days!
  5050. // pretty unlikely, but we should handle properly.
  5051. if (dwTicks < pCacheEntry->_nLastTimeUpdated)
  5052. {
  5053. pCacheEntry->_nLastTimeUpdated = 0;
  5054. _UpdateSlowWVDataCacheEntry(pCacheEntry);
  5055. }
  5056. else
  5057. {
  5058. if ((dwTicks - pCacheEntry->_nLastTimeUpdated) > WV_SLOW_DATA_CACHE_TIMEOUT)
  5059. {
  5060. // this cache entry has expired, kick off a thread to update...
  5061. _UpdateSlowWVDataCacheEntry(pCacheEntry);
  5062. }
  5063. }
  5064. }
  5065. }
  5066. else
  5067. {
  5068. // this item isn't in the cache - let's create a new one and request update.
  5069. pCacheEntry = new CSlowWVDataCacheEntry(this);
  5070. if (pCacheEntry)
  5071. {
  5072. hr = pCacheEntry->Initialize(pszPrinterName);
  5073. if (SUCCEEDED(hr))
  5074. {
  5075. iPos = _dpaSlowWVDataCache.Search(pCacheEntry, 0,
  5076. _CompareSlowWVDataCacheEntries, 0L, DPAS_SORTED | DPAS_INSERTAFTER);
  5077. iPos = _dpaSlowWVDataCache.InsertPtr(iPos, pCacheEntry);
  5078. if (-1 == iPos)
  5079. {
  5080. // failed to insert, bail...
  5081. delete pCacheEntry;
  5082. pCacheEntry = NULL;
  5083. hr = E_OUTOFMEMORY;
  5084. }
  5085. else
  5086. {
  5087. // kick off a thread to update...
  5088. hr = _UpdateSlowWVDataCacheEntry(pCacheEntry);
  5089. if (SUCCEEDED(hr))
  5090. {
  5091. // everything succeeded - return pending to the caller
  5092. hr = E_PENDING;
  5093. }
  5094. else
  5095. {
  5096. // failed to create the thread, cleanup
  5097. delete _dpaSlowWVDataCache.DeletePtr(iPos);
  5098. pCacheEntry = NULL;
  5099. }
  5100. }
  5101. }
  5102. }
  5103. else
  5104. {
  5105. hr = E_OUTOFMEMORY;
  5106. }
  5107. }
  5108. }
  5109. }
  5110. else
  5111. {
  5112. hr = E_OUTOFMEMORY;
  5113. }
  5114. }
  5115. else
  5116. {
  5117. hr = E_INVALIDARG;
  5118. }
  5119. return hr;
  5120. }
  5121. HRESULT CPrinterFolder::_UpdateSlowWVDataCacheEntry(CSlowWVDataCacheEntry *pCacheEntry)
  5122. {
  5123. HRESULT hr = S_OK;
  5124. if (pCacheEntry)
  5125. {
  5126. pCacheEntry->_bDataPending = TRUE;
  5127. pCacheEntry->_ppf->AddRef();
  5128. if (!SHQueueUserWorkItem(reinterpret_cast<LPTHREAD_START_ROUTINE>(_SlowWebviewData_WorkerProc),
  5129. pCacheEntry, 0, 0, NULL, "shell32.dll", 0))
  5130. {
  5131. // failed to queue the work item - call Release() to balance the AddRef() call.
  5132. pCacheEntry->_bDataPending = FALSE;
  5133. pCacheEntry->_nLastTimeUpdated = GetTickCount();
  5134. pCacheEntry->_ppf->Release();
  5135. // let's see if we can make something out of the win32 last error
  5136. DWORD dw = GetLastError();
  5137. hr = ((ERROR_SUCCESS == dw) ? E_FAIL : HRESULT_FROM_WIN32(dw));
  5138. }
  5139. }
  5140. else
  5141. {
  5142. hr = E_INVALIDARG;
  5143. }
  5144. return hr;
  5145. }
  5146. HRESULT CPrinterFolder::_SlowWVDataUpdateWebviewPane()
  5147. {
  5148. HRESULT hr = S_OK;
  5149. CComBSTR bstrSelectedPrinter;
  5150. UINT uFlags = SHCNF_IDLIST | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT;
  5151. // we fire SHCNE_UPDATEITEM for the PIDL of the currently selected printer
  5152. // to force refresh of the webview pane.
  5153. if (SUCCEEDED(hr = _GetSelectedPrinter(&bstrSelectedPrinter)))
  5154. {
  5155. if (GetServer())
  5156. {
  5157. LPCTSTR pszServer = NULL;
  5158. LPCTSTR pszPrinter = NULL;
  5159. TCHAR szBuffer[MAXNAMELENBUFFER] = {0};
  5160. // in the remote printer's folder we need to strip off the server
  5161. // part from the full printer name.
  5162. Printer_SplitFullName(szBuffer, bstrSelectedPrinter, &pszServer, &pszPrinter);
  5163. if (pszPrinter && pszPrinter[0])
  5164. {
  5165. bstrSelectedPrinter = pszPrinter;
  5166. }
  5167. }
  5168. LPITEMIDLIST pidl = NULL;
  5169. if (SUCCEEDED(hr = _GetFullIDList(bstrSelectedPrinter, &pidl)))
  5170. {
  5171. SHChangeNotify(SHCNE_UPDATEITEM, uFlags, pidl, NULL);
  5172. ILFree(pidl);
  5173. }
  5174. }
  5175. return hr;
  5176. }
  5177. HRESULT CPrinterFolder::_SlowWVDataCacheResetUnsafe()
  5178. {
  5179. // this is reseting the slow webview data cache
  5180. if (_dpaSlowWVDataCache)
  5181. {
  5182. INT_PTR iPos = 0;
  5183. CSlowWVDataCacheEntry *pCacheEntry = NULL;
  5184. while (iPos < _dpaSlowWVDataCache.GetPtrCount())
  5185. {
  5186. // delete only the entries which are not in pending
  5187. pCacheEntry = _dpaSlowWVDataCache.GetPtr(iPos);
  5188. if (!pCacheEntry->_bDataPending)
  5189. {
  5190. delete _dpaSlowWVDataCache.DeletePtr(iPos);
  5191. }
  5192. else
  5193. {
  5194. // this one is pending - skip.
  5195. iPos++;
  5196. }
  5197. }
  5198. }
  5199. return S_OK;
  5200. }
  5201. HRESULT CPrinterFolder::_GetCustomSupportURL(BSTR *pbstrVal)
  5202. {
  5203. HRESULT hr = S_OK;
  5204. if (pbstrVal)
  5205. {
  5206. *pbstrVal = NULL;
  5207. CComBSTR bstrOemSupportUrl;
  5208. CComBSTR bstrPrinterWebUrl;
  5209. hr = _SlowWVDataRetrieve(NULL, &bstrOemSupportUrl, &bstrPrinterWebUrl);
  5210. if (SUCCEEDED(hr))
  5211. {
  5212. *pbstrVal = bstrOemSupportUrl.Copy();
  5213. hr = S_OK;
  5214. }
  5215. }
  5216. else
  5217. {
  5218. hr = E_INVALIDARG;
  5219. }
  5220. return hr;
  5221. }
  5222. HRESULT CPrinterFolder::_GetFaxControl(IDispatch **ppDisp)
  5223. {
  5224. HRESULT hr = E_INVALIDARG;
  5225. if (ppDisp)
  5226. {
  5227. *ppDisp = NULL;
  5228. CLSID clsID = GUID_NULL;
  5229. hr = _GetClassIDFromString(TEXT("FaxControl.FaxControl"), &clsID);
  5230. if (SUCCEEDED(hr))
  5231. {
  5232. // SHExtCoCreateInstance to go through approval/app compat layer
  5233. hr = SHExtCoCreateInstance(NULL, &clsID, NULL, IID_PPV_ARG(IDispatch, ppDisp));
  5234. }
  5235. }
  5236. return hr;
  5237. }
  5238. HRESULT CPrinterFolder::_GetFaxCommand(UINT_PTR *puCmd)
  5239. {
  5240. HRESULT hr = E_INVALIDARG;
  5241. if (puCmd)
  5242. {
  5243. *puCmd = 0;
  5244. IDispatch *pDisp = NULL;
  5245. hr = _GetFaxControl(&pDisp);
  5246. if (SUCCEEDED(hr))
  5247. {
  5248. CComDispatchDriver drvDispatch(pDisp);
  5249. CComVariant varIsFxSvcInstalled;
  5250. CComVariant varIsFxPrnInstalled;
  5251. if (SUCCEEDED(hr = drvDispatch.GetPropertyByName(TEXT("IsFaxServiceInstalled"), &varIsFxSvcInstalled)) &&
  5252. SUCCEEDED(hr = drvDispatch.GetPropertyByName(TEXT("IsLocalFaxPrinterInstalled"), &varIsFxPrnInstalled)))
  5253. {
  5254. if (VT_BOOL == varIsFxSvcInstalled.vt && VT_BOOL == varIsFxPrnInstalled.vt)
  5255. {
  5256. if (VARIANT_TRUE == varIsFxSvcInstalled.boolVal)
  5257. {
  5258. if (VARIANT_TRUE == varIsFxPrnInstalled.boolVal)
  5259. {
  5260. *puCmd = FSIDM_SENDFAXWIZARD;
  5261. }
  5262. else
  5263. {
  5264. *puCmd = FSIDM_CREATELOCALFAX;
  5265. }
  5266. }
  5267. else
  5268. {
  5269. *puCmd = FSIDM_SETUPFAXING;
  5270. }
  5271. hr = S_OK;
  5272. }
  5273. else
  5274. {
  5275. hr = E_UNEXPECTED;
  5276. }
  5277. }
  5278. pDisp->Release();
  5279. }
  5280. }
  5281. return hr;
  5282. }
  5283. HRESULT CPrinterFolder::_InvokeFaxControlMethod(LPCTSTR pszMethodName)
  5284. {
  5285. HRESULT hr = E_INVALIDARG;
  5286. if (pszMethodName)
  5287. {
  5288. // this function will be called from background threads, so
  5289. // we need to call SHCoInitialize first.
  5290. HRESULT hrCOMInit = SHCoInitialize();
  5291. if (SUCCEEDED(hr = hrCOMInit))
  5292. {
  5293. IDispatch *pDisp = NULL;
  5294. hr = _GetFaxControl(&pDisp);
  5295. if (SUCCEEDED(hr))
  5296. {
  5297. CComDispatchDriver drvDispatch(pDisp);
  5298. hr = drvDispatch.Invoke0(pszMethodName);
  5299. pDisp->Release();
  5300. }
  5301. }
  5302. SHCoUninitialize(hrCOMInit);
  5303. }
  5304. return hr;
  5305. }
  5306. DWORD WINAPI CPrinterFolder::_ThreadProc_InstallFaxService(LPVOID lpParameter)
  5307. {
  5308. HRESULT hr = _InvokeFaxControlMethod(TEXT("InstallFaxService"));
  5309. return SUCCEEDED(hr) ? EXIT_SUCCESS : EXIT_FAILURE;
  5310. }
  5311. DWORD WINAPI CPrinterFolder::_ThreadProc_InstallLocalFaxPrinter(LPVOID lpParameter)
  5312. {
  5313. HRESULT hr = _InvokeFaxControlMethod(TEXT("InstallLocalFaxPrinter"));
  5314. return SUCCEEDED(hr) ? EXIT_SUCCESS : EXIT_FAILURE;
  5315. }
  5316. // conversion table from webview verbs into printer folder verbs
  5317. static const UINT_PTR
  5318. g_cVerbWV2VerbFolder[CPrinterFolder::WVIDM_COUNT] =
  5319. {
  5320. #define INVALID_CMD static_cast<UINT_PTR>(-1)
  5321. // folder verbs // corresponding webview verbs
  5322. DFM_CMD_DELETE, // WVIDM_DELETE,
  5323. DFM_CMD_RENAME, // WVIDM_RENAME,
  5324. DFM_CMD_PROPERTIES, // WVIDM_PROPERTIES,
  5325. // common verbs// common verbs
  5326. FSIDM_ADDPRINTERWIZARD, // WVIDM_ADDPRINTERWIZARD,
  5327. FSIDM_SERVERPROPERTIES, // WVIDM_SERVERPROPERTIES,
  5328. FSIDM_SETUPFAXING, // WVIDM_SETUPFAXING,
  5329. FSIDM_CREATELOCALFAX, // WVIDM_CREATELOCALFAX,
  5330. FSIDM_SENDFAXWIZARD, // WVIDM_SENDFAXWIZARD,
  5331. // special common verbs// special common verbs
  5332. INVALID_CMD, // WVIDM_TROUBLESHOOTER,
  5333. INVALID_CMD, // WVIDM_GOTOSUPPORT,
  5334. // printer verbs// printer verbs
  5335. FSIDM_OPENPRN, // WVIDM_OPENPRN,
  5336. FSIDM_NETPRN_INSTALL, // WVIDM_NETPRN_INSTALL,
  5337. FSIDM_SETDEFAULTPRN, // WVIDM_SETDEFAULTPRN,
  5338. FSIDM_DOCUMENTDEFAULTS, // WVIDM_DOCUMENTDEFAULTS,
  5339. FSIDM_PAUSEPRN, // WVIDM_PAUSEPRN,
  5340. FSIDM_RESUMEPRN, // WVIDM_RESUMEPRN,
  5341. FSIDM_PURGEPRN, // WVIDM_PURGEPRN,
  5342. FSIDM_SHARING, // WVIDM_SHARING,
  5343. FSIDM_WORKOFFLINE, // WVIDM_WORKOFFLINE,
  5344. FSIDM_WORKONLINE, // WVIDM_WORKONLINE,
  5345. // special commands// special commands
  5346. INVALID_CMD, // WVIDM_VENDORURL,
  5347. INVALID_CMD, // WVIDM_PRINTERURL,
  5348. };
  5349. HRESULT CPrinterFolder::_WebviewVerbIsEnabled(WV_VERB eVerbID, UINT uSelMask, BOOL *pbEnabled)
  5350. {
  5351. HRESULT hr = S_OK;
  5352. CCSLock::Locker lock(_csLock);
  5353. if (lock)
  5354. {
  5355. // not enabled by default
  5356. ASSERT(pbEnabled);
  5357. *pbEnabled = FALSE;
  5358. if (_pdoCache)
  5359. {
  5360. // if _pdoCache isn't NULL that means we have a selection
  5361. // let's see what command set will be enabled depending on
  5362. // the current selection (_uSelCurrent, _pdoCache) and on
  5363. // the passed in selection mask (uSelMask)
  5364. if (uSelMask & _uSelCurrent)
  5365. {
  5366. switch (_uSelCurrent)
  5367. {
  5368. case SEL_SINGLE_ADDPRN:
  5369. // only WVIDM_ADDPRINTERWIZARD is enabled
  5370. *pbEnabled = ((eVerbID == WVIDM_ADDPRINTERWIZARD) && !SHRestricted(REST_NOPRINTERADD));
  5371. break;
  5372. case SEL_SINGLE_PRINTER:
  5373. {
  5374. switch (eVerbID)
  5375. {
  5376. case WVIDM_PROPERTIES:
  5377. case WVIDM_OPENPRN:
  5378. case WVIDM_SHARING:
  5379. // always enabled
  5380. *pbEnabled = TRUE;
  5381. break;
  5382. case WVIDM_VENDORURL:
  5383. {
  5384. *pbEnabled = FALSE;
  5385. CComBSTR bstrCustomSupportURL;
  5386. if (FAILED(_GetCustomSupportURL(&bstrCustomSupportURL)))
  5387. {
  5388. // OEM support URL will be enabled only if there is no custom support URL.
  5389. CComBSTR bstrURL;
  5390. *pbEnabled = SUCCEEDED(_GetSlowWVDataForCurrentPrinter(WV_SLOW_DATA_OEM_SUPPORT_URL, &bstrURL));
  5391. }
  5392. }
  5393. break;
  5394. case WVIDM_PRINTERURL:
  5395. {
  5396. CComBSTR bstrURL;
  5397. *pbEnabled = SUCCEEDED(_GetSlowWVDataForCurrentPrinter(WV_SLOW_DATA_PRINTER_WEB_URL, &bstrURL));
  5398. }
  5399. break;
  5400. default:
  5401. // consult the cache
  5402. *pbEnabled = _aWVCommandStates[eVerbID];
  5403. break;
  5404. }
  5405. }
  5406. break;
  5407. case SEL_SINGLE_LINK:
  5408. {
  5409. // commands enabled for multiple selection of printer objects
  5410. switch (eVerbID)
  5411. {
  5412. case WVIDM_DELETE:
  5413. case WVIDM_RENAME:
  5414. case WVIDM_PROPERTIES:
  5415. *pbEnabled = TRUE;
  5416. break;
  5417. default:
  5418. break;
  5419. }
  5420. }
  5421. break;
  5422. case SEL_MULTI_PRINTER:
  5423. {
  5424. switch (eVerbID)
  5425. {
  5426. case WVIDM_DELETE:
  5427. case WVIDM_PROPERTIES:
  5428. case WVIDM_OPENPRN:
  5429. case WVIDM_DOCUMENTDEFAULTS:
  5430. case WVIDM_PURGEPRN:
  5431. case WVIDM_SHARING:
  5432. // those are always enabled
  5433. *pbEnabled = TRUE;
  5434. break;
  5435. default:
  5436. break;
  5437. }
  5438. }
  5439. break;
  5440. case SEL_MULTI_LINK:
  5441. case SEL_MULTI_MIXED:
  5442. {
  5443. switch (eVerbID)
  5444. {
  5445. case WVIDM_DELETE:
  5446. case WVIDM_PROPERTIES:
  5447. // those are always enabled
  5448. *pbEnabled = TRUE;
  5449. break;
  5450. default:
  5451. break;
  5452. }
  5453. }
  5454. break;
  5455. }
  5456. // here we deal with commands which are always enabled regardless
  5457. // of the selection type.
  5458. switch (eVerbID)
  5459. {
  5460. case WVIDM_ADDPRINTERWIZARD:
  5461. *pbEnabled = !SHRestricted(REST_NOPRINTERADD);
  5462. break;
  5463. default:
  5464. break;
  5465. }
  5466. }
  5467. }
  5468. else
  5469. {
  5470. // if _pdoCache is NULL that means we have no selection
  5471. // let's see what command set will be enabled depending
  5472. // on the passed in selection mask (uSelMask)
  5473. switch (eVerbID)
  5474. {
  5475. case WVIDM_ADDPRINTERWIZARD:
  5476. *pbEnabled = !SHRestricted(REST_NOPRINTERADD);
  5477. break;
  5478. case WVIDM_TROUBLESHOOTER:
  5479. case WVIDM_GOTOSUPPORT:
  5480. // the troubleshooter and goto support commands are always enabled.
  5481. *pbEnabled = TRUE;
  5482. break;
  5483. case WVIDM_SERVERPROPERTIES:
  5484. // server properties will be enabled in the non-selection case
  5485. // only on server SKUs.
  5486. *pbEnabled = IsOS(OS_ANYSERVER);
  5487. break;
  5488. case WVIDM_SETUPFAXING:
  5489. case WVIDM_CREATELOCALFAX:
  5490. case WVIDM_SENDFAXWIZARD:
  5491. {
  5492. UINT_PTR uCmd;
  5493. if (GetServer() || FAILED(_GetFaxCommand(&uCmd)))
  5494. {
  5495. uCmd = 0;
  5496. }
  5497. *pbEnabled = (uCmd == g_cVerbWV2VerbFolder[eVerbID]);
  5498. }
  5499. break;
  5500. default:
  5501. break;
  5502. }
  5503. }
  5504. }
  5505. else
  5506. {
  5507. // unable to enter the CS -- this can happen only in extremely low memory conditions!
  5508. hr = E_OUTOFMEMORY;
  5509. }
  5510. return hr;
  5511. }
  5512. HRESULT CPrinterFolder::_WebviewVerbInvoke(WV_VERB eVerbID, IUnknown* pv, IShellItemArray *psiItemArray)
  5513. {
  5514. HRESULT hr = S_OK;
  5515. HWND hwnd = NULL;
  5516. IShellView *psv = NULL;
  5517. IDataObject *pdo = NULL;
  5518. if (psiItemArray)
  5519. {
  5520. hr = psiItemArray->BindToHandler(NULL,BHID_DataObject,IID_PPV_ARG(IDataObject,&pdo));
  5521. }
  5522. if (SUCCEEDED(hr))
  5523. {
  5524. // quey some basic interfaces from the PIDL array
  5525. if (SUCCEEDED(hr = IUnknown_QueryService(pv, IID_IShellView, IID_PPV_ARG(IShellView, &psv))) &&
  5526. SUCCEEDED(hr = psv->GetWindow(&hwnd)))
  5527. {
  5528. switch( eVerbID)
  5529. {
  5530. // special common verbs
  5531. case WVIDM_TROUBLESHOOTER:
  5532. ShellExecute(hwnd, TEXT("open"), TEXT("helpctr.exe"),
  5533. TEXT("-Url hcp://help/tshoot/tsprint.htm"), NULL, SW_SHOWNORMAL);
  5534. break;
  5535. case WVIDM_GOTOSUPPORT:
  5536. {
  5537. CComBSTR bstrURL;
  5538. if (SUCCEEDED(_GetCustomSupportURL(&bstrURL)))
  5539. {
  5540. // the admin has provided a custom URL for support - navigate to it.
  5541. ShellExecute(hwnd, TEXT("open"), bstrURL, NULL, NULL, SW_SHOWNORMAL);
  5542. }
  5543. else
  5544. {
  5545. // custom support isn't provided - go to the default support URL.
  5546. ShellExecute(hwnd, TEXT("open"),
  5547. TEXT("http://www.microsoft.com/isapi/redir.dll?prd=Win2000&ar=Support&sba=printing"),
  5548. NULL, NULL, SW_SHOWNORMAL);
  5549. }
  5550. }
  5551. break;
  5552. // common verbs
  5553. case WVIDM_ADDPRINTERWIZARD:
  5554. case WVIDM_SERVERPROPERTIES:
  5555. case WVIDM_SETUPFAXING:
  5556. case WVIDM_CREATELOCALFAX:
  5557. case WVIDM_SENDFAXWIZARD:
  5558. {
  5559. // delegate the command to CPrinterFolder::CallBack
  5560. ASSERT(INVALID_CMD != g_cVerbWV2VerbFolder[eVerbID]);
  5561. hr = CallBack(this, hwnd, pdo, DFM_INVOKECOMMAND, g_cVerbWV2VerbFolder[eVerbID], 0L);
  5562. }
  5563. break;
  5564. // standard verbs
  5565. case WVIDM_DELETE:
  5566. case WVIDM_RENAME:
  5567. case WVIDM_PROPERTIES:
  5568. // printer verbs
  5569. case WVIDM_OPENPRN:
  5570. case WVIDM_NETPRN_INSTALL:
  5571. case WVIDM_SETDEFAULTPRN:
  5572. case WVIDM_DOCUMENTDEFAULTS:
  5573. case WVIDM_PAUSEPRN:
  5574. case WVIDM_RESUMEPRN:
  5575. case WVIDM_PURGEPRN:
  5576. case WVIDM_SHARING:
  5577. case WVIDM_WORKOFFLINE:
  5578. case WVIDM_WORKONLINE:
  5579. {
  5580. if (DFM_CMD_RENAME == g_cVerbWV2VerbFolder[eVerbID])
  5581. {
  5582. // we need to handle rename explicitly through IShellView2
  5583. IShellView2 *psv2;
  5584. if (SUCCEEDED(hr = IUnknown_QueryService(pv, IID_IShellView2,
  5585. IID_PPV_ARG(IShellView2, &psv2))))
  5586. {
  5587. // passing NULL to HandleRename is making defview to
  5588. // operate on the currently selected object
  5589. hr = psv2->HandleRename(NULL);
  5590. psv2->Release();
  5591. }
  5592. }
  5593. else
  5594. {
  5595. // just delegate the command to CPrinterFolder::_DFMCallBack
  5596. hr = _DFMCallBack(this, hwnd, pdo, DFM_INVOKECOMMAND, g_cVerbWV2VerbFolder[eVerbID], 0L);
  5597. }
  5598. }
  5599. break;
  5600. // special commands
  5601. case WVIDM_VENDORURL:
  5602. {
  5603. CComBSTR bstrVendorURL;
  5604. hr = _GetSlowWVDataForCurrentPrinter(WV_SLOW_DATA_OEM_SUPPORT_URL, &bstrVendorURL);
  5605. if (SUCCEEDED(hr))
  5606. {
  5607. ShellExecute(hwnd, TEXT("open"), bstrVendorURL, NULL, NULL, SW_SHOWNORMAL);
  5608. }
  5609. }
  5610. break;
  5611. case WVIDM_PRINTERURL:
  5612. {
  5613. CComBSTR bstrPrinterURL;
  5614. hr = _GetSlowWVDataForCurrentPrinter(WV_SLOW_DATA_PRINTER_WEB_URL, &bstrPrinterURL);
  5615. if (SUCCEEDED(hr))
  5616. {
  5617. ShellExecute(hwnd, TEXT("open"), bstrPrinterURL, NULL, NULL, SW_SHOWNORMAL);
  5618. }
  5619. }
  5620. break;
  5621. }
  5622. }
  5623. ATOMICRELEASE(pdo);
  5624. ATOMICRELEASE(psv);
  5625. }
  5626. return hr;
  5627. }
  5628. HRESULT CPrinterFolder::_WebviewCheckToUpdateDataObjectCache(IDataObject *pdo)
  5629. {
  5630. HRESULT hr = S_OK;
  5631. CCSLock::Locker lock(_csLock);
  5632. if (lock)
  5633. {
  5634. if (pdo)
  5635. {
  5636. // we need to compare the passed in data object with the one we are
  5637. // caching and update the cache if necessary
  5638. if (_pdoCache)
  5639. {
  5640. // compare the objects using the COM rules
  5641. IUnknown *punk1;
  5642. IUnknown *punk2;
  5643. if (SUCCEEDED(hr = pdo->QueryInterface(IID_PPV_ARG(IUnknown, &punk1))))
  5644. {
  5645. if (SUCCEEDED(hr = _pdoCache->QueryInterface(IID_PPV_ARG(IUnknown, &punk2))))
  5646. {
  5647. if (punk1 != punk2)
  5648. {
  5649. // release the current data object
  5650. _pdoCache->Release();
  5651. _pdoCache = pdo;
  5652. _pdoCache->AddRef();
  5653. // update the cache
  5654. hr = _UpdateDataObjectCache();
  5655. }
  5656. punk2->Release();
  5657. }
  5658. punk1->Release();
  5659. }
  5660. }
  5661. else
  5662. {
  5663. // _pdoCache is NULL, rebuild the cache
  5664. _pdoCache = pdo;
  5665. _pdoCache->AddRef();
  5666. // update the cache
  5667. hr = _UpdateDataObjectCache();
  5668. }
  5669. }
  5670. else
  5671. {
  5672. if (_pdoCache)
  5673. {
  5674. // clear the cache
  5675. _pdoCache->Release();
  5676. _pdoCache = NULL;
  5677. // update the cache
  5678. hr = _UpdateDataObjectCache();
  5679. }
  5680. }
  5681. }
  5682. else
  5683. {
  5684. // unable to enter the CS -- this can happen only in extremely low memory conditions!
  5685. hr = E_OUTOFMEMORY;
  5686. }
  5687. return hr;
  5688. }
  5689. // export for printui. uses standard namespace stuff
  5690. STDAPI_(void) Printer_LoadIcons(LPCTSTR pszPrinterName, HICON *phLargeIcon, HICON *phSmallIcon)
  5691. {
  5692. if (phLargeIcon) *phLargeIcon = NULL;
  5693. if (phSmallIcon) *phSmallIcon = NULL;
  5694. LPITEMIDLIST pidl;
  5695. if (SUCCEEDED(ParsePrinterNameEx(pszPrinterName, &pidl, TRUE, 0, 0)))
  5696. {
  5697. SHFILEINFO sfi;
  5698. if (phLargeIcon && SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_PIDL))
  5699. {
  5700. *phLargeIcon = sfi.hIcon;
  5701. }
  5702. if (phSmallIcon && SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_PIDL))
  5703. {
  5704. *phSmallIcon = sfi.hIcon;
  5705. }
  5706. ILFree(pidl);
  5707. }
  5708. // if above fails fallback to default icons
  5709. if (phLargeIcon && (NULL == *phLargeIcon))
  5710. *phLargeIcon = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_PRINTER), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  5711. if (phSmallIcon && (NULL == *phSmallIcon))
  5712. *phSmallIcon = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_PRINTER), IMAGE_ICON, g_cxSmIcon, g_cxSmIcon, 0);
  5713. }
  5714. typedef struct
  5715. {
  5716. USHORT cb;
  5717. SHCNF_PRINTJOB_DATA data;
  5718. USHORT uTerm;
  5719. } IDPRINTJOB, *LPIDPRINTJOB;
  5720. typedef const IDPRINTJOB *LPCIDPRINTJOB;
  5721. void Printjob_FillPidl(LPIDPRINTJOB pidl, LPSHCNF_PRINTJOB_DATA pData)
  5722. {
  5723. pidl->cb = FIELD_OFFSET(IDPRINTJOB, uTerm);
  5724. if (pData)
  5725. {
  5726. pidl->data = *pData;
  5727. }
  5728. else
  5729. {
  5730. ZeroMemory(&(pidl->data), sizeof(SHCNF_PRINTJOB_DATA));
  5731. }
  5732. pidl->uTerm = 0;
  5733. }
  5734. LPITEMIDLIST Printjob_GetPidl(LPCTSTR szName, LPSHCNF_PRINTJOB_DATA pData)
  5735. {
  5736. LPITEMIDLIST pidl = NULL;
  5737. LPITEMIDLIST pidlParent;
  5738. if (SUCCEEDED(ParsePrinterNameEx(szName, &pidlParent, TRUE, 0, 0)))
  5739. {
  5740. IDPRINTJOB idj;
  5741. Printjob_FillPidl(&idj, pData);
  5742. pidl = ILCombine(pidlParent, (LPITEMIDLIST)&idj);
  5743. ILFree(pidlParent);
  5744. }
  5745. return pidl;
  5746. }
  5747. const struct
  5748. {
  5749. DWORD bit; // bit of a bitfield
  5750. UINT uStringID; // the string id this bit maps to
  5751. }
  5752. c_map_bit_to_status[] =
  5753. {
  5754. PRINTER_STATUS_PAUSED, IDS_PRQSTATUS_PAUSED,
  5755. PRINTER_STATUS_ERROR, IDS_PRQSTATUS_ERROR,
  5756. PRINTER_STATUS_PENDING_DELETION, IDS_PRQSTATUS_PENDING_DELETION,
  5757. PRINTER_STATUS_PAPER_JAM, IDS_PRQSTATUS_PAPER_JAM,
  5758. PRINTER_STATUS_PAPER_OUT, IDS_PRQSTATUS_PAPER_OUT,
  5759. PRINTER_STATUS_MANUAL_FEED, IDS_PRQSTATUS_MANUAL_FEED,
  5760. PRINTER_STATUS_PAPER_PROBLEM, IDS_PRQSTATUS_PAPER_PROBLEM,
  5761. PRINTER_STATUS_OFFLINE, IDS_PRQSTATUS_OFFLINE,
  5762. PRINTER_STATUS_IO_ACTIVE, IDS_PRQSTATUS_IO_ACTIVE,
  5763. PRINTER_STATUS_BUSY, IDS_PRQSTATUS_BUSY,
  5764. PRINTER_STATUS_PRINTING, IDS_PRQSTATUS_PRINTING,
  5765. PRINTER_STATUS_OUTPUT_BIN_FULL, IDS_PRQSTATUS_OUTPUT_BIN_FULL,
  5766. PRINTER_STATUS_NOT_AVAILABLE, IDS_PRQSTATUS_NOT_AVAILABLE,
  5767. PRINTER_STATUS_WAITING, IDS_PRQSTATUS_WAITING,
  5768. PRINTER_STATUS_PROCESSING, IDS_PRQSTATUS_PROCESSING,
  5769. PRINTER_STATUS_INITIALIZING, IDS_PRQSTATUS_INITIALIZING,
  5770. PRINTER_STATUS_WARMING_UP, IDS_PRQSTATUS_WARMING_UP,
  5771. PRINTER_STATUS_TONER_LOW, IDS_PRQSTATUS_TONER_LOW,
  5772. PRINTER_STATUS_NO_TONER, IDS_PRQSTATUS_NO_TONER,
  5773. PRINTER_STATUS_PAGE_PUNT, IDS_PRQSTATUS_PAGE_PUNT,
  5774. PRINTER_STATUS_USER_INTERVENTION, IDS_PRQSTATUS_USER_INTERVENTION,
  5775. PRINTER_STATUS_OUT_OF_MEMORY, IDS_PRQSTATUS_OUT_OF_MEMORY,
  5776. PRINTER_STATUS_DOOR_OPEN, IDS_PRQSTATUS_DOOR_OPEN,
  5777. PRINTER_HACK_WORK_OFFLINE, IDS_PRQSTATUS_WORK_OFFLINE,
  5778. } ;
  5779. // maps bits into a string representation, putting
  5780. // the string idsSep in between each found bit.
  5781. // Returns the size of the created string.
  5782. UINT Printer_BitsToString(DWORD bits, UINT idsSep, LPTSTR lpszBuf, UINT cchMax)
  5783. {
  5784. UINT cchBuf = 0;
  5785. UINT cchSep = 0;
  5786. TCHAR szSep[20];
  5787. if (LoadString(HINST_THISDLL, idsSep, szSep, ARRAYSIZE(szSep)))
  5788. cchSep = lstrlen(szSep);
  5789. for (UINT i = 0; i < ARRAYSIZE(c_map_bit_to_status); i++)
  5790. {
  5791. if (bits & c_map_bit_to_status[i].bit)
  5792. {
  5793. TCHAR szTmp[258];
  5794. if (LoadString(HINST_THISDLL, c_map_bit_to_status[i].uStringID, szTmp, ARRAYSIZE(szTmp)))
  5795. {
  5796. UINT cchTmp = lstrlen(szTmp);
  5797. if (cchBuf + cchSep + cchTmp < cchMax)
  5798. {
  5799. if (cchBuf)
  5800. {
  5801. lstrcat(lpszBuf, szSep);
  5802. cchBuf += cchSep;
  5803. }
  5804. lstrcat(lpszBuf, szTmp);
  5805. cchBuf += cchTmp;
  5806. }
  5807. }
  5808. }
  5809. }
  5810. return cchBuf;
  5811. }
  5812. STDMETHODIMP CPrinterFolderViewCB::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  5813. {
  5814. switch (uMsg)
  5815. {
  5816. HANDLE_MSG(0, SFVM_INVOKECOMMAND, OnINVOKECOMMAND);
  5817. HANDLE_MSG(0, SFVM_GETHELPTEXT, OnGETHELPTEXT);
  5818. HANDLE_MSG(0, SFVM_BACKGROUNDENUM, OnBACKGROUNDENUM);
  5819. HANDLE_MSG(0, SFVM_GETHELPTOPIC, OnGETHELPTOPIC);
  5820. HANDLE_MSG(0, SFVM_REFRESH, OnREFRESH);
  5821. HANDLE_MSG(0, SFVM_DELAYWINDOWCREATE, OnDELAYWINDOWCREATE);
  5822. HANDLE_MSG(0, SFVM_GETDEFERREDVIEWSETTINGS, OnDEFERRED_VIEW_SETTING);
  5823. // DUI webview commands
  5824. HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
  5825. HANDLE_MSG(0, SFVM_GETWEBVIEWCONTENT, OnGetWebViewContent);
  5826. HANDLE_MSG(0, SFVM_GETWEBVIEWTASKS, OnGetWebViewTasks);
  5827. default:
  5828. return E_FAIL;
  5829. }
  5830. return S_OK;
  5831. }
  5832. STDMETHODIMP CPrinterFolderViewCB::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  5833. {
  5834. IUnknown *punkThis = static_cast<IServiceProvider*>(this);
  5835. IUnknown *punkSite = NULL;
  5836. HRESULT hr = E_NOINTERFACE;
  5837. //
  5838. // we are going to use IServiceProvider to be able to query the callback for some
  5839. // core interfaces associated with it (like IShellFolderView and IShellFolder, etc...).
  5840. // basically the idea is that we try QueryService/QueryInterafce on the printer's
  5841. // folder first and then if it fails we try our current site which supposedly will
  5842. // be defview.
  5843. //
  5844. if (_ppf)
  5845. {
  5846. IUnknown *punkPF = static_cast<IShellFolder*>(_ppf);
  5847. // try QueryService on the printer's folder
  5848. if (SUCCEEDED(hr = IUnknown_QueryService(punkPF, riid, riid, ppv)))
  5849. goto Exit;
  5850. // try QueryInterface on the printer's folder
  5851. if (SUCCEEDED(hr = punkPF->QueryInterface(riid, ppv)))
  5852. goto Exit;
  5853. }
  5854. if (FAILED(hr) && (SUCCEEDED(hr = IUnknown_GetSite(punkThis, IID_PPV_ARG(IUnknown, &punkSite)))))
  5855. {
  5856. ASSERT(punkSite);
  5857. // try QueryService on the site object
  5858. if (SUCCEEDED(hr = IUnknown_QueryService(punkSite, riid, riid, ppv)))
  5859. goto Exit;
  5860. // try QueryInterface on the site object
  5861. if (SUCCEEDED(hr = punkSite->QueryInterface(riid, ppv)))
  5862. goto Exit;
  5863. }
  5864. else
  5865. {
  5866. ASSERT(NULL == punkSite);
  5867. }
  5868. Exit:
  5869. if (punkSite)
  5870. {
  5871. punkSite->Release();
  5872. }
  5873. return hr;
  5874. }
  5875. // shell32.dll export, from srch.exe results no one uses this
  5876. STDAPI Printers_GetPidl(LPCITEMIDLIST pidlParent, LPCTSTR pszPrinterName, DWORD dwType, LPITEMIDLIST *ppidl)
  5877. {
  5878. return E_FAIL;
  5879. }