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