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)
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.
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.
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
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
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
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
51 #define WIN32_NO_STATUS
57 #define USE_COM_CONTEXT_DEF
65 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
119 CLSID classIdentifier;
121 LPUNKNOWN classObject;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /* wrapper for NtCreateKey that creates the key recursively if necessary */
141 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
143 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
145 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
147 HANDLE subkey, root = attr->RootDirectory;
148 WCHAR *buffer = attr->ObjectName->Buffer;
149 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
152 while (i < len && buffer[i] != '\\') i++;
153 if (i == len) return status;
155 attrs = attr->Attributes;
156 attr->ObjectName = &str;
160 str.Buffer = buffer + pos;
161 str.Length = (i - pos) * sizeof(WCHAR);
162 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
163 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
164 if (status) return status;
165 attr->RootDirectory = subkey;
166 while (i < len && buffer[i] == '\\') i++;
168 while (i < len && buffer[i] != '\\') i++;
170 str.Buffer = buffer + pos;
171 str.Length = (i - pos) * sizeof(WCHAR);
172 attr->Attributes = attrs;
173 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
174 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
179 static const WCHAR classes_rootW[] =
180 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
182 static HKEY classes_root_hkey;
184 /* create the special HKEY_CLASSES_ROOT key */
185 static HKEY create_classes_root_hkey(void)
188 OBJECT_ATTRIBUTES attr;
191 attr.Length = sizeof(attr);
192 attr.RootDirectory = 0;
193 attr.ObjectName = &name;
195 attr.SecurityDescriptor = NULL;
196 attr.SecurityQualityOfService = NULL;
197 RtlInitUnicodeString( &name, classes_rootW );
198 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
199 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
201 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
204 NtClose( hkey ); /* somebody beat us to it */
208 /* map the hkey from special root to normal key if necessary */
209 static inline HKEY get_classes_root_hkey( HKEY hkey )
213 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
214 ret = create_classes_root_hkey();
219 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
221 OBJECT_ATTRIBUTES attr;
222 UNICODE_STRING nameW;
224 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
226 attr.Length = sizeof(attr);
227 attr.RootDirectory = hkey;
228 attr.ObjectName = &nameW;
230 attr.SecurityDescriptor = NULL;
231 attr.SecurityQualityOfService = NULL;
232 RtlInitUnicodeString( &nameW, name );
234 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
237 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
239 OBJECT_ATTRIBUTES attr;
240 UNICODE_STRING nameW;
242 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
244 attr.Length = sizeof(attr);
245 attr.RootDirectory = hkey;
246 attr.ObjectName = &nameW;
248 attr.SecurityDescriptor = NULL;
249 attr.SecurityQualityOfService = NULL;
250 RtlInitUnicodeString( &nameW, name );
252 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
255 /*****************************************************************************
256 * This section contains OpenDllList definitions
258 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
259 * other functions that do LoadLibrary _without_ giving back a HMODULE.
260 * Without this list these handles would never be freed.
262 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
263 * next unload-call but not before 600 sec.
266 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
267 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
269 typedef struct tagOpenDll
274 DllGetClassObjectFunc DllGetClassObject;
275 DllCanUnloadNowFunc DllCanUnloadNow;
279 static struct list openDllList = LIST_INIT(openDllList);
281 static CRITICAL_SECTION csOpenDllList;
282 static CRITICAL_SECTION_DEBUG dll_cs_debug =
284 0, 0, &csOpenDllList,
285 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
286 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
288 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
290 struct apartment_loaded_dll
298 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',' ',
299 '0','x','#','#','#','#','#','#','#','#',' ',0};
301 /*****************************************************************************
302 * This section contains OpenDllList implementation
305 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
309 EnterCriticalSection(&csOpenDllList);
310 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
312 if (!strcmpiW(library_name, ptr->library_name) &&
313 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
319 LeaveCriticalSection(&csOpenDllList);
323 /* caller must ensure that library_name is not already in the open dll list */
324 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
330 DllCanUnloadNowFunc DllCanUnloadNow;
331 DllGetClassObjectFunc DllGetClassObject;
335 *ret = COMPOBJ_DllList_Get(library_name);
336 if (*ret) return S_OK;
338 /* do this outside the csOpenDllList to avoid creating a lock dependency on
340 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
343 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
344 /* failure: DLL could not be loaded */
345 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
348 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
349 /* Note: failing to find DllCanUnloadNow is not a failure */
350 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
351 if (!DllGetClassObject)
353 /* failure: the dll did not export DllGetClassObject */
354 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
355 FreeLibrary(hLibrary);
356 return CO_E_DLLNOTFOUND;
359 EnterCriticalSection( &csOpenDllList );
361 *ret = COMPOBJ_DllList_Get(library_name);
364 /* another caller to this function already added the dll while we
365 * weren't in the critical section */
366 FreeLibrary(hLibrary);
370 len = strlenW(library_name);
371 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
373 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
374 if (entry && entry->library_name)
376 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
377 entry->library = hLibrary;
379 entry->DllCanUnloadNow = DllCanUnloadNow;
380 entry->DllGetClassObject = DllGetClassObject;
381 list_add_tail(&openDllList, &entry->entry);
385 HeapFree(GetProcessHeap(), 0, entry);
387 FreeLibrary(hLibrary);
392 LeaveCriticalSection( &csOpenDllList );
397 /* pass FALSE for free_entry to release a reference without destroying the
398 * entry if it reaches zero or TRUE otherwise */
399 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
401 if (!InterlockedDecrement(&entry->refs) && free_entry)
403 EnterCriticalSection(&csOpenDllList);
404 list_remove(&entry->entry);
405 LeaveCriticalSection(&csOpenDllList);
407 TRACE("freeing %p\n", entry->library);
408 FreeLibrary(entry->library);
410 HeapFree(GetProcessHeap(), 0, entry->library_name);
411 HeapFree(GetProcessHeap(), 0, entry);
415 /* frees memory associated with active dll list */
416 static void COMPOBJ_DllList_Free(void)
418 OpenDll *entry, *cursor2;
419 EnterCriticalSection(&csOpenDllList);
420 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
422 list_remove(&entry->entry);
424 HeapFree(GetProcessHeap(), 0, entry->library_name);
425 HeapFree(GetProcessHeap(), 0, entry);
427 LeaveCriticalSection(&csOpenDllList);
428 DeleteCriticalSection(&csOpenDllList);
431 /******************************************************************************
435 static DWORD apartment_addref(struct apartment *apt)
437 DWORD refs = InterlockedIncrement(&apt->refs);
438 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
442 /* allocates memory and fills in the necessary fields for a new apartment
443 * object. must be called inside apartment cs */
444 static APARTMENT *apartment_construct(DWORD model)
448 TRACE("creating new apartment, model=%d\n", model);
450 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
451 apt->tid = GetCurrentThreadId();
453 list_init(&apt->proxies);
454 list_init(&apt->stubmgrs);
455 list_init(&apt->psclsids);
456 list_init(&apt->loaded_dlls);
459 apt->remunk_exported = FALSE;
461 InitializeCriticalSection(&apt->cs);
462 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
464 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
466 if (apt->multi_threaded)
468 /* FIXME: should be randomly generated by in an RPC call to rpcss */
469 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
473 /* FIXME: should be randomly generated by in an RPC call to rpcss */
474 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
477 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
479 list_add_head(&apts, &apt->entry);
484 /* gets and existing apartment if one exists or otherwise creates an apartment
485 * structure which stores OLE apartment-local information and stores a pointer
486 * to it in the thread-local storage */
487 static APARTMENT *apartment_get_or_create(DWORD model)
489 APARTMENT *apt = COM_CurrentApt();
493 if (model & COINIT_APARTMENTTHREADED)
495 EnterCriticalSection(&csApartment);
497 apt = apartment_construct(model);
502 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
505 LeaveCriticalSection(&csApartment);
508 apartment_createwindowifneeded(apt);
512 EnterCriticalSection(&csApartment);
514 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
515 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
519 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
520 apartment_addref(MTA);
523 MTA = apartment_construct(model);
527 LeaveCriticalSection(&csApartment);
529 COM_CurrentInfo()->apt = apt;
535 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
537 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
540 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
542 list_remove(&curClass->entry);
544 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
545 RPC_StopLocalServer(curClass->RpcRegistration);
548 * Release the reference to the class object.
550 IUnknown_Release(curClass->classObject);
552 if (curClass->pMarshaledData)
555 memset(&zero, 0, sizeof(zero));
556 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
557 CoReleaseMarshalData(curClass->pMarshaledData);
558 IStream_Release(curClass->pMarshaledData);
561 HeapFree(GetProcessHeap(), 0, curClass);
564 static void COM_RevokeAllClasses(const struct apartment *apt)
566 RegisteredClass *curClass, *cursor;
568 EnterCriticalSection( &csRegisteredClassList );
570 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
572 if (curClass->apartment_id == apt->oxid)
573 COM_RevokeRegisteredClassObject(curClass);
576 LeaveCriticalSection( &csRegisteredClassList );
579 /******************************************************************************
580 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
583 typedef struct ManualResetEvent {
584 ISynchronize ISynchronize_iface;
585 ISynchronizeHandle ISynchronizeHandle_iface;
590 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
592 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
595 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
597 MREImpl *This = impl_from_ISynchronize(iface);
599 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
601 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
602 *ppv = &This->ISynchronize_iface;
603 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
604 *ppv = &This->ISynchronizeHandle_iface;
606 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
608 return E_NOINTERFACE;
611 IUnknown_AddRef((IUnknown*)*ppv);
615 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
617 MREImpl *This = impl_from_ISynchronize(iface);
618 LONG ref = InterlockedIncrement(&This->ref);
619 TRACE("%p - ref %d\n", This, ref);
624 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
626 MREImpl *This = impl_from_ISynchronize(iface);
627 LONG ref = InterlockedDecrement(&This->ref);
628 TRACE("%p - ref %d\n", This, ref);
632 CloseHandle(This->event);
633 HeapFree(GetProcessHeap(), 0, This);
639 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
641 MREImpl *This = impl_from_ISynchronize(iface);
643 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
644 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
647 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
649 MREImpl *This = impl_from_ISynchronize(iface);
651 SetEvent(This->event);
655 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
657 MREImpl *This = impl_from_ISynchronize(iface);
659 ResetEvent(This->event);
663 static ISynchronizeVtbl vt_ISynchronize = {
664 ISynchronize_fnQueryInterface,
665 ISynchronize_fnAddRef,
666 ISynchronize_fnRelease,
668 ISynchronize_fnSignal,
672 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
674 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
677 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
679 MREImpl *This = impl_from_ISynchronizeHandle(iface);
680 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
683 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
685 MREImpl *This = impl_from_ISynchronizeHandle(iface);
686 return ISynchronize_AddRef(&This->ISynchronize_iface);
689 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
691 MREImpl *This = impl_from_ISynchronizeHandle(iface);
692 return ISynchronize_Release(&This->ISynchronize_iface);
695 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
697 MREImpl *This = impl_from_ISynchronizeHandle(iface);
703 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
704 SynchronizeHandle_QueryInterface,
705 SynchronizeHandle_AddRef,
706 SynchronizeHandle_Release,
707 SynchronizeHandle_GetHandle
710 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
712 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
716 FIXME("Aggregation not implemented.\n");
719 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
720 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
721 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
723 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
724 ISynchronize_Release(&This->ISynchronize_iface);
728 /***********************************************************************
729 * CoRevokeClassObject [OLE32.@]
731 * Removes a class object from the class registry.
734 * dwRegister [I] Cookie returned from CoRegisterClassObject().
738 * Failure: HRESULT code.
741 * Must be called from the same apartment that called CoRegisterClassObject(),
742 * otherwise it will fail with RPC_E_WRONG_THREAD.
745 * CoRegisterClassObject
747 HRESULT WINAPI CoRevokeClassObject(
750 HRESULT hr = E_INVALIDARG;
751 RegisteredClass *curClass;
754 TRACE("(%08x)\n",dwRegister);
756 apt = COM_CurrentApt();
759 ERR("COM was not initialized\n");
760 return CO_E_NOTINITIALIZED;
763 EnterCriticalSection( &csRegisteredClassList );
765 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
768 * Check if we have a match on the cookie.
770 if (curClass->dwCookie == dwRegister)
772 if (curClass->apartment_id == apt->oxid)
774 COM_RevokeRegisteredClassObject(curClass);
779 ERR("called from wrong apartment, should be called from %s\n",
780 wine_dbgstr_longlong(curClass->apartment_id));
781 hr = RPC_E_WRONG_THREAD;
787 LeaveCriticalSection( &csRegisteredClassList );
792 /* frees unused libraries loaded by apartment_getclassobject by calling the
793 * DLL's DllCanUnloadNow entry point */
794 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
796 struct apartment_loaded_dll *entry, *next;
797 EnterCriticalSection(&apt->cs);
798 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
800 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
802 DWORD real_delay = delay;
804 if (real_delay == INFINITE)
806 /* DLLs that return multi-threaded objects aren't unloaded
807 * straight away to cope for programs that have races between
808 * last object destruction and threads in the DLLs that haven't
809 * finished, despite DllCanUnloadNow returning S_OK */
810 if (entry->multi_threaded)
811 real_delay = 10 * 60 * 1000; /* 10 minutes */
816 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
818 list_remove(&entry->entry);
819 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
820 HeapFree(GetProcessHeap(), 0, entry);
824 entry->unload_time = GetTickCount() + real_delay;
825 if (!entry->unload_time) entry->unload_time = 1;
828 else if (entry->unload_time)
829 entry->unload_time = 0;
831 LeaveCriticalSection(&apt->cs);
834 DWORD apartment_release(struct apartment *apt)
838 EnterCriticalSection(&csApartment);
840 ret = InterlockedDecrement(&apt->refs);
841 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
842 /* destruction stuff that needs to happen under csApartment CS */
845 if (apt == MTA) MTA = NULL;
846 else if (apt == MainApartment) MainApartment = NULL;
847 list_remove(&apt->entry);
850 LeaveCriticalSection(&csApartment);
854 struct list *cursor, *cursor2;
856 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
858 /* Release the references to the registered class objects */
859 COM_RevokeAllClasses(apt);
861 /* no locking is needed for this apartment, because no other thread
862 * can access it at this point */
864 apartment_disconnectproxies(apt);
866 if (apt->win) DestroyWindow(apt->win);
867 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
869 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
871 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
872 /* release the implicit reference given by the fact that the
873 * stub has external references (it must do since it is in the
874 * stub manager list in the apartment and all non-apartment users
875 * must have a ref on the apartment and so it cannot be destroyed).
877 stub_manager_int_release(stubmgr);
880 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
882 struct registered_psclsid *registered_psclsid =
883 LIST_ENTRY(cursor, struct registered_psclsid, entry);
885 list_remove(®istered_psclsid->entry);
886 HeapFree(GetProcessHeap(), 0, registered_psclsid);
889 /* if this assert fires, then another thread took a reference to a
890 * stub manager without taking a reference to the containing
891 * apartment, which it must do. */
892 assert(list_empty(&apt->stubmgrs));
894 if (apt->filter) IMessageFilter_Release(apt->filter);
896 /* free as many unused libraries as possible... */
897 apartment_freeunusedlibraries(apt, 0);
899 /* ... and free the memory for the apartment loaded dll entry and
900 * release the dll list reference without freeing the library for the
902 while ((cursor = list_head(&apt->loaded_dlls)))
904 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
905 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
907 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
910 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
911 DeleteCriticalSection(&apt->cs);
913 HeapFree(GetProcessHeap(), 0, apt);
919 /* The given OXID must be local to this process:
921 * The ref parameter is here mostly to ensure people remember that
922 * they get one, you should normally take a ref for thread safety.
924 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
926 APARTMENT *result = NULL;
929 EnterCriticalSection(&csApartment);
930 LIST_FOR_EACH( cursor, &apts )
932 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
933 if (apt->oxid == oxid)
936 if (ref) apartment_addref(result);
940 LeaveCriticalSection(&csApartment);
945 /* gets the apartment which has a given creator thread ID. The caller must
946 * release the reference from the apartment as soon as the apartment pointer
947 * is no longer required. */
948 APARTMENT *apartment_findfromtid(DWORD tid)
950 APARTMENT *result = NULL;
953 EnterCriticalSection(&csApartment);
954 LIST_FOR_EACH( cursor, &apts )
956 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
960 apartment_addref(result);
964 LeaveCriticalSection(&csApartment);
969 /* gets the main apartment if it exists. The caller must
970 * release the reference from the apartment as soon as the apartment pointer
971 * is no longer required. */
972 static APARTMENT *apartment_findmain(void)
976 EnterCriticalSection(&csApartment);
978 result = MainApartment;
979 if (result) apartment_addref(result);
981 LeaveCriticalSection(&csApartment);
986 /* gets the multi-threaded apartment if it exists. The caller must
987 * release the reference from the apartment as soon as the apartment pointer
988 * is no longer required. */
989 static APARTMENT *apartment_find_multi_threaded(void)
991 APARTMENT *result = NULL;
994 EnterCriticalSection(&csApartment);
996 LIST_FOR_EACH( cursor, &apts )
998 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
999 if (apt->multi_threaded)
1002 apartment_addref(result);
1007 LeaveCriticalSection(&csApartment);
1011 /* gets the specified class object by loading the appropriate DLL, if
1012 * necessary and calls the DllGetClassObject function for the DLL */
1013 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1014 BOOL apartment_threaded,
1015 REFCLSID rclsid, REFIID riid, void **ppv)
1017 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1020 struct apartment_loaded_dll *apartment_loaded_dll;
1022 if (!strcmpiW(dllpath, wszOle32))
1024 /* we don't need to control the lifetime of this dll, so use the local
1025 * implementation of DllGetClassObject directly */
1026 TRACE("calling ole32!DllGetClassObject\n");
1027 hr = DllGetClassObject(rclsid, riid, ppv);
1030 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1035 EnterCriticalSection(&apt->cs);
1037 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1038 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1040 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1047 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1048 if (!apartment_loaded_dll)
1052 apartment_loaded_dll->unload_time = 0;
1053 apartment_loaded_dll->multi_threaded = FALSE;
1054 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1056 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1060 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1061 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1065 LeaveCriticalSection(&apt->cs);
1069 /* one component being multi-threaded overrides any number of
1070 * apartment-threaded components */
1071 if (!apartment_threaded)
1072 apartment_loaded_dll->multi_threaded = TRUE;
1074 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1075 /* OK: get the ClassObject */
1076 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1079 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1085 /***********************************************************************
1086 * COM_RegReadPath [internal]
1088 * Reads a registry value and expands it when necessary
1090 static DWORD COM_RegReadPath(HKEY hkeyroot, WCHAR * dst, DWORD dstlen)
1094 WCHAR src[MAX_PATH];
1095 DWORD dwLength = dstlen * sizeof(WCHAR);
1097 if( (ret = RegQueryValueExW(hkeyroot, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1098 if (keytype == REG_EXPAND_SZ) {
1099 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1101 const WCHAR *quote_start;
1102 quote_start = strchrW(src, '\"');
1104 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1106 memmove(src, quote_start + 1,
1107 (quote_end - quote_start - 1) * sizeof(WCHAR));
1108 src[quote_end - quote_start - 1] = '\0';
1111 lstrcpynW(dst, src, dstlen);
1117 struct host_object_params
1120 CLSID clsid; /* clsid of object to marshal */
1121 IID iid; /* interface to marshal */
1122 HANDLE event; /* event signalling when ready for multi-threaded case */
1123 HRESULT hr; /* result for multi-threaded case */
1124 IStream *stream; /* stream that the object will be marshaled into */
1125 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1128 static HRESULT apartment_hostobject(struct apartment *apt,
1129 const struct host_object_params *params)
1133 static const LARGE_INTEGER llZero;
1134 WCHAR dllpath[MAX_PATH+1];
1136 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
1138 if (COM_RegReadPath(params->hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1140 /* failure: CLSID is not found in registry */
1141 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
1142 return REGDB_E_CLASSNOTREG;
1145 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1146 ¶ms->clsid, ¶ms->iid, (void **)&object);
1150 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1152 IUnknown_Release(object);
1153 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1158 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1163 RPC_ExecuteCall((struct dispatch_params *)lParam);
1166 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1168 return DefWindowProcW(hWnd, msg, wParam, lParam);
1172 struct host_thread_params
1174 COINIT threading_model;
1176 HWND apartment_hwnd;
1179 /* thread for hosting an object to allow an object to appear to be created in
1180 * an apartment with an incompatible threading model */
1181 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1183 struct host_thread_params *params = p;
1186 struct apartment *apt;
1190 hr = CoInitializeEx(NULL, params->threading_model);
1191 if (FAILED(hr)) return hr;
1193 apt = COM_CurrentApt();
1194 if (params->threading_model == COINIT_APARTMENTTHREADED)
1196 apartment_createwindowifneeded(apt);
1197 params->apartment_hwnd = apartment_getwindow(apt);
1200 params->apartment_hwnd = NULL;
1202 /* force the message queue to be created before signaling parent thread */
1203 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1205 SetEvent(params->ready_event);
1206 params = NULL; /* can't touch params after here as it may be invalid */
1208 while (GetMessageW(&msg, NULL, 0, 0))
1210 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1212 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1213 obj_params->hr = apartment_hostobject(apt, obj_params);
1214 SetEvent(obj_params->event);
1218 TranslateMessage(&msg);
1219 DispatchMessageW(&msg);
1230 /* finds or creates a host apartment, creates the object inside it and returns
1231 * a proxy to it so that the object can be used in the apartment of the
1232 * caller of this function */
1233 static HRESULT apartment_hostobject_in_hostapt(
1234 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1235 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1237 struct host_object_params params;
1238 HWND apartment_hwnd = NULL;
1239 DWORD apartment_tid = 0;
1242 if (!multi_threaded && main_apartment)
1244 APARTMENT *host_apt = apartment_findmain();
1247 apartment_hwnd = apartment_getwindow(host_apt);
1248 apartment_release(host_apt);
1252 if (!apartment_hwnd)
1254 EnterCriticalSection(&apt->cs);
1256 if (!apt->host_apt_tid)
1258 struct host_thread_params thread_params;
1262 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1263 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1264 thread_params.apartment_hwnd = NULL;
1265 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1268 CloseHandle(handles[0]);
1269 LeaveCriticalSection(&apt->cs);
1270 return E_OUTOFMEMORY;
1272 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1273 CloseHandle(handles[0]);
1274 CloseHandle(handles[1]);
1275 if (wait_value == WAIT_OBJECT_0)
1276 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1279 LeaveCriticalSection(&apt->cs);
1280 return E_OUTOFMEMORY;
1284 if (multi_threaded || !main_apartment)
1286 apartment_hwnd = apt->host_apt_hwnd;
1287 apartment_tid = apt->host_apt_tid;
1290 LeaveCriticalSection(&apt->cs);
1293 /* another thread may have become the main apartment in the time it took
1294 * us to create the thread for the host apartment */
1295 if (!apartment_hwnd && !multi_threaded && main_apartment)
1297 APARTMENT *host_apt = apartment_findmain();
1300 apartment_hwnd = apartment_getwindow(host_apt);
1301 apartment_release(host_apt);
1305 params.hkeydll = hkeydll;
1306 params.clsid = *rclsid;
1308 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1311 params.apartment_threaded = !multi_threaded;
1315 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1316 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
1320 WaitForSingleObject(params.event, INFINITE);
1323 CloseHandle(params.event);
1327 if (!apartment_hwnd)
1329 ERR("host apartment didn't create window\n");
1333 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1336 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1337 IStream_Release(params.stream);
1341 /* create a window for the apartment or return the current one if one has
1342 * already been created */
1343 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1345 if (apt->multi_threaded)
1350 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1352 HWND_MESSAGE, 0, hProxyDll, NULL);
1355 ERR("CreateWindow failed with error %d\n", GetLastError());
1356 return HRESULT_FROM_WIN32(GetLastError());
1358 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1359 /* someone beat us to it */
1360 DestroyWindow(hwnd);
1366 /* retrieves the window for the main- or apartment-threaded apartment */
1367 HWND apartment_getwindow(const struct apartment *apt)
1369 assert(!apt->multi_threaded);
1373 void apartment_joinmta(void)
1375 apartment_addref(MTA);
1376 COM_CurrentInfo()->apt = MTA;
1379 static void COMPOBJ_InitProcess( void )
1383 /* Dispatching to the correct thread in an apartment is done through
1384 * window messages rather than RPC transports. When an interface is
1385 * marshalled into another apartment in the same process, a window of the
1386 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1387 * application) is responsible for pumping the message loop in that thread.
1388 * The WM_USER messages which point to the RPCs are then dispatched to
1389 * apartment_wndproc by the user's code from the apartment in which the
1390 * interface was unmarshalled.
1392 memset(&wclass, 0, sizeof(wclass));
1393 wclass.lpfnWndProc = apartment_wndproc;
1394 wclass.hInstance = hProxyDll;
1395 wclass.lpszClassName = wszAptWinClass;
1396 RegisterClassW(&wclass);
1399 static void COMPOBJ_UninitProcess( void )
1401 UnregisterClassW(wszAptWinClass, hProxyDll);
1404 static void COM_TlsDestroy(void)
1406 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1409 if (info->apt) apartment_release(info->apt);
1410 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1411 if (info->state) IUnknown_Release(info->state);
1412 if (info->spy) IInitializeSpy_Release(info->spy);
1413 if (info->context_token) IObjContext_Release(info->context_token);
1414 HeapFree(GetProcessHeap(), 0, info);
1415 NtCurrentTeb()->ReservedForOle = NULL;
1419 /******************************************************************************
1420 * CoBuildVersion [OLE32.@]
1422 * Gets the build version of the DLL.
1427 * Current build version, hiword is majornumber, loword is minornumber
1429 DWORD WINAPI CoBuildVersion(void)
1431 TRACE("Returning version %d, build %d.\n", rmm, rup);
1432 return (rmm<<16)+rup;
1435 /******************************************************************************
1436 * CoRegisterInitializeSpy [OLE32.@]
1438 * Add a Spy that watches CoInitializeEx calls
1441 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1442 * cookie [II] cookie receiver
1445 * Success: S_OK if not already initialized, S_FALSE otherwise.
1446 * Failure: HRESULT code.
1451 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1453 struct oletls *info = COM_CurrentInfo();
1456 TRACE("(%p, %p)\n", spy, cookie);
1458 if (!spy || !cookie || !info)
1461 WARN("Could not allocate tls\n");
1462 return E_INVALIDARG;
1467 FIXME("Already registered?\n");
1468 return E_UNEXPECTED;
1471 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1474 cookie->QuadPart = (DWORD_PTR)spy;
1480 /******************************************************************************
1481 * CoRevokeInitializeSpy [OLE32.@]
1483 * Remove a spy that previously watched CoInitializeEx calls
1486 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1489 * Success: S_OK if a spy is removed
1490 * Failure: E_INVALIDARG
1495 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1497 struct oletls *info = COM_CurrentInfo();
1498 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1500 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1501 return E_INVALIDARG;
1503 IInitializeSpy_Release(info->spy);
1509 /******************************************************************************
1510 * CoInitialize [OLE32.@]
1512 * Initializes the COM libraries by calling CoInitializeEx with
1513 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1516 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1519 * Success: S_OK if not already initialized, S_FALSE otherwise.
1520 * Failure: HRESULT code.
1525 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1528 * Just delegate to the newer method.
1530 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1533 /******************************************************************************
1534 * CoInitializeEx [OLE32.@]
1536 * Initializes the COM libraries.
1539 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1540 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1543 * S_OK if successful,
1544 * S_FALSE if this function was called already.
1545 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1550 * The behavior used to set the IMalloc used for memory management is
1552 * The dwCoInit parameter must specify one of the following apartment
1554 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1555 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1556 * The parameter may also specify zero or more of the following flags:
1557 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1558 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1563 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1565 struct oletls *info = COM_CurrentInfo();
1569 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1571 if (lpReserved!=NULL)
1573 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1577 * Check the lock count. If this is the first time going through the initialize
1578 * process, we have to initialize the libraries.
1580 * And crank-up that lock count.
1582 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1585 * Initialize the various COM libraries and data structures.
1587 TRACE("() - Initializing the COM libraries\n");
1589 /* we may need to defer this until after apartment initialisation */
1590 RunningObjectTableImpl_Initialize();
1594 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1596 if (!(apt = info->apt))
1598 apt = apartment_get_or_create(dwCoInit);
1599 if (!apt) return E_OUTOFMEMORY;
1601 else if (!apartment_is_model(apt, dwCoInit))
1603 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1604 code then we are probably using the wrong threading model to implement that API. */
1605 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1606 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1607 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1608 return RPC_E_CHANGED_MODE;
1616 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1621 /***********************************************************************
1622 * CoUninitialize [OLE32.@]
1624 * This method will decrement the refcount on the current apartment, freeing
1625 * the resources associated with it if it is the last thread in the apartment.
1626 * If the last apartment is freed, the function will additionally release
1627 * any COM resources associated with the process.
1637 void WINAPI CoUninitialize(void)
1639 struct oletls * info = COM_CurrentInfo();
1644 /* will only happen on OOM */
1648 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1653 ERR("Mismatched CoUninitialize\n");
1656 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1662 apartment_release(info->apt);
1667 * Decrease the reference count.
1668 * If we are back to 0 locks on the COM library, make sure we free
1669 * all the associated data structures.
1671 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1674 TRACE("() - Releasing the COM libraries\n");
1676 RunningObjectTableImpl_UnInitialize();
1678 else if (lCOMRefCnt<1) {
1679 ERR( "CoUninitialize() - not CoInitialized.\n" );
1680 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1683 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1686 /******************************************************************************
1687 * CoDisconnectObject [OLE32.@]
1689 * Disconnects all connections to this object from remote processes. Dispatches
1690 * pending RPCs while blocking new RPCs from occurring, and then calls
1691 * IMarshal::DisconnectObject on the given object.
1693 * Typically called when the object server is forced to shut down, for instance by
1697 * lpUnk [I] The object whose stub should be disconnected.
1698 * reserved [I] Reserved. Should be set to 0.
1702 * Failure: HRESULT code.
1705 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1707 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1713 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1715 if (!lpUnk) return E_INVALIDARG;
1717 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1720 hr = IMarshal_DisconnectObject(marshal, reserved);
1721 IMarshal_Release(marshal);
1725 apt = COM_CurrentApt();
1727 return CO_E_NOTINITIALIZED;
1729 apartment_disconnectobject(apt, lpUnk);
1731 /* Note: native is pretty broken here because it just silently
1732 * fails, without returning an appropriate error code if the object was
1733 * not found, making apps think that the object was disconnected, when
1734 * it actually wasn't */
1739 /******************************************************************************
1740 * CoCreateGuid [OLE32.@]
1742 * Simply forwards to UuidCreate in RPCRT4.
1745 * pguid [O] Points to the GUID to initialize.
1749 * Failure: HRESULT code.
1754 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1756 DWORD status = UuidCreate(pguid);
1757 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1758 return HRESULT_FROM_WIN32( status );
1761 static inline BOOL is_valid_hex(WCHAR c)
1763 if (!(((c >= '0') && (c <= '9')) ||
1764 ((c >= 'a') && (c <= 'f')) ||
1765 ((c >= 'A') && (c <= 'F'))))
1770 /******************************************************************************
1771 * CLSIDFromString [OLE32.@]
1772 * IIDFromString [OLE32.@]
1774 * Converts a unique identifier from its string representation into
1778 * idstr [I] The string representation of the GUID.
1779 * id [O] GUID converted from the string.
1783 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1788 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1793 if (!s || s[0]!='{') {
1794 memset( id, 0, sizeof (CLSID) );
1796 return CO_E_CLASSSTRING;
1799 TRACE("%s -> %p\n", debugstr_w(s), id);
1801 /* quick lookup table */
1802 memset(table, 0, 256);
1804 for (i = 0; i < 10; i++) {
1807 for (i = 0; i < 6; i++) {
1808 table['A' + i] = i+10;
1809 table['a' + i] = i+10;
1812 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1815 for (i = 1; i < 9; i++) {
1816 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1817 id->Data1 = (id->Data1 << 4) | table[s[i]];
1819 if (s[9]!='-') return CO_E_CLASSSTRING;
1822 for (i = 10; i < 14; i++) {
1823 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1824 id->Data2 = (id->Data2 << 4) | table[s[i]];
1826 if (s[14]!='-') return CO_E_CLASSSTRING;
1829 for (i = 15; i < 19; i++) {
1830 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1831 id->Data3 = (id->Data3 << 4) | table[s[i]];
1833 if (s[19]!='-') return CO_E_CLASSSTRING;
1835 for (i = 20; i < 37; i+=2) {
1837 if (s[i]!='-') return CO_E_CLASSSTRING;
1840 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1841 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1844 if (s[37] == '}' && s[38] == '\0')
1847 return CO_E_CLASSSTRING;
1850 /*****************************************************************************/
1852 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1857 return E_INVALIDARG;
1859 ret = __CLSIDFromString(idstr, id);
1860 if(ret != S_OK) { /* It appears a ProgID is also valid */
1862 ret = CLSIDFromProgID(idstr, &tmp_id);
1870 /******************************************************************************
1871 * StringFromCLSID [OLE32.@]
1872 * StringFromIID [OLE32.@]
1874 * Converts a GUID into the respective string representation.
1875 * The target string is allocated using the OLE IMalloc.
1878 * id [I] the GUID to be converted.
1879 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1886 * StringFromGUID2, CLSIDFromString
1888 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1893 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1894 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1895 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1899 /******************************************************************************
1900 * StringFromGUID2 [OLE32.@]
1902 * Modified version of StringFromCLSID that allows you to specify max
1906 * id [I] GUID to convert to string.
1907 * str [O] Buffer where the result will be stored.
1908 * cmax [I] Size of the buffer in characters.
1911 * Success: The length of the resulting string in characters.
1914 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1916 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1917 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1918 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1919 '%','0','2','X','%','0','2','X','}',0 };
1920 if (!id || cmax < CHARS_IN_GUID) return 0;
1921 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1922 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1923 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1924 return CHARS_IN_GUID;
1927 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1928 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1930 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1931 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1935 strcpyW(path, wszCLSIDSlash);
1936 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1937 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
1938 if (res == ERROR_FILE_NOT_FOUND)
1939 return REGDB_E_CLASSNOTREG;
1940 else if (res != ERROR_SUCCESS)
1941 return REGDB_E_READREGDB;
1949 res = open_classes_key(key, keyname, access, subkey);
1951 if (res == ERROR_FILE_NOT_FOUND)
1952 return REGDB_E_KEYMISSING;
1953 else if (res != ERROR_SUCCESS)
1954 return REGDB_E_READREGDB;
1959 /* open HKCR\\AppId\\{string form of appid clsid} key */
1960 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1962 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1963 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1965 WCHAR buf[CHARS_IN_GUID];
1966 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1972 /* read the AppID value under the class's key */
1973 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1978 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1980 if (res == ERROR_FILE_NOT_FOUND)
1981 return REGDB_E_KEYMISSING;
1982 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1983 return REGDB_E_READREGDB;
1985 strcpyW(keyname, szAppIdKey);
1986 strcatW(keyname, buf);
1987 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
1988 if (res == ERROR_FILE_NOT_FOUND)
1989 return REGDB_E_KEYMISSING;
1990 else if (res != ERROR_SUCCESS)
1991 return REGDB_E_READREGDB;
1996 /******************************************************************************
1997 * ProgIDFromCLSID [OLE32.@]
1999 * Converts a class id into the respective program ID.
2002 * clsid [I] Class ID, as found in registry.
2003 * ppszProgID [O] Associated ProgID.
2008 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2010 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2012 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2019 ERR("ppszProgId isn't optional\n");
2020 return E_INVALIDARG;
2024 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2028 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2029 ret = REGDB_E_CLASSNOTREG;
2033 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2036 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
2037 ret = REGDB_E_CLASSNOTREG;
2040 ret = E_OUTOFMEMORY;
2047 /******************************************************************************
2048 * CLSIDFromProgID [OLE32.@]
2050 * Converts a program id into the respective GUID.
2053 * progid [I] Unicode program ID, as found in registry.
2054 * clsid [O] Associated CLSID.
2058 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2060 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2062 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2063 WCHAR buf2[CHARS_IN_GUID];
2064 LONG buf2len = sizeof(buf2);
2068 if (!progid || !clsid)
2070 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2071 return E_INVALIDARG;
2074 /* initialise clsid in case of failure */
2075 memset(clsid, 0, sizeof(*clsid));
2077 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2078 strcpyW( buf, progid );
2079 strcatW( buf, clsidW );
2080 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2082 HeapFree(GetProcessHeap(),0,buf);
2083 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2084 return CO_E_CLASSSTRING;
2086 HeapFree(GetProcessHeap(),0,buf);
2088 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2091 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2092 return CO_E_CLASSSTRING;
2095 return __CLSIDFromString(buf2,clsid);
2099 /*****************************************************************************
2100 * CoGetPSClsid [OLE32.@]
2102 * Retrieves the CLSID of the proxy/stub factory that implements
2103 * IPSFactoryBuffer for the specified interface.
2106 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2107 * pclsid [O] Where to store returned proxy/stub CLSID.
2112 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2116 * The standard marshaller activates the object with the CLSID
2117 * returned and uses the CreateProxy and CreateStub methods on its
2118 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2121 * CoGetPSClsid determines this CLSID by searching the
2122 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2123 * in the registry and any interface id registered by
2124 * CoRegisterPSClsid within the current process.
2128 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2129 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2130 * considered a bug in native unless an application depends on this (unlikely).
2133 * CoRegisterPSClsid.
2135 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2137 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2138 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2139 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2140 WCHAR value[CHARS_IN_GUID];
2143 APARTMENT *apt = COM_CurrentApt();
2144 struct registered_psclsid *registered_psclsid;
2146 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2150 ERR("apartment not initialised\n");
2151 return CO_E_NOTINITIALIZED;
2156 ERR("pclsid isn't optional\n");
2157 return E_INVALIDARG;
2160 EnterCriticalSection(&apt->cs);
2162 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2163 if (IsEqualIID(®istered_psclsid->iid, riid))
2165 *pclsid = registered_psclsid->clsid;
2166 LeaveCriticalSection(&apt->cs);
2170 LeaveCriticalSection(&apt->cs);
2172 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2173 strcpyW(path, wszInterface);
2174 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2175 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2177 /* Open the key.. */
2178 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2180 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2181 return REGDB_E_IIDNOTREG;
2184 /* ... Once we have the key, query the registry to get the
2185 value of CLSID as a string, and convert it into a
2186 proper CLSID structure to be passed back to the app */
2187 len = sizeof(value);
2188 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2191 return REGDB_E_IIDNOTREG;
2195 /* We have the CLSID we want back from the registry as a string, so
2196 let's convert it into a CLSID structure */
2197 if (CLSIDFromString(value, pclsid) != NOERROR)
2198 return REGDB_E_IIDNOTREG;
2200 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2204 /*****************************************************************************
2205 * CoRegisterPSClsid [OLE32.@]
2207 * Register a proxy/stub CLSID for the given interface in the current process
2211 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2212 * rclsid [I] CLSID of the proxy/stub.
2216 * Failure: E_OUTOFMEMORY
2220 * This function does not add anything to the registry and the effects are
2221 * limited to the lifetime of the current process.
2226 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2228 APARTMENT *apt = COM_CurrentApt();
2229 struct registered_psclsid *registered_psclsid;
2231 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2235 ERR("apartment not initialised\n");
2236 return CO_E_NOTINITIALIZED;
2239 EnterCriticalSection(&apt->cs);
2241 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2242 if (IsEqualIID(®istered_psclsid->iid, riid))
2244 registered_psclsid->clsid = *rclsid;
2245 LeaveCriticalSection(&apt->cs);
2249 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2250 if (!registered_psclsid)
2252 LeaveCriticalSection(&apt->cs);
2253 return E_OUTOFMEMORY;
2256 registered_psclsid->iid = *riid;
2257 registered_psclsid->clsid = *rclsid;
2258 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
2260 LeaveCriticalSection(&apt->cs);
2267 * COM_GetRegisteredClassObject
2269 * This internal method is used to scan the registered class list to
2270 * find a class object.
2273 * rclsid Class ID of the class to find.
2274 * dwClsContext Class context to match.
2275 * ppv [out] returns a pointer to the class object. Complying
2276 * to normal COM usage, this method will increase the
2277 * reference count on this object.
2279 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2280 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2282 HRESULT hr = S_FALSE;
2283 RegisteredClass *curClass;
2285 EnterCriticalSection( &csRegisteredClassList );
2287 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2290 * Check if we have a match on the class ID and context.
2292 if ((apt->oxid == curClass->apartment_id) &&
2293 (dwClsContext & curClass->runContext) &&
2294 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2297 * We have a match, return the pointer to the class object.
2299 *ppUnk = curClass->classObject;
2301 IUnknown_AddRef(curClass->classObject);
2308 LeaveCriticalSection( &csRegisteredClassList );
2313 /******************************************************************************
2314 * CoRegisterClassObject [OLE32.@]
2316 * Registers the class object for a given class ID. Servers housed in EXE
2317 * files use this method instead of exporting DllGetClassObject to allow
2318 * other code to connect to their objects.
2321 * rclsid [I] CLSID of the object to register.
2322 * pUnk [I] IUnknown of the object.
2323 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2324 * flags [I] REGCLS flags indicating how connections are made.
2325 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2329 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2330 * CO_E_OBJISREG if the object is already registered. We should not return this.
2333 * CoRevokeClassObject, CoGetClassObject
2336 * In-process objects are only registered for the current apartment.
2337 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2338 * in other apartments.
2341 * MSDN claims that multiple interface registrations are legal, but we
2342 * can't do that with our current implementation.
2344 HRESULT WINAPI CoRegisterClassObject(
2349 LPDWORD lpdwRegister)
2351 static LONG next_cookie;
2352 RegisteredClass* newClass;
2353 LPUNKNOWN foundObject;
2357 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2358 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2360 if ( (lpdwRegister==0) || (pUnk==0) )
2361 return E_INVALIDARG;
2363 apt = COM_CurrentApt();
2366 ERR("COM was not initialized\n");
2367 return CO_E_NOTINITIALIZED;
2372 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2373 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2374 if (flags & REGCLS_MULTIPLEUSE)
2375 dwClsContext |= CLSCTX_INPROC_SERVER;
2378 * First, check if the class is already registered.
2379 * If it is, this should cause an error.
2381 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2383 if (flags & REGCLS_MULTIPLEUSE) {
2384 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2385 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2386 IUnknown_Release(foundObject);
2389 IUnknown_Release(foundObject);
2390 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2391 return CO_E_OBJISREG;
2394 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2395 if ( newClass == NULL )
2396 return E_OUTOFMEMORY;
2398 newClass->classIdentifier = *rclsid;
2399 newClass->apartment_id = apt->oxid;
2400 newClass->runContext = dwClsContext;
2401 newClass->connectFlags = flags;
2402 newClass->pMarshaledData = NULL;
2403 newClass->RpcRegistration = NULL;
2405 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2406 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2409 * Since we're making a copy of the object pointer, we have to increase its
2412 newClass->classObject = pUnk;
2413 IUnknown_AddRef(newClass->classObject);
2415 EnterCriticalSection( &csRegisteredClassList );
2416 list_add_tail(&RegisteredClassList, &newClass->entry);
2417 LeaveCriticalSection( &csRegisteredClassList );
2419 *lpdwRegister = newClass->dwCookie;
2421 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2422 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2424 FIXME("Failed to create stream on hglobal, %x\n", hr);
2427 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2428 newClass->classObject, MSHCTX_LOCAL, NULL,
2429 MSHLFLAGS_TABLESTRONG);
2431 FIXME("CoMarshalInterface failed, %x!\n",hr);
2435 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2436 newClass->pMarshaledData,
2437 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2438 &newClass->RpcRegistration);
2443 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2445 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2448 DWORD dwLength = len * sizeof(WCHAR);
2450 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2451 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2455 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2456 REFCLSID rclsid, REFIID riid,
2457 BOOL hostifnecessary, void **ppv)
2459 WCHAR dllpath[MAX_PATH+1];
2460 BOOL apartment_threaded;
2462 if (hostifnecessary)
2464 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2465 static const WCHAR wszFree[] = {'F','r','e','e',0};
2466 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2467 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2469 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2471 if (!strcmpiW(threading_model, wszApartment))
2473 apartment_threaded = TRUE;
2474 if (apt->multi_threaded)
2475 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2478 else if (!strcmpiW(threading_model, wszFree))
2480 apartment_threaded = FALSE;
2481 if (!apt->multi_threaded)
2482 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2484 /* everything except "Apartment", "Free" and "Both" */
2485 else if (strcmpiW(threading_model, wszBoth))
2487 apartment_threaded = TRUE;
2488 /* everything else is main-threaded */
2489 if (threading_model[0])
2490 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2491 debugstr_w(threading_model), debugstr_guid(rclsid));
2493 if (apt->multi_threaded || !apt->main)
2494 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2497 apartment_threaded = FALSE;
2500 apartment_threaded = !apt->multi_threaded;
2502 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2504 /* failure: CLSID is not found in registry */
2505 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2506 return REGDB_E_CLASSNOTREG;
2509 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2513 /***********************************************************************
2514 * CoGetClassObject [OLE32.@]
2516 * Creates an object of the specified class.
2519 * rclsid [I] Class ID to create an instance of.
2520 * dwClsContext [I] Flags to restrict the location of the created instance.
2521 * pServerInfo [I] Optional. Details for connecting to a remote server.
2522 * iid [I] The ID of the interface of the instance to return.
2523 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2527 * Failure: HRESULT code.
2530 * The dwClsContext parameter can be one or more of the following:
2531 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2532 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2533 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2534 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2537 * CoCreateInstance()
2539 HRESULT WINAPI CoGetClassObject(
2540 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2541 REFIID iid, LPVOID *ppv)
2543 LPUNKNOWN regClassObject;
2544 HRESULT hres = E_UNEXPECTED;
2546 BOOL release_apt = FALSE;
2548 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2551 return E_INVALIDARG;
2555 if (!(apt = COM_CurrentApt()))
2557 if (!(apt = apartment_find_multi_threaded()))
2559 ERR("apartment not initialised\n");
2560 return CO_E_NOTINITIALIZED;
2566 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2567 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2571 * First, try and see if we can't match the class ID with one of the
2572 * registered classes.
2574 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2577 /* Get the required interface from the retrieved pointer. */
2578 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2581 * Since QI got another reference on the pointer, we want to release the
2582 * one we already have. If QI was unsuccessful, this will release the object. This
2583 * is good since we are not returning it in the "out" parameter.
2585 IUnknown_Release(regClassObject);
2586 if (release_apt) apartment_release(apt);
2590 /* First try in-process server */
2591 if (CLSCTX_INPROC_SERVER & dwClsContext)
2593 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2596 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2598 if (release_apt) apartment_release(apt);
2599 return FTMarshalCF_Create(iid, ppv);
2602 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2605 if (hres == REGDB_E_CLASSNOTREG)
2606 ERR("class %s not registered\n", debugstr_guid(rclsid));
2607 else if (hres == REGDB_E_KEYMISSING)
2609 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2610 hres = REGDB_E_CLASSNOTREG;
2614 if (SUCCEEDED(hres))
2616 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2617 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2621 /* return if we got a class, otherwise fall through to one of the
2623 if (SUCCEEDED(hres))
2625 if (release_apt) apartment_release(apt);
2630 /* Next try in-process handler */
2631 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2633 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2636 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2639 if (hres == REGDB_E_CLASSNOTREG)
2640 ERR("class %s not registered\n", debugstr_guid(rclsid));
2641 else if (hres == REGDB_E_KEYMISSING)
2643 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2644 hres = REGDB_E_CLASSNOTREG;
2648 if (SUCCEEDED(hres))
2650 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2651 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2655 /* return if we got a class, otherwise fall through to one of the
2657 if (SUCCEEDED(hres))
2659 if (release_apt) apartment_release(apt);
2663 if (release_apt) apartment_release(apt);
2665 /* Next try out of process */
2666 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2668 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2669 if (SUCCEEDED(hres))
2673 /* Finally try remote: this requires networked DCOM (a lot of work) */
2674 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2676 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2677 hres = REGDB_E_CLASSNOTREG;
2681 ERR("no class object %s could be created for context 0x%x\n",
2682 debugstr_guid(rclsid), dwClsContext);
2686 /***********************************************************************
2687 * CoResumeClassObjects (OLE32.@)
2689 * Resumes all class objects registered with REGCLS_SUSPENDED.
2693 * Failure: HRESULT code.
2695 HRESULT WINAPI CoResumeClassObjects(void)
2701 /***********************************************************************
2702 * CoCreateInstance [OLE32.@]
2704 * Creates an instance of the specified class.
2707 * rclsid [I] Class ID to create an instance of.
2708 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2709 * dwClsContext [I] Flags to restrict the location of the created instance.
2710 * iid [I] The ID of the interface of the instance to return.
2711 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2715 * Failure: HRESULT code.
2718 * The dwClsContext parameter can be one or more of the following:
2719 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2720 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2721 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2722 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2724 * Aggregation is the concept of deferring the IUnknown of an object to another
2725 * object. This allows a separate object to behave as though it was part of
2726 * the object and to allow this the pUnkOuter parameter can be set. Note that
2727 * not all objects support having an outer of unknown.
2730 * CoGetClassObject()
2732 HRESULT WINAPI CoCreateInstance(
2734 LPUNKNOWN pUnkOuter,
2740 LPCLASSFACTORY lpclf = 0;
2743 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2744 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2751 if (!(apt = COM_CurrentApt()))
2753 if (!(apt = apartment_find_multi_threaded()))
2755 ERR("apartment not initialised\n");
2756 return CO_E_NOTINITIALIZED;
2758 apartment_release(apt);
2762 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2763 * Rather than create a class factory, we can just check for it here
2765 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
2767 if (StdGlobalInterfaceTableInstance == NULL)
2768 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2769 hres = IGlobalInterfaceTable_QueryInterface((IGlobalInterfaceTable*)StdGlobalInterfaceTableInstance,
2772 if (hres) return hres;
2774 TRACE("Retrieved GIT (%p)\n", *ppv);
2778 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2779 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2782 * Get a class factory to construct the object we want.
2784 hres = CoGetClassObject(rclsid,
2794 * Create the object and don't forget to release the factory
2796 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2797 IClassFactory_Release(lpclf);
2800 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2801 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2803 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2805 debugstr_guid(rclsid),hres);
2811 /***********************************************************************
2812 * CoCreateInstanceEx [OLE32.@]
2814 HRESULT WINAPI CoCreateInstanceEx(
2816 LPUNKNOWN pUnkOuter,
2818 COSERVERINFO* pServerInfo,
2822 IUnknown* pUnk = NULL;
2825 ULONG successCount = 0;
2830 if ( (cmq==0) || (pResults==NULL))
2831 return E_INVALIDARG;
2833 if (pServerInfo!=NULL)
2834 FIXME("() non-NULL pServerInfo not supported!\n");
2837 * Initialize all the "out" parameters.
2839 for (index = 0; index < cmq; index++)
2841 pResults[index].pItf = NULL;
2842 pResults[index].hr = E_NOINTERFACE;
2846 * Get the object and get its IUnknown pointer.
2848 hr = CoCreateInstance(rclsid,
2858 * Then, query for all the interfaces requested.
2860 for (index = 0; index < cmq; index++)
2862 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2863 pResults[index].pIID,
2864 (VOID**)&(pResults[index].pItf));
2866 if (pResults[index].hr == S_OK)
2871 * Release our temporary unknown pointer.
2873 IUnknown_Release(pUnk);
2875 if (successCount == 0)
2876 return E_NOINTERFACE;
2878 if (successCount!=cmq)
2879 return CO_S_NOTALLINTERFACES;
2884 /***********************************************************************
2885 * CoLoadLibrary (OLE32.@)
2890 * lpszLibName [I] Path to library.
2891 * bAutoFree [I] Whether the library should automatically be freed.
2894 * Success: Handle to loaded library.
2898 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2900 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2902 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2904 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2907 /***********************************************************************
2908 * CoFreeLibrary [OLE32.@]
2910 * Unloads a library from memory.
2913 * hLibrary [I] Handle to library to unload.
2919 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2921 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2923 FreeLibrary(hLibrary);
2927 /***********************************************************************
2928 * CoFreeAllLibraries [OLE32.@]
2930 * Function for backwards compatibility only. Does nothing.
2936 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2938 void WINAPI CoFreeAllLibraries(void)
2943 /***********************************************************************
2944 * CoFreeUnusedLibrariesEx [OLE32.@]
2946 * Frees any previously unused libraries whose delay has expired and marks
2947 * currently unused libraries for unloading. Unused are identified as those that
2948 * return S_OK from their DllCanUnloadNow function.
2951 * dwUnloadDelay [I] Unload delay in milliseconds.
2952 * dwReserved [I] Reserved. Set to 0.
2958 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2960 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2962 struct apartment *apt = COM_CurrentApt();
2965 ERR("apartment not initialised\n");
2969 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2972 /***********************************************************************
2973 * CoFreeUnusedLibraries [OLE32.@]
2975 * Frees any unused libraries. Unused are identified as those that return
2976 * S_OK from their DllCanUnloadNow function.
2982 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2984 void WINAPI CoFreeUnusedLibraries(void)
2986 CoFreeUnusedLibrariesEx(INFINITE, 0);
2989 /***********************************************************************
2990 * CoFileTimeNow [OLE32.@]
2992 * Retrieves the current time in FILETIME format.
2995 * lpFileTime [O] The current time.
3000 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3002 GetSystemTimeAsFileTime( lpFileTime );
3006 /******************************************************************************
3007 * CoLockObjectExternal [OLE32.@]
3009 * Increments or decrements the external reference count of a stub object.
3012 * pUnk [I] Stub object.
3013 * fLock [I] If TRUE then increments the external ref-count,
3014 * otherwise decrements.
3015 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3016 * calling CoDisconnectObject.
3020 * Failure: HRESULT code.
3023 * If fLock is TRUE and an object is passed in that doesn't have a stub
3024 * manager then a new stub manager is created for the object.
3026 HRESULT WINAPI CoLockObjectExternal(
3029 BOOL fLastUnlockReleases)
3031 struct stub_manager *stubmgr;
3032 struct apartment *apt;
3034 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3035 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3037 apt = COM_CurrentApt();
3038 if (!apt) return CO_E_NOTINITIALIZED;
3040 stubmgr = get_stub_manager_from_object(apt, pUnk);
3045 stub_manager_ext_addref(stubmgr, 1, FALSE);
3047 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3049 stub_manager_int_release(stubmgr);
3055 stubmgr = new_stub_manager(apt, pUnk);
3059 stub_manager_ext_addref(stubmgr, 1, FALSE);
3060 stub_manager_int_release(stubmgr);
3067 WARN("stub object not found %p\n", pUnk);
3068 /* Note: native is pretty broken here because it just silently
3069 * fails, without returning an appropriate error code, making apps
3070 * think that the object was disconnected, when it actually wasn't */
3075 /***********************************************************************
3076 * CoInitializeWOW (OLE32.@)
3078 * WOW equivalent of CoInitialize?
3087 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3089 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3093 /***********************************************************************
3094 * CoGetState [OLE32.@]
3096 * Retrieves the thread state object previously stored by CoSetState().
3099 * ppv [I] Address where pointer to object will be stored.
3103 * Failure: E_OUTOFMEMORY.
3106 * Crashes on all invalid ppv addresses, including NULL.
3107 * If the function returns a non-NULL object then the caller must release its
3108 * reference on the object when the object is no longer required.
3113 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3115 struct oletls *info = COM_CurrentInfo();
3116 if (!info) return E_OUTOFMEMORY;
3122 IUnknown_AddRef(info->state);
3124 TRACE("apt->state=%p\n", info->state);
3130 /***********************************************************************
3131 * CoSetState [OLE32.@]
3133 * Sets the thread state object.
3136 * pv [I] Pointer to state object to be stored.
3139 * The system keeps a reference on the object while the object stored.
3143 * Failure: E_OUTOFMEMORY.
3145 HRESULT WINAPI CoSetState(IUnknown * pv)
3147 struct oletls *info = COM_CurrentInfo();
3148 if (!info) return E_OUTOFMEMORY;
3150 if (pv) IUnknown_AddRef(pv);
3154 TRACE("-- release %p now\n", info->state);
3155 IUnknown_Release(info->state);
3164 /******************************************************************************
3165 * CoTreatAsClass [OLE32.@]
3167 * Sets the TreatAs value of a class.
3170 * clsidOld [I] Class to set TreatAs value on.
3171 * clsidNew [I] The class the clsidOld should be treated as.
3175 * Failure: HRESULT code.
3180 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3182 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3183 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3185 WCHAR szClsidNew[CHARS_IN_GUID];
3187 WCHAR auto_treat_as[CHARS_IN_GUID];
3188 LONG auto_treat_as_size = sizeof(auto_treat_as);
3191 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3194 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3196 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3197 CLSIDFromString(auto_treat_as, &id) == S_OK)
3199 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3201 res = REGDB_E_WRITEREGDB;
3207 RegDeleteKeyW(hkey, wszTreatAs);
3211 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3212 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3214 res = REGDB_E_WRITEREGDB;
3219 if (hkey) RegCloseKey(hkey);
3223 /******************************************************************************
3224 * CoGetTreatAsClass [OLE32.@]
3226 * Gets the TreatAs value of a class.
3229 * clsidOld [I] Class to get the TreatAs value of.
3230 * clsidNew [I] The class the clsidOld should be treated as.
3234 * Failure: HRESULT code.
3239 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3241 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3243 WCHAR szClsidNew[CHARS_IN_GUID];
3245 LONG len = sizeof(szClsidNew);
3247 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3248 *clsidNew = *clsidOld; /* copy over old value */
3250 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3256 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3261 res = CLSIDFromString(szClsidNew,clsidNew);
3263 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3265 if (hkey) RegCloseKey(hkey);
3269 /******************************************************************************
3270 * CoGetCurrentProcess [OLE32.@]
3272 * Gets the current process ID.
3275 * The current process ID.
3278 * Is DWORD really the correct return type for this function?
3280 DWORD WINAPI CoGetCurrentProcess(void)
3282 return GetCurrentProcessId();
3285 /******************************************************************************
3286 * CoRegisterMessageFilter [OLE32.@]
3288 * Registers a message filter.
3291 * lpMessageFilter [I] Pointer to interface.
3292 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3296 * Failure: HRESULT code.
3299 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3300 * lpMessageFilter removes the message filter.
3302 * If lplpMessageFilter is not NULL the previous message filter will be
3303 * returned in the memory pointer to this parameter and the caller is
3304 * responsible for releasing the object.
3306 * The current thread be in an apartment otherwise the function will crash.
3308 HRESULT WINAPI CoRegisterMessageFilter(
3309 LPMESSAGEFILTER lpMessageFilter,
3310 LPMESSAGEFILTER *lplpMessageFilter)
3312 struct apartment *apt;
3313 IMessageFilter *lpOldMessageFilter;
3315 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3317 apt = COM_CurrentApt();
3319 /* can't set a message filter in a multi-threaded apartment */
3320 if (!apt || apt->multi_threaded)
3322 WARN("can't set message filter in MTA or uninitialized apt\n");
3323 return CO_E_NOT_SUPPORTED;
3326 if (lpMessageFilter)
3327 IMessageFilter_AddRef(lpMessageFilter);
3329 EnterCriticalSection(&apt->cs);
3331 lpOldMessageFilter = apt->filter;
3332 apt->filter = lpMessageFilter;
3334 LeaveCriticalSection(&apt->cs);
3336 if (lplpMessageFilter)
3337 *lplpMessageFilter = lpOldMessageFilter;
3338 else if (lpOldMessageFilter)
3339 IMessageFilter_Release(lpOldMessageFilter);
3344 /***********************************************************************
3345 * CoIsOle1Class [OLE32.@]
3347 * Determines whether the specified class an OLE v1 class.
3350 * clsid [I] Class to test.
3353 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3355 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3357 FIXME("%s\n", debugstr_guid(clsid));
3361 /***********************************************************************
3362 * IsEqualGUID [OLE32.@]
3364 * Compares two Unique Identifiers.
3367 * rguid1 [I] The first GUID to compare.
3368 * rguid2 [I] The other GUID to compare.
3374 BOOL WINAPI IsEqualGUID(
3378 return !memcmp(rguid1,rguid2,sizeof(GUID));
3381 /***********************************************************************
3382 * CoInitializeSecurity [OLE32.@]
3384 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3385 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3386 void* pReserved1, DWORD dwAuthnLevel,
3387 DWORD dwImpLevel, void* pReserved2,
3388 DWORD dwCapabilities, void* pReserved3)
3390 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3391 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3392 dwCapabilities, pReserved3);
3396 /***********************************************************************
3397 * CoSuspendClassObjects [OLE32.@]
3399 * Suspends all registered class objects to prevent further requests coming in
3400 * for those objects.
3404 * Failure: HRESULT code.
3406 HRESULT WINAPI CoSuspendClassObjects(void)
3412 /***********************************************************************
3413 * CoAddRefServerProcess [OLE32.@]
3415 * Helper function for incrementing the reference count of a local-server
3419 * New reference count.
3422 * CoReleaseServerProcess().
3424 ULONG WINAPI CoAddRefServerProcess(void)
3430 EnterCriticalSection(&csRegisteredClassList);
3431 refs = ++s_COMServerProcessReferences;
3432 LeaveCriticalSection(&csRegisteredClassList);
3434 TRACE("refs before: %d\n", refs - 1);
3439 /***********************************************************************
3440 * CoReleaseServerProcess [OLE32.@]
3442 * Helper function for decrementing the reference count of a local-server
3446 * New reference count.
3449 * When reference count reaches 0, this function suspends all registered
3450 * classes so no new connections are accepted.
3453 * CoAddRefServerProcess(), CoSuspendClassObjects().
3455 ULONG WINAPI CoReleaseServerProcess(void)
3461 EnterCriticalSection(&csRegisteredClassList);
3463 refs = --s_COMServerProcessReferences;
3464 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3466 LeaveCriticalSection(&csRegisteredClassList);
3468 TRACE("refs after: %d\n", refs);
3473 /***********************************************************************
3474 * CoIsHandlerConnected [OLE32.@]
3476 * Determines whether a proxy is connected to a remote stub.
3479 * pUnk [I] Pointer to object that may or may not be connected.
3482 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3485 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3487 FIXME("%p\n", pUnk);
3492 /***********************************************************************
3493 * CoAllowSetForegroundWindow [OLE32.@]
3496 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3498 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3502 /***********************************************************************
3503 * CoQueryProxyBlanket [OLE32.@]
3505 * Retrieves the security settings being used by a proxy.
3508 * pProxy [I] Pointer to the proxy object.
3509 * pAuthnSvc [O] The type of authentication service.
3510 * pAuthzSvc [O] The type of authorization service.
3511 * ppServerPrincName [O] Optional. The server prinicple name.
3512 * pAuthnLevel [O] The authentication level.
3513 * pImpLevel [O] The impersonation level.
3514 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3515 * pCapabilities [O] Flags affecting the security behaviour.
3519 * Failure: HRESULT code.
3522 * CoCopyProxy, CoSetProxyBlanket.
3524 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3525 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3526 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3528 IClientSecurity *pCliSec;
3531 TRACE("%p\n", pProxy);
3533 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3536 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3537 pAuthzSvc, ppServerPrincName,
3538 pAuthnLevel, pImpLevel, ppAuthInfo,
3540 IClientSecurity_Release(pCliSec);
3543 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3547 /***********************************************************************
3548 * CoSetProxyBlanket [OLE32.@]
3550 * Sets the security settings for a proxy.
3553 * pProxy [I] Pointer to the proxy object.
3554 * AuthnSvc [I] The type of authentication service.
3555 * AuthzSvc [I] The type of authorization service.
3556 * pServerPrincName [I] The server prinicple name.
3557 * AuthnLevel [I] The authentication level.
3558 * ImpLevel [I] The impersonation level.
3559 * pAuthInfo [I] Information specific to the authorization/authentication service.
3560 * Capabilities [I] Flags affecting the security behaviour.
3564 * Failure: HRESULT code.
3567 * CoQueryProxyBlanket, CoCopyProxy.
3569 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3570 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3571 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3573 IClientSecurity *pCliSec;
3576 TRACE("%p\n", pProxy);
3578 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3581 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3582 AuthzSvc, pServerPrincName,
3583 AuthnLevel, ImpLevel, pAuthInfo,
3585 IClientSecurity_Release(pCliSec);
3588 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3592 /***********************************************************************
3593 * CoCopyProxy [OLE32.@]
3598 * pProxy [I] Pointer to the proxy object.
3599 * ppCopy [O] Copy of the proxy.
3603 * Failure: HRESULT code.
3606 * CoQueryProxyBlanket, CoSetProxyBlanket.
3608 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3610 IClientSecurity *pCliSec;
3613 TRACE("%p\n", pProxy);
3615 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3618 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3619 IClientSecurity_Release(pCliSec);
3622 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3627 /***********************************************************************
3628 * CoGetCallContext [OLE32.@]
3630 * Gets the context of the currently executing server call in the current
3634 * riid [I] Context interface to return.
3635 * ppv [O] Pointer to memory that will receive the context on return.
3639 * Failure: HRESULT code.
3641 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3643 struct oletls *info = COM_CurrentInfo();
3645 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3648 return E_OUTOFMEMORY;
3650 if (!info->call_state)
3651 return RPC_E_CALL_COMPLETE;
3653 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3656 /***********************************************************************
3657 * CoSwitchCallContext [OLE32.@]
3659 * Switches the context of the currently executing server call in the current
3663 * pObject [I] Pointer to new context object
3664 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3668 * Failure: HRESULT code.
3670 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3672 struct oletls *info = COM_CurrentInfo();
3674 TRACE("(%p, %p)\n", pObject, ppOldObject);
3677 return E_OUTOFMEMORY;
3679 *ppOldObject = info->call_state;
3680 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3685 /***********************************************************************
3686 * CoQueryClientBlanket [OLE32.@]
3688 * Retrieves the authentication information about the client of the currently
3689 * executing server call in the current thread.
3692 * pAuthnSvc [O] Optional. The type of authentication service.
3693 * pAuthzSvc [O] Optional. The type of authorization service.
3694 * pServerPrincName [O] Optional. The server prinicple name.
3695 * pAuthnLevel [O] Optional. The authentication level.
3696 * pImpLevel [O] Optional. The impersonation level.
3697 * pPrivs [O] Optional. Information about the privileges of the client.
3698 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3702 * Failure: HRESULT code.
3705 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3707 HRESULT WINAPI CoQueryClientBlanket(
3710 OLECHAR **pServerPrincName,
3713 RPC_AUTHZ_HANDLE *pPrivs,
3714 DWORD *pCapabilities)
3716 IServerSecurity *pSrvSec;
3719 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3720 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3721 pPrivs, pCapabilities);
3723 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3726 hr = IServerSecurity_QueryBlanket(
3727 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3728 pImpLevel, pPrivs, pCapabilities);
3729 IServerSecurity_Release(pSrvSec);
3735 /***********************************************************************
3736 * CoImpersonateClient [OLE32.@]
3738 * Impersonates the client of the currently executing server call in the
3746 * Failure: HRESULT code.
3749 * If this function fails then the current thread will not be impersonating
3750 * the client and all actions will take place on behalf of the server.
3751 * Therefore, it is important to check the return value from this function.
3754 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3756 HRESULT WINAPI CoImpersonateClient(void)
3758 IServerSecurity *pSrvSec;
3763 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3766 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3767 IServerSecurity_Release(pSrvSec);
3773 /***********************************************************************
3774 * CoRevertToSelf [OLE32.@]
3776 * Ends the impersonation of the client of the currently executing server
3777 * call in the current thread.
3784 * Failure: HRESULT code.
3787 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3789 HRESULT WINAPI CoRevertToSelf(void)
3791 IServerSecurity *pSrvSec;
3796 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3799 hr = IServerSecurity_RevertToSelf(pSrvSec);
3800 IServerSecurity_Release(pSrvSec);
3806 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3808 /* first try to retrieve messages for incoming COM calls to the apartment window */
3809 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3810 /* next retrieve other messages necessary for the app to remain responsive */
3811 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3812 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3815 /***********************************************************************
3816 * CoWaitForMultipleHandles [OLE32.@]
3818 * Waits for one or more handles to become signaled.
3821 * dwFlags [I] Flags. See notes.
3822 * dwTimeout [I] Timeout in milliseconds.
3823 * cHandles [I] Number of handles pointed to by pHandles.
3824 * pHandles [I] Handles to wait for.
3825 * lpdwindex [O] Index of handle that was signaled.
3829 * Failure: RPC_S_CALLPENDING on timeout.
3833 * The dwFlags parameter can be zero or more of the following:
3834 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3835 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3838 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3840 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3841 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3844 DWORD start_time = GetTickCount();
3845 APARTMENT *apt = COM_CurrentApt();
3846 BOOL message_loop = apt && !apt->multi_threaded;
3848 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3849 pHandles, lpdwindex);
3853 DWORD now = GetTickCount();
3856 if (now - start_time > dwTimeout)
3858 hr = RPC_S_CALLPENDING;
3864 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3865 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3867 TRACE("waiting for rpc completion or window message\n");
3869 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3870 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3871 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
3873 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3878 /* call message filter */
3880 if (COM_CurrentApt()->filter)
3882 PENDINGTYPE pendingtype =
3883 COM_CurrentInfo()->pending_call_count_server ?
3884 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3885 DWORD be_handled = IMessageFilter_MessagePending(
3886 COM_CurrentApt()->filter, 0 /* FIXME */,
3887 now - start_time, pendingtype);
3888 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3891 case PENDINGMSG_CANCELCALL:
3892 WARN("call canceled\n");
3893 hr = RPC_E_CALL_CANCELED;
3895 case PENDINGMSG_WAITNOPROCESS:
3896 case PENDINGMSG_WAITDEFPROCESS:
3898 /* FIXME: MSDN is very vague about the difference
3899 * between WAITNOPROCESS and WAITDEFPROCESS - there
3900 * appears to be none, so it is possibly a left-over
3901 * from the 16-bit world. */
3906 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3907 * so after processing 100 messages we go back to checking the wait handles */
3908 while (count++ < 100 && COM_PeekMessage(apt, &msg))
3910 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3911 TranslateMessage(&msg);
3912 DispatchMessageW(&msg);
3913 if (msg.message == WM_QUIT)
3915 TRACE("resending WM_QUIT to outer message loop\n");
3916 PostQuitMessage(msg.wParam);
3917 /* no longer need to process messages */
3918 message_loop = FALSE;
3927 TRACE("waiting for rpc completion\n");
3929 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
3930 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3931 (dwFlags & COWAIT_ALERTABLE) != 0);
3937 hr = RPC_S_CALLPENDING;
3940 hr = HRESULT_FROM_WIN32( GetLastError() );
3948 TRACE("-- 0x%08x\n", hr);
3953 /***********************************************************************
3954 * CoGetObject [OLE32.@]
3956 * Gets the object named by converting the name to a moniker and binding to it.
3959 * pszName [I] String representing the object.
3960 * pBindOptions [I] Parameters affecting the binding to the named object.
3961 * riid [I] Interface to bind to on the objecct.
3962 * ppv [O] On output, the interface riid of the object represented
3967 * Failure: HRESULT code.
3970 * MkParseDisplayName.
3972 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3973 REFIID riid, void **ppv)
3980 hr = CreateBindCtx(0, &pbc);
3984 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3991 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3994 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3995 IMoniker_Release(pmk);
3999 IBindCtx_Release(pbc);
4004 /***********************************************************************
4005 * CoRegisterChannelHook [OLE32.@]
4007 * Registers a process-wide hook that is called during ORPC calls.
4010 * guidExtension [I] GUID of the channel hook to register.
4011 * pChannelHook [I] Channel hook object to register.
4015 * Failure: HRESULT code.
4017 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4019 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4021 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4024 typedef struct Context
4026 IComThreadingInfo IComThreadingInfo_iface;
4027 IContextCallback IContextCallback_iface;
4028 IObjContext IObjContext_iface;
4033 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4035 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4038 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4040 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4043 static inline Context *impl_from_IObjContext( IObjContext *iface )
4045 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4048 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4052 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4053 IsEqualIID(riid, &IID_IUnknown))
4055 *ppv = &iface->IComThreadingInfo_iface;
4057 else if (IsEqualIID(riid, &IID_IContextCallback))
4059 *ppv = &iface->IContextCallback_iface;
4061 else if (IsEqualIID(riid, &IID_IObjContext))
4063 *ppv = &iface->IObjContext_iface;
4068 IUnknown_AddRef((IUnknown*)*ppv);
4072 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4073 return E_NOINTERFACE;
4076 static ULONG Context_AddRef(Context *This)
4078 return InterlockedIncrement(&This->refs);
4081 static ULONG Context_Release(Context *This)
4083 ULONG refs = InterlockedDecrement(&This->refs);
4085 HeapFree(GetProcessHeap(), 0, This);
4089 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4091 Context *This = impl_from_IComThreadingInfo(iface);
4092 return Context_QueryInterface(This, riid, ppv);
4095 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4097 Context *This = impl_from_IComThreadingInfo(iface);
4098 return Context_AddRef(This);
4101 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4103 Context *This = impl_from_IComThreadingInfo(iface);
4104 return Context_Release(This);
4107 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4109 Context *This = impl_from_IComThreadingInfo(iface);
4111 TRACE("(%p)\n", apttype);
4113 *apttype = This->apttype;
4117 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4119 Context *This = impl_from_IComThreadingInfo(iface);
4121 TRACE("(%p)\n", thdtype);
4123 switch (This->apttype)
4126 case APTTYPE_MAINSTA:
4127 *thdtype = THDTYPE_PROCESSMESSAGES;
4130 *thdtype = THDTYPE_BLOCKMESSAGES;
4136 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4138 FIXME("(%p): stub\n", logical_thread_id);
4142 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4144 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4148 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4150 Context_CTI_QueryInterface,
4152 Context_CTI_Release,
4153 Context_CTI_GetCurrentApartmentType,
4154 Context_CTI_GetCurrentThreadType,
4155 Context_CTI_GetCurrentLogicalThreadId,
4156 Context_CTI_SetCurrentLogicalThreadId
4159 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4161 Context *This = impl_from_IContextCallback(iface);
4162 return Context_QueryInterface(This, riid, ppv);
4165 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4167 Context *This = impl_from_IContextCallback(iface);
4168 return Context_AddRef(This);
4171 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4173 Context *This = impl_from_IContextCallback(iface);
4174 return Context_Release(This);
4177 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4178 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4180 Context *This = impl_from_IContextCallback(iface);
4182 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4186 static const IContextCallbackVtbl Context_Callback_Vtbl =
4188 Context_CC_QueryInterface,
4191 Context_CC_ContextCallback
4194 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4196 Context *This = impl_from_IObjContext(iface);
4197 return Context_QueryInterface(This, riid, ppv);
4200 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4202 Context *This = impl_from_IObjContext(iface);
4203 return Context_AddRef(This);
4206 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4208 Context *This = impl_from_IObjContext(iface);
4209 return Context_Release(This);
4212 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4214 Context *This = impl_from_IObjContext(iface);
4216 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4220 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4222 Context *This = impl_from_IObjContext(iface);
4224 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4228 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4230 Context *This = impl_from_IObjContext(iface);
4232 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4236 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4238 Context *This = impl_from_IObjContext(iface);
4240 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4244 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4246 Context *This = impl_from_IObjContext(iface);
4247 FIXME("(%p/%p)\n", This, iface);
4250 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4252 Context *This = impl_from_IObjContext(iface);
4253 FIXME("(%p/%p)\n", This, iface);
4256 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4258 Context *This = impl_from_IObjContext(iface);
4259 FIXME("(%p/%p)\n", This, iface);
4262 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4264 Context *This = impl_from_IObjContext(iface);
4265 FIXME("(%p/%p)\n", This, iface);
4268 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4270 Context *This = impl_from_IObjContext(iface);
4271 FIXME("(%p/%p)\n", This, iface);
4274 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4276 Context *This = impl_from_IObjContext(iface);
4277 FIXME("(%p/%p)\n", This, iface);
4280 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4282 Context *This = impl_from_IObjContext(iface);
4283 FIXME("(%p/%p)\n", This, iface);
4286 static const IObjContextVtbl Context_Object_Vtbl =
4288 Context_OC_QueryInterface,
4291 Context_OC_SetProperty,
4292 Context_OC_RemoveProperty,
4293 Context_OC_GetProperty,
4294 Context_OC_EnumContextProps,
4295 Context_OC_Reserved1,
4296 Context_OC_Reserved2,
4297 Context_OC_Reserved3,
4298 Context_OC_Reserved4,
4299 Context_OC_Reserved5,
4300 Context_OC_Reserved6,
4301 Context_OC_Reserved7
4304 /***********************************************************************
4305 * CoGetObjectContext [OLE32.@]
4307 * Retrieves an object associated with the current context (i.e. apartment).
4310 * riid [I] ID of the interface of the object to retrieve.
4311 * ppv [O] Address where object will be stored on return.
4315 * Failure: HRESULT code.
4317 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4319 APARTMENT *apt = COM_CurrentApt();
4323 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4328 if (!(apt = apartment_find_multi_threaded()))
4330 ERR("apartment not initialised\n");
4331 return CO_E_NOTINITIALIZED;
4333 apartment_release(apt);
4336 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4338 return E_OUTOFMEMORY;
4340 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4341 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4342 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4344 if (apt->multi_threaded)
4345 context->apttype = APTTYPE_MTA;
4347 context->apttype = APTTYPE_MAINSTA;
4349 context->apttype = APTTYPE_STA;
4351 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4352 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4358 /***********************************************************************
4359 * CoGetContextToken [OLE32.@]
4361 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4363 struct oletls *info = COM_CurrentInfo();
4365 TRACE("(%p)\n", token);
4368 return E_OUTOFMEMORY;
4373 if (!(apt = apartment_find_multi_threaded()))
4375 ERR("apartment not initialised\n");
4376 return CO_E_NOTINITIALIZED;
4378 apartment_release(apt);
4384 if (!info->context_token)
4389 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4390 if (FAILED(hr)) return hr;
4391 info->context_token = ctx;
4394 *token = (ULONG_PTR)info->context_token;
4395 TRACE("apt->context_token=%p\n", info->context_token);
4400 /***********************************************************************
4401 * CoGetDefaultContext [OLE32.@]
4403 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4405 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4406 return E_NOINTERFACE;
4409 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4411 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4415 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4416 if (SUCCEEDED(hres))
4418 WCHAR dllpath[MAX_PATH+1];
4420 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4422 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4423 if (!strcmpiW(dllpath, wszOle32))
4426 return HandlerCF_Create(rclsid, riid, ppv);
4430 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4434 return CLASS_E_CLASSNOTAVAILABLE;
4437 /***********************************************************************
4440 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4442 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4445 case DLL_PROCESS_ATTACH:
4446 hProxyDll = hinstDLL;
4447 COMPOBJ_InitProcess();
4450 case DLL_PROCESS_DETACH:
4451 COMPOBJ_UninitProcess();
4452 RPC_UnregisterAllChannelHooks();
4453 COMPOBJ_DllList_Free();
4454 DeleteCriticalSection(&csRegisteredClassList);
4455 DeleteCriticalSection(&csApartment);
4458 case DLL_THREAD_DETACH:
4465 /***********************************************************************
4466 * DllRegisterServer (OLE32.@)
4468 HRESULT WINAPI DllRegisterServer(void)
4470 return OLE32_DllRegisterServer();
4473 /***********************************************************************
4474 * DllUnregisterServer (OLE32.@)
4476 HRESULT WINAPI DllUnregisterServer(void)
4478 return OLE32_DllUnregisterServer();