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