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