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 = 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 */ 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 192 CPrinterFolder::CPrinterFolder() 193 { 194 pidlRoot = NULL; 195 dwAttributes = 0; 196 pclsid = NULL; 197 } 198 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 413 HRESULT WINAPI CPrinterFolder::GetDefaultSearchGUID(GUID *pguid) 414 { 415 FIXME("(%p)\n", this); 416 return E_NOTIMPL; 417 } 418 419 HRESULT WINAPI CPrinterFolder::EnumSearches(IEnumExtraSearch **ppenum) 420 { 421 FIXME("(%p)\n", this); 422 return E_NOTIMPL; 423 } 424 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 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 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 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 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 */ 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 */ 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 */ 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