1 /* 2 * IEnumMoniker implementation for DEVENUM.dll 3 * 4 * Copyright (C) 2002 Robert Shearman 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * NOTES ON THIS FILE: 21 * - Implements IEnumMoniker interface which enumerates through moniker 22 * objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance 23 */ 24 25 #include "devenum_private.h" 26 #include "oleauto.h" 27 #include "ocidl.h" 28 29 #include "wine/debug.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(devenum); 32 33 typedef struct 34 { 35 IEnumMoniker IEnumMoniker_iface; 36 LONG ref; 37 DWORD index; 38 DWORD subkey_cnt; 39 HKEY hkey; 40 HKEY special_hkey; 41 } EnumMonikerImpl; 42 43 typedef struct 44 { 45 IPropertyBag IPropertyBag_iface; 46 LONG ref; 47 HKEY hkey; 48 } RegPropBagImpl; 49 50 51 static inline RegPropBagImpl *impl_from_IPropertyBag(IPropertyBag *iface) 52 { 53 return CONTAINING_RECORD(iface, RegPropBagImpl, IPropertyBag_iface); 54 } 55 56 static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface( 57 LPPROPERTYBAG iface, 58 REFIID riid, 59 LPVOID *ppvObj) 60 { 61 RegPropBagImpl *This = impl_from_IPropertyBag(iface); 62 63 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj); 64 65 if (This == NULL || ppvObj == NULL) return E_POINTER; 66 67 if (IsEqualGUID(riid, &IID_IUnknown) || 68 IsEqualGUID(riid, &IID_IPropertyBag)) 69 { 70 *ppvObj = iface; 71 IPropertyBag_AddRef(iface); 72 return S_OK; 73 } 74 75 FIXME("- no interface IID: %s\n", debugstr_guid(riid)); 76 return E_NOINTERFACE; 77 } 78 79 /********************************************************************** 80 * DEVENUM_IPropertyBag_AddRef (also IUnknown) 81 */ 82 static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface) 83 { 84 RegPropBagImpl *This = impl_from_IPropertyBag(iface); 85 86 TRACE("(%p)->() AddRef from %d\n", iface, This->ref); 87 88 return InterlockedIncrement(&This->ref); 89 } 90 91 /********************************************************************** 92 * DEVENUM_IPropertyBag_Release (also IUnknown) 93 */ 94 static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface) 95 { 96 RegPropBagImpl *This = impl_from_IPropertyBag(iface); 97 ULONG ref; 98 99 TRACE("(%p)->() ReleaseThis->ref from %d\n", iface, This->ref); 100 101 ref = InterlockedDecrement(&This->ref); 102 if (ref == 0) { 103 RegCloseKey(This->hkey); 104 CoTaskMemFree(This); 105 DEVENUM_UnlockModule(); 106 } 107 return ref; 108 } 109 110 static HRESULT WINAPI DEVENUM_IPropertyBag_Read( 111 LPPROPERTYBAG iface, 112 LPCOLESTR pszPropName, 113 VARIANT* pVar, 114 IErrorLog* pErrorLog) 115 { 116 LPVOID pData = NULL; 117 DWORD received; 118 DWORD type = 0; 119 RegPropBagImpl *This = impl_from_IPropertyBag(iface); 120 HRESULT res = S_OK; 121 LONG reswin32; 122 123 TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog); 124 125 if (!pszPropName || !pVar) 126 return E_POINTER; 127 128 reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, NULL, NULL, &received); 129 res = HRESULT_FROM_WIN32(reswin32); 130 131 if (SUCCEEDED(res)) 132 { 133 pData = HeapAlloc(GetProcessHeap(), 0, received); 134 135 /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */ 136 reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, pData, &received); 137 res = HRESULT_FROM_WIN32(reswin32); 138 } 139 140 if (SUCCEEDED(res)) 141 { 142 res = E_INVALIDARG; /* assume we cannot coerce into right type */ 143 144 TRACE("Read %d bytes (%s)\n", received, type == REG_SZ ? debugstr_w(pData) : "binary data"); 145 146 switch (type) 147 { 148 case REG_SZ: 149 switch (V_VT(pVar)) 150 { 151 case VT_LPWSTR: 152 V_BSTR(pVar) = CoTaskMemAlloc(received); 153 memcpy(V_BSTR(pVar), pData, received); 154 res = S_OK; 155 break; 156 case VT_EMPTY: 157 V_VT(pVar) = VT_BSTR; 158 /* fall through */ 159 case VT_BSTR: 160 V_BSTR(pVar) = SysAllocStringLen(pData, received/sizeof(WCHAR) - 1); 161 res = S_OK; 162 break; 163 } 164 break; 165 case REG_DWORD: 166 TRACE("REG_DWORD: %x\n", *(DWORD *)pData); 167 switch (V_VT(pVar)) 168 { 169 case VT_EMPTY: 170 V_VT(pVar) = VT_I4; 171 /* fall through */ 172 case VT_I4: 173 case VT_UI4: 174 V_I4(pVar) = *(DWORD *)pData; 175 res = S_OK; 176 break; 177 } 178 break; 179 case REG_BINARY: 180 { 181 SAFEARRAYBOUND bound; 182 void * pArrayElements; 183 bound.lLbound = 0; 184 bound.cElements = received; 185 TRACE("REG_BINARY: len = %d\n", received); 186 switch (V_VT(pVar)) 187 { 188 case VT_EMPTY: 189 V_VT(pVar) = VT_ARRAY | VT_UI1; 190 /* fall through */ 191 case VT_ARRAY | VT_UI1: 192 if (!(V_ARRAY(pVar) = SafeArrayCreate(VT_UI1, 1, &bound))) 193 res = E_OUTOFMEMORY; 194 else 195 res = S_OK; 196 break; 197 } 198 199 if (res == E_INVALIDARG) 200 break; 201 202 res = SafeArrayAccessData(V_ARRAY(pVar), &pArrayElements); 203 if (FAILED(res)) 204 break; 205 206 CopyMemory(pArrayElements, pData, received); 207 res = SafeArrayUnaccessData(V_ARRAY(pVar)); 208 break; 209 } 210 } 211 if (res == E_INVALIDARG) 212 FIXME("Variant type %x not supported for regtype %x\n", V_VT(pVar), type); 213 } 214 215 HeapFree(GetProcessHeap(), 0, pData); 216 217 TRACE("<- %x\n", res); 218 return res; 219 } 220 221 static HRESULT WINAPI DEVENUM_IPropertyBag_Write( 222 LPPROPERTYBAG iface, 223 LPCOLESTR pszPropName, 224 VARIANT* pVar) 225 { 226 RegPropBagImpl *This = impl_from_IPropertyBag(iface); 227 LPVOID lpData = NULL; 228 DWORD cbData = 0; 229 DWORD dwType = 0; 230 HRESULT res = S_OK; 231 232 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar); 233 234 switch (V_VT(pVar)) 235 { 236 case VT_BSTR: 237 case VT_LPWSTR: 238 TRACE("writing %s\n", debugstr_w(V_BSTR(pVar))); 239 lpData = V_BSTR(pVar); 240 dwType = REG_SZ; 241 cbData = (lstrlenW(V_BSTR(pVar)) + 1) * sizeof(WCHAR); 242 break; 243 case VT_I4: 244 case VT_UI4: 245 TRACE("writing %u\n", V_UI4(pVar)); 246 lpData = &V_UI4(pVar); 247 dwType = REG_DWORD; 248 cbData = sizeof(DWORD); 249 break; 250 case VT_ARRAY | VT_UI1: 251 { 252 LONG lUbound = 0; 253 LONG lLbound = 0; 254 dwType = REG_BINARY; 255 res = SafeArrayGetLBound(V_ARRAY(pVar), 1, &lLbound); 256 res = SafeArrayGetUBound(V_ARRAY(pVar), 1, &lUbound); 257 cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/; 258 TRACE("cbData: %d\n", cbData); 259 res = SafeArrayAccessData(V_ARRAY(pVar), &lpData); 260 break; 261 } 262 default: 263 FIXME("Variant type %d not handled\n", V_VT(pVar)); 264 return E_FAIL; 265 } 266 267 if (RegSetValueExW(This->hkey, 268 pszPropName, 0, 269 dwType, lpData, cbData) != ERROR_SUCCESS) 270 res = E_FAIL; 271 272 if (V_VT(pVar) & VT_ARRAY) 273 res = SafeArrayUnaccessData(V_ARRAY(pVar)); 274 275 return res; 276 } 277 278 static const IPropertyBagVtbl IPropertyBag_Vtbl = 279 { 280 DEVENUM_IPropertyBag_QueryInterface, 281 DEVENUM_IPropertyBag_AddRef, 282 DEVENUM_IPropertyBag_Release, 283 DEVENUM_IPropertyBag_Read, 284 DEVENUM_IPropertyBag_Write 285 }; 286 287 static HRESULT DEVENUM_IPropertyBag_Construct(HANDLE hkey, IPropertyBag **ppBag) 288 { 289 RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl)); 290 if (!rpb) 291 return E_OUTOFMEMORY; 292 rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl; 293 rpb->ref = 1; 294 rpb->hkey = hkey; 295 *ppBag = &rpb->IPropertyBag_iface; 296 DEVENUM_LockModule(); 297 return S_OK; 298 } 299 300 301 static inline MediaCatMoniker *impl_from_IMoniker(IMoniker *iface) 302 { 303 return CONTAINING_RECORD(iface, MediaCatMoniker, IMoniker_iface); 304 } 305 306 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker *iface, REFIID riid, 307 void **ppv) 308 { 309 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); 310 311 if (!ppv) 312 return E_POINTER; 313 314 if (IsEqualGUID(riid, &IID_IUnknown) || 315 IsEqualGUID(riid, &IID_IPersist) || 316 IsEqualGUID(riid, &IID_IPersistStream) || 317 IsEqualGUID(riid, &IID_IMoniker)) 318 { 319 *ppv = iface; 320 IMoniker_AddRef(iface); 321 return S_OK; 322 } 323 324 FIXME("- no interface IID: %s\n", debugstr_guid(riid)); 325 *ppv = NULL; 326 return E_NOINTERFACE; 327 } 328 329 static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(IMoniker *iface) 330 { 331 MediaCatMoniker *This = impl_from_IMoniker(iface); 332 ULONG ref = InterlockedIncrement(&This->ref); 333 334 TRACE("(%p) ref=%d\n", This, ref); 335 336 return ref; 337 } 338 339 static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface) 340 { 341 MediaCatMoniker *This = impl_from_IMoniker(iface); 342 ULONG ref = InterlockedDecrement(&This->ref); 343 344 TRACE("(%p) ref=%d\n", This, ref); 345 346 if (ref == 0) { 347 RegCloseKey(This->hkey); 348 CoTaskMemFree(This); 349 DEVENUM_UnlockModule(); 350 } 351 return ref; 352 } 353 354 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(IMoniker *iface, CLSID *pClassID) 355 { 356 MediaCatMoniker *This = impl_from_IMoniker(iface); 357 358 TRACE("(%p)->(%p)\n", This, pClassID); 359 360 if (pClassID == NULL) 361 return E_INVALIDARG; 362 363 *pClassID = CLSID_CDeviceMoniker; 364 365 return S_OK; 366 } 367 368 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(IMoniker *iface) 369 { 370 FIXME("(%p)->(): stub\n", iface); 371 372 return S_FALSE; 373 } 374 375 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(IMoniker *iface, IStream *pStm) 376 { 377 FIXME("(%p)->(%p): stub\n", iface, pStm); 378 379 return E_NOTIMPL; 380 } 381 382 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty) 383 { 384 FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false"); 385 386 return STG_E_CANTSAVE; 387 } 388 389 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize) 390 { 391 FIXME("(%p)->(%p): stub\n", iface, pcbSize); 392 393 ZeroMemory(pcbSize, sizeof(*pcbSize)); 394 395 return S_OK; 396 } 397 398 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBindCtx *pbc, 399 IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult) 400 { 401 MediaCatMoniker *This = impl_from_IMoniker(iface); 402 IUnknown * pObj = NULL; 403 IPropertyBag * pProp = NULL; 404 CLSID clsID; 405 VARIANT var; 406 HRESULT res = E_FAIL; 407 408 TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult); 409 410 VariantInit(&var); 411 *ppvResult = NULL; 412 413 if(pmkToLeft==NULL) 414 { 415 /* first activation of this class */ 416 LPVOID pvptr; 417 res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr); 418 pProp = pvptr; 419 if (SUCCEEDED(res)) 420 { 421 V_VT(&var) = VT_LPWSTR; 422 res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL); 423 } 424 if (SUCCEEDED(res)) 425 { 426 res = CLSIDFromString(V_BSTR(&var), &clsID); 427 CoTaskMemFree(V_BSTR(&var)); 428 } 429 if (SUCCEEDED(res)) 430 { 431 res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr); 432 pObj = pvptr; 433 } 434 } 435 436 if (pObj!=NULL) 437 { 438 /* get the requested interface from the loaded class */ 439 res = S_OK; 440 if (pProp) { 441 HRESULT res2; 442 LPVOID ppv = NULL; 443 res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv); 444 if (SUCCEEDED(res2)) { 445 res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL); 446 IPersistPropertyBag_Release((IPersistPropertyBag *) ppv); 447 } 448 } 449 if (SUCCEEDED(res)) 450 res= IUnknown_QueryInterface(pObj,riidResult,ppvResult); 451 IUnknown_Release(pObj); 452 } 453 454 if (pProp) 455 { 456 IPropertyBag_Release(pProp); 457 } 458 459 TRACE("<- 0x%x\n", res); 460 461 return res; 462 } 463 464 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, 465 IMoniker *pmkToLeft, REFIID riid, void **ppvObj) 466 { 467 MediaCatMoniker *This = impl_from_IMoniker(iface); 468 469 TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj); 470 471 *ppvObj = NULL; 472 473 if (pmkToLeft) 474 return MK_E_NOSTORAGE; 475 476 if (pbc != NULL) 477 { 478 static DWORD reported; 479 if (!reported) 480 { 481 FIXME("ignoring IBindCtx %p\n", pbc); 482 reported++; 483 } 484 } 485 486 if (IsEqualGUID(riid, &IID_IPropertyBag)) 487 { 488 HANDLE hkey; 489 DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), &hkey, 0, 0, DUPLICATE_SAME_ACCESS); 490 return DEVENUM_IPropertyBag_Construct(hkey, (IPropertyBag**)ppvObj); 491 } 492 493 return MK_E_NOSTORAGE; 494 } 495 496 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(IMoniker *iface, IBindCtx *pbc, 497 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced) 498 { 499 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced); 500 501 if (ppmkToLeft) 502 *ppmkToLeft = NULL; 503 *ppmkReduced = iface; 504 505 return MK_S_REDUCED_TO_SELF; 506 } 507 508 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight, 509 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite) 510 { 511 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite); 512 513 /* FIXME: use CreateGenericComposite? */ 514 *ppmkComposite = NULL; 515 516 return E_NOTIMPL; 517 } 518 519 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(IMoniker *iface, BOOL fForward, 520 IEnumMoniker **ppenumMoniker) 521 { 522 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker); 523 524 *ppenumMoniker = NULL; 525 526 return S_OK; 527 } 528 529 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker) 530 { 531 CLSID clsid; 532 LPOLESTR this_name, other_name; 533 IBindCtx *bind; 534 HRESULT res; 535 536 TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker); 537 538 if (!pmkOtherMoniker) 539 return E_INVALIDARG; 540 541 IMoniker_GetClassID(pmkOtherMoniker, &clsid); 542 if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker)) 543 return S_FALSE; 544 545 res = CreateBindCtx(0, &bind); 546 if (FAILED(res)) 547 return res; 548 549 res = S_FALSE; 550 if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) && 551 SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name))) 552 { 553 int result = lstrcmpiW(this_name, other_name); 554 CoTaskMemFree(this_name); 555 CoTaskMemFree(other_name); 556 if (!result) 557 res = S_OK; 558 } 559 IBindCtx_Release(bind); 560 return res; 561 } 562 563 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(IMoniker *iface, DWORD *pdwHash) 564 { 565 TRACE("(%p)->(%p)\n", iface, pdwHash); 566 567 *pdwHash = 0; 568 569 return S_OK; 570 } 571 572 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(IMoniker *iface, IBindCtx *pbc, 573 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning) 574 { 575 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning); 576 577 return S_FALSE; 578 } 579 580 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc, 581 IMoniker *pmkToLeft, FILETIME *pFileTime) 582 { 583 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime); 584 585 pFileTime->dwLowDateTime = 0xFFFFFFFF; 586 pFileTime->dwHighDateTime = 0x7FFFFFFF; 587 588 return MK_E_UNAVAILABLE; 589 } 590 591 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(IMoniker *iface, IMoniker **ppmk) 592 { 593 TRACE("(%p)->(%p)\n", iface, ppmk); 594 595 *ppmk = NULL; 596 597 return MK_E_NOINVERSE; 598 } 599 600 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker *iface, 601 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix) 602 { 603 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix); 604 605 *ppmkPrefix = NULL; 606 607 return MK_E_NOPREFIX; 608 } 609 610 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther, 611 IMoniker **ppmkRelPath) 612 { 613 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath); 614 615 *ppmkRelPath = pmkOther; 616 617 return MK_S_HIM; 618 } 619 620 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, 621 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName) 622 { 623 MediaCatMoniker *This = impl_from_IMoniker(iface); 624 WCHAR wszBuffer[MAX_PATH]; 625 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; 626 DWORD received = sizeof(wszBuffer); 627 628 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName); 629 630 *ppszDisplayName = NULL; 631 632 /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */ 633 if (RegQueryValueExW(This->hkey, wszFriendlyName, NULL, NULL, (LPBYTE)wszBuffer, &received) == ERROR_SUCCESS) 634 { 635 *ppszDisplayName = CoTaskMemAlloc(received); 636 strcpyW(*ppszDisplayName, wszBuffer); 637 return S_OK; 638 } 639 640 return E_FAIL; 641 } 642 643 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, 644 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) 645 { 646 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut); 647 648 *pchEaten = 0; 649 *ppmkOut = NULL; 650 651 return MK_E_SYNTAX; 652 } 653 654 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys) 655 { 656 TRACE("(%p)->(%p)\n", iface, pdwMksys); 657 658 return S_FALSE; 659 } 660 661 static const IMonikerVtbl IMoniker_Vtbl = 662 { 663 DEVENUM_IMediaCatMoniker_QueryInterface, 664 DEVENUM_IMediaCatMoniker_AddRef, 665 DEVENUM_IMediaCatMoniker_Release, 666 DEVENUM_IMediaCatMoniker_GetClassID, 667 DEVENUM_IMediaCatMoniker_IsDirty, 668 DEVENUM_IMediaCatMoniker_Load, 669 DEVENUM_IMediaCatMoniker_Save, 670 DEVENUM_IMediaCatMoniker_GetSizeMax, 671 DEVENUM_IMediaCatMoniker_BindToObject, 672 DEVENUM_IMediaCatMoniker_BindToStorage, 673 DEVENUM_IMediaCatMoniker_Reduce, 674 DEVENUM_IMediaCatMoniker_ComposeWith, 675 DEVENUM_IMediaCatMoniker_Enum, 676 DEVENUM_IMediaCatMoniker_IsEqual, 677 DEVENUM_IMediaCatMoniker_Hash, 678 DEVENUM_IMediaCatMoniker_IsRunning, 679 DEVENUM_IMediaCatMoniker_GetTimeOfLastChange, 680 DEVENUM_IMediaCatMoniker_Inverse, 681 DEVENUM_IMediaCatMoniker_CommonPrefixWith, 682 DEVENUM_IMediaCatMoniker_RelativePathTo, 683 DEVENUM_IMediaCatMoniker_GetDisplayName, 684 DEVENUM_IMediaCatMoniker_ParseDisplayName, 685 DEVENUM_IMediaCatMoniker_IsSystemMoniker 686 }; 687 688 MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) 689 { 690 MediaCatMoniker * pMoniker = NULL; 691 pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker)); 692 if (!pMoniker) 693 return NULL; 694 695 pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl; 696 pMoniker->ref = 0; 697 pMoniker->hkey = NULL; 698 699 DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface); 700 701 DEVENUM_LockModule(); 702 703 return pMoniker; 704 } 705 706 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface) 707 { 708 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface); 709 } 710 711 static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker *iface, REFIID riid, 712 void **ppv) 713 { 714 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 715 716 if (!ppv) 717 return E_POINTER; 718 719 if (IsEqualGUID(riid, &IID_IUnknown) || 720 IsEqualGUID(riid, &IID_IEnumMoniker)) 721 { 722 *ppv = iface; 723 IEnumMoniker_AddRef(iface); 724 return S_OK; 725 } 726 727 FIXME("- no interface IID: %s\n", debugstr_guid(riid)); 728 *ppv = NULL; 729 return E_NOINTERFACE; 730 } 731 732 static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(IEnumMoniker *iface) 733 { 734 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); 735 ULONG ref = InterlockedIncrement(&This->ref); 736 737 TRACE("(%p) ref=%d\n", This, ref); 738 739 return ref; 740 } 741 742 static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface) 743 { 744 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); 745 ULONG ref = InterlockedDecrement(&This->ref); 746 747 TRACE("(%p) ref=%d\n", This, ref); 748 749 if (!ref) 750 { 751 if(This->special_hkey) 752 RegCloseKey(This->special_hkey); 753 RegCloseKey(This->hkey); 754 CoTaskMemFree(This); 755 DEVENUM_UnlockModule(); 756 return 0; 757 } 758 return ref; 759 } 760 761 static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt, 762 ULONG *pceltFetched) 763 { 764 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); 765 WCHAR buffer[MAX_PATH + 1]; 766 LONG res; 767 ULONG fetched = 0; 768 MediaCatMoniker * pMoniker; 769 770 TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched); 771 772 while (fetched < celt) 773 { 774 if(This->index+fetched < This->subkey_cnt) 775 res = RegEnumKeyW(This->hkey, This->index+fetched, buffer, sizeof(buffer) / sizeof(WCHAR)); 776 else if(This->special_hkey) 777 res = RegEnumKeyW(This->special_hkey, This->index+fetched-This->subkey_cnt, buffer, sizeof(buffer) / sizeof(WCHAR)); 778 else 779 break; 780 if (res != ERROR_SUCCESS) 781 { 782 break; 783 } 784 pMoniker = DEVENUM_IMediaCatMoniker_Construct(); 785 if (!pMoniker) 786 return E_OUTOFMEMORY; 787 788 if (RegOpenKeyW(This->index+fetched < This->subkey_cnt ? This->hkey : This->special_hkey, 789 buffer, &pMoniker->hkey) != ERROR_SUCCESS) 790 { 791 IMoniker_Release(&pMoniker->IMoniker_iface); 792 break; 793 } 794 rgelt[fetched] = &pMoniker->IMoniker_iface; 795 fetched++; 796 } 797 798 This->index += fetched; 799 800 TRACE("-- fetched %d\n", fetched); 801 802 if (pceltFetched) 803 *pceltFetched = fetched; 804 805 if (fetched != celt) 806 return S_FALSE; 807 else 808 return S_OK; 809 } 810 811 static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt) 812 { 813 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); 814 DWORD special_subkeys = 0; 815 816 TRACE("(%p)->(%d)\n", iface, celt); 817 818 /* Before incrementing, check if there are any more values to run through. 819 Some programs use the Skip() function to get the number of devices */ 820 if(This->special_hkey) 821 RegQueryInfoKeyW(This->special_hkey, NULL, NULL, NULL, &special_subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 822 823 if((This->index + celt) >= This->subkey_cnt + special_subkeys) 824 { 825 return S_FALSE; 826 } 827 828 This->index += celt; 829 830 return S_OK; 831 } 832 833 static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface) 834 { 835 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); 836 837 TRACE("(%p)->()\n", iface); 838 839 This->index = 0; 840 841 return S_OK; 842 } 843 844 static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum) 845 { 846 FIXME("(%p)->(%p): stub\n", iface, ppenum); 847 848 return E_NOTIMPL; 849 } 850 851 /********************************************************************** 852 * IEnumMoniker_Vtbl 853 */ 854 static const IEnumMonikerVtbl IEnumMoniker_Vtbl = 855 { 856 DEVENUM_IEnumMoniker_QueryInterface, 857 DEVENUM_IEnumMoniker_AddRef, 858 DEVENUM_IEnumMoniker_Release, 859 DEVENUM_IEnumMoniker_Next, 860 DEVENUM_IEnumMoniker_Skip, 861 DEVENUM_IEnumMoniker_Reset, 862 DEVENUM_IEnumMoniker_Clone 863 }; 864 865 HRESULT DEVENUM_IEnumMoniker_Construct(HKEY hkey, HKEY special_hkey, IEnumMoniker ** ppEnumMoniker) 866 { 867 EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl)); 868 if (!pEnumMoniker) 869 return E_OUTOFMEMORY; 870 871 pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl; 872 pEnumMoniker->ref = 1; 873 pEnumMoniker->index = 0; 874 pEnumMoniker->hkey = hkey; 875 pEnumMoniker->special_hkey = special_hkey; 876 877 *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface; 878 879 if(RegQueryInfoKeyW(pEnumMoniker->hkey, NULL, NULL, NULL, &pEnumMoniker->subkey_cnt, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) 880 pEnumMoniker->subkey_cnt = 0; 881 882 883 DEVENUM_LockModule(); 884 885 return S_OK; 886 } 887