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