Leaked source code of windows server 2003
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.

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