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 */ 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 83 CPrintersEnum::CPrintersEnum() 84 { 85 } 86 87 CPrintersEnum::~CPrintersEnum() 88 { 89 } 90 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 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, cchServerName; 106 107 cchPrinterName = wcslen(pi->pPrinterName); 108 cchServerName = wcslen(pi->pServerName); 109 if ((cchPrinterName + cchServerName) > (MAXUSHORT - 2)) 110 { 111 return NULL; 112 } 113 114 tmp.type = 0x00; 115 tmp.u.cprinter.dummy = 0xFF; 116 if (pi->pPrinterName) 117 tmp.u.cprinter.offsServer = cchPrinterName + 1; 118 else 119 tmp.u.cprinter.offsServer = 1; 120 121 size += tmp.u.cprinter.offsServer * sizeof(WCHAR); 122 if (pi->pServerName) 123 size += (cchServerName + 1) * sizeof(WCHAR); 124 else 125 size += sizeof(WCHAR); 126 127 pidl = (LPITEMIDLIST)SHAlloc(size + 4); 128 if (!pidl) 129 return pidl; 130 131 pidl->mkid.cb = size + 2; 132 memcpy(pidl->mkid.abID, &tmp, 2 + size0); 133 134 p = &((PIDLDATA*)pidl->mkid.abID)->u.cprinter; 135 136 p->Attributes = pi->Attributes; 137 if (pi->pPrinterName) 138 wcscpy(p->szName, pi->pPrinterName); 139 else 140 p->szName[0] = L'\0'; 141 142 if (pi->pServerName) 143 wcscpy(p->szName + p->offsServer, pi->pServerName); 144 else 145 p->szName[p->offsServer] = L'\0'; 146 147 *(WORD*)((char*)pidl + (size + 2)) = 0; 148 return pidl; 149 } 150 151 /************************************************************************** 152 * CPrintersEnum::CreatePrintersEnumList() 153 */ 154 BOOL CPrintersEnum::CreatePrintersEnumList(DWORD dwFlags) 155 { 156 BOOL ret = TRUE; 157 158 TRACE("(%p)->(flags=0x%08lx) \n", this, dwFlags); 159 160 /* enumerate the folders */ 161 if (dwFlags & SHCONTF_NONFOLDERS) 162 { 163 DWORD needed = 0, num = 0, i; 164 PRINTER_INFO_4W *pi; 165 166 EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &needed, &num); 167 if (!needed) 168 return ret; 169 170 pi = (PRINTER_INFO_4W *)HeapAlloc(GetProcessHeap(), 0, needed); 171 if(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)pi, needed, &needed, &num)) { 172 HeapFree(GetProcessHeap(), 0, pi); 173 return FALSE; 174 } 175 176 for(i = 0; i < num; i++) { 177 LPITEMIDLIST pidl = _ILCreatePrinterItem(&pi[i]); 178 if (pidl) 179 { 180 if (!AddToEnumList(pidl)) 181 SHFree(pidl); 182 } 183 } 184 HeapFree(GetProcessHeap(), 0, pi); 185 } 186 return ret; 187 } 188 189 CPrinterFolder::CPrinterFolder() 190 { 191 pidlRoot = NULL; 192 dwAttributes = 0; 193 pclsid = NULL; 194 } 195 196 CPrinterFolder::~CPrinterFolder() 197 { 198 TRACE("-- destroying IShellFolder(%p)\n", this); 199 if (pidlRoot) 200 SHFree(pidlRoot); 201 } 202 203 /************************************************************************** 204 * CPrinterFolder::ParseDisplayName 205 * 206 * This is E_NOTIMPL in Windows too. 207 */ 208 HRESULT WINAPI CPrinterFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, 209 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) 210 { 211 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", 212 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName), 213 pchEaten, ppidl, pdwAttributes); 214 215 *ppidl = 0; 216 if (pchEaten) 217 *pchEaten = 0; 218 219 return E_NOTIMPL; 220 } 221 222 static PIDLPrinterStruct * _ILGetPrinterStruct(LPCITEMIDLIST pidl) 223 { 224 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 225 226 if (pdata && pdata->type == 0x00) 227 return (PIDLPrinterStruct*) & (pdata->u.cfont); 228 229 return NULL; 230 } 231 232 /************************************************************************** 233 * CPrinterFolder::EnumObjects 234 */ 235 HRESULT WINAPI CPrinterFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList) 236 { 237 return ShellObjectCreatorInit<CPrintersEnum>(hwndOwner, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 238 } 239 240 /************************************************************************** 241 * CPrinterFolder::BindToObject 242 */ 243 HRESULT WINAPI CPrinterFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut) 244 { 245 return E_NOTIMPL; 246 } 247 248 /************************************************************************** 249 * ISF_Printers_fnBindToStorage 250 */ 251 HRESULT WINAPI CPrinterFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut) 252 { 253 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", 254 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut); 255 256 *ppvOut = NULL; 257 return E_NOTIMPL; 258 } 259 260 /************************************************************************** 261 * CPrinterFolder::CompareIDs 262 */ 263 HRESULT WINAPI CPrinterFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 264 { 265 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 266 } 267 268 /************************************************************************** 269 * CPrinterFolder::CreateViewObject 270 */ 271 HRESULT WINAPI CPrinterFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut) 272 { 273 CComPtr<IShellView> pShellView; 274 HRESULT hr = E_INVALIDARG; 275 276 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, 277 hwndOwner, shdebugstr_guid (&riid), ppvOut); 278 279 if (!ppvOut) 280 return hr; 281 282 *ppvOut = NULL; 283 284 if (IsEqualIID(riid, IID_IDropTarget)) 285 { 286 WARN("IDropTarget not implemented\n"); 287 hr = E_NOTIMPL; 288 } 289 else if(IsEqualIID(riid, IID_IContextMenu)) 290 { 291 WARN("IContextMenu not implemented\n"); 292 hr = E_NOTIMPL; 293 } 294 else if(IsEqualIID(riid, IID_IShellView)) 295 { 296 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 297 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 298 } 299 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut); 300 return hr; 301 } 302 303 /************************************************************************** 304 * CPrinterFolder::GetAttributesOf 305 */ 306 HRESULT WINAPI CPrinterFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) 307 { 308 static const DWORD dwPrintersAttributes = 309 SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE; 310 HRESULT hr = S_OK; 311 312 FIXME ("(%p)->(cidl=%d apidl=%p mask=0x%08lx): stub\n", 313 this, cidl, apidl, *rgfInOut); 314 315 *rgfInOut &= dwPrintersAttributes; 316 317 *rgfInOut &= ~SFGAO_VALIDATE; 318 319 TRACE ("-- result=0x%08x\n", *rgfInOut); 320 return hr; 321 } 322 323 /************************************************************************** 324 * CPrinterFolder::GetUIObjectOf 325 * 326 * PARAMETERS 327 * HWND hwndOwner, //[in ] Parent window for any output 328 * UINT cidl, //[in ] array size 329 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 330 * REFIID riid, //[in ] Requested Interface 331 * UINT* prgfInOut, //[ ] reserved 332 * LPVOID* ppvObject) //[out] Resulting Interface 333 * 334 */ 335 HRESULT WINAPI CPrinterFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 336 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 337 { 338 LPVOID pObj = NULL; 339 HRESULT hr = E_INVALIDARG; 340 341 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 342 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 343 344 if (!ppvOut) 345 return hr; 346 347 *ppvOut = NULL; 348 349 if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && cidl == 1) 350 hr = CPrintersExtractIconW_CreateInstane(apidl[0], riid, &pObj); 351 else 352 hr = E_NOINTERFACE; 353 354 if (SUCCEEDED(hr) && !pObj) 355 hr = E_OUTOFMEMORY; 356 357 *ppvOut = pObj; 358 TRACE ("(%p)->hr=0x%08lx\n", this, hr); 359 return hr; 360 } 361 362 /************************************************************************** 363 * CPrinterFolder::GetDisplayNameOf 364 * 365 */ 366 HRESULT WINAPI CPrinterFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 367 { 368 PIDLPrinterStruct * p; 369 370 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl, dwFlags, strRet); 371 pdump (pidl); 372 373 if (!strRet) 374 { 375 WARN("no strRet\n"); 376 return E_INVALIDARG; 377 } 378 379 p = _ILGetPrinterStruct(pidl); 380 if (!p) 381 { 382 ERR("no printer struct\n"); 383 return E_INVALIDARG; 384 } 385 386 return SHSetStrRet(strRet, p->szName); 387 } 388 389 /************************************************************************** 390 * CPrinterFolder::SetNameOf 391 * Changes the name of a file object or subfolder, possibly changing its item 392 * identifier in the process. 393 * 394 * PARAMETERS 395 * HWND hwndOwner, //[in ] Owner window for output 396 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 397 * LPCOLESTR lpszName, //[in ] the items new display name 398 * DWORD dwFlags, //[in ] SHGNO formatting flags 399 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 400 */ 401 HRESULT WINAPI CPrinterFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */ 402 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 403 { 404 FIXME("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl, 405 debugstr_w (lpName), dwFlags, pPidlOut); 406 407 return E_FAIL; 408 } 409 410 HRESULT WINAPI CPrinterFolder::GetDefaultSearchGUID(GUID *pguid) 411 { 412 FIXME("(%p)\n", this); 413 return E_NOTIMPL; 414 } 415 416 HRESULT WINAPI CPrinterFolder::EnumSearches(IEnumExtraSearch **ppenum) 417 { 418 FIXME("(%p)\n", this); 419 return E_NOTIMPL; 420 } 421 422 HRESULT WINAPI CPrinterFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 423 { 424 if (pSort) 425 *pSort = 0; 426 if (pDisplay) 427 *pDisplay = 0; 428 429 return S_OK; 430 } 431 432 HRESULT WINAPI CPrinterFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 433 { 434 if (!pcsFlags || iColumn >= PrinterSHELLVIEWCOLUMNS) 435 return E_INVALIDARG; 436 *pcsFlags = PrinterSFHeader[iColumn].pcsFlags; 437 return S_OK; 438 439 } 440 441 HRESULT WINAPI CPrinterFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 442 { 443 FIXME("(%p): stub\n", this); 444 445 return E_NOTIMPL; 446 } 447 448 HRESULT WINAPI CPrinterFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 449 { 450 TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd); 451 452 if (iColumn >= PrinterSHELLVIEWCOLUMNS) 453 return E_FAIL; 454 455 psd->fmt = PrinterSFHeader[iColumn].fmt; 456 psd->cxChar = PrinterSFHeader[iColumn].cxChar; 457 if (pidl == NULL) 458 return SHSetStrRet(&psd->str, PrinterSFHeader[iColumn].colnameid); 459 460 if (iColumn == COLUMN_NAME) 461 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str); 462 463 psd->str.uType = STRRET_CSTR; 464 psd->str.cStr[0] = '\0'; 465 466 return E_NOTIMPL; 467 } 468 469 HRESULT WINAPI CPrinterFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 470 { 471 FIXME ("(%p): stub\n", this); 472 return E_NOTIMPL; 473 } 474 475 /************************************************************************ 476 * CPrinterFolder::GetClassID 477 */ 478 HRESULT WINAPI CPrinterFolder::GetClassID(CLSID *lpClassId) 479 { 480 TRACE ("(%p)\n", this); 481 482 *lpClassId = CLSID_Printers; 483 484 return S_OK; 485 } 486 487 /************************************************************************ 488 * CPrinterFolder::Initialize 489 */ 490 HRESULT WINAPI CPrinterFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 491 { 492 if (pidlRoot) 493 SHFree((LPVOID)pidlRoot); 494 495 pidlRoot = ILClone(pidl); 496 return S_OK; 497 } 498 499 /************************************************************************** 500 * CPrinterFolder::GetCurFolder 501 */ 502 HRESULT WINAPI CPrinterFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 503 { 504 TRACE ("(%p)->(%p)\n", this, pidl); 505 506 *pidl = ILClone (pidlRoot); 507 return S_OK; 508 } 509