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