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