1 /* 2 * COMPOBJ library 3 * 4 * Copyright 1995 Martin von Loewis 5 * Copyright 1998 Justin Bradford 6 * Copyright 1999 Francis Beaudet 7 * Copyright 1999 Sylvain St-Germain 8 * Copyright 2002 Marcus Meissner 9 * Copyright 2004 Mike Hearn 10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers) 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Lesser General Public 14 * License as published by the Free Software Foundation; either 15 * version 2.1 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Lesser General Public License for more details. 21 * 22 * You should have received a copy of the GNU Lesser General Public 23 * License along with this library; if not, write to the Free Software 24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 25 * 26 * Note 27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED 28 * Therefore do not test against COINIT_MULTITHREADED 29 * 30 * TODO list: (items bunched together depend on each other) 31 * 32 * - Implement the service control manager (in rpcss) to keep track 33 * of registered class objects: ISCM::ServerRegisterClsid et al 34 * - Implement the OXID resolver so we don't need magic endpoint names for 35 * clients and servers to meet up 36 * 37 */ 38 39 #include <stdarg.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <assert.h> 43 44 #define COBJMACROS 45 #define NONAMELESSUNION 46 47 #include "ntstatus.h" 48 #define WIN32_NO_STATUS 49 #include "windef.h" 50 #include "winbase.h" 51 #include "winerror.h" 52 #include "winreg.h" 53 #include "winuser.h" 54 #define USE_COM_CONTEXT_DEF 55 #include "objbase.h" 56 #include "ole2.h" 57 #include "ole2ver.h" 58 #include "ctxtcall.h" 59 #include "dde.h" 60 #include "servprov.h" 61 62 #ifndef __REACTOS__ 63 #include "initguid.h" 64 #endif 65 #include "compobj_private.h" 66 #include "moniker.h" 67 68 #include "wine/debug.h" 69 70 WINE_DEFAULT_DEBUG_CHANNEL(ole); 71 72 /**************************************************************************** 73 * This section defines variables internal to the COM module. 74 */ 75 76 static APARTMENT *MTA; /* protected by csApartment */ 77 static APARTMENT *MainApartment; /* the first STA apartment */ 78 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ 79 80 static CRITICAL_SECTION csApartment; 81 static CRITICAL_SECTION_DEBUG critsect_debug = 82 { 83 0, 0, &csApartment, 84 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 85 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") } 86 }; 87 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; 88 89 enum comclass_threadingmodel 90 { 91 ThreadingModel_Apartment = 1, 92 ThreadingModel_Free = 2, 93 ThreadingModel_No = 3, 94 ThreadingModel_Both = 4, 95 ThreadingModel_Neutral = 5 96 }; 97 98 enum comclass_miscfields 99 { 100 MiscStatus = 1, 101 MiscStatusIcon = 2, 102 MiscStatusContent = 4, 103 MiscStatusThumbnail = 8, 104 MiscStatusDocPrint = 16 105 }; 106 107 struct comclassredirect_data 108 { 109 ULONG size; 110 BYTE res; 111 BYTE miscmask; 112 BYTE res1[2]; 113 DWORD model; 114 GUID clsid; 115 GUID alias; 116 GUID clsid2; 117 GUID tlbid; 118 ULONG name_len; 119 ULONG name_offset; 120 ULONG progid_len; 121 ULONG progid_offset; 122 ULONG clrdata_len; 123 ULONG clrdata_offset; 124 DWORD miscstatus; 125 DWORD miscstatuscontent; 126 DWORD miscstatusthumbnail; 127 DWORD miscstatusicon; 128 DWORD miscstatusdocprint; 129 }; 130 131 struct ifacepsredirect_data 132 { 133 ULONG size; 134 DWORD mask; 135 GUID iid; 136 ULONG nummethods; 137 GUID tlbid; 138 GUID base; 139 ULONG name_len; 140 ULONG name_offset; 141 }; 142 143 struct progidredirect_data 144 { 145 ULONG size; 146 DWORD reserved; 147 ULONG clsid_offset; 148 }; 149 150 struct class_reg_data 151 { 152 union 153 { 154 struct 155 { 156 struct comclassredirect_data *data; 157 void *section; 158 HANDLE hactctx; 159 } actctx; 160 HKEY hkey; 161 } u; 162 BOOL hkey; 163 }; 164 165 struct registered_psclsid 166 { 167 struct list entry; 168 IID iid; 169 CLSID clsid; 170 }; 171 172 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list); 173 174 static CRITICAL_SECTION cs_registered_psclsid_list; 175 static CRITICAL_SECTION_DEBUG psclsid_cs_debug = 176 { 177 0, 0, &cs_registered_psclsid_list, 178 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList }, 179 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") } 180 }; 181 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 }; 182 183 /* 184 * This is a marshallable object exposing registered local servers. 185 * IServiceProvider is used only because it happens meet requirements 186 * and already has proxy/stub code. If more functionality is needed, 187 * a custom interface may be used instead. 188 */ 189 struct LocalServer 190 { 191 IServiceProvider IServiceProvider_iface; 192 LONG ref; 193 APARTMENT *apt; 194 IStream *marshal_stream; 195 }; 196 197 /* 198 * This lock count counts the number of times CoInitialize is called. It is 199 * decreased every time CoUninitialize is called. When it hits 0, the COM 200 * libraries are freed 201 */ 202 static LONG s_COMLockCount = 0; 203 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */ 204 static LONG s_COMServerProcessReferences = 0; 205 206 /* 207 * This linked list contains the list of registered class objects. These 208 * are mostly used to register the factories for out-of-proc servers of OLE 209 * objects. 210 * 211 * TODO: Make this data structure aware of inter-process communication. This 212 * means that parts of this will be exported to rpcss. 213 */ 214 typedef struct tagRegisteredClass 215 { 216 struct list entry; 217 CLSID classIdentifier; 218 OXID apartment_id; 219 LPUNKNOWN classObject; 220 DWORD runContext; 221 DWORD connectFlags; 222 DWORD dwCookie; 223 void *RpcRegistration; 224 } RegisteredClass; 225 226 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList); 227 228 static CRITICAL_SECTION csRegisteredClassList; 229 static CRITICAL_SECTION_DEBUG class_cs_debug = 230 { 231 0, 0, &csRegisteredClassList, 232 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, 233 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") } 234 }; 235 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; 236 237 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect) 238 { 239 switch (aspect) 240 { 241 case DVASPECT_CONTENT: 242 return MiscStatusContent; 243 case DVASPECT_THUMBNAIL: 244 return MiscStatusThumbnail; 245 case DVASPECT_ICON: 246 return MiscStatusIcon; 247 case DVASPECT_DOCPRINT: 248 return MiscStatusDocPrint; 249 default: 250 return MiscStatus; 251 }; 252 } 253 254 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status) 255 { 256 ACTCTX_SECTION_KEYED_DATA data; 257 258 data.cbSize = sizeof(data); 259 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 260 clsid, &data)) 261 { 262 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 263 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect); 264 265 if (!(comclass->miscmask & misc)) 266 { 267 if (!(comclass->miscmask & MiscStatus)) 268 { 269 *status = 0; 270 return TRUE; 271 } 272 misc = MiscStatus; 273 } 274 275 switch (misc) 276 { 277 case MiscStatus: 278 *status = comclass->miscstatus; 279 break; 280 case MiscStatusIcon: 281 *status = comclass->miscstatusicon; 282 break; 283 case MiscStatusContent: 284 *status = comclass->miscstatuscontent; 285 break; 286 case MiscStatusThumbnail: 287 *status = comclass->miscstatusthumbnail; 288 break; 289 case MiscStatusDocPrint: 290 *status = comclass->miscstatusdocprint; 291 break; 292 default: 293 ; 294 }; 295 296 return TRUE; 297 } 298 else 299 return FALSE; 300 } 301 302 /* wrapper for NtCreateKey that creates the key recursively if necessary */ 303 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) 304 { 305 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL ); 306 307 if (status == STATUS_OBJECT_NAME_NOT_FOUND) 308 { 309 HANDLE subkey, root = attr->RootDirectory; 310 WCHAR *buffer = attr->ObjectName->Buffer; 311 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); 312 UNICODE_STRING str; 313 314 while (i < len && buffer[i] != '\\') i++; 315 if (i == len) return status; 316 317 attrs = attr->Attributes; 318 attr->ObjectName = &str; 319 320 while (i < len) 321 { 322 str.Buffer = buffer + pos; 323 str.Length = (i - pos) * sizeof(WCHAR); 324 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL ); 325 if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); 326 if (status) return status; 327 attr->RootDirectory = subkey; 328 while (i < len && buffer[i] == '\\') i++; 329 pos = i; 330 while (i < len && buffer[i] != '\\') i++; 331 } 332 str.Buffer = buffer + pos; 333 str.Length = (i - pos) * sizeof(WCHAR); 334 attr->Attributes = attrs; 335 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL ); 336 if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); 337 } 338 return status; 339 } 340 341 #ifdef __REACTOS__ 342 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes"; 343 #else 344 static const WCHAR classes_rootW[] = 345 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e', 346 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0}; 347 #endif 348 349 static HKEY classes_root_hkey; 350 351 /* create the special HKEY_CLASSES_ROOT key */ 352 static HKEY create_classes_root_hkey(DWORD access) 353 { 354 HKEY hkey, ret = 0; 355 OBJECT_ATTRIBUTES attr; 356 UNICODE_STRING name; 357 358 attr.Length = sizeof(attr); 359 attr.RootDirectory = 0; 360 attr.ObjectName = &name; 361 attr.Attributes = 0; 362 attr.SecurityDescriptor = NULL; 363 attr.SecurityQualityOfService = NULL; 364 RtlInitUnicodeString( &name, classes_rootW ); 365 if (create_key( &hkey, access, &attr )) return 0; 366 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey ); 367 368 if (!(access & KEY_WOW64_64KEY)) 369 { 370 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 ))) 371 ret = hkey; 372 else 373 NtClose( hkey ); /* somebody beat us to it */ 374 } 375 else 376 ret = hkey; 377 return ret; 378 } 379 380 /* map the hkey from special root to normal key if necessary */ 381 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access ) 382 { 383 HKEY ret = hkey; 384 const BOOL is_win64 = sizeof(void*) > sizeof(int); 385 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); 386 387 if (hkey == HKEY_CLASSES_ROOT && 388 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey))) 389 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY)); 390 if (force_wow32 && ret && ret == classes_root_hkey) 391 { 392 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0}; 393 access &= ~KEY_WOW64_32KEY; 394 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey)) 395 return 0; 396 ret = hkey; 397 } 398 399 return ret; 400 } 401 402 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey ) 403 { 404 OBJECT_ATTRIBUTES attr; 405 UNICODE_STRING nameW; 406 407 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; 408 409 attr.Length = sizeof(attr); 410 attr.RootDirectory = hkey; 411 attr.ObjectName = &nameW; 412 attr.Attributes = 0; 413 attr.SecurityDescriptor = NULL; 414 attr.SecurityQualityOfService = NULL; 415 RtlInitUnicodeString( &nameW, name ); 416 417 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) ); 418 } 419 420 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey ) 421 { 422 OBJECT_ATTRIBUTES attr; 423 UNICODE_STRING nameW; 424 425 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE; 426 427 attr.Length = sizeof(attr); 428 attr.RootDirectory = hkey; 429 attr.ObjectName = &nameW; 430 attr.Attributes = 0; 431 attr.SecurityDescriptor = NULL; 432 attr.SecurityQualityOfService = NULL; 433 RtlInitUnicodeString( &nameW, name ); 434 435 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) ); 436 } 437 438 /***************************************************************************** 439 * This section contains OpenDllList definitions 440 * 441 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or 442 * other functions that do LoadLibrary _without_ giving back a HMODULE. 443 * Without this list these handles would never be freed. 444 * 445 * FIXME: a DLL that says OK when asked for unloading is unloaded in the 446 * next unload-call but not before 600 sec. 447 */ 448 449 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); 450 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); 451 452 typedef struct tagOpenDll 453 { 454 LONG refs; 455 LPWSTR library_name; 456 HANDLE library; 457 DllGetClassObjectFunc DllGetClassObject; 458 DllCanUnloadNowFunc DllCanUnloadNow; 459 struct list entry; 460 } OpenDll; 461 462 static struct list openDllList = LIST_INIT(openDllList); 463 464 static CRITICAL_SECTION csOpenDllList; 465 static CRITICAL_SECTION_DEBUG dll_cs_debug = 466 { 467 0, 0, &csOpenDllList, 468 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, 469 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") } 470 }; 471 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; 472 473 struct apartment_loaded_dll 474 { 475 struct list entry; 476 OpenDll *dll; 477 DWORD unload_time; 478 BOOL multi_threaded; 479 }; 480 481 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0}; 482 483 static ATOM apt_win_class; 484 485 /***************************************************************************** 486 * This section contains OpenDllList implementation 487 */ 488 489 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name) 490 { 491 OpenDll *ptr; 492 OpenDll *ret = NULL; 493 EnterCriticalSection(&csOpenDllList); 494 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry) 495 { 496 if (!wcsicmp(library_name, ptr->library_name) && 497 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */) 498 { 499 ret = ptr; 500 break; 501 } 502 } 503 LeaveCriticalSection(&csOpenDllList); 504 return ret; 505 } 506 507 /* caller must ensure that library_name is not already in the open dll list */ 508 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) 509 { 510 OpenDll *entry; 511 int len; 512 HRESULT hr = S_OK; 513 HANDLE hLibrary; 514 DllCanUnloadNowFunc DllCanUnloadNow; 515 DllGetClassObjectFunc DllGetClassObject; 516 517 TRACE("%s\n", debugstr_w(library_name)); 518 519 *ret = COMPOBJ_DllList_Get(library_name); 520 if (*ret) return S_OK; 521 522 /* do this outside the csOpenDllList to avoid creating a lock dependency on 523 * the loader lock */ 524 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 525 if (!hLibrary) 526 { 527 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); 528 /* failure: DLL could not be loaded */ 529 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ 530 } 531 532 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); 533 /* Note: failing to find DllCanUnloadNow is not a failure */ 534 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject"); 535 if (!DllGetClassObject) 536 { 537 /* failure: the dll did not export DllGetClassObject */ 538 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); 539 FreeLibrary(hLibrary); 540 return CO_E_DLLNOTFOUND; 541 } 542 543 EnterCriticalSection( &csOpenDllList ); 544 545 *ret = COMPOBJ_DllList_Get(library_name); 546 if (*ret) 547 { 548 /* another caller to this function already added the dll while we 549 * weren't in the critical section */ 550 FreeLibrary(hLibrary); 551 } 552 else 553 { 554 len = lstrlenW(library_name); 555 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); 556 if (entry) 557 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 558 if (entry && entry->library_name) 559 { 560 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); 561 entry->library = hLibrary; 562 entry->refs = 1; 563 entry->DllCanUnloadNow = DllCanUnloadNow; 564 entry->DllGetClassObject = DllGetClassObject; 565 list_add_tail(&openDllList, &entry->entry); 566 *ret = entry; 567 } 568 else 569 { 570 HeapFree(GetProcessHeap(), 0, entry); 571 hr = E_OUTOFMEMORY; 572 FreeLibrary(hLibrary); 573 } 574 } 575 576 LeaveCriticalSection( &csOpenDllList ); 577 578 return hr; 579 } 580 581 /* pass FALSE for free_entry to release a reference without destroying the 582 * entry if it reaches zero or TRUE otherwise */ 583 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) 584 { 585 if (!InterlockedDecrement(&entry->refs) && free_entry) 586 { 587 EnterCriticalSection(&csOpenDllList); 588 list_remove(&entry->entry); 589 LeaveCriticalSection(&csOpenDllList); 590 591 TRACE("freeing %p\n", entry->library); 592 FreeLibrary(entry->library); 593 594 HeapFree(GetProcessHeap(), 0, entry->library_name); 595 HeapFree(GetProcessHeap(), 0, entry); 596 } 597 } 598 599 /* frees memory associated with active dll list */ 600 static void COMPOBJ_DllList_Free(void) 601 { 602 OpenDll *entry, *cursor2; 603 EnterCriticalSection(&csOpenDllList); 604 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) 605 { 606 list_remove(&entry->entry); 607 608 HeapFree(GetProcessHeap(), 0, entry->library_name); 609 HeapFree(GetProcessHeap(), 0, entry); 610 } 611 LeaveCriticalSection(&csOpenDllList); 612 DeleteCriticalSection(&csOpenDllList); 613 } 614 615 /****************************************************************************** 616 * Manage apartments. 617 */ 618 619 static DWORD apartment_addref(struct apartment *apt) 620 { 621 DWORD refs = InterlockedIncrement(&apt->refs); 622 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); 623 return refs; 624 } 625 626 /* allocates memory and fills in the necessary fields for a new apartment 627 * object. must be called inside apartment cs */ 628 static APARTMENT *apartment_construct(DWORD model) 629 { 630 APARTMENT *apt; 631 632 TRACE("creating new apartment, model=%d\n", model); 633 634 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); 635 apt->tid = GetCurrentThreadId(); 636 637 list_init(&apt->proxies); 638 list_init(&apt->stubmgrs); 639 list_init(&apt->loaded_dlls); 640 apt->ipidc = 0; 641 apt->refs = 1; 642 apt->remunk_exported = FALSE; 643 apt->oidc = 1; 644 InitializeCriticalSection(&apt->cs); 645 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); 646 647 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); 648 649 if (apt->multi_threaded) 650 { 651 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 652 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; 653 } 654 else 655 { 656 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 657 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); 658 } 659 660 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 661 662 list_add_head(&apts, &apt->entry); 663 664 return apt; 665 } 666 667 /* gets and existing apartment if one exists or otherwise creates an apartment 668 * structure which stores OLE apartment-local information and stores a pointer 669 * to it in the thread-local storage */ 670 static APARTMENT *apartment_get_or_create(DWORD model) 671 { 672 APARTMENT *apt = COM_CurrentApt(); 673 674 if (!apt) 675 { 676 if (model & COINIT_APARTMENTTHREADED) 677 { 678 EnterCriticalSection(&csApartment); 679 680 apt = apartment_construct(model); 681 if (!MainApartment) 682 { 683 MainApartment = apt; 684 apt->main = TRUE; 685 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 686 } 687 688 LeaveCriticalSection(&csApartment); 689 690 if (apt->main) 691 apartment_createwindowifneeded(apt); 692 } 693 else 694 { 695 EnterCriticalSection(&csApartment); 696 697 /* The multi-threaded apartment (MTA) contains zero or more threads interacting 698 * with free threaded (ie thread safe) COM objects. There is only ever one MTA 699 * in a process */ 700 if (MTA) 701 { 702 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); 703 apartment_addref(MTA); 704 } 705 else 706 MTA = apartment_construct(model); 707 708 apt = MTA; 709 710 LeaveCriticalSection(&csApartment); 711 } 712 COM_CurrentInfo()->apt = apt; 713 } 714 715 return apt; 716 } 717 718 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) 719 { 720 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); 721 } 722 723 /* gets the multi-threaded apartment if it exists. The caller must 724 * release the reference from the apartment as soon as the apartment pointer 725 * is no longer required. */ 726 static APARTMENT *apartment_find_mta(void) 727 { 728 APARTMENT *apt; 729 730 EnterCriticalSection(&csApartment); 731 732 if ((apt = MTA)) 733 apartment_addref(apt); 734 735 LeaveCriticalSection(&csApartment); 736 737 return apt; 738 } 739 740 /* Return the current apartment if it exists, or, failing that, the MTA. Caller 741 * must free the returned apartment in either case. */ 742 APARTMENT *apartment_get_current_or_mta(void) 743 { 744 APARTMENT *apt = COM_CurrentApt(); 745 if (apt) 746 { 747 apartment_addref(apt); 748 return apt; 749 } 750 return apartment_find_mta(); 751 } 752 753 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) 754 { 755 list_remove(&curClass->entry); 756 757 if (curClass->runContext & CLSCTX_LOCAL_SERVER) 758 RPC_StopLocalServer(curClass->RpcRegistration); 759 760 IUnknown_Release(curClass->classObject); 761 HeapFree(GetProcessHeap(), 0, curClass); 762 } 763 764 static void COM_RevokeAllClasses(const struct apartment *apt) 765 { 766 RegisteredClass *curClass, *cursor; 767 768 EnterCriticalSection( &csRegisteredClassList ); 769 770 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) 771 { 772 if (curClass->apartment_id == apt->oxid) 773 COM_RevokeRegisteredClassObject(curClass); 774 } 775 776 LeaveCriticalSection( &csRegisteredClassList ); 777 } 778 779 static void revoke_registered_psclsids(void) 780 { 781 struct registered_psclsid *psclsid, *psclsid2; 782 783 EnterCriticalSection( &cs_registered_psclsid_list ); 784 785 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, ®istered_psclsid_list, struct registered_psclsid, entry) 786 { 787 list_remove(&psclsid->entry); 788 HeapFree(GetProcessHeap(), 0, psclsid); 789 } 790 791 LeaveCriticalSection( &cs_registered_psclsid_list ); 792 } 793 794 /****************************************************************************** 795 * Implementation of the manual reset event object. (CLSID_ManualResetEvent) 796 */ 797 798 typedef struct ManualResetEvent { 799 ISynchronize ISynchronize_iface; 800 ISynchronizeHandle ISynchronizeHandle_iface; 801 LONG ref; 802 HANDLE event; 803 } MREImpl; 804 805 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface) 806 { 807 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface); 808 } 809 810 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv) 811 { 812 MREImpl *This = impl_from_ISynchronize(iface); 813 814 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv); 815 816 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) { 817 *ppv = &This->ISynchronize_iface; 818 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) { 819 *ppv = &This->ISynchronizeHandle_iface; 820 }else { 821 ERR("Unknown interface %s requested.\n", debugstr_guid(riid)); 822 *ppv = NULL; 823 return E_NOINTERFACE; 824 } 825 826 IUnknown_AddRef((IUnknown*)*ppv); 827 return S_OK; 828 } 829 830 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface) 831 { 832 MREImpl *This = impl_from_ISynchronize(iface); 833 LONG ref = InterlockedIncrement(&This->ref); 834 TRACE("%p - ref %d\n", This, ref); 835 836 return ref; 837 } 838 839 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface) 840 { 841 MREImpl *This = impl_from_ISynchronize(iface); 842 LONG ref = InterlockedDecrement(&This->ref); 843 TRACE("%p - ref %d\n", This, ref); 844 845 if(!ref) 846 { 847 CloseHandle(This->event); 848 HeapFree(GetProcessHeap(), 0, This); 849 } 850 851 return ref; 852 } 853 854 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds) 855 { 856 MREImpl *This = impl_from_ISynchronize(iface); 857 UINT index; 858 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds); 859 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index); 860 } 861 862 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface) 863 { 864 MREImpl *This = impl_from_ISynchronize(iface); 865 TRACE("%p\n", This); 866 SetEvent(This->event); 867 return S_OK; 868 } 869 870 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface) 871 { 872 MREImpl *This = impl_from_ISynchronize(iface); 873 TRACE("%p\n", This); 874 ResetEvent(This->event); 875 return S_OK; 876 } 877 878 static ISynchronizeVtbl vt_ISynchronize = { 879 ISynchronize_fnQueryInterface, 880 ISynchronize_fnAddRef, 881 ISynchronize_fnRelease, 882 ISynchronize_fnWait, 883 ISynchronize_fnSignal, 884 ISynchronize_fnReset 885 }; 886 887 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface) 888 { 889 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface); 890 } 891 892 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv) 893 { 894 MREImpl *This = impl_from_ISynchronizeHandle(iface); 895 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv); 896 } 897 898 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface) 899 { 900 MREImpl *This = impl_from_ISynchronizeHandle(iface); 901 return ISynchronize_AddRef(&This->ISynchronize_iface); 902 } 903 904 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface) 905 { 906 MREImpl *This = impl_from_ISynchronizeHandle(iface); 907 return ISynchronize_Release(&This->ISynchronize_iface); 908 } 909 910 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph) 911 { 912 MREImpl *This = impl_from_ISynchronizeHandle(iface); 913 914 *ph = This->event; 915 return S_OK; 916 } 917 918 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = { 919 SynchronizeHandle_QueryInterface, 920 SynchronizeHandle_AddRef, 921 SynchronizeHandle_Release, 922 SynchronizeHandle_GetHandle 923 }; 924 925 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv) 926 { 927 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl)); 928 HRESULT hr; 929 930 if(punkouter) 931 FIXME("Aggregation not implemented.\n"); 932 933 This->ref = 1; 934 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize; 935 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl; 936 This->event = CreateEventW(NULL, TRUE, FALSE, NULL); 937 938 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv); 939 ISynchronize_Release(&This->ISynchronize_iface); 940 return hr; 941 } 942 943 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface) 944 { 945 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface); 946 } 947 948 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) 949 { 950 LocalServer *This = impl_from_IServiceProvider(iface); 951 952 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 953 954 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) { 955 *ppv = &This->IServiceProvider_iface; 956 }else { 957 *ppv = NULL; 958 return E_NOINTERFACE; 959 } 960 961 IUnknown_AddRef((IUnknown*)*ppv); 962 return S_OK; 963 } 964 965 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface) 966 { 967 LocalServer *This = impl_from_IServiceProvider(iface); 968 LONG ref = InterlockedIncrement(&This->ref); 969 970 TRACE("(%p) ref=%d\n", This, ref); 971 972 return ref; 973 } 974 975 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface) 976 { 977 LocalServer *This = impl_from_IServiceProvider(iface); 978 LONG ref = InterlockedDecrement(&This->ref); 979 980 TRACE("(%p) ref=%d\n", This, ref); 981 982 if(!ref) { 983 assert(!This->apt); 984 HeapFree(GetProcessHeap(), 0, This); 985 } 986 987 return ref; 988 } 989 990 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv) 991 { 992 LocalServer *This = impl_from_IServiceProvider(iface); 993 APARTMENT *apt = COM_CurrentApt(); 994 RegisteredClass *iter; 995 HRESULT hres = E_FAIL; 996 997 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv); 998 999 if(!This->apt) 1000 return E_UNEXPECTED; 1001 1002 EnterCriticalSection(&csRegisteredClassList); 1003 1004 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) { 1005 if(iter->apartment_id == apt->oxid 1006 && (iter->runContext & CLSCTX_LOCAL_SERVER) 1007 && IsEqualGUID(&iter->classIdentifier, guid)) { 1008 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv); 1009 break; 1010 } 1011 } 1012 1013 LeaveCriticalSection( &csRegisteredClassList ); 1014 1015 return hres; 1016 } 1017 1018 static const IServiceProviderVtbl LocalServerVtbl = { 1019 LocalServer_QueryInterface, 1020 LocalServer_AddRef, 1021 LocalServer_Release, 1022 LocalServer_QueryService 1023 }; 1024 1025 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret) 1026 { 1027 HRESULT hres = S_OK; 1028 1029 EnterCriticalSection(&apt->cs); 1030 1031 if(!apt->local_server) { 1032 LocalServer *obj; 1033 1034 obj = heap_alloc(sizeof(*obj)); 1035 if(obj) { 1036 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl; 1037 obj->ref = 1; 1038 obj->apt = apt; 1039 1040 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream); 1041 if(SUCCEEDED(hres)) { 1042 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface, 1043 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); 1044 if(FAILED(hres)) 1045 IStream_Release(obj->marshal_stream); 1046 } 1047 1048 if(SUCCEEDED(hres)) 1049 apt->local_server = obj; 1050 else 1051 heap_free(obj); 1052 }else { 1053 hres = E_OUTOFMEMORY; 1054 } 1055 } 1056 1057 if(SUCCEEDED(hres)) 1058 hres = IStream_Clone(apt->local_server->marshal_stream, ret); 1059 1060 LeaveCriticalSection(&apt->cs); 1061 1062 if(FAILED(hres)) 1063 ERR("Failed: %08x\n", hres); 1064 return hres; 1065 } 1066 1067 /*********************************************************************** 1068 * CoRevokeClassObject [OLE32.@] 1069 * 1070 * Removes a class object from the class registry. 1071 * 1072 * PARAMS 1073 * dwRegister [I] Cookie returned from CoRegisterClassObject(). 1074 * 1075 * RETURNS 1076 * Success: S_OK. 1077 * Failure: HRESULT code. 1078 * 1079 * NOTES 1080 * Must be called from the same apartment that called CoRegisterClassObject(), 1081 * otherwise it will fail with RPC_E_WRONG_THREAD. 1082 * 1083 * SEE ALSO 1084 * CoRegisterClassObject 1085 */ 1086 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( 1087 DWORD dwRegister) 1088 { 1089 HRESULT hr = E_INVALIDARG; 1090 RegisteredClass *curClass; 1091 APARTMENT *apt; 1092 1093 TRACE("(%08x)\n",dwRegister); 1094 1095 if (!(apt = apartment_get_current_or_mta())) 1096 { 1097 ERR("COM was not initialized\n"); 1098 return CO_E_NOTINITIALIZED; 1099 } 1100 1101 EnterCriticalSection( &csRegisteredClassList ); 1102 1103 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 1104 { 1105 /* 1106 * Check if we have a match on the cookie. 1107 */ 1108 if (curClass->dwCookie == dwRegister) 1109 { 1110 if (curClass->apartment_id == apt->oxid) 1111 { 1112 COM_RevokeRegisteredClassObject(curClass); 1113 hr = S_OK; 1114 } 1115 else 1116 { 1117 ERR("called from wrong apartment, should be called from %s\n", 1118 wine_dbgstr_longlong(curClass->apartment_id)); 1119 hr = RPC_E_WRONG_THREAD; 1120 } 1121 break; 1122 } 1123 } 1124 1125 LeaveCriticalSection( &csRegisteredClassList ); 1126 apartment_release(apt); 1127 return hr; 1128 } 1129 1130 /* frees unused libraries loaded by apartment_getclassobject by calling the 1131 * DLL's DllCanUnloadNow entry point */ 1132 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) 1133 { 1134 struct apartment_loaded_dll *entry, *next; 1135 EnterCriticalSection(&apt->cs); 1136 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 1137 { 1138 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) 1139 { 1140 DWORD real_delay = delay; 1141 1142 if (real_delay == INFINITE) 1143 { 1144 /* DLLs that return multi-threaded objects aren't unloaded 1145 * straight away to cope for programs that have races between 1146 * last object destruction and threads in the DLLs that haven't 1147 * finished, despite DllCanUnloadNow returning S_OK */ 1148 if (entry->multi_threaded) 1149 real_delay = 10 * 60 * 1000; /* 10 minutes */ 1150 else 1151 real_delay = 0; 1152 } 1153 1154 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0))) 1155 { 1156 list_remove(&entry->entry); 1157 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); 1158 HeapFree(GetProcessHeap(), 0, entry); 1159 } 1160 else 1161 { 1162 entry->unload_time = GetTickCount() + real_delay; 1163 if (!entry->unload_time) entry->unload_time = 1; 1164 } 1165 } 1166 else if (entry->unload_time) 1167 entry->unload_time = 0; 1168 } 1169 LeaveCriticalSection(&apt->cs); 1170 } 1171 1172 DWORD apartment_release(struct apartment *apt) 1173 { 1174 DWORD ret; 1175 1176 EnterCriticalSection(&csApartment); 1177 1178 ret = InterlockedDecrement(&apt->refs); 1179 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret); 1180 1181 if (apt->being_destroyed) 1182 { 1183 LeaveCriticalSection(&csApartment); 1184 return ret; 1185 } 1186 1187 /* destruction stuff that needs to happen under csApartment CS */ 1188 if (ret == 0) 1189 { 1190 apt->being_destroyed = TRUE; 1191 if (apt == MTA) MTA = NULL; 1192 else if (apt == MainApartment) MainApartment = NULL; 1193 list_remove(&apt->entry); 1194 } 1195 1196 LeaveCriticalSection(&csApartment); 1197 1198 if (ret == 0) 1199 { 1200 struct list *cursor, *cursor2; 1201 1202 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); 1203 1204 if(apt->local_server) { 1205 LocalServer *local_server = apt->local_server; 1206 LARGE_INTEGER zero; 1207 1208 memset(&zero, 0, sizeof(zero)); 1209 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL); 1210 CoReleaseMarshalData(local_server->marshal_stream); 1211 IStream_Release(local_server->marshal_stream); 1212 local_server->marshal_stream = NULL; 1213 1214 apt->local_server = NULL; 1215 local_server->apt = NULL; 1216 IServiceProvider_Release(&local_server->IServiceProvider_iface); 1217 } 1218 1219 /* Release the references to the registered class objects */ 1220 COM_RevokeAllClasses(apt); 1221 1222 /* no locking is needed for this apartment, because no other thread 1223 * can access it at this point */ 1224 1225 apartment_disconnectproxies(apt); 1226 1227 if (apt->win) DestroyWindow(apt->win); 1228 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); 1229 1230 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) 1231 { 1232 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); 1233 /* release the implicit reference given by the fact that the 1234 * stub has external references (it must do since it is in the 1235 * stub manager list in the apartment and all non-apartment users 1236 * must have a ref on the apartment and so it cannot be destroyed). 1237 */ 1238 stub_manager_int_release(stubmgr); 1239 } 1240 1241 /* if this assert fires, then another thread took a reference to a 1242 * stub manager without taking a reference to the containing 1243 * apartment, which it must do. */ 1244 assert(list_empty(&apt->stubmgrs)); 1245 1246 if (apt->filter) IMessageFilter_Release(apt->filter); 1247 1248 /* free as many unused libraries as possible... */ 1249 apartment_freeunusedlibraries(apt, 0); 1250 1251 /* ... and free the memory for the apartment loaded dll entry and 1252 * release the dll list reference without freeing the library for the 1253 * rest */ 1254 while ((cursor = list_head(&apt->loaded_dlls))) 1255 { 1256 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); 1257 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE); 1258 list_remove(cursor); 1259 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 1260 } 1261 1262 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); 1263 DeleteCriticalSection(&apt->cs); 1264 1265 HeapFree(GetProcessHeap(), 0, apt); 1266 } 1267 1268 return ret; 1269 } 1270 1271 /* The given OXID must be local to this process: 1272 * 1273 * The ref parameter is here mostly to ensure people remember that 1274 * they get one, you should normally take a ref for thread safety. 1275 */ 1276 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) 1277 { 1278 APARTMENT *result = NULL; 1279 struct list *cursor; 1280 1281 EnterCriticalSection(&csApartment); 1282 LIST_FOR_EACH( cursor, &apts ) 1283 { 1284 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 1285 if (apt->oxid == oxid) 1286 { 1287 result = apt; 1288 if (ref) apartment_addref(result); 1289 break; 1290 } 1291 } 1292 LeaveCriticalSection(&csApartment); 1293 1294 return result; 1295 } 1296 1297 /* gets the apartment which has a given creator thread ID. The caller must 1298 * release the reference from the apartment as soon as the apartment pointer 1299 * is no longer required. */ 1300 APARTMENT *apartment_findfromtid(DWORD tid) 1301 { 1302 APARTMENT *result = NULL; 1303 struct list *cursor; 1304 1305 EnterCriticalSection(&csApartment); 1306 LIST_FOR_EACH( cursor, &apts ) 1307 { 1308 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 1309 if (apt->tid == tid) 1310 { 1311 result = apt; 1312 apartment_addref(result); 1313 break; 1314 } 1315 } 1316 LeaveCriticalSection(&csApartment); 1317 1318 return result; 1319 } 1320 1321 /* gets the main apartment if it exists. The caller must 1322 * release the reference from the apartment as soon as the apartment pointer 1323 * is no longer required. */ 1324 static APARTMENT *apartment_findmain(void) 1325 { 1326 APARTMENT *result; 1327 1328 EnterCriticalSection(&csApartment); 1329 1330 result = MainApartment; 1331 if (result) apartment_addref(result); 1332 1333 LeaveCriticalSection(&csApartment); 1334 1335 return result; 1336 } 1337 1338 /* gets the specified class object by loading the appropriate DLL, if 1339 * necessary and calls the DllGetClassObject function for the DLL */ 1340 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, 1341 BOOL apartment_threaded, 1342 REFCLSID rclsid, REFIID riid, void **ppv) 1343 { 1344 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 1345 HRESULT hr = S_OK; 1346 BOOL found = FALSE; 1347 struct apartment_loaded_dll *apartment_loaded_dll; 1348 1349 if (!wcsicmp(dllpath, wszOle32)) 1350 { 1351 /* we don't need to control the lifetime of this dll, so use the local 1352 * implementation of DllGetClassObject directly */ 1353 TRACE("calling ole32!DllGetClassObject\n"); 1354 hr = DllGetClassObject(rclsid, riid, ppv); 1355 1356 if (hr != S_OK) 1357 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); 1358 1359 return hr; 1360 } 1361 1362 EnterCriticalSection(&apt->cs); 1363 1364 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 1365 if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name)) 1366 { 1367 TRACE("found %s already loaded\n", debugstr_w(dllpath)); 1368 found = TRUE; 1369 break; 1370 } 1371 1372 if (!found) 1373 { 1374 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll)); 1375 if (!apartment_loaded_dll) 1376 hr = E_OUTOFMEMORY; 1377 if (SUCCEEDED(hr)) 1378 { 1379 apartment_loaded_dll->unload_time = 0; 1380 apartment_loaded_dll->multi_threaded = FALSE; 1381 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); 1382 if (FAILED(hr)) 1383 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 1384 } 1385 if (SUCCEEDED(hr)) 1386 { 1387 TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); 1388 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); 1389 } 1390 } 1391 1392 LeaveCriticalSection(&apt->cs); 1393 1394 if (SUCCEEDED(hr)) 1395 { 1396 /* one component being multi-threaded overrides any number of 1397 * apartment-threaded components */ 1398 if (!apartment_threaded) 1399 apartment_loaded_dll->multi_threaded = TRUE; 1400 1401 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); 1402 /* OK: get the ClassObject */ 1403 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); 1404 1405 if (hr != S_OK) 1406 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); 1407 } 1408 1409 return hr; 1410 } 1411 1412 /* Returns expanded dll path from the registry or activation context. */ 1413 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen) 1414 { 1415 DWORD ret; 1416 1417 if (regdata->hkey) 1418 { 1419 DWORD keytype; 1420 WCHAR src[MAX_PATH]; 1421 DWORD dwLength = dstlen * sizeof(WCHAR); 1422 1423 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) { 1424 if (keytype == REG_EXPAND_SZ) { 1425 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; 1426 } else { 1427 const WCHAR *quote_start; 1428 quote_start = wcschr(src, '\"'); 1429 if (quote_start) { 1430 const WCHAR *quote_end = wcschr(quote_start + 1, '\"'); 1431 if (quote_end) { 1432 memmove(src, quote_start + 1, 1433 (quote_end - quote_start - 1) * sizeof(WCHAR)); 1434 src[quote_end - quote_start - 1] = '\0'; 1435 } 1436 } 1437 lstrcpynW(dst, src, dstlen); 1438 } 1439 } 1440 return !ret; 1441 } 1442 else 1443 { 1444 static const WCHAR dllW[] = {'.','d','l','l',0}; 1445 ULONG_PTR cookie; 1446 WCHAR *nameW; 1447 1448 *dst = 0; 1449 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset); 1450 ActivateActCtx(regdata->u.actctx.hactctx, &cookie); 1451 ret = SearchPathW(NULL, nameW, dllW, dstlen, dst, NULL); 1452 DeactivateActCtx(0, cookie); 1453 return *dst != 0; 1454 } 1455 } 1456 1457 struct host_object_params 1458 { 1459 struct class_reg_data regdata; 1460 CLSID clsid; /* clsid of object to marshal */ 1461 IID iid; /* interface to marshal */ 1462 HANDLE event; /* event signalling when ready for multi-threaded case */ 1463 HRESULT hr; /* result for multi-threaded case */ 1464 IStream *stream; /* stream that the object will be marshaled into */ 1465 BOOL apartment_threaded; /* is the component purely apartment-threaded? */ 1466 }; 1467 1468 static HRESULT apartment_hostobject(struct apartment *apt, 1469 const struct host_object_params *params) 1470 { 1471 IUnknown *object; 1472 HRESULT hr; 1473 static const LARGE_INTEGER llZero; 1474 WCHAR dllpath[MAX_PATH+1]; 1475 1476 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); 1477 1478 if (!get_object_dll_path(¶ms->regdata, dllpath, ARRAY_SIZE(dllpath))) 1479 { 1480 /* failure: CLSID is not found in registry */ 1481 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); 1482 return REGDB_E_CLASSNOTREG; 1483 } 1484 1485 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded, 1486 ¶ms->clsid, ¶ms->iid, (void **)&object); 1487 if (FAILED(hr)) 1488 return hr; 1489 1490 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 1491 if (FAILED(hr)) 1492 IUnknown_Release(object); 1493 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); 1494 1495 return hr; 1496 } 1497 1498 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 1499 { 1500 switch (msg) 1501 { 1502 case DM_EXECUTERPC: 1503 RPC_ExecuteCall((struct dispatch_params *)lParam); 1504 return 0; 1505 case DM_HOSTOBJECT: 1506 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); 1507 default: 1508 return DefWindowProcW(hWnd, msg, wParam, lParam); 1509 } 1510 } 1511 1512 struct host_thread_params 1513 { 1514 COINIT threading_model; 1515 HANDLE ready_event; 1516 HWND apartment_hwnd; 1517 }; 1518 1519 /* thread for hosting an object to allow an object to appear to be created in 1520 * an apartment with an incompatible threading model */ 1521 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p) 1522 { 1523 struct host_thread_params *params = p; 1524 MSG msg; 1525 HRESULT hr; 1526 struct apartment *apt; 1527 1528 TRACE("\n"); 1529 1530 hr = CoInitializeEx(NULL, params->threading_model); 1531 if (FAILED(hr)) return hr; 1532 1533 apt = COM_CurrentApt(); 1534 if (params->threading_model == COINIT_APARTMENTTHREADED) 1535 { 1536 apartment_createwindowifneeded(apt); 1537 params->apartment_hwnd = apartment_getwindow(apt); 1538 } 1539 else 1540 params->apartment_hwnd = NULL; 1541 1542 /* force the message queue to be created before signaling parent thread */ 1543 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 1544 1545 SetEvent(params->ready_event); 1546 params = NULL; /* can't touch params after here as it may be invalid */ 1547 1548 while (GetMessageW(&msg, NULL, 0, 0)) 1549 { 1550 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) 1551 { 1552 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam; 1553 obj_params->hr = apartment_hostobject(apt, obj_params); 1554 SetEvent(obj_params->event); 1555 } 1556 else 1557 { 1558 TranslateMessage(&msg); 1559 DispatchMessageW(&msg); 1560 } 1561 } 1562 1563 TRACE("exiting\n"); 1564 1565 CoUninitialize(); 1566 1567 return S_OK; 1568 } 1569 1570 /* finds or creates a host apartment, creates the object inside it and returns 1571 * a proxy to it so that the object can be used in the apartment of the 1572 * caller of this function */ 1573 static HRESULT apartment_hostobject_in_hostapt( 1574 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, 1575 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv) 1576 { 1577 struct host_object_params params; 1578 HWND apartment_hwnd = NULL; 1579 DWORD apartment_tid = 0; 1580 HRESULT hr; 1581 1582 if (!multi_threaded && main_apartment) 1583 { 1584 APARTMENT *host_apt = apartment_findmain(); 1585 if (host_apt) 1586 { 1587 apartment_hwnd = apartment_getwindow(host_apt); 1588 apartment_release(host_apt); 1589 } 1590 } 1591 1592 if (!apartment_hwnd) 1593 { 1594 EnterCriticalSection(&apt->cs); 1595 1596 if (!apt->host_apt_tid) 1597 { 1598 struct host_thread_params thread_params; 1599 HANDLE handles[2]; 1600 DWORD wait_value; 1601 1602 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; 1603 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1604 thread_params.apartment_hwnd = NULL; 1605 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); 1606 if (!handles[1]) 1607 { 1608 CloseHandle(handles[0]); 1609 LeaveCriticalSection(&apt->cs); 1610 return E_OUTOFMEMORY; 1611 } 1612 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 1613 CloseHandle(handles[0]); 1614 CloseHandle(handles[1]); 1615 if (wait_value == WAIT_OBJECT_0) 1616 apt->host_apt_hwnd = thread_params.apartment_hwnd; 1617 else 1618 { 1619 LeaveCriticalSection(&apt->cs); 1620 return E_OUTOFMEMORY; 1621 } 1622 } 1623 1624 if (multi_threaded || !main_apartment) 1625 { 1626 apartment_hwnd = apt->host_apt_hwnd; 1627 apartment_tid = apt->host_apt_tid; 1628 } 1629 1630 LeaveCriticalSection(&apt->cs); 1631 } 1632 1633 /* another thread may have become the main apartment in the time it took 1634 * us to create the thread for the host apartment */ 1635 if (!apartment_hwnd && !multi_threaded && main_apartment) 1636 { 1637 APARTMENT *host_apt = apartment_findmain(); 1638 if (host_apt) 1639 { 1640 apartment_hwnd = apartment_getwindow(host_apt); 1641 apartment_release(host_apt); 1642 } 1643 } 1644 1645 params.regdata = *regdata; 1646 params.clsid = *rclsid; 1647 params.iid = *riid; 1648 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); 1649 if (FAILED(hr)) 1650 return hr; 1651 params.apartment_threaded = !multi_threaded; 1652 if (multi_threaded) 1653 { 1654 params.hr = S_OK; 1655 params.event = CreateEventW(NULL, FALSE, FALSE, NULL); 1656 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) 1657 hr = E_OUTOFMEMORY; 1658 else 1659 { 1660 WaitForSingleObject(params.event, INFINITE); 1661 hr = params.hr; 1662 } 1663 CloseHandle(params.event); 1664 } 1665 else 1666 { 1667 if (!apartment_hwnd) 1668 { 1669 ERR("host apartment didn't create window\n"); 1670 hr = E_OUTOFMEMORY; 1671 } 1672 else 1673 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); 1674 } 1675 if (SUCCEEDED(hr)) 1676 hr = CoUnmarshalInterface(params.stream, riid, ppv); 1677 IStream_Release(params.stream); 1678 return hr; 1679 } 1680 1681 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context ) 1682 { 1683 WNDCLASSW wclass; 1684 1685 /* Dispatching to the correct thread in an apartment is done through 1686 * window messages rather than RPC transports. When an interface is 1687 * marshalled into another apartment in the same process, a window of the 1688 * following class is created. The *caller* of CoMarshalInterface (i.e., the 1689 * application) is responsible for pumping the message loop in that thread. 1690 * The WM_USER messages which point to the RPCs are then dispatched to 1691 * apartment_wndproc by the user's code from the apartment in which the 1692 * interface was unmarshalled. 1693 */ 1694 memset(&wclass, 0, sizeof(wclass)); 1695 wclass.lpfnWndProc = apartment_wndproc; 1696 wclass.hInstance = hProxyDll; 1697 wclass.lpszClassName = wszAptWinClass; 1698 apt_win_class = RegisterClassW(&wclass); 1699 return TRUE; 1700 } 1701 1702 /* create a window for the apartment or return the current one if one has 1703 * already been created */ 1704 HRESULT apartment_createwindowifneeded(struct apartment *apt) 1705 { 1706 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT; 1707 1708 if (apt->multi_threaded) 1709 return S_OK; 1710 1711 if (!apt->win) 1712 { 1713 HWND hwnd; 1714 1715 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL ); 1716 1717 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0, 1718 HWND_MESSAGE, 0, hProxyDll, NULL); 1719 if (!hwnd) 1720 { 1721 ERR("CreateWindow failed with error %d\n", GetLastError()); 1722 return HRESULT_FROM_WIN32(GetLastError()); 1723 } 1724 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL)) 1725 /* someone beat us to it */ 1726 DestroyWindow(hwnd); 1727 } 1728 1729 return S_OK; 1730 } 1731 1732 /* retrieves the window for the main- or apartment-threaded apartment */ 1733 HWND apartment_getwindow(const struct apartment *apt) 1734 { 1735 assert(!apt->multi_threaded); 1736 return apt->win; 1737 } 1738 1739 static void COM_TlsDestroy(void) 1740 { 1741 struct oletls *info = NtCurrentTeb()->ReservedForOle; 1742 if (info) 1743 { 1744 struct init_spy *cursor, *cursor2; 1745 1746 if (info->apt) apartment_release(info->apt); 1747 if (info->errorinfo) IErrorInfo_Release(info->errorinfo); 1748 if (info->state) IUnknown_Release(info->state); 1749 1750 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry) 1751 { 1752 list_remove(&cursor->entry); 1753 if (cursor->spy) IInitializeSpy_Release(cursor->spy); 1754 heap_free(cursor); 1755 } 1756 1757 if (info->context_token) IObjContext_Release(info->context_token); 1758 1759 HeapFree(GetProcessHeap(), 0, info); 1760 NtCurrentTeb()->ReservedForOle = NULL; 1761 } 1762 } 1763 1764 /****************************************************************************** 1765 * CoBuildVersion [OLE32.@] 1766 * 1767 * Gets the build version of the DLL. 1768 * 1769 * PARAMS 1770 * 1771 * RETURNS 1772 * Current build version, hiword is majornumber, loword is minornumber 1773 */ 1774 DWORD WINAPI CoBuildVersion(void) 1775 { 1776 TRACE("Returning version %d, build %d.\n", rmm, rup); 1777 return (rmm<<16)+rup; 1778 } 1779 1780 static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id) 1781 { 1782 struct init_spy *spy; 1783 1784 LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry) 1785 { 1786 if (id == spy->id && spy->spy) 1787 return spy; 1788 } 1789 1790 return NULL; 1791 } 1792 1793 /* 1794 * When locked, don't modify list (unless we add a new head), so that it's 1795 * safe to iterate it. Freeing of list entries is delayed and done on unlock. 1796 */ 1797 static inline void lock_init_spies(struct oletls *info) 1798 { 1799 info->spies_lock++; 1800 } 1801 1802 static void unlock_init_spies(struct oletls *info) 1803 { 1804 struct init_spy *spy, *next; 1805 1806 if (--info->spies_lock) return; 1807 1808 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry) 1809 { 1810 if (spy->spy) continue; 1811 list_remove(&spy->entry); 1812 heap_free(spy); 1813 } 1814 } 1815 1816 /****************************************************************************** 1817 * CoRegisterInitializeSpy [OLE32.@] 1818 * 1819 * Add a Spy that watches CoInitializeEx calls 1820 * 1821 * PARAMS 1822 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd. 1823 * cookie [II] cookie receiver 1824 * 1825 * RETURNS 1826 * Success: S_OK if not already initialized, S_FALSE otherwise. 1827 * Failure: HRESULT code. 1828 * 1829 * SEE ALSO 1830 * CoInitializeEx 1831 */ 1832 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) 1833 { 1834 struct oletls *info = COM_CurrentInfo(); 1835 struct init_spy *entry; 1836 unsigned int id; 1837 HRESULT hr; 1838 1839 TRACE("(%p, %p)\n", spy, cookie); 1840 1841 if (!spy || !cookie || !info) 1842 { 1843 if (!info) 1844 WARN("Could not allocate tls\n"); 1845 return E_INVALIDARG; 1846 } 1847 1848 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy); 1849 if (FAILED(hr)) 1850 return hr; 1851 1852 entry = heap_alloc(sizeof(*entry)); 1853 if (!entry) 1854 { 1855 IInitializeSpy_Release(spy); 1856 return E_OUTOFMEMORY; 1857 } 1858 1859 entry->spy = spy; 1860 1861 id = 0; 1862 while (get_spy_entry(info, id) != NULL) 1863 { 1864 id++; 1865 } 1866 1867 entry->id = id; 1868 list_add_head(&info->spies, &entry->entry); 1869 1870 cookie->s.HighPart = GetCurrentThreadId(); 1871 cookie->s.LowPart = entry->id; 1872 1873 return S_OK; 1874 } 1875 1876 /****************************************************************************** 1877 * CoRevokeInitializeSpy [OLE32.@] 1878 * 1879 * Remove a spy that previously watched CoInitializeEx calls 1880 * 1881 * PARAMS 1882 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call 1883 * 1884 * RETURNS 1885 * Success: S_OK if a spy is removed 1886 * Failure: E_INVALIDARG 1887 * 1888 * SEE ALSO 1889 * CoInitializeEx 1890 */ 1891 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) 1892 { 1893 struct oletls *info = COM_CurrentInfo(); 1894 struct init_spy *spy; 1895 1896 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart)); 1897 1898 if (!info || cookie.s.HighPart != GetCurrentThreadId()) 1899 return E_INVALIDARG; 1900 1901 if (!(spy = get_spy_entry(info, cookie.s.LowPart))) return E_INVALIDARG; 1902 1903 IInitializeSpy_Release(spy->spy); 1904 spy->spy = NULL; 1905 if (!info->spies_lock) 1906 { 1907 list_remove(&spy->entry); 1908 heap_free(spy); 1909 } 1910 return S_OK; 1911 } 1912 1913 HRESULT enter_apartment( struct oletls *info, DWORD model ) 1914 { 1915 HRESULT hr = S_OK; 1916 1917 if (!info->apt) 1918 { 1919 if (!apartment_get_or_create( model )) 1920 return E_OUTOFMEMORY; 1921 } 1922 else if (!apartment_is_model( info->apt, model )) 1923 { 1924 WARN( "Attempt to change threading model of this apartment from %s to %s\n", 1925 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded", 1926 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" ); 1927 return RPC_E_CHANGED_MODE; 1928 } 1929 else 1930 hr = S_FALSE; 1931 1932 info->inits++; 1933 1934 return hr; 1935 } 1936 1937 void leave_apartment( struct oletls *info ) 1938 { 1939 if (!--info->inits) 1940 { 1941 if (info->ole_inits) 1942 WARN( "Uninitializing apartment while Ole is still initialized\n" ); 1943 apartment_release( info->apt ); 1944 info->apt = NULL; 1945 } 1946 } 1947 1948 /****************************************************************************** 1949 * CoInitialize [OLE32.@] 1950 * 1951 * Initializes the COM libraries by calling CoInitializeEx with 1952 * COINIT_APARTMENTTHREADED, ie it enters a STA thread. 1953 * 1954 * PARAMS 1955 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1956 * 1957 * RETURNS 1958 * Success: S_OK if not already initialized, S_FALSE otherwise. 1959 * Failure: HRESULT code. 1960 * 1961 * SEE ALSO 1962 * CoInitializeEx 1963 */ 1964 HRESULT WINAPI CoInitialize(LPVOID lpReserved) 1965 { 1966 /* 1967 * Just delegate to the newer method. 1968 */ 1969 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); 1970 } 1971 1972 /****************************************************************************** 1973 * CoInitializeEx [OLE32.@] 1974 * 1975 * Initializes the COM libraries. 1976 * 1977 * PARAMS 1978 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 1979 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. 1980 * 1981 * RETURNS 1982 * S_OK if successful, 1983 * S_FALSE if this function was called already. 1984 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another 1985 * threading model. 1986 * 1987 * NOTES 1988 * 1989 * The behavior used to set the IMalloc used for memory management is 1990 * obsolete. 1991 * The dwCoInit parameter must specify one of the following apartment 1992 * threading models: 1993 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). 1994 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). 1995 * The parameter may also specify zero or more of the following flags: 1996 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. 1997 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. 1998 * 1999 * SEE ALSO 2000 * CoUninitialize 2001 */ 2002 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) 2003 { 2004 struct oletls *info = COM_CurrentInfo(); 2005 struct init_spy *cursor; 2006 HRESULT hr; 2007 2008 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); 2009 2010 if (lpReserved!=NULL) 2011 { 2012 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); 2013 } 2014 2015 /* 2016 * Check the lock count. If this is the first time going through the initialize 2017 * process, we have to initialize the libraries. 2018 * 2019 * And crank-up that lock count. 2020 */ 2021 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) 2022 { 2023 /* 2024 * Initialize the various COM libraries and data structures. 2025 */ 2026 TRACE("() - Initializing the COM libraries\n"); 2027 2028 /* we may need to defer this until after apartment initialisation */ 2029 RunningObjectTableImpl_Initialize(); 2030 } 2031 2032 lock_init_spies(info); 2033 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) 2034 { 2035 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits); 2036 } 2037 unlock_init_spies(info); 2038 2039 hr = enter_apartment( info, dwCoInit ); 2040 2041 lock_init_spies(info); 2042 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) 2043 { 2044 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits); 2045 } 2046 unlock_init_spies(info); 2047 2048 return hr; 2049 } 2050 2051 /*********************************************************************** 2052 * CoUninitialize [OLE32.@] 2053 * 2054 * This method will decrement the refcount on the current apartment, freeing 2055 * the resources associated with it if it is the last thread in the apartment. 2056 * If the last apartment is freed, the function will additionally release 2057 * any COM resources associated with the process. 2058 * 2059 * PARAMS 2060 * 2061 * RETURNS 2062 * Nothing. 2063 * 2064 * SEE ALSO 2065 * CoInitializeEx 2066 */ 2067 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) 2068 { 2069 struct oletls * info = COM_CurrentInfo(); 2070 struct init_spy *cursor, *next; 2071 LONG lCOMRefCnt; 2072 2073 TRACE("()\n"); 2074 2075 /* will only happen on OOM */ 2076 if (!info) return; 2077 2078 lock_init_spies(info); 2079 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry) 2080 { 2081 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits); 2082 } 2083 unlock_init_spies(info); 2084 2085 /* sanity check */ 2086 if (!info->inits) 2087 { 2088 ERR("Mismatched CoUninitialize\n"); 2089 2090 lock_init_spies(info); 2091 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry) 2092 { 2093 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits); 2094 } 2095 unlock_init_spies(info); 2096 2097 return; 2098 } 2099 2100 leave_apartment( info ); 2101 2102 /* 2103 * Decrease the reference count. 2104 * If we are back to 0 locks on the COM library, make sure we free 2105 * all the associated data structures. 2106 */ 2107 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); 2108 if (lCOMRefCnt==1) 2109 { 2110 TRACE("() - Releasing the COM libraries\n"); 2111 2112 revoke_registered_psclsids(); 2113 RunningObjectTableImpl_UnInitialize(); 2114 } 2115 else if (lCOMRefCnt<1) { 2116 ERR( "CoUninitialize() - not CoInitialized.\n" ); 2117 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ 2118 } 2119 2120 lock_init_spies(info); 2121 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) 2122 { 2123 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits); 2124 } 2125 unlock_init_spies(info); 2126 } 2127 2128 /****************************************************************************** 2129 * CoDisconnectObject [OLE32.@] 2130 * 2131 * Disconnects all connections to this object from remote processes. Dispatches 2132 * pending RPCs while blocking new RPCs from occurring, and then calls 2133 * IMarshal::DisconnectObject on the given object. 2134 * 2135 * Typically called when the object server is forced to shut down, for instance by 2136 * the user. 2137 * 2138 * PARAMS 2139 * lpUnk [I] The object whose stub should be disconnected. 2140 * reserved [I] Reserved. Should be set to 0. 2141 * 2142 * RETURNS 2143 * Success: S_OK. 2144 * Failure: HRESULT code. 2145 * 2146 * SEE ALSO 2147 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal 2148 */ 2149 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) 2150 { 2151 struct stub_manager *manager; 2152 HRESULT hr; 2153 IMarshal *marshal; 2154 APARTMENT *apt; 2155 2156 TRACE("(%p, 0x%08x)\n", lpUnk, reserved); 2157 2158 if (!lpUnk) return E_INVALIDARG; 2159 2160 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); 2161 if (hr == S_OK) 2162 { 2163 hr = IMarshal_DisconnectObject(marshal, reserved); 2164 IMarshal_Release(marshal); 2165 return hr; 2166 } 2167 2168 if (!(apt = apartment_get_current_or_mta())) 2169 { 2170 ERR("apartment not initialised\n"); 2171 return CO_E_NOTINITIALIZED; 2172 } 2173 2174 manager = get_stub_manager_from_object(apt, lpUnk, FALSE); 2175 if (manager) { 2176 stub_manager_disconnect(manager); 2177 /* Release stub manager twice, to remove the apartment reference. */ 2178 stub_manager_int_release(manager); 2179 stub_manager_int_release(manager); 2180 } 2181 2182 /* Note: native is pretty broken here because it just silently 2183 * fails, without returning an appropriate error code if the object was 2184 * not found, making apps think that the object was disconnected, when 2185 * it actually wasn't */ 2186 2187 apartment_release(apt); 2188 return S_OK; 2189 } 2190 2191 /****************************************************************************** 2192 * CoCreateGuid [OLE32.@] 2193 * 2194 * Simply forwards to UuidCreate in RPCRT4. 2195 * 2196 * PARAMS 2197 * pguid [O] Points to the GUID to initialize. 2198 * 2199 * RETURNS 2200 * Success: S_OK. 2201 * Failure: HRESULT code. 2202 * 2203 * SEE ALSO 2204 * UuidCreate 2205 */ 2206 HRESULT WINAPI CoCreateGuid(GUID *pguid) 2207 { 2208 DWORD status; 2209 2210 if(!pguid) return E_INVALIDARG; 2211 2212 status = UuidCreate(pguid); 2213 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK; 2214 return HRESULT_FROM_WIN32( status ); 2215 } 2216 2217 static inline BOOL is_valid_hex(WCHAR c) 2218 { 2219 if (!(((c >= '0') && (c <= '9')) || 2220 ((c >= 'a') && (c <= 'f')) || 2221 ((c >= 'A') && (c <= 'F')))) 2222 return FALSE; 2223 return TRUE; 2224 } 2225 2226 static const BYTE guid_conv_table[256] = 2227 { 2228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ 2229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 2230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 2231 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */ 2232 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ 2233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 2234 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */ 2235 }; 2236 2237 /* conversion helper for CLSIDFromString/IIDFromString */ 2238 static BOOL guid_from_string(LPCWSTR s, GUID *id) 2239 { 2240 int i; 2241 2242 if (!s || s[0]!='{') { 2243 memset( id, 0, sizeof (CLSID) ); 2244 if(!s) return TRUE; 2245 return FALSE; 2246 } 2247 2248 TRACE("%s -> %p\n", debugstr_w(s), id); 2249 2250 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 2251 2252 id->Data1 = 0; 2253 for (i = 1; i < 9; i++) { 2254 if (!is_valid_hex(s[i])) return FALSE; 2255 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]]; 2256 } 2257 if (s[9]!='-') return FALSE; 2258 2259 id->Data2 = 0; 2260 for (i = 10; i < 14; i++) { 2261 if (!is_valid_hex(s[i])) return FALSE; 2262 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]]; 2263 } 2264 if (s[14]!='-') return FALSE; 2265 2266 id->Data3 = 0; 2267 for (i = 15; i < 19; i++) { 2268 if (!is_valid_hex(s[i])) return FALSE; 2269 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]]; 2270 } 2271 if (s[19]!='-') return FALSE; 2272 2273 for (i = 20; i < 37; i+=2) { 2274 if (i == 24) { 2275 if (s[i]!='-') return FALSE; 2276 i++; 2277 } 2278 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE; 2279 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]]; 2280 } 2281 2282 if (s[37] == '}' && s[38] == '\0') 2283 return TRUE; 2284 2285 return FALSE; 2286 } 2287 2288 /*****************************************************************************/ 2289 2290 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) 2291 { 2292 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; 2293 WCHAR buf2[CHARS_IN_GUID]; 2294 LONG buf2len = sizeof(buf2); 2295 HKEY xhkey; 2296 WCHAR *buf; 2297 2298 memset(clsid, 0, sizeof(*clsid)); 2299 buf = HeapAlloc( GetProcessHeap(),0,(lstrlenW(progid)+8) * sizeof(WCHAR) ); 2300 if (!buf) return E_OUTOFMEMORY; 2301 lstrcpyW( buf, progid ); 2302 lstrcatW( buf, clsidW ); 2303 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) 2304 { 2305 HeapFree(GetProcessHeap(),0,buf); 2306 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); 2307 return CO_E_CLASSSTRING; 2308 } 2309 HeapFree(GetProcessHeap(),0,buf); 2310 2311 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len)) 2312 { 2313 RegCloseKey(xhkey); 2314 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); 2315 return CO_E_CLASSSTRING; 2316 } 2317 RegCloseKey(xhkey); 2318 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; 2319 } 2320 2321 /****************************************************************************** 2322 * CLSIDFromString [OLE32.@] 2323 * 2324 * Converts a unique identifier from its string representation into 2325 * the GUID struct. 2326 * 2327 * PARAMS 2328 * idstr [I] The string representation of the GUID. 2329 * id [O] GUID converted from the string. 2330 * 2331 * RETURNS 2332 * S_OK on success 2333 * CO_E_CLASSSTRING if idstr is not a valid CLSID 2334 * 2335 * SEE ALSO 2336 * StringFromCLSID 2337 */ 2338 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id ) 2339 { 2340 HRESULT ret = CO_E_CLASSSTRING; 2341 CLSID tmp_id; 2342 2343 if (!id) 2344 return E_INVALIDARG; 2345 2346 if (guid_from_string(idstr, id)) 2347 return S_OK; 2348 2349 /* It appears a ProgID is also valid */ 2350 ret = clsid_from_string_reg(idstr, &tmp_id); 2351 if(SUCCEEDED(ret)) 2352 *id = tmp_id; 2353 2354 return ret; 2355 } 2356 2357 /****************************************************************************** 2358 * IIDFromString [OLE32.@] 2359 * 2360 * Converts an interface identifier from its string representation to 2361 * the IID struct. 2362 * 2363 * PARAMS 2364 * idstr [I] The string representation of the GUID. 2365 * id [O] IID converted from the string. 2366 * 2367 * RETURNS 2368 * S_OK on success 2369 * CO_E_IIDSTRING if idstr is not a valid IID 2370 * 2371 * SEE ALSO 2372 * StringFromIID 2373 */ 2374 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid) 2375 { 2376 TRACE("%s -> %p\n", debugstr_w(s), iid); 2377 2378 if (!s) 2379 { 2380 memset(iid, 0, sizeof(*iid)); 2381 return S_OK; 2382 } 2383 2384 /* length mismatch is a special case */ 2385 if (lstrlenW(s) + 1 != CHARS_IN_GUID) 2386 return E_INVALIDARG; 2387 2388 if (s[0] != '{') 2389 return CO_E_IIDSTRING; 2390 2391 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING; 2392 } 2393 2394 /****************************************************************************** 2395 * StringFromCLSID [OLE32.@] 2396 * StringFromIID [OLE32.@] 2397 * 2398 * Converts a GUID into the respective string representation. 2399 * The target string is allocated using the OLE IMalloc. 2400 * 2401 * PARAMS 2402 * id [I] the GUID to be converted. 2403 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. 2404 * 2405 * RETURNS 2406 * S_OK 2407 * E_FAIL 2408 * 2409 * SEE ALSO 2410 * StringFromGUID2, CLSIDFromString 2411 */ 2412 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) 2413 { 2414 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY; 2415 StringFromGUID2( id, *idstr, CHARS_IN_GUID ); 2416 return S_OK; 2417 } 2418 2419 /****************************************************************************** 2420 * StringFromGUID2 [OLE32.@] 2421 * 2422 * Modified version of StringFromCLSID that allows you to specify max 2423 * buffer size. 2424 * 2425 * PARAMS 2426 * id [I] GUID to convert to string. 2427 * str [O] Buffer where the result will be stored. 2428 * cmax [I] Size of the buffer in characters. 2429 * 2430 * RETURNS 2431 * Success: The length of the resulting string in characters. 2432 * Failure: 0. 2433 */ 2434 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) 2435 { 2436 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-', 2437 '%','0','4','X','-','%','0','2','X','%','0','2','X','-', 2438 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', 2439 '%','0','2','X','%','0','2','X','}',0 }; 2440 if (!id || cmax < CHARS_IN_GUID) return 0; 2441 swprintf( str, formatW, id->Data1, id->Data2, id->Data3, 2442 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], 2443 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); 2444 return CHARS_IN_GUID; 2445 } 2446 2447 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */ 2448 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey) 2449 { 2450 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; 2451 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1]; 2452 LONG res; 2453 HKEY key; 2454 2455 lstrcpyW(path, wszCLSIDSlash); 2456 StringFromGUID2(clsid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID); 2457 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key); 2458 if (res == ERROR_FILE_NOT_FOUND) 2459 return REGDB_E_CLASSNOTREG; 2460 else if (res != ERROR_SUCCESS) 2461 return REGDB_E_READREGDB; 2462 2463 if (!keyname) 2464 { 2465 *subkey = key; 2466 return S_OK; 2467 } 2468 2469 res = open_classes_key(key, keyname, access, subkey); 2470 RegCloseKey(key); 2471 if (res == ERROR_FILE_NOT_FOUND) 2472 return REGDB_E_KEYMISSING; 2473 else if (res != ERROR_SUCCESS) 2474 return REGDB_E_READREGDB; 2475 2476 return S_OK; 2477 } 2478 2479 /* open HKCR\\AppId\\{string form of appid clsid} key */ 2480 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey) 2481 { 2482 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; 2483 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; 2484 DWORD res; 2485 WCHAR buf[CHARS_IN_GUID]; 2486 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID]; 2487 DWORD size; 2488 HKEY hkey; 2489 DWORD type; 2490 HRESULT hr; 2491 2492 /* read the AppID value under the class's key */ 2493 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey); 2494 if (FAILED(hr)) 2495 return hr; 2496 2497 size = sizeof(buf); 2498 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size); 2499 RegCloseKey(hkey); 2500 if (res == ERROR_FILE_NOT_FOUND) 2501 return REGDB_E_KEYMISSING; 2502 else if (res != ERROR_SUCCESS || type!=REG_SZ) 2503 return REGDB_E_READREGDB; 2504 2505 lstrcpyW(keyname, szAppIdKey); 2506 lstrcatW(keyname, buf); 2507 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey); 2508 if (res == ERROR_FILE_NOT_FOUND) 2509 return REGDB_E_KEYMISSING; 2510 else if (res != ERROR_SUCCESS) 2511 return REGDB_E_READREGDB; 2512 2513 return S_OK; 2514 } 2515 2516 /****************************************************************************** 2517 * ProgIDFromCLSID [OLE32.@] 2518 * 2519 * Converts a class id into the respective program ID. 2520 * 2521 * PARAMS 2522 * clsid [I] Class ID, as found in registry. 2523 * ppszProgID [O] Associated ProgID. 2524 * 2525 * RETURNS 2526 * S_OK 2527 * E_OUTOFMEMORY 2528 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID 2529 */ 2530 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID) 2531 { 2532 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0}; 2533 ACTCTX_SECTION_KEYED_DATA data; 2534 HKEY hkey; 2535 HRESULT ret; 2536 LONG progidlen = 0; 2537 2538 if (!ppszProgID) 2539 return E_INVALIDARG; 2540 2541 *ppszProgID = NULL; 2542 2543 data.cbSize = sizeof(data); 2544 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 2545 clsid, &data)) 2546 { 2547 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 2548 if (comclass->progid_len) 2549 { 2550 WCHAR *ptrW; 2551 2552 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR)); 2553 if (!*ppszProgID) return E_OUTOFMEMORY; 2554 2555 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset); 2556 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR)); 2557 return S_OK; 2558 } 2559 else 2560 return REGDB_E_CLASSNOTREG; 2561 } 2562 2563 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey); 2564 if (FAILED(ret)) 2565 return ret; 2566 2567 if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) 2568 ret = REGDB_E_CLASSNOTREG; 2569 2570 if (ret == S_OK) 2571 { 2572 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); 2573 if (*ppszProgID) 2574 { 2575 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) { 2576 ret = REGDB_E_CLASSNOTREG; 2577 CoTaskMemFree(*ppszProgID); 2578 *ppszProgID = NULL; 2579 } 2580 } 2581 else 2582 ret = E_OUTOFMEMORY; 2583 } 2584 2585 RegCloseKey(hkey); 2586 return ret; 2587 } 2588 2589 /****************************************************************************** 2590 * CLSIDFromProgID [OLE32.@] 2591 * 2592 * Converts a program id into the respective GUID. 2593 * 2594 * PARAMS 2595 * progid [I] Unicode program ID, as found in registry. 2596 * clsid [O] Associated CLSID. 2597 * 2598 * RETURNS 2599 * Success: S_OK 2600 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found. 2601 */ 2602 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) 2603 { 2604 ACTCTX_SECTION_KEYED_DATA data; 2605 2606 if (!progid || !clsid) 2607 return E_INVALIDARG; 2608 2609 data.cbSize = sizeof(data); 2610 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, 2611 progid, &data)) 2612 { 2613 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData; 2614 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset); 2615 *clsid = *alias; 2616 return S_OK; 2617 } 2618 2619 return clsid_from_string_reg(progid, clsid); 2620 } 2621 2622 /****************************************************************************** 2623 * CLSIDFromProgIDEx [OLE32.@] 2624 */ 2625 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid) 2626 { 2627 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid); 2628 2629 return CLSIDFromProgID(progid, clsid); 2630 } 2631 2632 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid) 2633 { 2634 HKEY hkey; 2635 WCHAR value[CHARS_IN_GUID]; 2636 DWORD len; 2637 2638 access |= KEY_READ; 2639 2640 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey)) 2641 return REGDB_E_IIDNOTREG; 2642 2643 len = sizeof(value); 2644 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len)) 2645 return REGDB_E_IIDNOTREG; 2646 RegCloseKey(hkey); 2647 2648 if (CLSIDFromString(value, pclsid) != NOERROR) 2649 return REGDB_E_IIDNOTREG; 2650 2651 return S_OK; 2652 } 2653 2654 /***************************************************************************** 2655 * CoGetPSClsid [OLE32.@] 2656 * 2657 * Retrieves the CLSID of the proxy/stub factory that implements 2658 * IPSFactoryBuffer for the specified interface. 2659 * 2660 * PARAMS 2661 * riid [I] Interface whose proxy/stub CLSID is to be returned. 2662 * pclsid [O] Where to store returned proxy/stub CLSID. 2663 * 2664 * RETURNS 2665 * S_OK 2666 * E_OUTOFMEMORY 2667 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed 2668 * 2669 * NOTES 2670 * 2671 * The standard marshaller activates the object with the CLSID 2672 * returned and uses the CreateProxy and CreateStub methods on its 2673 * IPSFactoryBuffer interface to construct the proxies and stubs for a 2674 * given object. 2675 * 2676 * CoGetPSClsid determines this CLSID by searching the 2677 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 2678 * in the registry and any interface id registered by 2679 * CoRegisterPSClsid within the current process. 2680 * 2681 * BUGS 2682 * 2683 * Native returns S_OK for interfaces with a key in HKCR\Interface, but 2684 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be 2685 * considered a bug in native unless an application depends on this (unlikely). 2686 * 2687 * SEE ALSO 2688 * CoRegisterPSClsid. 2689 */ 2690 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) 2691 { 2692 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0}; 2693 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; 2694 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)]; 2695 APARTMENT *apt; 2696 struct registered_psclsid *registered_psclsid; 2697 ACTCTX_SECTION_KEYED_DATA data; 2698 HRESULT hr; 2699 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; 2700 BOOL is_wow64; 2701 2702 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); 2703 2704 if (!(apt = apartment_get_current_or_mta())) 2705 { 2706 ERR("apartment not initialised\n"); 2707 return CO_E_NOTINITIALIZED; 2708 } 2709 apartment_release(apt); 2710 2711 if (!pclsid) 2712 return E_INVALIDARG; 2713 2714 EnterCriticalSection(&cs_registered_psclsid_list); 2715 2716 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2717 if (IsEqualIID(®istered_psclsid->iid, riid)) 2718 { 2719 *pclsid = registered_psclsid->clsid; 2720 LeaveCriticalSection(&cs_registered_psclsid_list); 2721 return S_OK; 2722 } 2723 2724 LeaveCriticalSection(&cs_registered_psclsid_list); 2725 2726 data.cbSize = sizeof(data); 2727 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION, 2728 riid, &data)) 2729 { 2730 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData; 2731 *pclsid = ifaceps->iid; 2732 return S_OK; 2733 } 2734 2735 /* Interface\\{string form of riid}\\ProxyStubClsid32 */ 2736 lstrcpyW(path, wszInterface); 2737 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID); 2738 lstrcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC); 2739 2740 hr = get_ps_clsid_from_registry(path, 0, pclsid); 2741 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || 2742 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))) 2743 hr = get_ps_clsid_from_registry(path, opposite, pclsid); 2744 2745 if (hr == S_OK) 2746 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); 2747 else 2748 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); 2749 2750 return hr; 2751 } 2752 2753 /***************************************************************************** 2754 * CoRegisterPSClsid [OLE32.@] 2755 * 2756 * Register a proxy/stub CLSID for the given interface in the current process 2757 * only. 2758 * 2759 * PARAMS 2760 * riid [I] Interface whose proxy/stub CLSID is to be registered. 2761 * rclsid [I] CLSID of the proxy/stub. 2762 * 2763 * RETURNS 2764 * Success: S_OK 2765 * Failure: E_OUTOFMEMORY 2766 * 2767 * NOTES 2768 * 2769 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid() 2770 * will be returned from other apartments in the same process. 2771 * 2772 * This function does not add anything to the registry and the effects are 2773 * limited to the lifetime of the current process. 2774 * 2775 * SEE ALSO 2776 * CoGetPSClsid. 2777 */ 2778 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) 2779 { 2780 APARTMENT *apt; 2781 struct registered_psclsid *registered_psclsid; 2782 2783 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); 2784 2785 if (!(apt = apartment_get_current_or_mta())) 2786 { 2787 ERR("apartment not initialised\n"); 2788 return CO_E_NOTINITIALIZED; 2789 } 2790 apartment_release(apt); 2791 2792 EnterCriticalSection(&cs_registered_psclsid_list); 2793 2794 LIST_FOR_EACH_ENTRY(registered_psclsid, ®istered_psclsid_list, struct registered_psclsid, entry) 2795 if (IsEqualIID(®istered_psclsid->iid, riid)) 2796 { 2797 registered_psclsid->clsid = *rclsid; 2798 LeaveCriticalSection(&cs_registered_psclsid_list); 2799 return S_OK; 2800 } 2801 2802 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid)); 2803 if (!registered_psclsid) 2804 { 2805 LeaveCriticalSection(&cs_registered_psclsid_list); 2806 return E_OUTOFMEMORY; 2807 } 2808 2809 registered_psclsid->iid = *riid; 2810 registered_psclsid->clsid = *rclsid; 2811 list_add_head(®istered_psclsid_list, ®istered_psclsid->entry); 2812 2813 LeaveCriticalSection(&cs_registered_psclsid_list); 2814 2815 return S_OK; 2816 } 2817 2818 2819 /*** 2820 * COM_GetRegisteredClassObject 2821 * 2822 * This internal method is used to scan the registered class list to 2823 * find a class object. 2824 * 2825 * Params: 2826 * rclsid Class ID of the class to find. 2827 * dwClsContext Class context to match. 2828 * ppv [out] returns a pointer to the class object. Complying 2829 * to normal COM usage, this method will increase the 2830 * reference count on this object. 2831 */ 2832 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, 2833 DWORD dwClsContext, LPUNKNOWN* ppUnk) 2834 { 2835 HRESULT hr = S_FALSE; 2836 RegisteredClass *curClass; 2837 2838 EnterCriticalSection( &csRegisteredClassList ); 2839 2840 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 2841 { 2842 /* 2843 * Check if we have a match on the class ID and context. 2844 */ 2845 if ((apt->oxid == curClass->apartment_id) && 2846 (dwClsContext & curClass->runContext) && 2847 IsEqualGUID(&(curClass->classIdentifier), rclsid)) 2848 { 2849 /* 2850 * We have a match, return the pointer to the class object. 2851 */ 2852 *ppUnk = curClass->classObject; 2853 2854 IUnknown_AddRef(curClass->classObject); 2855 2856 hr = S_OK; 2857 break; 2858 } 2859 } 2860 2861 LeaveCriticalSection( &csRegisteredClassList ); 2862 2863 return hr; 2864 } 2865 2866 /****************************************************************************** 2867 * CoRegisterClassObject [OLE32.@] 2868 * 2869 * Registers the class object for a given class ID. Servers housed in EXE 2870 * files use this method instead of exporting DllGetClassObject to allow 2871 * other code to connect to their objects. 2872 * 2873 * PARAMS 2874 * rclsid [I] CLSID of the object to register. 2875 * pUnk [I] IUnknown of the object. 2876 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. 2877 * flags [I] REGCLS flags indicating how connections are made. 2878 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. 2879 * 2880 * RETURNS 2881 * S_OK on success, 2882 * E_INVALIDARG if lpdwRegister or pUnk are NULL, 2883 * CO_E_OBJISREG if the object is already registered. We should not return this. 2884 * 2885 * SEE ALSO 2886 * CoRevokeClassObject, CoGetClassObject 2887 * 2888 * NOTES 2889 * In-process objects are only registered for the current apartment. 2890 * CoGetClassObject() and CoCreateInstance() will not return objects registered 2891 * in other apartments. 2892 * 2893 * BUGS 2894 * MSDN claims that multiple interface registrations are legal, but we 2895 * can't do that with our current implementation. 2896 */ 2897 HRESULT WINAPI CoRegisterClassObject( 2898 REFCLSID rclsid, 2899 LPUNKNOWN pUnk, 2900 DWORD dwClsContext, 2901 DWORD flags, 2902 LPDWORD lpdwRegister) 2903 { 2904 static LONG next_cookie; 2905 RegisteredClass* newClass; 2906 LPUNKNOWN foundObject; 2907 HRESULT hr; 2908 APARTMENT *apt; 2909 2910 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", 2911 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); 2912 2913 if ( (lpdwRegister==0) || (pUnk==0) ) 2914 return E_INVALIDARG; 2915 2916 if (!(apt = apartment_get_current_or_mta())) 2917 { 2918 ERR("COM was not initialized\n"); 2919 return CO_E_NOTINITIALIZED; 2920 } 2921 2922 *lpdwRegister = 0; 2923 2924 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what 2925 * differentiates the flag from REGCLS_MULTI_SEPARATE. */ 2926 if (flags & REGCLS_MULTIPLEUSE) 2927 dwClsContext |= CLSCTX_INPROC_SERVER; 2928 2929 /* 2930 * First, check if the class is already registered. 2931 * If it is, this should cause an error. 2932 */ 2933 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); 2934 if (hr == S_OK) { 2935 if (flags & REGCLS_MULTIPLEUSE) { 2936 if (dwClsContext & CLSCTX_LOCAL_SERVER) 2937 hr = CoLockObjectExternal(foundObject, TRUE, FALSE); 2938 IUnknown_Release(foundObject); 2939 apartment_release(apt); 2940 return hr; 2941 } 2942 IUnknown_Release(foundObject); 2943 ERR("object already registered for class %s\n", debugstr_guid(rclsid)); 2944 apartment_release(apt); 2945 return CO_E_OBJISREG; 2946 } 2947 2948 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); 2949 if ( newClass == NULL ) 2950 { 2951 apartment_release(apt); 2952 return E_OUTOFMEMORY; 2953 } 2954 2955 newClass->classIdentifier = *rclsid; 2956 newClass->apartment_id = apt->oxid; 2957 newClass->runContext = dwClsContext; 2958 newClass->connectFlags = flags; 2959 newClass->RpcRegistration = NULL; 2960 2961 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) 2962 newClass->dwCookie = InterlockedIncrement( &next_cookie ); 2963 2964 /* 2965 * Since we're making a copy of the object pointer, we have to increase its 2966 * reference count. 2967 */ 2968 newClass->classObject = pUnk; 2969 IUnknown_AddRef(newClass->classObject); 2970 2971 EnterCriticalSection( &csRegisteredClassList ); 2972 list_add_tail(&RegisteredClassList, &newClass->entry); 2973 LeaveCriticalSection( &csRegisteredClassList ); 2974 2975 *lpdwRegister = newClass->dwCookie; 2976 2977 if (dwClsContext & CLSCTX_LOCAL_SERVER) { 2978 IStream *marshal_stream; 2979 2980 hr = get_local_server_stream(apt, &marshal_stream); 2981 if(FAILED(hr)) 2982 { 2983 apartment_release(apt); 2984 return hr; 2985 } 2986 2987 hr = RPC_StartLocalServer(&newClass->classIdentifier, 2988 marshal_stream, 2989 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), 2990 &newClass->RpcRegistration); 2991 IStream_Release(marshal_stream); 2992 } 2993 apartment_release(apt); 2994 return S_OK; 2995 } 2996 2997 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data) 2998 { 2999 if (data->hkey) 3000 { 3001 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; 3002 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; 3003 static const WCHAR wszFree[] = {'F','r','e','e',0}; 3004 static const WCHAR wszBoth[] = {'B','o','t','h',0}; 3005 WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */]; 3006 DWORD dwLength = sizeof(threading_model); 3007 DWORD keytype; 3008 DWORD ret; 3009 3010 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength); 3011 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) 3012 threading_model[0] = '\0'; 3013 3014 if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment; 3015 if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free; 3016 if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both; 3017 3018 /* there's not specific handling for this case */ 3019 if (threading_model[0]) return ThreadingModel_Neutral; 3020 return ThreadingModel_No; 3021 } 3022 else 3023 return data->u.actctx.data->model; 3024 } 3025 3026 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata, 3027 REFCLSID rclsid, REFIID riid, 3028 BOOL hostifnecessary, void **ppv) 3029 { 3030 WCHAR dllpath[MAX_PATH+1]; 3031 BOOL apartment_threaded; 3032 3033 if (hostifnecessary) 3034 { 3035 enum comclass_threadingmodel model = get_threading_model(regdata); 3036 3037 if (model == ThreadingModel_Apartment) 3038 { 3039 apartment_threaded = TRUE; 3040 if (apt->multi_threaded) 3041 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv); 3042 } 3043 else if (model == ThreadingModel_Free) 3044 { 3045 apartment_threaded = FALSE; 3046 if (!apt->multi_threaded) 3047 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv); 3048 } 3049 /* everything except "Apartment", "Free" and "Both" */ 3050 else if (model != ThreadingModel_Both) 3051 { 3052 apartment_threaded = TRUE; 3053 /* everything else is main-threaded */ 3054 if (model != ThreadingModel_No) 3055 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid)); 3056 3057 if (apt->multi_threaded || !apt->main) 3058 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv); 3059 } 3060 else 3061 apartment_threaded = FALSE; 3062 } 3063 else 3064 apartment_threaded = !apt->multi_threaded; 3065 3066 if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath))) 3067 { 3068 /* failure: CLSID is not found in registry */ 3069 WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); 3070 return REGDB_E_CLASSNOTREG; 3071 } 3072 3073 return apartment_getclassobject(apt, dllpath, apartment_threaded, 3074 rclsid, riid, ppv); 3075 } 3076 3077 /*********************************************************************** 3078 * CoGetClassObject [OLE32.@] 3079 * 3080 * Creates an object of the specified class. 3081 * 3082 * PARAMS 3083 * rclsid [I] Class ID to create an instance of. 3084 * dwClsContext [I] Flags to restrict the location of the created instance. 3085 * pServerInfo [I] Optional. Details for connecting to a remote server. 3086 * iid [I] The ID of the interface of the instance to return. 3087 * ppv [O] On returns, contains a pointer to the specified interface of the object. 3088 * 3089 * RETURNS 3090 * Success: S_OK 3091 * Failure: HRESULT code. 3092 * 3093 * NOTES 3094 * The dwClsContext parameter can be one or more of the following: 3095 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 3096 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 3097 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 3098 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 3099 * 3100 * SEE ALSO 3101 * CoCreateInstance() 3102 */ 3103 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( 3104 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, 3105 REFIID iid, LPVOID *ppv) 3106 { 3107 struct class_reg_data clsreg; 3108 IUnknown *regClassObject; 3109 HRESULT hres = E_UNEXPECTED; 3110 APARTMENT *apt; 3111 3112 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); 3113 3114 if (!ppv) 3115 return E_INVALIDARG; 3116 3117 *ppv = NULL; 3118 3119 if (!(apt = apartment_get_current_or_mta())) 3120 { 3121 ERR("apartment not initialised\n"); 3122 return CO_E_NOTINITIALIZED; 3123 } 3124 3125 if (pServerInfo) { 3126 FIXME("pServerInfo->name=%s pAuthInfo=%p\n", 3127 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo); 3128 } 3129 3130 if (CLSCTX_INPROC_SERVER & dwClsContext) 3131 { 3132 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) 3133 { 3134 apartment_release(apt); 3135 return FTMarshalCF_Create(iid, ppv); 3136 } 3137 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) 3138 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv); 3139 } 3140 3141 if (CLSCTX_INPROC & dwClsContext) 3142 { 3143 ACTCTX_SECTION_KEYED_DATA data; 3144 3145 data.cbSize = sizeof(data); 3146 /* search activation context first */ 3147 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, 3148 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, 3149 rclsid, &data)) 3150 { 3151 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData; 3152 3153 clsreg.u.actctx.hactctx = data.hActCtx; 3154 clsreg.u.actctx.data = data.lpData; 3155 clsreg.u.actctx.section = data.lpSectionBase; 3156 clsreg.hkey = FALSE; 3157 3158 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3159 ReleaseActCtx(data.hActCtx); 3160 apartment_release(apt); 3161 return hres; 3162 } 3163 } 3164 3165 /* 3166 * First, try and see if we can't match the class ID with one of the 3167 * registered classes. 3168 */ 3169 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, 3170 ®ClassObject)) 3171 { 3172 /* Get the required interface from the retrieved pointer. */ 3173 hres = IUnknown_QueryInterface(regClassObject, iid, ppv); 3174 3175 /* 3176 * Since QI got another reference on the pointer, we want to release the 3177 * one we already have. If QI was unsuccessful, this will release the object. This 3178 * is good since we are not returning it in the "out" parameter. 3179 */ 3180 IUnknown_Release(regClassObject); 3181 apartment_release(apt); 3182 return hres; 3183 } 3184 3185 /* First try in-process server */ 3186 if (CLSCTX_INPROC_SERVER & dwClsContext) 3187 { 3188 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 3189 HKEY hkey; 3190 3191 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey); 3192 if (FAILED(hres)) 3193 { 3194 if (hres == REGDB_E_CLASSNOTREG) 3195 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3196 else if (hres == REGDB_E_KEYMISSING) 3197 { 3198 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid)); 3199 hres = REGDB_E_CLASSNOTREG; 3200 } 3201 } 3202 3203 if (SUCCEEDED(hres)) 3204 { 3205 clsreg.u.hkey = hkey; 3206 clsreg.hkey = TRUE; 3207 3208 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3209 RegCloseKey(hkey); 3210 } 3211 3212 /* return if we got a class, otherwise fall through to one of the 3213 * other types */ 3214 if (SUCCEEDED(hres)) 3215 { 3216 apartment_release(apt); 3217 return hres; 3218 } 3219 } 3220 3221 /* Next try in-process handler */ 3222 if (CLSCTX_INPROC_HANDLER & dwClsContext) 3223 { 3224 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 3225 HKEY hkey; 3226 3227 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 3228 if (FAILED(hres)) 3229 { 3230 if (hres == REGDB_E_CLASSNOTREG) 3231 ERR("class %s not registered\n", debugstr_guid(rclsid)); 3232 else if (hres == REGDB_E_KEYMISSING) 3233 { 3234 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid)); 3235 hres = REGDB_E_CLASSNOTREG; 3236 } 3237 } 3238 3239 if (SUCCEEDED(hres)) 3240 { 3241 clsreg.u.hkey = hkey; 3242 clsreg.hkey = TRUE; 3243 3244 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 3245 RegCloseKey(hkey); 3246 } 3247 3248 /* return if we got a class, otherwise fall through to one of the 3249 * other types */ 3250 if (SUCCEEDED(hres)) 3251 { 3252 apartment_release(apt); 3253 return hres; 3254 } 3255 } 3256 apartment_release(apt); 3257 3258 /* Next try out of process */ 3259 if (CLSCTX_LOCAL_SERVER & dwClsContext) 3260 { 3261 hres = RPC_GetLocalClassObject(rclsid,iid,ppv); 3262 if (SUCCEEDED(hres)) 3263 return hres; 3264 } 3265 3266 /* Finally try remote: this requires networked DCOM (a lot of work) */ 3267 if (CLSCTX_REMOTE_SERVER & dwClsContext) 3268 { 3269 FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); 3270 hres = REGDB_E_CLASSNOTREG; 3271 } 3272 3273 if (FAILED(hres)) 3274 ERR("no class object %s could be created for context 0x%x\n", 3275 debugstr_guid(rclsid), dwClsContext); 3276 return hres; 3277 } 3278 3279 /*********************************************************************** 3280 * CoResumeClassObjects (OLE32.@) 3281 * 3282 * Resumes all class objects registered with REGCLS_SUSPENDED. 3283 * 3284 * RETURNS 3285 * Success: S_OK. 3286 * Failure: HRESULT code. 3287 */ 3288 HRESULT WINAPI CoResumeClassObjects(void) 3289 { 3290 FIXME("stub\n"); 3291 return S_OK; 3292 } 3293 3294 /*********************************************************************** 3295 * CoCreateInstance [OLE32.@] 3296 * 3297 * Creates an instance of the specified class. 3298 * 3299 * PARAMS 3300 * rclsid [I] Class ID to create an instance of. 3301 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object. 3302 * dwClsContext [I] Flags to restrict the location of the created instance. 3303 * iid [I] The ID of the interface of the instance to return. 3304 * ppv [O] On returns, contains a pointer to the specified interface of the instance. 3305 * 3306 * RETURNS 3307 * Success: S_OK 3308 * Failure: HRESULT code. 3309 * 3310 * NOTES 3311 * The dwClsContext parameter can be one or more of the following: 3312 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 3313 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 3314 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 3315 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 3316 * 3317 * Aggregation is the concept of deferring the IUnknown of an object to another 3318 * object. This allows a separate object to behave as though it was part of 3319 * the object and to allow this the pUnkOuter parameter can be set. Note that 3320 * not all objects support having an outer of unknown. 3321 * 3322 * SEE ALSO 3323 * CoGetClassObject() 3324 */ 3325 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance( 3326 REFCLSID rclsid, 3327 LPUNKNOWN pUnkOuter, 3328 DWORD dwClsContext, 3329 REFIID iid, 3330 LPVOID *ppv) 3331 { 3332 MULTI_QI multi_qi = { iid }; 3333 HRESULT hres; 3334 3335 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), 3336 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv); 3337 3338 if (ppv==0) 3339 return E_POINTER; 3340 3341 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi); 3342 *ppv = multi_qi.pItf; 3343 return hres; 3344 } 3345 3346 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr) 3347 { 3348 ULONG i; 3349 3350 for (i = 0; i < count; i++) 3351 { 3352 mqi[i].pItf = NULL; 3353 mqi[i].hr = hr; 3354 } 3355 } 3356 3357 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk) 3358 { 3359 ULONG index = 0, fetched = 0; 3360 3361 if (include_unk) 3362 { 3363 mqi[0].hr = S_OK; 3364 mqi[0].pItf = unk; 3365 index = fetched = 1; 3366 } 3367 3368 for (; index < count; index++) 3369 { 3370 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf); 3371 if (mqi[index].hr == S_OK) 3372 fetched++; 3373 } 3374 3375 if (!include_unk) 3376 IUnknown_Release(unk); 3377 3378 if (fetched == 0) 3379 return E_NOINTERFACE; 3380 3381 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES; 3382 } 3383 3384 /*********************************************************************** 3385 * CoCreateInstanceEx [OLE32.@] 3386 */ 3387 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx( 3388 REFCLSID rclsid, 3389 LPUNKNOWN pUnkOuter, 3390 DWORD dwClsContext, 3391 COSERVERINFO* pServerInfo, 3392 ULONG cmq, 3393 MULTI_QI* pResults) 3394 { 3395 IUnknown *unk = NULL; 3396 IClassFactory *cf; 3397 APARTMENT *apt; 3398 CLSID clsid; 3399 HRESULT hres; 3400 3401 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults); 3402 3403 if (!cmq || !pResults) 3404 return E_INVALIDARG; 3405 3406 if (pServerInfo) 3407 FIXME("() non-NULL pServerInfo not supported!\n"); 3408 3409 init_multi_qi(cmq, pResults, E_NOINTERFACE); 3410 3411 hres = CoGetTreatAsClass(rclsid, &clsid); 3412 if(FAILED(hres)) 3413 clsid = *rclsid; 3414 3415 if (!(apt = apartment_get_current_or_mta())) 3416 { 3417 ERR("apartment not initialised\n"); 3418 return CO_E_NOTINITIALIZED; 3419 } 3420 apartment_release(apt); 3421 3422 /* 3423 * The Standard Global Interface Table (GIT) object is a process-wide singleton. 3424 */ 3425 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable)) 3426 { 3427 IGlobalInterfaceTable *git = get_std_git(); 3428 TRACE("Retrieving GIT\n"); 3429 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE); 3430 } 3431 3432 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) { 3433 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk); 3434 if (FAILED(hres)) 3435 return hres; 3436 return return_multi_qi(unk, cmq, pResults, TRUE); 3437 } 3438 3439 /* 3440 * Get a class factory to construct the object we want. 3441 */ 3442 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf); 3443 if (FAILED(hres)) 3444 return hres; 3445 3446 /* 3447 * Create the object and don't forget to release the factory 3448 */ 3449 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk); 3450 IClassFactory_Release(cf); 3451 if (FAILED(hres)) 3452 { 3453 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter) 3454 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid)); 3455 else 3456 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", 3457 debugstr_guid(pResults[0].pIID), 3458 debugstr_guid(&clsid),hres); 3459 return hres; 3460 } 3461 3462 return return_multi_qi(unk, cmq, pResults, TRUE); 3463 } 3464 3465 /*********************************************************************** 3466 * CoGetInstanceFromFile [OLE32.@] 3467 */ 3468 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile( 3469 COSERVERINFO *server_info, 3470 CLSID *rclsid, 3471 IUnknown *outer, 3472 DWORD cls_context, 3473 DWORD grfmode, 3474 OLECHAR *filename, 3475 DWORD count, 3476 MULTI_QI *results 3477 ) 3478 { 3479 IPersistFile *pf = NULL; 3480 IUnknown* unk = NULL; 3481 CLSID clsid; 3482 HRESULT hr; 3483 3484 if (count == 0 || !results) 3485 return E_INVALIDARG; 3486 3487 if (server_info) 3488 FIXME("() non-NULL server_info not supported\n"); 3489 3490 init_multi_qi(count, results, E_NOINTERFACE); 3491 3492 /* optionally get CLSID from a file */ 3493 if (!rclsid) 3494 { 3495 hr = GetClassFile(filename, &clsid); 3496 if (FAILED(hr)) 3497 { 3498 ERR("failed to get CLSID from a file\n"); 3499 return hr; 3500 } 3501 3502 rclsid = &clsid; 3503 } 3504 3505 hr = CoCreateInstance(rclsid, 3506 outer, 3507 cls_context, 3508 &IID_IUnknown, 3509 (void**)&unk); 3510 3511 if (hr != S_OK) 3512 { 3513 init_multi_qi(count, results, hr); 3514 return hr; 3515 } 3516 3517 /* init from file */ 3518 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf); 3519 if (FAILED(hr)) 3520 { 3521 init_multi_qi(count, results, hr); 3522 IUnknown_Release(unk); 3523 return hr; 3524 } 3525 3526 hr = IPersistFile_Load(pf, filename, grfmode); 3527 IPersistFile_Release(pf); 3528 if (SUCCEEDED(hr)) 3529 return return_multi_qi(unk, count, results, FALSE); 3530 else 3531 { 3532 init_multi_qi(count, results, hr); 3533 IUnknown_Release(unk); 3534 return hr; 3535 } 3536 } 3537 3538 /*********************************************************************** 3539 * CoGetInstanceFromIStorage [OLE32.@] 3540 */ 3541 HRESULT WINAPI CoGetInstanceFromIStorage( 3542 COSERVERINFO *server_info, 3543 CLSID *rclsid, 3544 IUnknown *outer, 3545 DWORD cls_context, 3546 IStorage *storage, 3547 DWORD count, 3548 MULTI_QI *results 3549 ) 3550 { 3551 IPersistStorage *ps = NULL; 3552 IUnknown* unk = NULL; 3553 STATSTG stat; 3554 HRESULT hr; 3555 3556 if (count == 0 || !results || !storage) 3557 return E_INVALIDARG; 3558 3559 if (server_info) 3560 FIXME("() non-NULL server_info not supported\n"); 3561 3562 init_multi_qi(count, results, E_NOINTERFACE); 3563 3564 /* optionally get CLSID from a file */ 3565 if (!rclsid) 3566 { 3567 memset(&stat.clsid, 0, sizeof(stat.clsid)); 3568 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME); 3569 if (FAILED(hr)) 3570 { 3571 ERR("failed to get CLSID from a file\n"); 3572 return hr; 3573 } 3574 3575 rclsid = &stat.clsid; 3576 } 3577 3578 hr = CoCreateInstance(rclsid, 3579 outer, 3580 cls_context, 3581 &IID_IUnknown, 3582 (void**)&unk); 3583 3584 if (hr != S_OK) 3585 return hr; 3586 3587 /* init from IStorage */ 3588 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps); 3589 if (FAILED(hr)) 3590 ERR("failed to get IPersistStorage\n"); 3591 3592 if (ps) 3593 { 3594 IPersistStorage_Load(ps, storage); 3595 IPersistStorage_Release(ps); 3596 } 3597 3598 return return_multi_qi(unk, count, results, FALSE); 3599 } 3600 3601 /*********************************************************************** 3602 * CoLoadLibrary (OLE32.@) 3603 * 3604 * Loads a library. 3605 * 3606 * PARAMS 3607 * lpszLibName [I] Path to library. 3608 * bAutoFree [I] Whether the library should automatically be freed. 3609 * 3610 * RETURNS 3611 * Success: Handle to loaded library. 3612 * Failure: NULL. 3613 * 3614 * SEE ALSO 3615 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3616 */ 3617 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) 3618 { 3619 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); 3620 3621 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 3622 } 3623 3624 /*********************************************************************** 3625 * CoFreeLibrary [OLE32.@] 3626 * 3627 * Unloads a library from memory. 3628 * 3629 * PARAMS 3630 * hLibrary [I] Handle to library to unload. 3631 * 3632 * RETURNS 3633 * Nothing 3634 * 3635 * SEE ALSO 3636 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 3637 */ 3638 void WINAPI CoFreeLibrary(HINSTANCE hLibrary) 3639 { 3640 FreeLibrary(hLibrary); 3641 } 3642 3643 3644 /*********************************************************************** 3645 * CoFreeAllLibraries [OLE32.@] 3646 * 3647 * Function for backwards compatibility only. Does nothing. 3648 * 3649 * RETURNS 3650 * Nothing. 3651 * 3652 * SEE ALSO 3653 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries 3654 */ 3655 void WINAPI CoFreeAllLibraries(void) 3656 { 3657 /* NOP */ 3658 } 3659 3660 /*********************************************************************** 3661 * CoFreeUnusedLibrariesEx [OLE32.@] 3662 * 3663 * Frees any previously unused libraries whose delay has expired and marks 3664 * currently unused libraries for unloading. Unused are identified as those that 3665 * return S_OK from their DllCanUnloadNow function. 3666 * 3667 * PARAMS 3668 * dwUnloadDelay [I] Unload delay in milliseconds. 3669 * dwReserved [I] Reserved. Set to 0. 3670 * 3671 * RETURNS 3672 * Nothing. 3673 * 3674 * SEE ALSO 3675 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3676 */ 3677 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) 3678 { 3679 struct apartment *apt = COM_CurrentApt(); 3680 if (!apt) 3681 { 3682 ERR("apartment not initialised\n"); 3683 return; 3684 } 3685 3686 apartment_freeunusedlibraries(apt, dwUnloadDelay); 3687 } 3688 3689 /*********************************************************************** 3690 * CoFreeUnusedLibraries [OLE32.@] 3691 * 3692 * Frees any unused libraries. Unused are identified as those that return 3693 * S_OK from their DllCanUnloadNow function. 3694 * 3695 * RETURNS 3696 * Nothing. 3697 * 3698 * SEE ALSO 3699 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 3700 */ 3701 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void) 3702 { 3703 CoFreeUnusedLibrariesEx(INFINITE, 0); 3704 } 3705 3706 /*********************************************************************** 3707 * CoFileTimeNow [OLE32.@] 3708 * 3709 * Retrieves the current time in FILETIME format. 3710 * 3711 * PARAMS 3712 * lpFileTime [O] The current time. 3713 * 3714 * RETURNS 3715 * S_OK. 3716 */ 3717 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) 3718 { 3719 GetSystemTimeAsFileTime( lpFileTime ); 3720 return S_OK; 3721 } 3722 3723 /****************************************************************************** 3724 * CoLockObjectExternal [OLE32.@] 3725 * 3726 * Increments or decrements the external reference count of a stub object. 3727 * 3728 * PARAMS 3729 * pUnk [I] Stub object. 3730 * fLock [I] If TRUE then increments the external ref-count, 3731 * otherwise decrements. 3732 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of 3733 * calling CoDisconnectObject. 3734 * 3735 * RETURNS 3736 * Success: S_OK. 3737 * Failure: HRESULT code. 3738 * 3739 * NOTES 3740 * If fLock is TRUE and an object is passed in that doesn't have a stub 3741 * manager then a new stub manager is created for the object. 3742 */ 3743 HRESULT WINAPI CoLockObjectExternal( 3744 LPUNKNOWN pUnk, 3745 BOOL fLock, 3746 BOOL fLastUnlockReleases) 3747 { 3748 struct stub_manager *stubmgr; 3749 struct apartment *apt; 3750 3751 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", 3752 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); 3753 3754 if (!(apt = apartment_get_current_or_mta())) 3755 { 3756 ERR("apartment not initialised\n"); 3757 return CO_E_NOTINITIALIZED; 3758 } 3759 3760 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock); 3761 if (!stubmgr) 3762 { 3763 WARN("stub object not found %p\n", pUnk); 3764 /* Note: native is pretty broken here because it just silently 3765 * fails, without returning an appropriate error code, making apps 3766 * think that the object was disconnected, when it actually wasn't */ 3767 apartment_release(apt); 3768 return S_OK; 3769 } 3770 3771 if (fLock) 3772 stub_manager_ext_addref(stubmgr, 1, FALSE); 3773 else 3774 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases); 3775 3776 stub_manager_int_release(stubmgr); 3777 apartment_release(apt); 3778 return S_OK; 3779 } 3780 3781 /*********************************************************************** 3782 * CoInitializeWOW (OLE32.@) 3783 * 3784 * WOW equivalent of CoInitialize? 3785 * 3786 * PARAMS 3787 * x [I] Unknown. 3788 * y [I] Unknown. 3789 * 3790 * RETURNS 3791 * Unknown. 3792 */ 3793 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) 3794 { 3795 FIXME("(0x%08x,0x%08x),stub!\n",x,y); 3796 return 0; 3797 } 3798 3799 /*********************************************************************** 3800 * CoGetState [OLE32.@] 3801 * 3802 * Retrieves the thread state object previously stored by CoSetState(). 3803 * 3804 * PARAMS 3805 * ppv [I] Address where pointer to object will be stored. 3806 * 3807 * RETURNS 3808 * Success: S_OK. 3809 * Failure: E_OUTOFMEMORY. 3810 * 3811 * NOTES 3812 * Crashes on all invalid ppv addresses, including NULL. 3813 * If the function returns a non-NULL object then the caller must release its 3814 * reference on the object when the object is no longer required. 3815 * 3816 * SEE ALSO 3817 * CoSetState(). 3818 */ 3819 HRESULT WINAPI CoGetState(IUnknown ** ppv) 3820 { 3821 struct oletls *info = COM_CurrentInfo(); 3822 if (!info) return E_OUTOFMEMORY; 3823 3824 *ppv = NULL; 3825 3826 if (info->state) 3827 { 3828 IUnknown_AddRef(info->state); 3829 *ppv = info->state; 3830 TRACE("apt->state=%p\n", info->state); 3831 } 3832 3833 return S_OK; 3834 } 3835 3836 /*********************************************************************** 3837 * CoSetState [OLE32.@] 3838 * 3839 * Sets the thread state object. 3840 * 3841 * PARAMS 3842 * pv [I] Pointer to state object to be stored. 3843 * 3844 * NOTES 3845 * The system keeps a reference on the object while the object stored. 3846 * 3847 * RETURNS 3848 * Success: S_OK. 3849 * Failure: E_OUTOFMEMORY. 3850 */ 3851 HRESULT WINAPI CoSetState(IUnknown * pv) 3852 { 3853 struct oletls *info = COM_CurrentInfo(); 3854 if (!info) return E_OUTOFMEMORY; 3855 3856 if (pv) IUnknown_AddRef(pv); 3857 3858 if (info->state) 3859 { 3860 TRACE("-- release %p now\n", info->state); 3861 IUnknown_Release(info->state); 3862 } 3863 3864 info->state = pv; 3865 3866 return S_OK; 3867 } 3868 3869 3870 /****************************************************************************** 3871 * CoTreatAsClass [OLE32.@] 3872 * 3873 * Sets the TreatAs value of a class. 3874 * 3875 * PARAMS 3876 * clsidOld [I] Class to set TreatAs value on. 3877 * clsidNew [I] The class the clsidOld should be treated as. 3878 * 3879 * RETURNS 3880 * Success: S_OK. 3881 * Failure: HRESULT code. 3882 * 3883 * SEE ALSO 3884 * CoGetTreatAsClass 3885 */ 3886 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) 3887 { 3888 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0}; 3889 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3890 HKEY hkey = NULL; 3891 WCHAR szClsidNew[CHARS_IN_GUID]; 3892 HRESULT res = S_OK; 3893 WCHAR auto_treat_as[CHARS_IN_GUID]; 3894 LONG auto_treat_as_size = sizeof(auto_treat_as); 3895 CLSID id; 3896 3897 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); 3898 if (FAILED(res)) 3899 goto done; 3900 3901 if (IsEqualGUID( clsidOld, clsidNew )) 3902 { 3903 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) && 3904 CLSIDFromString(auto_treat_as, &id) == S_OK) 3905 { 3906 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as))) 3907 { 3908 res = REGDB_E_WRITEREGDB; 3909 goto done; 3910 } 3911 } 3912 else 3913 { 3914 if(RegDeleteKeyW(hkey, wszTreatAs)) 3915 res = REGDB_E_WRITEREGDB; 3916 goto done; 3917 } 3918 } 3919 else 3920 { 3921 if(IsEqualGUID(clsidNew, &CLSID_NULL)){ 3922 RegDeleteKeyW(hkey, wszTreatAs); 3923 }else{ 3924 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){ 3925 WARN("StringFromGUID2 failed\n"); 3926 res = E_FAIL; 3927 goto done; 3928 } 3929 3930 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){ 3931 WARN("RegSetValue failed\n"); 3932 res = REGDB_E_WRITEREGDB; 3933 goto done; 3934 } 3935 } 3936 } 3937 3938 done: 3939 if (hkey) RegCloseKey(hkey); 3940 return res; 3941 } 3942 3943 /****************************************************************************** 3944 * CoGetTreatAsClass [OLE32.@] 3945 * 3946 * Gets the TreatAs value of a class. 3947 * 3948 * PARAMS 3949 * clsidOld [I] Class to get the TreatAs value of. 3950 * clsidNew [I] The class the clsidOld should be treated as. 3951 * 3952 * RETURNS 3953 * Success: S_OK. 3954 * Failure: HRESULT code. 3955 * 3956 * SEE ALSO 3957 * CoSetTreatAsClass 3958 */ 3959 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) 3960 { 3961 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 3962 HKEY hkey = NULL; 3963 WCHAR szClsidNew[CHARS_IN_GUID]; 3964 HRESULT res = S_OK; 3965 LONG len = sizeof(szClsidNew); 3966 3967 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); 3968 3969 if (!clsidOld || !clsidNew) 3970 return E_INVALIDARG; 3971 3972 *clsidNew = *clsidOld; /* copy over old value */ 3973 3974 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey); 3975 if (FAILED(res)) 3976 { 3977 res = S_FALSE; 3978 goto done; 3979 } 3980 if (RegQueryValueW(hkey, NULL, szClsidNew, &len)) 3981 { 3982 res = S_FALSE; 3983 goto done; 3984 } 3985 res = CLSIDFromString(szClsidNew,clsidNew); 3986 if (FAILED(res)) 3987 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res); 3988 done: 3989 if (hkey) RegCloseKey(hkey); 3990 return res; 3991 } 3992 3993 /****************************************************************************** 3994 * CoGetCurrentProcess [OLE32.@] 3995 * 3996 * Gets the current process ID. 3997 * 3998 * RETURNS 3999 * The current process ID. 4000 * 4001 * NOTES 4002 * Is DWORD really the correct return type for this function? 4003 */ 4004 DWORD WINAPI CoGetCurrentProcess(void) 4005 { 4006 return GetCurrentProcessId(); 4007 } 4008 4009 /*********************************************************************** 4010 * CoGetCurrentLogicalThreadId [OLE32.@] 4011 */ 4012 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id) 4013 { 4014 TRACE("(%p)\n", id); 4015 4016 if (!id) 4017 return E_INVALIDARG; 4018 4019 *id = COM_CurrentCausalityId(); 4020 return S_OK; 4021 } 4022 4023 /****************************************************************************** 4024 * CoRegisterMessageFilter [OLE32.@] 4025 * 4026 * Registers a message filter. 4027 * 4028 * PARAMS 4029 * lpMessageFilter [I] Pointer to interface. 4030 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. 4031 * 4032 * RETURNS 4033 * Success: S_OK. 4034 * Failure: HRESULT code. 4035 * 4036 * NOTES 4037 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL 4038 * lpMessageFilter removes the message filter. 4039 * 4040 * If lplpMessageFilter is not NULL the previous message filter will be 4041 * returned in the memory pointer to this parameter and the caller is 4042 * responsible for releasing the object. 4043 * 4044 * The current thread be in an apartment otherwise the function will crash. 4045 */ 4046 HRESULT WINAPI CoRegisterMessageFilter( 4047 LPMESSAGEFILTER lpMessageFilter, 4048 LPMESSAGEFILTER *lplpMessageFilter) 4049 { 4050 struct apartment *apt; 4051 IMessageFilter *lpOldMessageFilter; 4052 4053 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); 4054 4055 apt = COM_CurrentApt(); 4056 4057 /* can't set a message filter in a multi-threaded apartment */ 4058 if (!apt || apt->multi_threaded) 4059 { 4060 WARN("can't set message filter in MTA or uninitialized apt\n"); 4061 return CO_E_NOT_SUPPORTED; 4062 } 4063 4064 if (lpMessageFilter) 4065 IMessageFilter_AddRef(lpMessageFilter); 4066 4067 EnterCriticalSection(&apt->cs); 4068 4069 lpOldMessageFilter = apt->filter; 4070 apt->filter = lpMessageFilter; 4071 4072 LeaveCriticalSection(&apt->cs); 4073 4074 if (lplpMessageFilter) 4075 *lplpMessageFilter = lpOldMessageFilter; 4076 else if (lpOldMessageFilter) 4077 IMessageFilter_Release(lpOldMessageFilter); 4078 4079 return S_OK; 4080 } 4081 4082 /*********************************************************************** 4083 * CoIsOle1Class [OLE32.@] 4084 * 4085 * Determines whether the specified class an OLE v1 class. 4086 * 4087 * PARAMS 4088 * clsid [I] Class to test. 4089 * 4090 * RETURNS 4091 * TRUE if the class is an OLE v1 class, or FALSE otherwise. 4092 */ 4093 BOOL WINAPI CoIsOle1Class(REFCLSID clsid) 4094 { 4095 FIXME("%s\n", debugstr_guid(clsid)); 4096 return FALSE; 4097 } 4098 4099 /*********************************************************************** 4100 * IsEqualGUID [OLE32.@] 4101 * 4102 * Compares two Unique Identifiers. 4103 * 4104 * PARAMS 4105 * rguid1 [I] The first GUID to compare. 4106 * rguid2 [I] The other GUID to compare. 4107 * 4108 * RETURNS 4109 * TRUE if equal 4110 */ 4111 #undef IsEqualGUID 4112 BOOL WINAPI IsEqualGUID( 4113 REFGUID rguid1, 4114 REFGUID rguid2) 4115 { 4116 return !memcmp(rguid1,rguid2,sizeof(GUID)); 4117 } 4118 4119 /*********************************************************************** 4120 * CoInitializeSecurity [OLE32.@] 4121 */ 4122 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, 4123 SOLE_AUTHENTICATION_SERVICE* asAuthSvc, 4124 void* pReserved1, DWORD dwAuthnLevel, 4125 DWORD dwImpLevel, void* pReserved2, 4126 DWORD dwCapabilities, void* pReserved3) 4127 { 4128 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc, 4129 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, 4130 dwCapabilities, pReserved3); 4131 return S_OK; 4132 } 4133 4134 /*********************************************************************** 4135 * CoSuspendClassObjects [OLE32.@] 4136 * 4137 * Suspends all registered class objects to prevent further requests coming in 4138 * for those objects. 4139 * 4140 * RETURNS 4141 * Success: S_OK. 4142 * Failure: HRESULT code. 4143 */ 4144 HRESULT WINAPI CoSuspendClassObjects(void) 4145 { 4146 FIXME("\n"); 4147 return S_OK; 4148 } 4149 4150 /*********************************************************************** 4151 * CoAddRefServerProcess [OLE32.@] 4152 * 4153 * Helper function for incrementing the reference count of a local-server 4154 * process. 4155 * 4156 * RETURNS 4157 * New reference count. 4158 * 4159 * SEE ALSO 4160 * CoReleaseServerProcess(). 4161 */ 4162 ULONG WINAPI CoAddRefServerProcess(void) 4163 { 4164 ULONG refs; 4165 4166 TRACE("\n"); 4167 4168 EnterCriticalSection(&csRegisteredClassList); 4169 refs = ++s_COMServerProcessReferences; 4170 LeaveCriticalSection(&csRegisteredClassList); 4171 4172 TRACE("refs before: %d\n", refs - 1); 4173 4174 return refs; 4175 } 4176 4177 /*********************************************************************** 4178 * CoReleaseServerProcess [OLE32.@] 4179 * 4180 * Helper function for decrementing the reference count of a local-server 4181 * process. 4182 * 4183 * RETURNS 4184 * New reference count. 4185 * 4186 * NOTES 4187 * When reference count reaches 0, this function suspends all registered 4188 * classes so no new connections are accepted. 4189 * 4190 * SEE ALSO 4191 * CoAddRefServerProcess(), CoSuspendClassObjects(). 4192 */ 4193 ULONG WINAPI CoReleaseServerProcess(void) 4194 { 4195 ULONG refs; 4196 4197 TRACE("\n"); 4198 4199 EnterCriticalSection(&csRegisteredClassList); 4200 4201 refs = --s_COMServerProcessReferences; 4202 /* FIXME: if (!refs) COM_SuspendClassObjects(); */ 4203 4204 LeaveCriticalSection(&csRegisteredClassList); 4205 4206 TRACE("refs after: %d\n", refs); 4207 4208 return refs; 4209 } 4210 4211 /*********************************************************************** 4212 * CoIsHandlerConnected [OLE32.@] 4213 * 4214 * Determines whether a proxy is connected to a remote stub. 4215 * 4216 * PARAMS 4217 * pUnk [I] Pointer to object that may or may not be connected. 4218 * 4219 * RETURNS 4220 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or 4221 * FALSE otherwise. 4222 */ 4223 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) 4224 { 4225 FIXME("%p\n", pUnk); 4226 4227 return TRUE; 4228 } 4229 4230 /*********************************************************************** 4231 * CoAllowSetForegroundWindow [OLE32.@] 4232 * 4233 */ 4234 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved) 4235 { 4236 FIXME("(%p, %p): stub\n", pUnk, pvReserved); 4237 return S_OK; 4238 } 4239 4240 /*********************************************************************** 4241 * CoQueryProxyBlanket [OLE32.@] 4242 * 4243 * Retrieves the security settings being used by a proxy. 4244 * 4245 * PARAMS 4246 * pProxy [I] Pointer to the proxy object. 4247 * pAuthnSvc [O] The type of authentication service. 4248 * pAuthzSvc [O] The type of authorization service. 4249 * ppServerPrincName [O] Optional. The server prinicple name. 4250 * pAuthnLevel [O] The authentication level. 4251 * pImpLevel [O] The impersonation level. 4252 * ppAuthInfo [O] Information specific to the authorization/authentication service. 4253 * pCapabilities [O] Flags affecting the security behaviour. 4254 * 4255 * RETURNS 4256 * Success: S_OK. 4257 * Failure: HRESULT code. 4258 * 4259 * SEE ALSO 4260 * CoCopyProxy, CoSetProxyBlanket. 4261 */ 4262 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, 4263 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, 4264 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) 4265 { 4266 IClientSecurity *pCliSec; 4267 HRESULT hr; 4268 4269 TRACE("%p\n", pProxy); 4270 4271 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4272 if (SUCCEEDED(hr)) 4273 { 4274 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, 4275 pAuthzSvc, ppServerPrincName, 4276 pAuthnLevel, pImpLevel, ppAuthInfo, 4277 pCapabilities); 4278 IClientSecurity_Release(pCliSec); 4279 } 4280 4281 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4282 return hr; 4283 } 4284 4285 /*********************************************************************** 4286 * CoSetProxyBlanket [OLE32.@] 4287 * 4288 * Sets the security settings for a proxy. 4289 * 4290 * PARAMS 4291 * pProxy [I] Pointer to the proxy object. 4292 * AuthnSvc [I] The type of authentication service. 4293 * AuthzSvc [I] The type of authorization service. 4294 * pServerPrincName [I] The server prinicple name. 4295 * AuthnLevel [I] The authentication level. 4296 * ImpLevel [I] The impersonation level. 4297 * pAuthInfo [I] Information specific to the authorization/authentication service. 4298 * Capabilities [I] Flags affecting the security behaviour. 4299 * 4300 * RETURNS 4301 * Success: S_OK. 4302 * Failure: HRESULT code. 4303 * 4304 * SEE ALSO 4305 * CoQueryProxyBlanket, CoCopyProxy. 4306 */ 4307 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, 4308 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, 4309 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) 4310 { 4311 IClientSecurity *pCliSec; 4312 HRESULT hr; 4313 4314 TRACE("%p\n", pProxy); 4315 4316 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4317 if (SUCCEEDED(hr)) 4318 { 4319 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, 4320 AuthzSvc, pServerPrincName, 4321 AuthnLevel, ImpLevel, pAuthInfo, 4322 Capabilities); 4323 IClientSecurity_Release(pCliSec); 4324 } 4325 4326 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4327 return hr; 4328 } 4329 4330 /*********************************************************************** 4331 * CoCopyProxy [OLE32.@] 4332 * 4333 * Copies a proxy. 4334 * 4335 * PARAMS 4336 * pProxy [I] Pointer to the proxy object. 4337 * ppCopy [O] Copy of the proxy. 4338 * 4339 * RETURNS 4340 * Success: S_OK. 4341 * Failure: HRESULT code. 4342 * 4343 * SEE ALSO 4344 * CoQueryProxyBlanket, CoSetProxyBlanket. 4345 */ 4346 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) 4347 { 4348 IClientSecurity *pCliSec; 4349 HRESULT hr; 4350 4351 TRACE("%p\n", pProxy); 4352 4353 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 4354 if (SUCCEEDED(hr)) 4355 { 4356 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); 4357 IClientSecurity_Release(pCliSec); 4358 } 4359 4360 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 4361 return hr; 4362 } 4363 4364 4365 /*********************************************************************** 4366 * CoGetCallContext [OLE32.@] 4367 * 4368 * Gets the context of the currently executing server call in the current 4369 * thread. 4370 * 4371 * PARAMS 4372 * riid [I] Context interface to return. 4373 * ppv [O] Pointer to memory that will receive the context on return. 4374 * 4375 * RETURNS 4376 * Success: S_OK. 4377 * Failure: HRESULT code. 4378 */ 4379 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) 4380 { 4381 struct oletls *info = COM_CurrentInfo(); 4382 4383 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 4384 4385 if (!info) 4386 return E_OUTOFMEMORY; 4387 4388 if (!info->call_state) 4389 return RPC_E_CALL_COMPLETE; 4390 4391 return IUnknown_QueryInterface(info->call_state, riid, ppv); 4392 } 4393 4394 /*********************************************************************** 4395 * CoSwitchCallContext [OLE32.@] 4396 * 4397 * Switches the context of the currently executing server call in the current 4398 * thread. 4399 * 4400 * PARAMS 4401 * pObject [I] Pointer to new context object 4402 * ppOldObject [O] Pointer to memory that will receive old context object pointer 4403 * 4404 * RETURNS 4405 * Success: S_OK. 4406 * Failure: HRESULT code. 4407 */ 4408 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject) 4409 { 4410 struct oletls *info = COM_CurrentInfo(); 4411 4412 TRACE("(%p, %p)\n", pObject, ppOldObject); 4413 4414 if (!info) 4415 return E_OUTOFMEMORY; 4416 4417 *ppOldObject = info->call_state; 4418 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */ 4419 4420 return S_OK; 4421 } 4422 4423 /*********************************************************************** 4424 * CoQueryClientBlanket [OLE32.@] 4425 * 4426 * Retrieves the authentication information about the client of the currently 4427 * executing server call in the current thread. 4428 * 4429 * PARAMS 4430 * pAuthnSvc [O] Optional. The type of authentication service. 4431 * pAuthzSvc [O] Optional. The type of authorization service. 4432 * pServerPrincName [O] Optional. The server prinicple name. 4433 * pAuthnLevel [O] Optional. The authentication level. 4434 * pImpLevel [O] Optional. The impersonation level. 4435 * pPrivs [O] Optional. Information about the privileges of the client. 4436 * pCapabilities [IO] Optional. Flags affecting the security behaviour. 4437 * 4438 * RETURNS 4439 * Success: S_OK. 4440 * Failure: HRESULT code. 4441 * 4442 * SEE ALSO 4443 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext. 4444 */ 4445 HRESULT WINAPI CoQueryClientBlanket( 4446 DWORD *pAuthnSvc, 4447 DWORD *pAuthzSvc, 4448 OLECHAR **pServerPrincName, 4449 DWORD *pAuthnLevel, 4450 DWORD *pImpLevel, 4451 RPC_AUTHZ_HANDLE *pPrivs, 4452 DWORD *pCapabilities) 4453 { 4454 IServerSecurity *pSrvSec; 4455 HRESULT hr; 4456 4457 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n", 4458 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, 4459 pPrivs, pCapabilities); 4460 4461 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4462 if (SUCCEEDED(hr)) 4463 { 4464 hr = IServerSecurity_QueryBlanket( 4465 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, 4466 pImpLevel, pPrivs, pCapabilities); 4467 IServerSecurity_Release(pSrvSec); 4468 } 4469 4470 return hr; 4471 } 4472 4473 /*********************************************************************** 4474 * CoImpersonateClient [OLE32.@] 4475 * 4476 * Impersonates the client of the currently executing server call in the 4477 * current thread. 4478 * 4479 * PARAMS 4480 * None. 4481 * 4482 * RETURNS 4483 * Success: S_OK. 4484 * Failure: HRESULT code. 4485 * 4486 * NOTES 4487 * If this function fails then the current thread will not be impersonating 4488 * the client and all actions will take place on behalf of the server. 4489 * Therefore, it is important to check the return value from this function. 4490 * 4491 * SEE ALSO 4492 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext. 4493 */ 4494 HRESULT WINAPI CoImpersonateClient(void) 4495 { 4496 IServerSecurity *pSrvSec; 4497 HRESULT hr; 4498 4499 TRACE("\n"); 4500 4501 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4502 if (SUCCEEDED(hr)) 4503 { 4504 hr = IServerSecurity_ImpersonateClient(pSrvSec); 4505 IServerSecurity_Release(pSrvSec); 4506 } 4507 4508 return hr; 4509 } 4510 4511 /*********************************************************************** 4512 * CoRevertToSelf [OLE32.@] 4513 * 4514 * Ends the impersonation of the client of the currently executing server 4515 * call in the current thread. 4516 * 4517 * PARAMS 4518 * None. 4519 * 4520 * RETURNS 4521 * Success: S_OK. 4522 * Failure: HRESULT code. 4523 * 4524 * SEE ALSO 4525 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext. 4526 */ 4527 HRESULT WINAPI CoRevertToSelf(void) 4528 { 4529 IServerSecurity *pSrvSec; 4530 HRESULT hr; 4531 4532 TRACE("\n"); 4533 4534 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 4535 if (SUCCEEDED(hr)) 4536 { 4537 hr = IServerSecurity_RevertToSelf(pSrvSec); 4538 IServerSecurity_Release(pSrvSec); 4539 } 4540 4541 return hr; 4542 } 4543 4544 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg) 4545 { 4546 /* first try to retrieve messages for incoming COM calls to the apartment window */ 4547 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) || 4548 /* next retrieve other messages necessary for the app to remain responsive */ 4549 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) || 4550 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD); 4551 } 4552 4553 /*********************************************************************** 4554 * CoWaitForMultipleHandles [OLE32.@] 4555 * 4556 * Waits for one or more handles to become signaled. 4557 * 4558 * PARAMS 4559 * dwFlags [I] Flags. See notes. 4560 * dwTimeout [I] Timeout in milliseconds. 4561 * cHandles [I] Number of handles pointed to by pHandles. 4562 * pHandles [I] Handles to wait for. 4563 * lpdwindex [O] Index of handle that was signaled. 4564 * 4565 * RETURNS 4566 * Success: S_OK. 4567 * Failure: RPC_S_CALLPENDING on timeout. 4568 * 4569 * NOTES 4570 * 4571 * The dwFlags parameter can be zero or more of the following: 4572 *| COWAIT_WAITALL - Wait for all of the handles to become signaled. 4573 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. 4574 * 4575 * SEE ALSO 4576 * MsgWaitForMultipleObjects, WaitForMultipleObjects. 4577 */ 4578 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, 4579 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex) 4580 { 4581 HRESULT hr = S_OK; 4582 DWORD start_time = GetTickCount(); 4583 APARTMENT *apt = COM_CurrentApt(); 4584 BOOL message_loop = apt && !apt->multi_threaded; 4585 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0; 4586 BOOL post_quit = FALSE; 4587 UINT exit_code; 4588 4589 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, 4590 pHandles, lpdwindex); 4591 4592 if (!lpdwindex) 4593 return E_INVALIDARG; 4594 4595 *lpdwindex = 0; 4596 4597 if (!pHandles) 4598 return E_INVALIDARG; 4599 4600 if (!cHandles) 4601 return RPC_E_NO_SYNC; 4602 4603 while (TRUE) 4604 { 4605 DWORD now = GetTickCount(); 4606 DWORD res; 4607 4608 if (now - start_time > dwTimeout) 4609 { 4610 hr = RPC_S_CALLPENDING; 4611 break; 4612 } 4613 4614 if (message_loop) 4615 { 4616 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) | 4617 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0); 4618 4619 TRACE("waiting for rpc completion or window message\n"); 4620 4621 res = WAIT_TIMEOUT; 4622 4623 if (check_apc) 4624 { 4625 res = WaitForMultipleObjectsEx(cHandles, pHandles, 4626 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE); 4627 check_apc = FALSE; 4628 } 4629 4630 if (res == WAIT_TIMEOUT) 4631 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, 4632 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4633 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); 4634 4635 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ 4636 { 4637 MSG msg; 4638 int count = 0; 4639 4640 /* call message filter */ 4641 4642 if (COM_CurrentApt()->filter) 4643 { 4644 PENDINGTYPE pendingtype = 4645 COM_CurrentInfo()->pending_call_count_server ? 4646 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; 4647 DWORD be_handled = IMessageFilter_MessagePending( 4648 COM_CurrentApt()->filter, 0 /* FIXME */, 4649 now - start_time, pendingtype); 4650 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); 4651 switch (be_handled) 4652 { 4653 case PENDINGMSG_CANCELCALL: 4654 WARN("call canceled\n"); 4655 hr = RPC_E_CALL_CANCELED; 4656 break; 4657 case PENDINGMSG_WAITNOPROCESS: 4658 case PENDINGMSG_WAITDEFPROCESS: 4659 default: 4660 /* FIXME: MSDN is very vague about the difference 4661 * between WAITNOPROCESS and WAITDEFPROCESS - there 4662 * appears to be none, so it is possibly a left-over 4663 * from the 16-bit world. */ 4664 break; 4665 } 4666 } 4667 4668 if (!apt->win) 4669 { 4670 /* If window is NULL on apartment, peek at messages so that it will not trigger 4671 * MsgWaitForMultipleObjects next time. */ 4672 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD); 4673 } 4674 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, 4675 * so after processing 100 messages we go back to checking the wait handles */ 4676 while (count++ < 100 && COM_PeekMessage(apt, &msg)) 4677 { 4678 if (msg.message == WM_QUIT) 4679 { 4680 TRACE("received WM_QUIT message\n"); 4681 post_quit = TRUE; 4682 exit_code = msg.wParam; 4683 } 4684 else 4685 { 4686 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); 4687 TranslateMessage(&msg); 4688 DispatchMessageW(&msg); 4689 } 4690 } 4691 continue; 4692 } 4693 } 4694 else 4695 { 4696 TRACE("waiting for rpc completion\n"); 4697 4698 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0, 4699 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 4700 (dwFlags & COWAIT_ALERTABLE) != 0); 4701 } 4702 4703 switch (res) 4704 { 4705 case WAIT_TIMEOUT: 4706 hr = RPC_S_CALLPENDING; 4707 break; 4708 case WAIT_FAILED: 4709 hr = HRESULT_FROM_WIN32( GetLastError() ); 4710 break; 4711 default: 4712 *lpdwindex = res; 4713 break; 4714 } 4715 break; 4716 } 4717 if (post_quit) PostQuitMessage(exit_code); 4718 TRACE("-- 0x%08x\n", hr); 4719 return hr; 4720 } 4721 4722 4723 /*********************************************************************** 4724 * CoGetObject [OLE32.@] 4725 * 4726 * Gets the object named by converting the name to a moniker and binding to it. 4727 * 4728 * PARAMS 4729 * pszName [I] String representing the object. 4730 * pBindOptions [I] Parameters affecting the binding to the named object. 4731 * riid [I] Interface to bind to on the objecct. 4732 * ppv [O] On output, the interface riid of the object represented 4733 * by pszName. 4734 * 4735 * RETURNS 4736 * Success: S_OK. 4737 * Failure: HRESULT code. 4738 * 4739 * SEE ALSO 4740 * MkParseDisplayName. 4741 */ 4742 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, 4743 REFIID riid, void **ppv) 4744 { 4745 IBindCtx *pbc; 4746 HRESULT hr; 4747 4748 *ppv = NULL; 4749 4750 hr = CreateBindCtx(0, &pbc); 4751 if (SUCCEEDED(hr)) 4752 { 4753 if (pBindOptions) 4754 hr = IBindCtx_SetBindOptions(pbc, pBindOptions); 4755 4756 if (SUCCEEDED(hr)) 4757 { 4758 ULONG chEaten; 4759 IMoniker *pmk; 4760 4761 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk); 4762 if (SUCCEEDED(hr)) 4763 { 4764 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv); 4765 IMoniker_Release(pmk); 4766 } 4767 } 4768 4769 IBindCtx_Release(pbc); 4770 } 4771 return hr; 4772 } 4773 4774 /*********************************************************************** 4775 * CoRegisterChannelHook [OLE32.@] 4776 * 4777 * Registers a process-wide hook that is called during ORPC calls. 4778 * 4779 * PARAMS 4780 * guidExtension [I] GUID of the channel hook to register. 4781 * pChannelHook [I] Channel hook object to register. 4782 * 4783 * RETURNS 4784 * Success: S_OK. 4785 * Failure: HRESULT code. 4786 */ 4787 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook) 4788 { 4789 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook); 4790 4791 return RPC_RegisterChannelHook(guidExtension, pChannelHook); 4792 } 4793 4794 typedef struct Context 4795 { 4796 IComThreadingInfo IComThreadingInfo_iface; 4797 IContextCallback IContextCallback_iface; 4798 IObjContext IObjContext_iface; 4799 LONG refs; 4800 } Context; 4801 4802 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface ) 4803 { 4804 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface); 4805 } 4806 4807 static inline Context *impl_from_IContextCallback( IContextCallback *iface ) 4808 { 4809 return CONTAINING_RECORD(iface, Context, IContextCallback_iface); 4810 } 4811 4812 static inline Context *impl_from_IObjContext( IObjContext *iface ) 4813 { 4814 return CONTAINING_RECORD(iface, Context, IObjContext_iface); 4815 } 4816 4817 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) 4818 { 4819 *ppv = NULL; 4820 4821 if (IsEqualIID(riid, &IID_IComThreadingInfo) || 4822 IsEqualIID(riid, &IID_IUnknown)) 4823 { 4824 *ppv = &iface->IComThreadingInfo_iface; 4825 } 4826 else if (IsEqualIID(riid, &IID_IContextCallback)) 4827 { 4828 *ppv = &iface->IContextCallback_iface; 4829 } 4830 else if (IsEqualIID(riid, &IID_IObjContext)) 4831 { 4832 *ppv = &iface->IObjContext_iface; 4833 } 4834 4835 if (*ppv) 4836 { 4837 IUnknown_AddRef((IUnknown*)*ppv); 4838 return S_OK; 4839 } 4840 4841 FIXME("interface not implemented %s\n", debugstr_guid(riid)); 4842 return E_NOINTERFACE; 4843 } 4844 4845 static ULONG Context_AddRef(Context *This) 4846 { 4847 return InterlockedIncrement(&This->refs); 4848 } 4849 4850 static ULONG Context_Release(Context *This) 4851 { 4852 /* Context instance is initially created with CoGetContextToken() with refcount set to 0, 4853 releasing context while refcount is at 0 destroys it. */ 4854 if (!This->refs) 4855 { 4856 HeapFree(GetProcessHeap(), 0, This); 4857 return 0; 4858 } 4859 4860 return InterlockedDecrement(&This->refs); 4861 } 4862 4863 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv) 4864 { 4865 Context *This = impl_from_IComThreadingInfo(iface); 4866 return Context_QueryInterface(This, riid, ppv); 4867 } 4868 4869 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface) 4870 { 4871 Context *This = impl_from_IComThreadingInfo(iface); 4872 return Context_AddRef(This); 4873 } 4874 4875 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface) 4876 { 4877 Context *This = impl_from_IComThreadingInfo(iface); 4878 return Context_Release(This); 4879 } 4880 4881 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) 4882 { 4883 APTTYPEQUALIFIER qualifier; 4884 4885 TRACE("(%p)\n", apttype); 4886 4887 return CoGetApartmentType(apttype, &qualifier); 4888 } 4889 4890 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype) 4891 { 4892 APTTYPEQUALIFIER qualifier; 4893 APTTYPE apttype; 4894 HRESULT hr; 4895 4896 hr = CoGetApartmentType(&apttype, &qualifier); 4897 if (FAILED(hr)) 4898 return hr; 4899 4900 TRACE("(%p)\n", thdtype); 4901 4902 switch (apttype) 4903 { 4904 case APTTYPE_STA: 4905 case APTTYPE_MAINSTA: 4906 *thdtype = THDTYPE_PROCESSMESSAGES; 4907 break; 4908 default: 4909 *thdtype = THDTYPE_BLOCKMESSAGES; 4910 break; 4911 } 4912 return S_OK; 4913 } 4914 4915 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id) 4916 { 4917 TRACE("(%p)\n", logical_thread_id); 4918 return CoGetCurrentLogicalThreadId(logical_thread_id); 4919 } 4920 4921 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) 4922 { 4923 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id)); 4924 return E_NOTIMPL; 4925 } 4926 4927 static const IComThreadingInfoVtbl Context_Threading_Vtbl = 4928 { 4929 Context_CTI_QueryInterface, 4930 Context_CTI_AddRef, 4931 Context_CTI_Release, 4932 Context_CTI_GetCurrentApartmentType, 4933 Context_CTI_GetCurrentThreadType, 4934 Context_CTI_GetCurrentLogicalThreadId, 4935 Context_CTI_SetCurrentLogicalThreadId 4936 }; 4937 4938 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv) 4939 { 4940 Context *This = impl_from_IContextCallback(iface); 4941 return Context_QueryInterface(This, riid, ppv); 4942 } 4943 4944 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface) 4945 { 4946 Context *This = impl_from_IContextCallback(iface); 4947 return Context_AddRef(This); 4948 } 4949 4950 static ULONG WINAPI Context_CC_Release(IContextCallback *iface) 4951 { 4952 Context *This = impl_from_IContextCallback(iface); 4953 return Context_Release(This); 4954 } 4955 4956 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback, 4957 ComCallData *param, REFIID riid, int method, IUnknown *punk) 4958 { 4959 Context *This = impl_from_IContextCallback(iface); 4960 4961 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk); 4962 return E_NOTIMPL; 4963 } 4964 4965 static const IContextCallbackVtbl Context_Callback_Vtbl = 4966 { 4967 Context_CC_QueryInterface, 4968 Context_CC_AddRef, 4969 Context_CC_Release, 4970 Context_CC_ContextCallback 4971 }; 4972 4973 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv) 4974 { 4975 Context *This = impl_from_IObjContext(iface); 4976 return Context_QueryInterface(This, riid, ppv); 4977 } 4978 4979 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface) 4980 { 4981 Context *This = impl_from_IObjContext(iface); 4982 return Context_AddRef(This); 4983 } 4984 4985 static ULONG WINAPI Context_OC_Release(IObjContext *iface) 4986 { 4987 Context *This = impl_from_IObjContext(iface); 4988 return Context_Release(This); 4989 } 4990 4991 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) 4992 { 4993 Context *This = impl_from_IObjContext(iface); 4994 4995 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 4996 return E_NOTIMPL; 4997 } 4998 4999 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid) 5000 { 5001 Context *This = impl_from_IObjContext(iface); 5002 5003 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid)); 5004 return E_NOTIMPL; 5005 } 5006 5007 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) 5008 { 5009 Context *This = impl_from_IObjContext(iface); 5010 5011 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 5012 return E_NOTIMPL; 5013 } 5014 5015 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props) 5016 { 5017 Context *This = impl_from_IObjContext(iface); 5018 5019 FIXME("(%p/%p)->(%p)\n", This, iface, props); 5020 return E_NOTIMPL; 5021 } 5022 5023 static void WINAPI Context_OC_Reserved1(IObjContext *iface) 5024 { 5025 Context *This = impl_from_IObjContext(iface); 5026 FIXME("(%p/%p)\n", This, iface); 5027 } 5028 5029 static void WINAPI Context_OC_Reserved2(IObjContext *iface) 5030 { 5031 Context *This = impl_from_IObjContext(iface); 5032 FIXME("(%p/%p)\n", This, iface); 5033 } 5034 5035 static void WINAPI Context_OC_Reserved3(IObjContext *iface) 5036 { 5037 Context *This = impl_from_IObjContext(iface); 5038 FIXME("(%p/%p)\n", This, iface); 5039 } 5040 5041 static void WINAPI Context_OC_Reserved4(IObjContext *iface) 5042 { 5043 Context *This = impl_from_IObjContext(iface); 5044 FIXME("(%p/%p)\n", This, iface); 5045 } 5046 5047 static void WINAPI Context_OC_Reserved5(IObjContext *iface) 5048 { 5049 Context *This = impl_from_IObjContext(iface); 5050 FIXME("(%p/%p)\n", This, iface); 5051 } 5052 5053 static void WINAPI Context_OC_Reserved6(IObjContext *iface) 5054 { 5055 Context *This = impl_from_IObjContext(iface); 5056 FIXME("(%p/%p)\n", This, iface); 5057 } 5058 5059 static void WINAPI Context_OC_Reserved7(IObjContext *iface) 5060 { 5061 Context *This = impl_from_IObjContext(iface); 5062 FIXME("(%p/%p)\n", This, iface); 5063 } 5064 5065 static const IObjContextVtbl Context_Object_Vtbl = 5066 { 5067 Context_OC_QueryInterface, 5068 Context_OC_AddRef, 5069 Context_OC_Release, 5070 Context_OC_SetProperty, 5071 Context_OC_RemoveProperty, 5072 Context_OC_GetProperty, 5073 Context_OC_EnumContextProps, 5074 Context_OC_Reserved1, 5075 Context_OC_Reserved2, 5076 Context_OC_Reserved3, 5077 Context_OC_Reserved4, 5078 Context_OC_Reserved5, 5079 Context_OC_Reserved6, 5080 Context_OC_Reserved7 5081 }; 5082 5083 /*********************************************************************** 5084 * CoGetObjectContext [OLE32.@] 5085 * 5086 * Retrieves an object associated with the current context (i.e. apartment). 5087 * 5088 * PARAMS 5089 * riid [I] ID of the interface of the object to retrieve. 5090 * ppv [O] Address where object will be stored on return. 5091 * 5092 * RETURNS 5093 * Success: S_OK. 5094 * Failure: HRESULT code. 5095 */ 5096 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) 5097 { 5098 IObjContext *context; 5099 HRESULT hr; 5100 5101 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 5102 5103 *ppv = NULL; 5104 hr = CoGetContextToken((ULONG_PTR*)&context); 5105 if (FAILED(hr)) 5106 return hr; 5107 5108 return IObjContext_QueryInterface(context, riid, ppv); 5109 } 5110 5111 /*********************************************************************** 5112 * CoGetContextToken [OLE32.@] 5113 */ 5114 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) 5115 { 5116 struct oletls *info = COM_CurrentInfo(); 5117 APARTMENT *apt; 5118 5119 TRACE("(%p)\n", token); 5120 5121 if (!info) 5122 return E_OUTOFMEMORY; 5123 5124 if (!(apt = apartment_get_current_or_mta())) 5125 { 5126 ERR("apartment not initialised\n"); 5127 return CO_E_NOTINITIALIZED; 5128 } 5129 apartment_release(apt); 5130 5131 if (!token) 5132 return E_POINTER; 5133 5134 if (!info->context_token) 5135 { 5136 Context *context; 5137 5138 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); 5139 if (!context) 5140 return E_OUTOFMEMORY; 5141 5142 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl; 5143 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl; 5144 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl; 5145 /* Context token does not take a reference, it's always zero until the 5146 interface is explicitly requested with CoGetObjectContext(). */ 5147 context->refs = 0; 5148 5149 info->context_token = &context->IObjContext_iface; 5150 } 5151 5152 *token = (ULONG_PTR)info->context_token; 5153 TRACE("context_token=%p\n", info->context_token); 5154 5155 return S_OK; 5156 } 5157 5158 /*********************************************************************** 5159 * CoGetDefaultContext [OLE32.@] 5160 */ 5161 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv) 5162 { 5163 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv); 5164 return E_NOINTERFACE; 5165 } 5166 5167 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 5168 { 5169 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 5170 HKEY hkey; 5171 HRESULT hres; 5172 5173 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 5174 if (SUCCEEDED(hres)) 5175 { 5176 struct class_reg_data regdata; 5177 WCHAR dllpath[MAX_PATH+1]; 5178 5179 regdata.u.hkey = hkey; 5180 regdata.hkey = TRUE; 5181 5182 if (get_object_dll_path(®data, dllpath, ARRAY_SIZE(dllpath))) 5183 { 5184 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 5185 if (!wcsicmp(dllpath, wszOle32)) 5186 { 5187 RegCloseKey(hkey); 5188 return HandlerCF_Create(rclsid, riid, ppv); 5189 } 5190 } 5191 else 5192 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); 5193 RegCloseKey(hkey); 5194 } 5195 5196 return CLASS_E_CLASSNOTAVAILABLE; 5197 } 5198 5199 /*********************************************************************** 5200 * CoGetApartmentType [OLE32.@] 5201 */ 5202 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) 5203 { 5204 struct oletls *info = COM_CurrentInfo(); 5205 APARTMENT *apt; 5206 5207 TRACE("(%p, %p)\n", type, qualifier); 5208 5209 if (!type || !qualifier) 5210 return E_INVALIDARG; 5211 5212 if (!info) 5213 return E_OUTOFMEMORY; 5214 5215 if (!info->apt) 5216 *type = APTTYPE_CURRENT; 5217 else if (info->apt->multi_threaded) 5218 *type = APTTYPE_MTA; 5219 else if (info->apt->main) 5220 *type = APTTYPE_MAINSTA; 5221 else 5222 *type = APTTYPE_STA; 5223 5224 *qualifier = APTTYPEQUALIFIER_NONE; 5225 5226 if (!info->apt && (apt = apartment_find_mta())) 5227 { 5228 apartment_release(apt); 5229 *type = APTTYPE_MTA; 5230 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; 5231 } 5232 5233 return info->apt ? S_OK : CO_E_NOTINITIALIZED; 5234 } 5235 5236 /*********************************************************************** 5237 * CoDisableCallCancellation [OLE32.@] 5238 */ 5239 HRESULT WINAPI CoDisableCallCancellation(void *reserved) 5240 { 5241 FIXME("(%p): stub\n", reserved); 5242 5243 return E_NOTIMPL; 5244 } 5245 5246 /*********************************************************************** 5247 * CoEnableCallCancellation [OLE32.@] 5248 */ 5249 HRESULT WINAPI CoEnableCallCancellation(void *reserved) 5250 { 5251 FIXME("(%p): stub\n", reserved); 5252 5253 return E_NOTIMPL; 5254 } 5255 5256 /*********************************************************************** 5257 * CoRegisterSurrogate [OLE32.@] 5258 */ 5259 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) 5260 { 5261 FIXME("(%p): stub\n", surrogate); 5262 5263 return E_NOTIMPL; 5264 } 5265 5266 /*********************************************************************** 5267 * CoRegisterSurrogateEx [OLE32.@] 5268 */ 5269 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) 5270 { 5271 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved); 5272 5273 return E_NOTIMPL; 5274 } 5275 5276 typedef struct { 5277 IGlobalOptions IGlobalOptions_iface; 5278 LONG ref; 5279 } GlobalOptions; 5280 5281 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface) 5282 { 5283 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface); 5284 } 5285 5286 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv) 5287 { 5288 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5289 5290 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 5291 5292 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid)) 5293 { 5294 *ppv = iface; 5295 } 5296 else 5297 { 5298 *ppv = NULL; 5299 return E_NOINTERFACE; 5300 } 5301 5302 IUnknown_AddRef((IUnknown*)*ppv); 5303 return S_OK; 5304 } 5305 5306 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface) 5307 { 5308 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5309 LONG ref = InterlockedIncrement(&This->ref); 5310 5311 TRACE("(%p) ref=%d\n", This, ref); 5312 5313 return ref; 5314 } 5315 5316 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface) 5317 { 5318 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5319 LONG ref = InterlockedDecrement(&This->ref); 5320 5321 TRACE("(%p) ref=%d\n", This, ref); 5322 5323 if (!ref) 5324 heap_free(This); 5325 5326 return ref; 5327 } 5328 5329 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value) 5330 { 5331 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5332 FIXME("(%p)->(%u %lx)\n", This, property, value); 5333 return S_OK; 5334 } 5335 5336 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value) 5337 { 5338 GlobalOptions *This = impl_from_IGlobalOptions(iface); 5339 FIXME("(%p)->(%u %p)\n", This, property, value); 5340 return E_NOTIMPL; 5341 } 5342 5343 static const IGlobalOptionsVtbl GlobalOptionsVtbl = { 5344 GlobalOptions_QueryInterface, 5345 GlobalOptions_AddRef, 5346 GlobalOptions_Release, 5347 GlobalOptions_Set, 5348 GlobalOptions_Query 5349 }; 5350 5351 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 5352 { 5353 GlobalOptions *global_options; 5354 HRESULT hres; 5355 5356 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); 5357 5358 if (outer) 5359 return E_INVALIDARG; 5360 5361 global_options = heap_alloc(sizeof(*global_options)); 5362 if (!global_options) 5363 return E_OUTOFMEMORY; 5364 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl; 5365 global_options->ref = 1; 5366 5367 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv); 5368 IGlobalOptions_Release(&global_options->IGlobalOptions_iface); 5369 return hres; 5370 } 5371 5372 /*********************************************************************** 5373 * DllMain (OLE32.@) 5374 */ 5375 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved) 5376 { 5377 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved); 5378 5379 switch(fdwReason) { 5380 case DLL_PROCESS_ATTACH: 5381 hProxyDll = hinstDLL; 5382 break; 5383 5384 case DLL_PROCESS_DETACH: 5385 if (reserved) break; 5386 release_std_git(); 5387 if(apt_win_class) 5388 UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll ); 5389 RPC_UnregisterAllChannelHooks(); 5390 COMPOBJ_DllList_Free(); 5391 DeleteCriticalSection(&csRegisteredClassList); 5392 DeleteCriticalSection(&csApartment); 5393 break; 5394 5395 case DLL_THREAD_DETACH: 5396 COM_TlsDestroy(); 5397 break; 5398 } 5399 return TRUE; 5400 } 5401 5402 /*********************************************************************** 5403 * DllRegisterServer (OLE32.@) 5404 */ 5405 HRESULT WINAPI DllRegisterServer(void) 5406 { 5407 return OLE32_DllRegisterServer(); 5408 } 5409 5410 /*********************************************************************** 5411 * DllUnregisterServer (OLE32.@) 5412 */ 5413 HRESULT WINAPI DllUnregisterServer(void) 5414 { 5415 return OLE32_DllUnregisterServer(); 5416 } 5417