1 /*
2 * Virtual Printers Folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2005 Huw Davies
7 * Copyright 2009 Andrew Hill
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include <precomp.h>
25
26 #include <winspool.h>
27
28 WINE_DEFAULT_DEBUG_CHANNEL (shell);
29
30 static shvheader PrinterSFHeader[] = {
31 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
32 {IDS_SHV_COLUMN_DOCUMENTS , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
33 {IDS_SHV_COLUMN_STATUS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
34 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
35 {IDS_SHV_COLUMN_LOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
36 {IDS_SHV_COLUMN_MODEL, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}
37 };
38
39 #define COLUMN_NAME 0
40 #define COLUMN_DOCUMENTS 1
41 #define COLUMN_STATUS 2
42 #define COLUMN_COMMENTS 3
43 #define COLUMN_LOCATION 4
44 #define COLUMN_MODEL 5
45
46 #define PrinterSHELLVIEWCOLUMNS (6)
47
48 /**************************************************************************
49 * CPrintersExtractIconW_CreateInstane
50 *
51 * There is no CPrintersExtractIconW. We just initialize CExtractIcon properly to do our job.
52 */
CPrintersExtractIconW_CreateInstane(LPCITEMIDLIST pidl,REFIID riid,LPVOID * ppv)53 HRESULT WINAPI CPrintersExtractIconW_CreateInstane(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv)
54 {
55 CComPtr<IDefaultExtractIconInit> initIcon;
56 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
57 if (FAILED_UNEXPECTEDLY(hr))
58 return hr;
59
60 /* FIXME: other icons for default, network, print to file */
61 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_PRINTER);
62
63 return initIcon->QueryInterface(riid,ppv);
64 }
65
66 /***********************************************************************
67 * Printers folder implementation
68 */
69
70 class CPrintersEnum: public CEnumIDListBase
71 {
72 public:
73 CPrintersEnum();
74 ~CPrintersEnum();
75 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
76 BOOL CreatePrintersEnumList(DWORD dwFlags);
77
78 BEGIN_COM_MAP(CPrintersEnum)
79 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
80 END_COM_MAP()
81 };
82
CPrintersEnum()83 CPrintersEnum::CPrintersEnum()
84 {
85 }
86
~CPrintersEnum()87 CPrintersEnum::~CPrintersEnum()
88 {
89 }
90
Initialize(HWND hwndOwner,DWORD dwFlags)91 HRESULT WINAPI CPrintersEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
92 {
93 if (CreatePrintersEnumList(dwFlags) == FALSE)
94 return E_FAIL;
95 return S_OK;
96 }
97
_ILCreatePrinterItem(PRINTER_INFO_4W * pi)98 static LPITEMIDLIST _ILCreatePrinterItem(PRINTER_INFO_4W *pi)
99 {
100 PIDLDATA tmp;
101 LPITEMIDLIST pidl;
102 PIDLPrinterStruct * p;
103 int size0 = (char*)&tmp.u.cprinter.szName - (char*)&tmp.u.cprinter;
104 int size = size0;
105 SIZE_T cchPrinterName = 0;
106 SIZE_T cchServerName = 0;
107
108 if (pi->pPrinterName)
109 cchPrinterName = wcslen(pi->pPrinterName);
110 if (pi->pServerName)
111 cchServerName = wcslen(pi->pServerName);
112 if ((cchPrinterName + cchServerName) > (MAXUSHORT - 2))
113 {
114 return NULL;
115 }
116
117 tmp.type = 0x00;
118 tmp.u.cprinter.dummy = 0xFF;
119 if (pi->pPrinterName)
120 tmp.u.cprinter.offsServer = cchPrinterName + 1;
121 else
122 tmp.u.cprinter.offsServer = 1;
123
124 size += tmp.u.cprinter.offsServer * sizeof(WCHAR);
125 if (pi->pServerName)
126 size += (cchServerName + 1) * sizeof(WCHAR);
127 else
128 size += sizeof(WCHAR);
129
130 pidl = (LPITEMIDLIST)SHAlloc(size + 4);
131 if (!pidl)
132 return pidl;
133
134 pidl->mkid.cb = size + 2;
135 memcpy(pidl->mkid.abID, &tmp, 2 + size0);
136
137 p = &((PIDLDATA*)pidl->mkid.abID)->u.cprinter;
138
139 p->Attributes = pi->Attributes;
140 if (pi->pPrinterName)
141 wcscpy(p->szName, pi->pPrinterName);
142 else
143 p->szName[0] = L'\0';
144
145 if (pi->pServerName)
146 wcscpy(p->szName + p->offsServer, pi->pServerName);
147 else
148 p->szName[p->offsServer] = L'\0';
149
150 *(WORD*)((char*)pidl + (size + 2)) = 0;
151 return pidl;
152 }
153
154 /**************************************************************************
155 * CPrintersEnum::CreatePrintersEnumList()
156 */
CreatePrintersEnumList(DWORD dwFlags)157 BOOL CPrintersEnum::CreatePrintersEnumList(DWORD dwFlags)
158 {
159 BOOL ret = TRUE;
160
161 TRACE("(%p)->(flags=0x%08lx) \n", this, dwFlags);
162
163 /* enumerate the folders */
164 if (dwFlags & SHCONTF_NONFOLDERS)
165 {
166 DWORD needed = 0, num = 0, i;
167 PRINTER_INFO_4W *pi;
168
169 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &needed, &num);
170 if (!needed)
171 return ret;
172
173 pi = (PRINTER_INFO_4W *)HeapAlloc(GetProcessHeap(), 0, needed);
174 if(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)pi, needed, &needed, &num)) {
175 HeapFree(GetProcessHeap(), 0, pi);
176 return FALSE;
177 }
178
179 for(i = 0; i < num; i++) {
180 LPITEMIDLIST pidl = _ILCreatePrinterItem(&pi[i]);
181 if (pidl)
182 {
183 if (!AddToEnumList(pidl))
184 SHFree(pidl);
185 }
186 }
187 HeapFree(GetProcessHeap(), 0, pi);
188 }
189 return ret;
190 }
191
CPrinterFolder()192 CPrinterFolder::CPrinterFolder()
193 {
194 pidlRoot = NULL;
195 dwAttributes = 0;
196 pclsid = NULL;
197 }
198
~CPrinterFolder()199 CPrinterFolder::~CPrinterFolder()
200 {
201 TRACE("-- destroying IShellFolder(%p)\n", this);
202 if (pidlRoot)
203 SHFree(pidlRoot);
204 }
205
206 /**************************************************************************
207 * CPrinterFolder::ParseDisplayName
208 *
209 * This is E_NOTIMPL in Windows too.
210 */
ParseDisplayName(HWND hwndOwner,LPBC pbc,LPOLESTR lpszDisplayName,DWORD * pchEaten,PIDLIST_RELATIVE * ppidl,DWORD * pdwAttributes)211 HRESULT WINAPI CPrinterFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
212 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
213 {
214 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
215 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
216 pchEaten, ppidl, pdwAttributes);
217
218 *ppidl = 0;
219 if (pchEaten)
220 *pchEaten = 0;
221
222 return E_NOTIMPL;
223 }
224
_ILGetPrinterStruct(LPCITEMIDLIST pidl)225 static PIDLPrinterStruct * _ILGetPrinterStruct(LPCITEMIDLIST pidl)
226 {
227 LPPIDLDATA pdata = _ILGetDataPointer(pidl);
228
229 if (pdata && pdata->type == 0x00)
230 return (PIDLPrinterStruct*) & (pdata->u.cfont);
231
232 return NULL;
233 }
234
235 /**************************************************************************
236 * CPrinterFolder::EnumObjects
237 */
EnumObjects(HWND hwndOwner,DWORD dwFlags,LPENUMIDLIST * ppEnumIDList)238 HRESULT WINAPI CPrinterFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
239 {
240 return ShellObjectCreatorInit<CPrintersEnum>(hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
241 }
242
243 /**************************************************************************
244 * CPrinterFolder::BindToObject
245 */
BindToObject(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)246 HRESULT WINAPI CPrinterFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
247 {
248 return E_NOTIMPL;
249 }
250
251 /**************************************************************************
252 * ISF_Printers_fnBindToStorage
253 */
BindToStorage(PCUIDLIST_RELATIVE pidl,LPBC pbcReserved,REFIID riid,LPVOID * ppvOut)254 HRESULT WINAPI CPrinterFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
255 {
256 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
257 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
258
259 *ppvOut = NULL;
260 return E_NOTIMPL;
261 }
262
263 /**************************************************************************
264 * CPrinterFolder::CompareIDs
265 */
CompareIDs(LPARAM lParam,PCUIDLIST_RELATIVE pidl1,PCUIDLIST_RELATIVE pidl2)266 HRESULT WINAPI CPrinterFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
267 {
268 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
269 }
270
271 /**************************************************************************
272 * CPrinterFolder::CreateViewObject
273 */
CreateViewObject(HWND hwndOwner,REFIID riid,LPVOID * ppvOut)274 HRESULT WINAPI CPrinterFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
275 {
276 CComPtr<IShellView> pShellView;
277 HRESULT hr = E_INVALIDARG;
278
279 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
280 hwndOwner, shdebugstr_guid (&riid), ppvOut);
281
282 if (!ppvOut)
283 return hr;
284
285 *ppvOut = NULL;
286
287 if (IsEqualIID(riid, IID_IDropTarget))
288 {
289 WARN("IDropTarget not implemented\n");
290 hr = E_NOTIMPL;
291 }
292 else if(IsEqualIID(riid, IID_IContextMenu))
293 {
294 WARN("IContextMenu not implemented\n");
295 hr = E_NOTIMPL;
296 }
297 else if(IsEqualIID(riid, IID_IShellView))
298 {
299 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
300 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
301 }
302 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
303 return hr;
304 }
305
306 /**************************************************************************
307 * CPrinterFolder::GetAttributesOf
308 */
GetAttributesOf(UINT cidl,PCUITEMID_CHILD_ARRAY apidl,DWORD * rgfInOut)309 HRESULT WINAPI CPrinterFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
310 {
311 static const DWORD dwPrintersAttributes =
312 SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
313 HRESULT hr = S_OK;
314
315 FIXME ("(%p)->(cidl=%d apidl=%p mask=0x%08lx): stub\n",
316 this, cidl, apidl, *rgfInOut);
317
318 *rgfInOut &= dwPrintersAttributes;
319
320 *rgfInOut &= ~SFGAO_VALIDATE;
321
322 TRACE ("-- result=0x%08x\n", *rgfInOut);
323 return hr;
324 }
325
326 /**************************************************************************
327 * CPrinterFolder::GetUIObjectOf
328 *
329 * PARAMETERS
330 * HWND hwndOwner, //[in ] Parent window for any output
331 * UINT cidl, //[in ] array size
332 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
333 * REFIID riid, //[in ] Requested Interface
334 * UINT* prgfInOut, //[ ] reserved
335 * LPVOID* ppvObject) //[out] Resulting Interface
336 *
337 */
GetUIObjectOf(HWND hwndOwner,UINT cidl,PCUITEMID_CHILD_ARRAY apidl,REFIID riid,UINT * prgfInOut,LPVOID * ppvOut)338 HRESULT WINAPI CPrinterFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
339 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
340 {
341 LPVOID pObj = NULL;
342 HRESULT hr = E_INVALIDARG;
343
344 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
345 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
346
347 if (!ppvOut)
348 return hr;
349
350 *ppvOut = NULL;
351
352 if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && cidl == 1)
353 hr = CPrintersExtractIconW_CreateInstane(apidl[0], riid, &pObj);
354 else
355 hr = E_NOINTERFACE;
356
357 if (SUCCEEDED(hr) && !pObj)
358 hr = E_OUTOFMEMORY;
359
360 *ppvOut = pObj;
361 TRACE ("(%p)->hr=0x%08lx\n", this, hr);
362 return hr;
363 }
364
365 /**************************************************************************
366 * CPrinterFolder::GetDisplayNameOf
367 *
368 */
GetDisplayNameOf(PCUITEMID_CHILD pidl,DWORD dwFlags,LPSTRRET strRet)369 HRESULT WINAPI CPrinterFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
370 {
371 PIDLPrinterStruct * p;
372
373 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl, dwFlags, strRet);
374 pdump (pidl);
375
376 if (!strRet)
377 {
378 WARN("no strRet\n");
379 return E_INVALIDARG;
380 }
381
382 p = _ILGetPrinterStruct(pidl);
383 if (!p)
384 {
385 ERR("no printer struct\n");
386 return E_INVALIDARG;
387 }
388
389 return SHSetStrRet(strRet, p->szName);
390 }
391
392 /**************************************************************************
393 * CPrinterFolder::SetNameOf
394 * Changes the name of a file object or subfolder, possibly changing its item
395 * identifier in the process.
396 *
397 * PARAMETERS
398 * HWND hwndOwner, //[in ] Owner window for output
399 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
400 * LPCOLESTR lpszName, //[in ] the items new display name
401 * DWORD dwFlags, //[in ] SHGNO formatting flags
402 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
403 */
SetNameOf(HWND hwndOwner,PCUITEMID_CHILD pidl,LPCOLESTR lpName,DWORD dwFlags,PITEMID_CHILD * pPidlOut)404 HRESULT WINAPI CPrinterFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */
405 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
406 {
407 FIXME("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl,
408 debugstr_w (lpName), dwFlags, pPidlOut);
409
410 return E_FAIL;
411 }
412
GetDefaultSearchGUID(GUID * pguid)413 HRESULT WINAPI CPrinterFolder::GetDefaultSearchGUID(GUID *pguid)
414 {
415 FIXME("(%p)\n", this);
416 return E_NOTIMPL;
417 }
418
EnumSearches(IEnumExtraSearch ** ppenum)419 HRESULT WINAPI CPrinterFolder::EnumSearches(IEnumExtraSearch **ppenum)
420 {
421 FIXME("(%p)\n", this);
422 return E_NOTIMPL;
423 }
424
GetDefaultColumn(DWORD dwRes,ULONG * pSort,ULONG * pDisplay)425 HRESULT WINAPI CPrinterFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
426 {
427 if (pSort)
428 *pSort = 0;
429 if (pDisplay)
430 *pDisplay = 0;
431
432 return S_OK;
433 }
434
GetDefaultColumnState(UINT iColumn,SHCOLSTATEF * pcsFlags)435 HRESULT WINAPI CPrinterFolder::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
436 {
437 if (!pcsFlags || iColumn >= PrinterSHELLVIEWCOLUMNS)
438 return E_INVALIDARG;
439 *pcsFlags = PrinterSFHeader[iColumn].colstate;
440 return S_OK;
441
442 }
443
GetDetailsEx(PCUITEMID_CHILD pidl,const SHCOLUMNID * pscid,VARIANT * pv)444 HRESULT WINAPI CPrinterFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
445 {
446 FIXME("(%p): stub\n", this);
447
448 return E_NOTIMPL;
449 }
450
GetDetailsOf(PCUITEMID_CHILD pidl,UINT iColumn,SHELLDETAILS * psd)451 HRESULT WINAPI CPrinterFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
452 {
453 TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd);
454
455 if (iColumn >= PrinterSHELLVIEWCOLUMNS)
456 return E_FAIL;
457
458 psd->fmt = PrinterSFHeader[iColumn].fmt;
459 psd->cxChar = PrinterSFHeader[iColumn].cxChar;
460 if (pidl == NULL)
461 return SHSetStrRet(&psd->str, PrinterSFHeader[iColumn].colnameid);
462
463 if (iColumn == COLUMN_NAME)
464 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
465
466 psd->str.uType = STRRET_CSTR;
467 psd->str.cStr[0] = '\0';
468
469 return E_NOTIMPL;
470 }
471
MapColumnToSCID(UINT column,SHCOLUMNID * pscid)472 HRESULT WINAPI CPrinterFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
473 {
474 FIXME ("(%p): stub\n", this);
475 return E_NOTIMPL;
476 }
477
478 /************************************************************************
479 * CPrinterFolder::GetClassID
480 */
GetClassID(CLSID * lpClassId)481 HRESULT WINAPI CPrinterFolder::GetClassID(CLSID *lpClassId)
482 {
483 TRACE ("(%p)\n", this);
484
485 *lpClassId = CLSID_Printers;
486
487 return S_OK;
488 }
489
490 /************************************************************************
491 * CPrinterFolder::Initialize
492 */
Initialize(PCIDLIST_ABSOLUTE pidl)493 HRESULT WINAPI CPrinterFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
494 {
495 if (pidlRoot)
496 SHFree((LPVOID)pidlRoot);
497
498 pidlRoot = ILClone(pidl);
499 return S_OK;
500 }
501
502 /**************************************************************************
503 * CPrinterFolder::GetCurFolder
504 */
GetCurFolder(PIDLIST_ABSOLUTE * pidl)505 HRESULT WINAPI CPrinterFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl)
506 {
507 TRACE ("(%p)->(%p)\n", this, pidl);
508
509 *pidl = ILClone (pidlRoot);
510 return S_OK;
511 }
512