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
55 #define USE_COM_CONTEXT_DEF
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
71 /****************************************************************************
72 * This section defines variables internal to the COM module.
75 static APARTMENT *MTA; /* protected by csApartment */
76 static APARTMENT *MainApartment; /* the first STA apartment */
77 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
79 static CRITICAL_SECTION csApartment;
80 static CRITICAL_SECTION_DEBUG critsect_debug =
83 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
84 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
86 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
88 struct registered_psclsid
96 * This lock count counts the number of times CoInitialize is called. It is
97 * decreased every time CoUninitialize is called. When it hits 0, the COM
100 static LONG s_COMLockCount = 0;
101 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
102 static LONG s_COMServerProcessReferences = 0;
105 * This linked list contains the list of registered class objects. These
106 * are mostly used to register the factories for out-of-proc servers of OLE
109 * TODO: Make this data structure aware of inter-process communication. This
110 * means that parts of this will be exported to rpcss.
112 typedef struct tagRegisteredClass
115 CLSID classIdentifier;
117 LPUNKNOWN classObject;
121 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
122 void *RpcRegistration;
125 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
127 static CRITICAL_SECTION csRegisteredClassList;
128 static CRITICAL_SECTION_DEBUG class_cs_debug =
130 0, 0, &csRegisteredClassList,
131 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
134 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
136 /*****************************************************************************
137 * This section contains OpenDllList definitions
139 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
140 * other functions that do LoadLibrary _without_ giving back a HMODULE.
141 * Without this list these handles would never be freed.
143 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
144 * next unload-call but not before 600 sec.
147 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
148 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
150 typedef struct tagOpenDll
155 DllGetClassObjectFunc DllGetClassObject;
156 DllCanUnloadNowFunc DllCanUnloadNow;
160 static struct list openDllList = LIST_INIT(openDllList);
162 static CRITICAL_SECTION csOpenDllList;
163 static CRITICAL_SECTION_DEBUG dll_cs_debug =
165 0, 0, &csOpenDllList,
166 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
169 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
171 struct apartment_loaded_dll
179 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',' ',
180 '0','x','#','#','#','#','#','#','#','#',' ',0};
182 /*****************************************************************************
183 * This section contains OpenDllList implementation
186 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
190 EnterCriticalSection(&csOpenDllList);
191 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
193 if (!strcmpiW(library_name, ptr->library_name) &&
194 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
200 LeaveCriticalSection(&csOpenDllList);
204 /* caller must ensure that library_name is not already in the open dll list */
205 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
211 DllCanUnloadNowFunc DllCanUnloadNow;
212 DllGetClassObjectFunc DllGetClassObject;
216 *ret = COMPOBJ_DllList_Get(library_name);
217 if (*ret) return S_OK;
219 /* do this outside the csOpenDllList to avoid creating a lock dependency on
221 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
224 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
225 /* failure: DLL could not be loaded */
226 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
229 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
230 /* Note: failing to find DllCanUnloadNow is not a failure */
231 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
232 if (!DllGetClassObject)
234 /* failure: the dll did not export DllGetClassObject */
235 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
236 FreeLibrary(hLibrary);
237 return CO_E_DLLNOTFOUND;
240 EnterCriticalSection( &csOpenDllList );
242 *ret = COMPOBJ_DllList_Get(library_name);
245 /* another caller to this function already added the dll while we
246 * weren't in the critical section */
247 FreeLibrary(hLibrary);
251 len = strlenW(library_name);
252 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
254 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
255 if (entry && entry->library_name)
257 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
258 entry->library = hLibrary;
260 entry->DllCanUnloadNow = DllCanUnloadNow;
261 entry->DllGetClassObject = DllGetClassObject;
262 list_add_tail(&openDllList, &entry->entry);
266 HeapFree(GetProcessHeap(), 0, entry);
268 FreeLibrary(hLibrary);
273 LeaveCriticalSection( &csOpenDllList );
278 /* pass FALSE for free_entry to release a reference without destroying the
279 * entry if it reaches zero or TRUE otherwise */
280 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
282 if (!InterlockedDecrement(&entry->refs) && free_entry)
284 EnterCriticalSection(&csOpenDllList);
285 list_remove(&entry->entry);
286 LeaveCriticalSection(&csOpenDllList);
288 TRACE("freeing %p\n", entry->library);
289 FreeLibrary(entry->library);
291 HeapFree(GetProcessHeap(), 0, entry->library_name);
292 HeapFree(GetProcessHeap(), 0, entry);
296 /* frees memory associated with active dll list */
297 static void COMPOBJ_DllList_Free(void)
299 OpenDll *entry, *cursor2;
300 EnterCriticalSection(&csOpenDllList);
301 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
303 list_remove(&entry->entry);
305 HeapFree(GetProcessHeap(), 0, entry->library_name);
306 HeapFree(GetProcessHeap(), 0, entry);
308 LeaveCriticalSection(&csOpenDllList);
311 /******************************************************************************
315 static DWORD apartment_addref(struct apartment *apt)
317 DWORD refs = InterlockedIncrement(&apt->refs);
318 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
322 /* allocates memory and fills in the necessary fields for a new apartment
323 * object. must be called inside apartment cs */
324 static APARTMENT *apartment_construct(DWORD model)
328 TRACE("creating new apartment, model=%d\n", model);
330 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
331 apt->tid = GetCurrentThreadId();
333 list_init(&apt->proxies);
334 list_init(&apt->stubmgrs);
335 list_init(&apt->psclsids);
336 list_init(&apt->loaded_dlls);
339 apt->remunk_exported = FALSE;
341 InitializeCriticalSection(&apt->cs);
342 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
344 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
346 if (apt->multi_threaded)
348 /* FIXME: should be randomly generated by in an RPC call to rpcss */
349 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
353 /* FIXME: should be randomly generated by in an RPC call to rpcss */
354 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
357 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
359 list_add_head(&apts, &apt->entry);
364 /* gets and existing apartment if one exists or otherwise creates an apartment
365 * structure which stores OLE apartment-local information and stores a pointer
366 * to it in the thread-local storage */
367 static APARTMENT *apartment_get_or_create(DWORD model)
369 APARTMENT *apt = COM_CurrentApt();
373 if (model & COINIT_APARTMENTTHREADED)
375 EnterCriticalSection(&csApartment);
377 apt = apartment_construct(model);
382 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
385 LeaveCriticalSection(&csApartment);
388 apartment_createwindowifneeded(apt);
392 EnterCriticalSection(&csApartment);
394 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
395 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
399 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
400 apartment_addref(MTA);
403 MTA = apartment_construct(model);
407 LeaveCriticalSection(&csApartment);
409 COM_CurrentInfo()->apt = apt;
415 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
417 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
420 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
422 list_remove(&curClass->entry);
424 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
425 RPC_StopLocalServer(curClass->RpcRegistration);
428 * Release the reference to the class object.
430 IUnknown_Release(curClass->classObject);
432 if (curClass->pMarshaledData)
435 memset(&zero, 0, sizeof(zero));
436 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
437 CoReleaseMarshalData(curClass->pMarshaledData);
438 IStream_Release(curClass->pMarshaledData);
441 HeapFree(GetProcessHeap(), 0, curClass);
444 static void COM_RevokeAllClasses(const struct apartment *apt)
446 RegisteredClass *curClass, *cursor;
448 EnterCriticalSection( &csRegisteredClassList );
450 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
452 if (curClass->apartment_id == apt->oxid)
453 COM_RevokeRegisteredClassObject(curClass);
456 LeaveCriticalSection( &csRegisteredClassList );
459 /***********************************************************************
460 * CoRevokeClassObject [OLE32.@]
462 * Removes a class object from the class registry.
465 * dwRegister [I] Cookie returned from CoRegisterClassObject().
469 * Failure: HRESULT code.
472 * Must be called from the same apartment that called CoRegisterClassObject(),
473 * otherwise it will fail with RPC_E_WRONG_THREAD.
476 * CoRegisterClassObject
478 HRESULT WINAPI CoRevokeClassObject(
481 HRESULT hr = E_INVALIDARG;
482 RegisteredClass *curClass;
485 TRACE("(%08x)\n",dwRegister);
487 apt = COM_CurrentApt();
490 ERR("COM was not initialized\n");
491 return CO_E_NOTINITIALIZED;
494 EnterCriticalSection( &csRegisteredClassList );
496 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
499 * Check if we have a match on the cookie.
501 if (curClass->dwCookie == dwRegister)
503 if (curClass->apartment_id == apt->oxid)
505 COM_RevokeRegisteredClassObject(curClass);
510 ERR("called from wrong apartment, should be called from %s\n",
511 wine_dbgstr_longlong(curClass->apartment_id));
512 hr = RPC_E_WRONG_THREAD;
518 LeaveCriticalSection( &csRegisteredClassList );
523 /* frees unused libraries loaded by apartment_getclassobject by calling the
524 * DLL's DllCanUnloadNow entry point */
525 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
527 struct apartment_loaded_dll *entry, *next;
528 EnterCriticalSection(&apt->cs);
529 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
531 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
533 DWORD real_delay = delay;
535 if (real_delay == INFINITE)
537 /* DLLs that return multi-threaded objects aren't unloaded
538 * straight away to cope for programs that have races between
539 * last object destruction and threads in the DLLs that haven't
540 * finished, despite DllCanUnloadNow returning S_OK */
541 if (entry->multi_threaded)
542 real_delay = 10 * 60 * 1000; /* 10 minutes */
547 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
549 list_remove(&entry->entry);
550 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
551 HeapFree(GetProcessHeap(), 0, entry);
554 entry->unload_time = GetTickCount() + real_delay;
556 else if (entry->unload_time)
557 entry->unload_time = 0;
559 LeaveCriticalSection(&apt->cs);
562 DWORD apartment_release(struct apartment *apt)
566 EnterCriticalSection(&csApartment);
568 ret = InterlockedDecrement(&apt->refs);
569 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
570 /* destruction stuff that needs to happen under csApartment CS */
573 if (apt == MTA) MTA = NULL;
574 else if (apt == MainApartment) MainApartment = NULL;
575 list_remove(&apt->entry);
578 LeaveCriticalSection(&csApartment);
582 struct list *cursor, *cursor2;
584 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
586 /* Release the references to the registered class objects */
587 COM_RevokeAllClasses(apt);
589 /* no locking is needed for this apartment, because no other thread
590 * can access it at this point */
592 apartment_disconnectproxies(apt);
594 if (apt->win) DestroyWindow(apt->win);
595 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
597 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
599 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
600 /* release the implicit reference given by the fact that the
601 * stub has external references (it must do since it is in the
602 * stub manager list in the apartment and all non-apartment users
603 * must have a ref on the apartment and so it cannot be destroyed).
605 stub_manager_int_release(stubmgr);
608 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
610 struct registered_psclsid *registered_psclsid =
611 LIST_ENTRY(cursor, struct registered_psclsid, entry);
613 list_remove(®istered_psclsid->entry);
614 HeapFree(GetProcessHeap(), 0, registered_psclsid);
617 /* if this assert fires, then another thread took a reference to a
618 * stub manager without taking a reference to the containing
619 * apartment, which it must do. */
620 assert(list_empty(&apt->stubmgrs));
622 if (apt->filter) IUnknown_Release(apt->filter);
624 /* free as many unused libraries as possible... */
625 apartment_freeunusedlibraries(apt, 0);
627 /* ... and free the memory for the apartment loaded dll entry and
628 * release the dll list reference without freeing the library for the
630 while ((cursor = list_head(&apt->loaded_dlls)))
632 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
633 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
635 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
638 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
639 DeleteCriticalSection(&apt->cs);
641 HeapFree(GetProcessHeap(), 0, apt);
647 /* The given OXID must be local to this process:
649 * The ref parameter is here mostly to ensure people remember that
650 * they get one, you should normally take a ref for thread safety.
652 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
654 APARTMENT *result = NULL;
657 EnterCriticalSection(&csApartment);
658 LIST_FOR_EACH( cursor, &apts )
660 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
661 if (apt->oxid == oxid)
664 if (ref) apartment_addref(result);
668 LeaveCriticalSection(&csApartment);
673 /* gets the apartment which has a given creator thread ID. The caller must
674 * release the reference from the apartment as soon as the apartment pointer
675 * is no longer required. */
676 APARTMENT *apartment_findfromtid(DWORD tid)
678 APARTMENT *result = NULL;
681 EnterCriticalSection(&csApartment);
682 LIST_FOR_EACH( cursor, &apts )
684 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
688 apartment_addref(result);
692 LeaveCriticalSection(&csApartment);
697 /* gets the main apartment if it exists. The caller must
698 * release the reference from the apartment as soon as the apartment pointer
699 * is no longer required. */
700 static APARTMENT *apartment_findmain(void)
704 EnterCriticalSection(&csApartment);
706 result = MainApartment;
707 if (result) apartment_addref(result);
709 LeaveCriticalSection(&csApartment);
714 /* gets the multi-threaded apartment if it exists. The caller must
715 * release the reference from the apartment as soon as the apartment pointer
716 * is no longer required. */
717 static APARTMENT *apartment_find_multi_threaded(void)
719 APARTMENT *result = NULL;
722 EnterCriticalSection(&csApartment);
724 LIST_FOR_EACH( cursor, &apts )
726 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
727 if (apt->multi_threaded)
730 apartment_addref(result);
735 LeaveCriticalSection(&csApartment);
739 /* gets the specified class object by loading the appropriate DLL, if
740 * necessary and calls the DllGetClassObject function for the DLL */
741 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
742 BOOL apartment_threaded,
743 REFCLSID rclsid, REFIID riid, void **ppv)
745 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
748 struct apartment_loaded_dll *apartment_loaded_dll;
750 if (!strcmpiW(dllpath, wszOle32))
752 /* we don't need to control the lifetime of this dll, so use the local
753 * implementation of DllGetClassObject directly */
754 TRACE("calling ole32!DllGetClassObject\n");
755 hr = DllGetClassObject(rclsid, riid, ppv);
758 ERR("DllGetClassObject returned error 0x%08x\n", hr);
763 EnterCriticalSection(&apt->cs);
765 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
766 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
768 TRACE("found %s already loaded\n", debugstr_w(dllpath));
775 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
776 if (!apartment_loaded_dll)
780 apartment_loaded_dll->unload_time = 0;
781 apartment_loaded_dll->multi_threaded = FALSE;
782 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
784 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
788 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
789 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
793 LeaveCriticalSection(&apt->cs);
797 /* one component being multi-threaded overrides any number of
798 * apartment-threaded components */
799 if (!apartment_threaded)
800 apartment_loaded_dll->multi_threaded = TRUE;
802 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
803 /* OK: get the ClassObject */
804 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
807 ERR("DllGetClassObject returned error 0x%08x\n", hr);
813 /***********************************************************************
814 * COM_RegReadPath [internal]
816 * Reads a registry value and expands it when necessary
818 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
824 DWORD dwLength = dstlen * sizeof(WCHAR);
826 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
827 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
828 if (keytype == REG_EXPAND_SZ) {
829 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
831 lstrcpynW(dst, src, dstlen);
839 struct host_object_params
842 CLSID clsid; /* clsid of object to marshal */
843 IID iid; /* interface to marshal */
844 HANDLE event; /* event signalling when ready for multi-threaded case */
845 HRESULT hr; /* result for multi-threaded case */
846 IStream *stream; /* stream that the object will be marshaled into */
847 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
850 static HRESULT apartment_hostobject(struct apartment *apt,
851 const struct host_object_params *params)
855 static const LARGE_INTEGER llZero;
856 WCHAR dllpath[MAX_PATH+1];
858 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
860 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
862 /* failure: CLSID is not found in registry */
863 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
864 return REGDB_E_CLASSNOTREG;
867 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
868 ¶ms->clsid, ¶ms->iid, (void **)&object);
872 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
874 IUnknown_Release(object);
875 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
880 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
885 RPC_ExecuteCall((struct dispatch_params *)lParam);
888 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
890 return DefWindowProcW(hWnd, msg, wParam, lParam);
894 struct host_thread_params
896 COINIT threading_model;
901 /* thread for hosting an object to allow an object to appear to be created in
902 * an apartment with an incompatible threading model */
903 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
905 struct host_thread_params *params = p;
908 struct apartment *apt;
912 hr = CoInitializeEx(NULL, params->threading_model);
913 if (FAILED(hr)) return hr;
915 apt = COM_CurrentApt();
916 if (params->threading_model == COINIT_APARTMENTTHREADED)
918 apartment_createwindowifneeded(apt);
919 params->apartment_hwnd = apartment_getwindow(apt);
922 params->apartment_hwnd = NULL;
924 /* force the message queue to be created before signaling parent thread */
925 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
927 SetEvent(params->ready_event);
928 params = NULL; /* can't touch params after here as it may be invalid */
930 while (GetMessageW(&msg, NULL, 0, 0))
932 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
934 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
935 obj_params->hr = apartment_hostobject(apt, obj_params);
936 SetEvent(obj_params->event);
940 TranslateMessage(&msg);
941 DispatchMessageW(&msg);
952 /* finds or creates a host apartment, creates the object inside it and returns
953 * a proxy to it so that the object can be used in the apartment of the
954 * caller of this function */
955 static HRESULT apartment_hostobject_in_hostapt(
956 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
957 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
959 struct host_object_params params;
960 HWND apartment_hwnd = NULL;
961 DWORD apartment_tid = 0;
964 if (!multi_threaded && main_apartment)
966 APARTMENT *host_apt = apartment_findmain();
969 apartment_hwnd = apartment_getwindow(host_apt);
970 apartment_release(host_apt);
976 EnterCriticalSection(&apt->cs);
978 if (!apt->host_apt_tid)
980 struct host_thread_params thread_params;
984 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
985 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
986 thread_params.apartment_hwnd = NULL;
987 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
990 CloseHandle(handles[0]);
991 LeaveCriticalSection(&apt->cs);
992 return E_OUTOFMEMORY;
994 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
995 CloseHandle(handles[0]);
996 CloseHandle(handles[1]);
997 if (wait_value == WAIT_OBJECT_0)
998 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1001 LeaveCriticalSection(&apt->cs);
1002 return E_OUTOFMEMORY;
1006 if (multi_threaded || !main_apartment)
1008 apartment_hwnd = apt->host_apt_hwnd;
1009 apartment_tid = apt->host_apt_tid;
1012 LeaveCriticalSection(&apt->cs);
1015 /* another thread may have become the main apartment in the time it took
1016 * us to create the thread for the host apartment */
1017 if (!apartment_hwnd && !multi_threaded && main_apartment)
1019 APARTMENT *host_apt = apartment_findmain();
1022 apartment_hwnd = apartment_getwindow(host_apt);
1023 apartment_release(host_apt);
1027 params.hkeydll = hkeydll;
1028 params.clsid = *rclsid;
1030 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1033 params.apartment_threaded = !multi_threaded;
1037 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1038 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
1042 WaitForSingleObject(params.event, INFINITE);
1045 CloseHandle(params.event);
1049 if (!apartment_hwnd)
1051 ERR("host apartment didn't create window\n");
1055 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1058 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1059 IStream_Release(params.stream);
1063 /* create a window for the apartment or return the current one if one has
1064 * already been created */
1065 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1067 if (apt->multi_threaded)
1072 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1074 HWND_MESSAGE, 0, hProxyDll, NULL);
1077 ERR("CreateWindow failed with error %d\n", GetLastError());
1078 return HRESULT_FROM_WIN32(GetLastError());
1080 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1081 /* someone beat us to it */
1082 DestroyWindow(hwnd);
1088 /* retrieves the window for the main- or apartment-threaded apartment */
1089 HWND apartment_getwindow(const struct apartment *apt)
1091 assert(!apt->multi_threaded);
1095 void apartment_joinmta(void)
1097 apartment_addref(MTA);
1098 COM_CurrentInfo()->apt = MTA;
1101 static void COMPOBJ_InitProcess( void )
1105 /* Dispatching to the correct thread in an apartment is done through
1106 * window messages rather than RPC transports. When an interface is
1107 * marshalled into another apartment in the same process, a window of the
1108 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1109 * application) is responsible for pumping the message loop in that thread.
1110 * The WM_USER messages which point to the RPCs are then dispatched to
1111 * apartment_wndproc by the user's code from the apartment in which the
1112 * interface was unmarshalled.
1114 memset(&wclass, 0, sizeof(wclass));
1115 wclass.lpfnWndProc = apartment_wndproc;
1116 wclass.hInstance = hProxyDll;
1117 wclass.lpszClassName = wszAptWinClass;
1118 RegisterClassW(&wclass);
1121 static void COMPOBJ_UninitProcess( void )
1123 UnregisterClassW(wszAptWinClass, hProxyDll);
1126 static void COM_TlsDestroy(void)
1128 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1131 if (info->apt) apartment_release(info->apt);
1132 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1133 if (info->state) IUnknown_Release(info->state);
1134 if (info->spy) IUnknown_Release(info->spy);
1135 if (info->context_token) IObjContext_Release(info->context_token);
1136 HeapFree(GetProcessHeap(), 0, info);
1137 NtCurrentTeb()->ReservedForOle = NULL;
1141 /******************************************************************************
1142 * CoBuildVersion [OLE32.@]
1144 * Gets the build version of the DLL.
1149 * Current build version, hiword is majornumber, loword is minornumber
1151 DWORD WINAPI CoBuildVersion(void)
1153 TRACE("Returning version %d, build %d.\n", rmm, rup);
1154 return (rmm<<16)+rup;
1157 /******************************************************************************
1158 * CoRegisterInitializeSpy [OLE32.@]
1160 * Add a Spy that watches CoInitializeEx calls
1163 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1164 * cookie [II] cookie receiver
1167 * Success: S_OK if not already initialized, S_FALSE otherwise.
1168 * Failure: HRESULT code.
1173 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1175 struct oletls *info = COM_CurrentInfo();
1178 TRACE("(%p, %p)\n", spy, cookie);
1180 if (!spy || !cookie || !info)
1183 WARN("Could not allocate tls\n");
1184 return E_INVALIDARG;
1189 FIXME("Already registered?\n");
1190 return E_UNEXPECTED;
1193 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1196 cookie->QuadPart = (DWORD_PTR)spy;
1202 /******************************************************************************
1203 * CoRevokeInitializeSpy [OLE32.@]
1205 * Remove a spy that previously watched CoInitializeEx calls
1208 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1211 * Success: S_OK if a spy is removed
1212 * Failure: E_INVALIDARG
1217 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1219 struct oletls *info = COM_CurrentInfo();
1220 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1222 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1223 return E_INVALIDARG;
1225 IUnknown_Release(info->spy);
1231 /******************************************************************************
1232 * CoInitialize [OLE32.@]
1234 * Initializes the COM libraries by calling CoInitializeEx with
1235 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1238 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1241 * Success: S_OK if not already initialized, S_FALSE otherwise.
1242 * Failure: HRESULT code.
1247 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1250 * Just delegate to the newer method.
1252 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1255 /******************************************************************************
1256 * CoInitializeEx [OLE32.@]
1258 * Initializes the COM libraries.
1261 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1262 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1265 * S_OK if successful,
1266 * S_FALSE if this function was called already.
1267 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1272 * The behavior used to set the IMalloc used for memory management is
1274 * The dwCoInit parameter must specify one of the following apartment
1276 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1277 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1278 * The parameter may also specify zero or more of the following flags:
1279 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1280 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1285 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1287 struct oletls *info = COM_CurrentInfo();
1291 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1293 if (lpReserved!=NULL)
1295 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1299 * Check the lock count. If this is the first time going through the initialize
1300 * process, we have to initialize the libraries.
1302 * And crank-up that lock count.
1304 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1307 * Initialize the various COM libraries and data structures.
1309 TRACE("() - Initializing the COM libraries\n");
1311 /* we may need to defer this until after apartment initialisation */
1312 RunningObjectTableImpl_Initialize();
1316 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1318 if (!(apt = info->apt))
1320 apt = apartment_get_or_create(dwCoInit);
1321 if (!apt) return E_OUTOFMEMORY;
1323 else if (!apartment_is_model(apt, dwCoInit))
1325 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1326 code then we are probably using the wrong threading model to implement that API. */
1327 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1328 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1329 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1330 return RPC_E_CHANGED_MODE;
1338 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1343 /***********************************************************************
1344 * CoUninitialize [OLE32.@]
1346 * This method will decrement the refcount on the current apartment, freeing
1347 * the resources associated with it if it is the last thread in the apartment.
1348 * If the last apartment is freed, the function will additionally release
1349 * any COM resources associated with the process.
1359 void WINAPI CoUninitialize(void)
1361 struct oletls * info = COM_CurrentInfo();
1366 /* will only happen on OOM */
1370 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1375 ERR("Mismatched CoUninitialize\n");
1378 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1384 apartment_release(info->apt);
1389 * Decrease the reference count.
1390 * If we are back to 0 locks on the COM library, make sure we free
1391 * all the associated data structures.
1393 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1396 TRACE("() - Releasing the COM libraries\n");
1398 RunningObjectTableImpl_UnInitialize();
1400 else if (lCOMRefCnt<1) {
1401 ERR( "CoUninitialize() - not CoInitialized.\n" );
1402 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1405 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1408 /******************************************************************************
1409 * CoDisconnectObject [OLE32.@]
1411 * Disconnects all connections to this object from remote processes. Dispatches
1412 * pending RPCs while blocking new RPCs from occurring, and then calls
1413 * IMarshal::DisconnectObject on the given object.
1415 * Typically called when the object server is forced to shut down, for instance by
1419 * lpUnk [I] The object whose stub should be disconnected.
1420 * reserved [I] Reserved. Should be set to 0.
1424 * Failure: HRESULT code.
1427 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1429 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1435 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1437 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1440 hr = IMarshal_DisconnectObject(marshal, reserved);
1441 IMarshal_Release(marshal);
1445 apt = COM_CurrentApt();
1447 return CO_E_NOTINITIALIZED;
1449 apartment_disconnectobject(apt, lpUnk);
1451 /* Note: native is pretty broken here because it just silently
1452 * fails, without returning an appropriate error code if the object was
1453 * not found, making apps think that the object was disconnected, when
1454 * it actually wasn't */
1459 /******************************************************************************
1460 * CoCreateGuid [OLE32.@]
1462 * Simply forwards to UuidCreate in RPCRT4.
1465 * pguid [O] Points to the GUID to initialize.
1469 * Failure: HRESULT code.
1474 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1476 DWORD status = UuidCreate(pguid);
1477 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1478 return HRESULT_FROM_WIN32( status );
1481 /******************************************************************************
1482 * CLSIDFromString [OLE32.@]
1483 * IIDFromString [OLE32.@]
1485 * Converts a unique identifier from its string representation into
1489 * idstr [I] The string representation of the GUID.
1490 * id [O] GUID converted from the string.
1494 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1499 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1505 memset( id, 0, sizeof (CLSID) );
1509 /* validate the CLSID string */
1510 if (strlenW(s) != 38)
1511 return CO_E_CLASSSTRING;
1513 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1514 return CO_E_CLASSSTRING;
1516 for (i=1; i<37; i++) {
1517 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1518 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1519 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1520 ((s[i] >= 'A') && (s[i] <= 'F'))))
1521 return CO_E_CLASSSTRING;
1524 TRACE("%s -> %p\n", debugstr_w(s), id);
1526 /* quick lookup table */
1527 memset(table, 0, 256);
1529 for (i = 0; i < 10; i++) {
1532 for (i = 0; i < 6; i++) {
1533 table['A' + i] = i+10;
1534 table['a' + i] = i+10;
1537 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1539 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1540 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1541 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1542 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1544 /* these are just sequential bytes */
1545 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1546 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1547 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1548 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1549 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1550 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1551 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1552 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1557 /*****************************************************************************/
1559 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1564 return E_INVALIDARG;
1566 ret = __CLSIDFromString(idstr, id);
1567 if(ret != S_OK) { /* It appears a ProgID is also valid */
1568 ret = CLSIDFromProgID(idstr, id);
1574 /******************************************************************************
1575 * StringFromCLSID [OLE32.@]
1576 * StringFromIID [OLE32.@]
1578 * Converts a GUID into the respective string representation.
1579 * The target string is allocated using the OLE IMalloc.
1582 * id [I] the GUID to be converted.
1583 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1590 * StringFromGUID2, CLSIDFromString
1592 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1597 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1598 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1599 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1603 /******************************************************************************
1604 * StringFromGUID2 [OLE32.@]
1606 * Modified version of StringFromCLSID that allows you to specify max
1610 * id [I] GUID to convert to string.
1611 * str [O] Buffer where the result will be stored.
1612 * cmax [I] Size of the buffer in characters.
1615 * Success: The length of the resulting string in characters.
1618 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1620 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1621 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1622 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1623 '%','0','2','X','%','0','2','X','}',0 };
1624 if (!id || cmax < CHARS_IN_GUID) return 0;
1625 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1626 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1627 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1628 return CHARS_IN_GUID;
1631 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1632 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1634 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1635 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1639 strcpyW(path, wszCLSIDSlash);
1640 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1641 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1642 if (res == ERROR_FILE_NOT_FOUND)
1643 return REGDB_E_CLASSNOTREG;
1644 else if (res != ERROR_SUCCESS)
1645 return REGDB_E_READREGDB;
1653 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1655 if (res == ERROR_FILE_NOT_FOUND)
1656 return REGDB_E_KEYMISSING;
1657 else if (res != ERROR_SUCCESS)
1658 return REGDB_E_READREGDB;
1663 /* open HKCR\\AppId\\{string form of appid clsid} key */
1664 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1666 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1667 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1669 WCHAR buf[CHARS_IN_GUID];
1670 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1676 /* read the AppID value under the class's key */
1677 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1682 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1684 if (res == ERROR_FILE_NOT_FOUND)
1685 return REGDB_E_KEYMISSING;
1686 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1687 return REGDB_E_READREGDB;
1689 strcpyW(keyname, szAppIdKey);
1690 strcatW(keyname, buf);
1691 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1692 if (res == ERROR_FILE_NOT_FOUND)
1693 return REGDB_E_KEYMISSING;
1694 else if (res != ERROR_SUCCESS)
1695 return REGDB_E_READREGDB;
1700 /******************************************************************************
1701 * ProgIDFromCLSID [OLE32.@]
1703 * Converts a class id into the respective program ID.
1706 * clsid [I] Class ID, as found in registry.
1707 * ppszProgID [O] Associated ProgID.
1712 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1714 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1716 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1723 ERR("ppszProgId isn't optional\n");
1724 return E_INVALIDARG;
1728 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1732 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1733 ret = REGDB_E_CLASSNOTREG;
1737 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1740 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1741 ret = REGDB_E_CLASSNOTREG;
1744 ret = E_OUTOFMEMORY;
1751 /******************************************************************************
1752 * CLSIDFromProgID [OLE32.@]
1754 * Converts a program id into the respective GUID.
1757 * progid [I] Unicode program ID, as found in registry.
1758 * clsid [O] Associated CLSID.
1762 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1764 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1766 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1767 WCHAR buf2[CHARS_IN_GUID];
1768 LONG buf2len = sizeof(buf2);
1772 if (!progid || !clsid)
1774 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1775 return E_INVALIDARG;
1778 /* initialise clsid in case of failure */
1779 memset(clsid, 0, sizeof(*clsid));
1781 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1782 strcpyW( buf, progid );
1783 strcatW( buf, clsidW );
1784 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1786 HeapFree(GetProcessHeap(),0,buf);
1787 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1788 return CO_E_CLASSSTRING;
1790 HeapFree(GetProcessHeap(),0,buf);
1792 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1795 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1796 return CO_E_CLASSSTRING;
1799 return __CLSIDFromString(buf2,clsid);
1803 /*****************************************************************************
1804 * CoGetPSClsid [OLE32.@]
1806 * Retrieves the CLSID of the proxy/stub factory that implements
1807 * IPSFactoryBuffer for the specified interface.
1810 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1811 * pclsid [O] Where to store returned proxy/stub CLSID.
1816 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1820 * The standard marshaller activates the object with the CLSID
1821 * returned and uses the CreateProxy and CreateStub methods on its
1822 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1825 * CoGetPSClsid determines this CLSID by searching the
1826 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1827 * in the registry and any interface id registered by
1828 * CoRegisterPSClsid within the current process.
1832 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1833 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1834 * considered a bug in native unless an application depends on this (unlikely).
1837 * CoRegisterPSClsid.
1839 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1841 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1842 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1843 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1844 WCHAR value[CHARS_IN_GUID];
1847 APARTMENT *apt = COM_CurrentApt();
1848 struct registered_psclsid *registered_psclsid;
1850 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1854 ERR("apartment not initialised\n");
1855 return CO_E_NOTINITIALIZED;
1860 ERR("pclsid isn't optional\n");
1861 return E_INVALIDARG;
1864 EnterCriticalSection(&apt->cs);
1866 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1867 if (IsEqualIID(®istered_psclsid->iid, riid))
1869 *pclsid = registered_psclsid->clsid;
1870 LeaveCriticalSection(&apt->cs);
1874 LeaveCriticalSection(&apt->cs);
1876 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1877 strcpyW(path, wszInterface);
1878 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1879 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1881 /* Open the key.. */
1882 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1884 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1885 return REGDB_E_IIDNOTREG;
1888 /* ... Once we have the key, query the registry to get the
1889 value of CLSID as a string, and convert it into a
1890 proper CLSID structure to be passed back to the app */
1891 len = sizeof(value);
1892 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1895 return REGDB_E_IIDNOTREG;
1899 /* We have the CLSID we want back from the registry as a string, so
1900 let's convert it into a CLSID structure */
1901 if (CLSIDFromString(value, pclsid) != NOERROR)
1902 return REGDB_E_IIDNOTREG;
1904 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1908 /*****************************************************************************
1909 * CoRegisterPSClsid [OLE32.@]
1911 * Register a proxy/stub CLSID for the given interface in the current process
1915 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1916 * rclsid [I] CLSID of the proxy/stub.
1920 * Failure: E_OUTOFMEMORY
1924 * This function does not add anything to the registry and the effects are
1925 * limited to the lifetime of the current process.
1930 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1932 APARTMENT *apt = COM_CurrentApt();
1933 struct registered_psclsid *registered_psclsid;
1935 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1939 ERR("apartment not initialised\n");
1940 return CO_E_NOTINITIALIZED;
1943 EnterCriticalSection(&apt->cs);
1945 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1946 if (IsEqualIID(®istered_psclsid->iid, riid))
1948 registered_psclsid->clsid = *rclsid;
1949 LeaveCriticalSection(&apt->cs);
1953 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1954 if (!registered_psclsid)
1956 LeaveCriticalSection(&apt->cs);
1957 return E_OUTOFMEMORY;
1960 registered_psclsid->iid = *riid;
1961 registered_psclsid->clsid = *rclsid;
1962 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1964 LeaveCriticalSection(&apt->cs);
1971 * COM_GetRegisteredClassObject
1973 * This internal method is used to scan the registered class list to
1974 * find a class object.
1977 * rclsid Class ID of the class to find.
1978 * dwClsContext Class context to match.
1979 * ppv [out] returns a pointer to the class object. Complying
1980 * to normal COM usage, this method will increase the
1981 * reference count on this object.
1983 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1984 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1986 HRESULT hr = S_FALSE;
1987 RegisteredClass *curClass;
1989 EnterCriticalSection( &csRegisteredClassList );
1991 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1994 * Check if we have a match on the class ID and context.
1996 if ((apt->oxid == curClass->apartment_id) &&
1997 (dwClsContext & curClass->runContext) &&
1998 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2001 * We have a match, return the pointer to the class object.
2003 *ppUnk = curClass->classObject;
2005 IUnknown_AddRef(curClass->classObject);
2012 LeaveCriticalSection( &csRegisteredClassList );
2017 /******************************************************************************
2018 * CoRegisterClassObject [OLE32.@]
2020 * Registers the class object for a given class ID. Servers housed in EXE
2021 * files use this method instead of exporting DllGetClassObject to allow
2022 * other code to connect to their objects.
2025 * rclsid [I] CLSID of the object to register.
2026 * pUnk [I] IUnknown of the object.
2027 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2028 * flags [I] REGCLS flags indicating how connections are made.
2029 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2033 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2034 * CO_E_OBJISREG if the object is already registered. We should not return this.
2037 * CoRevokeClassObject, CoGetClassObject
2040 * In-process objects are only registered for the current apartment.
2041 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2042 * in other apartments.
2045 * MSDN claims that multiple interface registrations are legal, but we
2046 * can't do that with our current implementation.
2048 HRESULT WINAPI CoRegisterClassObject(
2053 LPDWORD lpdwRegister)
2055 RegisteredClass* newClass;
2056 LPUNKNOWN foundObject;
2060 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2061 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2063 if ( (lpdwRegister==0) || (pUnk==0) )
2064 return E_INVALIDARG;
2066 apt = COM_CurrentApt();
2069 ERR("COM was not initialized\n");
2070 return CO_E_NOTINITIALIZED;
2075 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2076 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2077 if (flags & REGCLS_MULTIPLEUSE)
2078 dwClsContext |= CLSCTX_INPROC_SERVER;
2081 * First, check if the class is already registered.
2082 * If it is, this should cause an error.
2084 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2086 if (flags & REGCLS_MULTIPLEUSE) {
2087 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2088 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2089 IUnknown_Release(foundObject);
2092 IUnknown_Release(foundObject);
2093 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2094 return CO_E_OBJISREG;
2097 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2098 if ( newClass == NULL )
2099 return E_OUTOFMEMORY;
2101 newClass->classIdentifier = *rclsid;
2102 newClass->apartment_id = apt->oxid;
2103 newClass->runContext = dwClsContext;
2104 newClass->connectFlags = flags;
2105 newClass->pMarshaledData = NULL;
2106 newClass->RpcRegistration = NULL;
2109 * Use the address of the chain node as the cookie since we are sure it's
2110 * unique. FIXME: not on 64-bit platforms.
2112 newClass->dwCookie = (DWORD)newClass;
2115 * Since we're making a copy of the object pointer, we have to increase its
2118 newClass->classObject = pUnk;
2119 IUnknown_AddRef(newClass->classObject);
2121 EnterCriticalSection( &csRegisteredClassList );
2122 list_add_tail(&RegisteredClassList, &newClass->entry);
2123 LeaveCriticalSection( &csRegisteredClassList );
2125 *lpdwRegister = newClass->dwCookie;
2127 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2128 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2130 FIXME("Failed to create stream on hglobal, %x\n", hr);
2133 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2134 newClass->classObject, MSHCTX_LOCAL, NULL,
2135 MSHLFLAGS_TABLESTRONG);
2137 FIXME("CoMarshalInterface failed, %x!\n",hr);
2141 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2142 newClass->pMarshaledData,
2143 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2144 &newClass->RpcRegistration);
2149 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2151 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2154 DWORD dwLength = len * sizeof(WCHAR);
2156 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2157 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2161 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2162 REFCLSID rclsid, REFIID riid,
2163 BOOL hostifnecessary, void **ppv)
2165 WCHAR dllpath[MAX_PATH+1];
2166 BOOL apartment_threaded;
2168 if (hostifnecessary)
2170 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2171 static const WCHAR wszFree[] = {'F','r','e','e',0};
2172 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2173 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2175 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2177 if (!strcmpiW(threading_model, wszApartment))
2179 apartment_threaded = TRUE;
2180 if (apt->multi_threaded)
2181 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2184 else if (!strcmpiW(threading_model, wszFree))
2186 apartment_threaded = FALSE;
2187 if (!apt->multi_threaded)
2188 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2190 /* everything except "Apartment", "Free" and "Both" */
2191 else if (strcmpiW(threading_model, wszBoth))
2193 apartment_threaded = TRUE;
2194 /* everything else is main-threaded */
2195 if (threading_model[0])
2196 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2197 debugstr_w(threading_model), debugstr_guid(rclsid));
2199 if (apt->multi_threaded || !apt->main)
2200 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2203 apartment_threaded = FALSE;
2206 apartment_threaded = !apt->multi_threaded;
2208 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2210 /* failure: CLSID is not found in registry */
2211 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2212 return REGDB_E_CLASSNOTREG;
2215 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2219 /***********************************************************************
2220 * CoGetClassObject [OLE32.@]
2222 * Creates an object of the specified class.
2225 * rclsid [I] Class ID to create an instance of.
2226 * dwClsContext [I] Flags to restrict the location of the created instance.
2227 * pServerInfo [I] Optional. Details for connecting to a remote server.
2228 * iid [I] The ID of the interface of the instance to return.
2229 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2233 * Failure: HRESULT code.
2236 * The dwClsContext parameter can be one or more of the following:
2237 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2238 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2239 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2240 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2243 * CoCreateInstance()
2245 HRESULT WINAPI CoGetClassObject(
2246 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2247 REFIID iid, LPVOID *ppv)
2249 LPUNKNOWN regClassObject;
2250 HRESULT hres = E_UNEXPECTED;
2252 BOOL release_apt = FALSE;
2254 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2257 return E_INVALIDARG;
2261 if (!(apt = COM_CurrentApt()))
2263 if (!(apt = apartment_find_multi_threaded()))
2265 ERR("apartment not initialised\n");
2266 return CO_E_NOTINITIALIZED;
2272 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2273 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2277 * First, try and see if we can't match the class ID with one of the
2278 * registered classes.
2280 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2283 /* Get the required interface from the retrieved pointer. */
2284 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2287 * Since QI got another reference on the pointer, we want to release the
2288 * one we already have. If QI was unsuccessful, this will release the object. This
2289 * is good since we are not returning it in the "out" parameter.
2291 IUnknown_Release(regClassObject);
2292 if (release_apt) apartment_release(apt);
2296 /* First try in-process server */
2297 if (CLSCTX_INPROC_SERVER & dwClsContext)
2299 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2302 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2304 if (release_apt) apartment_release(apt);
2305 return FTMarshalCF_Create(iid, ppv);
2308 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2311 if (hres == REGDB_E_CLASSNOTREG)
2312 ERR("class %s not registered\n", debugstr_guid(rclsid));
2313 else if (hres == REGDB_E_KEYMISSING)
2315 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2316 hres = REGDB_E_CLASSNOTREG;
2320 if (SUCCEEDED(hres))
2322 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2323 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2327 /* return if we got a class, otherwise fall through to one of the
2329 if (SUCCEEDED(hres))
2331 if (release_apt) apartment_release(apt);
2336 /* Next try in-process handler */
2337 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2339 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2342 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2345 if (hres == REGDB_E_CLASSNOTREG)
2346 ERR("class %s not registered\n", debugstr_guid(rclsid));
2347 else if (hres == REGDB_E_KEYMISSING)
2349 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2350 hres = REGDB_E_CLASSNOTREG;
2354 if (SUCCEEDED(hres))
2356 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2357 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2361 /* return if we got a class, otherwise fall through to one of the
2363 if (SUCCEEDED(hres))
2365 if (release_apt) apartment_release(apt);
2369 if (release_apt) apartment_release(apt);
2371 /* Next try out of process */
2372 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2374 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2375 if (SUCCEEDED(hres))
2379 /* Finally try remote: this requires networked DCOM (a lot of work) */
2380 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2382 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2383 hres = E_NOINTERFACE;
2387 ERR("no class object %s could be created for context 0x%x\n",
2388 debugstr_guid(rclsid), dwClsContext);
2392 /***********************************************************************
2393 * CoResumeClassObjects (OLE32.@)
2395 * Resumes all class objects registered with REGCLS_SUSPENDED.
2399 * Failure: HRESULT code.
2401 HRESULT WINAPI CoResumeClassObjects(void)
2407 /***********************************************************************
2408 * CoCreateInstance [OLE32.@]
2410 * Creates an instance of the specified class.
2413 * rclsid [I] Class ID to create an instance of.
2414 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2415 * dwClsContext [I] Flags to restrict the location of the created instance.
2416 * iid [I] The ID of the interface of the instance to return.
2417 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2421 * Failure: HRESULT code.
2424 * The dwClsContext parameter can be one or more of the following:
2425 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2426 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2427 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2428 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2430 * Aggregation is the concept of deferring the IUnknown of an object to another
2431 * object. This allows a separate object to behave as though it was part of
2432 * the object and to allow this the pUnkOuter parameter can be set. Note that
2433 * not all objects support having an outer of unknown.
2436 * CoGetClassObject()
2438 HRESULT WINAPI CoCreateInstance(
2440 LPUNKNOWN pUnkOuter,
2446 LPCLASSFACTORY lpclf = 0;
2449 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2450 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2459 * Initialize the "out" parameter
2463 if (!(apt = COM_CurrentApt()))
2465 if (!(apt = apartment_find_multi_threaded()))
2467 ERR("apartment not initialised\n");
2468 return CO_E_NOTINITIALIZED;
2470 apartment_release(apt);
2474 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2475 * Rather than create a class factory, we can just check for it here
2477 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2478 if (StdGlobalInterfaceTableInstance == NULL)
2479 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2480 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2481 if (hres) return hres;
2483 TRACE("Retrieved GIT (%p)\n", *ppv);
2488 * Get a class factory to construct the object we want.
2490 hres = CoGetClassObject(rclsid,
2500 * Create the object and don't forget to release the factory
2502 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2503 IClassFactory_Release(lpclf);
2506 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2507 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2509 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2515 /***********************************************************************
2516 * CoCreateInstanceEx [OLE32.@]
2518 HRESULT WINAPI CoCreateInstanceEx(
2520 LPUNKNOWN pUnkOuter,
2522 COSERVERINFO* pServerInfo,
2526 IUnknown* pUnk = NULL;
2529 ULONG successCount = 0;
2534 if ( (cmq==0) || (pResults==NULL))
2535 return E_INVALIDARG;
2537 if (pServerInfo!=NULL)
2538 FIXME("() non-NULL pServerInfo not supported!\n");
2541 * Initialize all the "out" parameters.
2543 for (index = 0; index < cmq; index++)
2545 pResults[index].pItf = NULL;
2546 pResults[index].hr = E_NOINTERFACE;
2550 * Get the object and get its IUnknown pointer.
2552 hr = CoCreateInstance(rclsid,
2562 * Then, query for all the interfaces requested.
2564 for (index = 0; index < cmq; index++)
2566 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2567 pResults[index].pIID,
2568 (VOID**)&(pResults[index].pItf));
2570 if (pResults[index].hr == S_OK)
2575 * Release our temporary unknown pointer.
2577 IUnknown_Release(pUnk);
2579 if (successCount == 0)
2580 return E_NOINTERFACE;
2582 if (successCount!=cmq)
2583 return CO_S_NOTALLINTERFACES;
2588 /***********************************************************************
2589 * CoLoadLibrary (OLE32.@)
2594 * lpszLibName [I] Path to library.
2595 * bAutoFree [I] Whether the library should automatically be freed.
2598 * Success: Handle to loaded library.
2602 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2604 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2606 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2608 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2611 /***********************************************************************
2612 * CoFreeLibrary [OLE32.@]
2614 * Unloads a library from memory.
2617 * hLibrary [I] Handle to library to unload.
2623 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2625 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2627 FreeLibrary(hLibrary);
2631 /***********************************************************************
2632 * CoFreeAllLibraries [OLE32.@]
2634 * Function for backwards compatibility only. Does nothing.
2640 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2642 void WINAPI CoFreeAllLibraries(void)
2647 /***********************************************************************
2648 * CoFreeUnusedLibrariesEx [OLE32.@]
2650 * Frees any previously unused libraries whose delay has expired and marks
2651 * currently unused libraries for unloading. Unused are identified as those that
2652 * return S_OK from their DllCanUnloadNow function.
2655 * dwUnloadDelay [I] Unload delay in milliseconds.
2656 * dwReserved [I] Reserved. Set to 0.
2662 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2664 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2666 struct apartment *apt = COM_CurrentApt();
2669 ERR("apartment not initialised\n");
2673 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2676 /***********************************************************************
2677 * CoFreeUnusedLibraries [OLE32.@]
2679 * Frees any unused libraries. Unused are identified as those that return
2680 * S_OK from their DllCanUnloadNow function.
2686 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2688 void WINAPI CoFreeUnusedLibraries(void)
2690 CoFreeUnusedLibrariesEx(INFINITE, 0);
2693 /***********************************************************************
2694 * CoFileTimeNow [OLE32.@]
2696 * Retrieves the current time in FILETIME format.
2699 * lpFileTime [O] The current time.
2704 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2706 GetSystemTimeAsFileTime( lpFileTime );
2710 /******************************************************************************
2711 * CoLockObjectExternal [OLE32.@]
2713 * Increments or decrements the external reference count of a stub object.
2716 * pUnk [I] Stub object.
2717 * fLock [I] If TRUE then increments the external ref-count,
2718 * otherwise decrements.
2719 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2720 * calling CoDisconnectObject.
2724 * Failure: HRESULT code.
2727 * If fLock is TRUE and an object is passed in that doesn't have a stub
2728 * manager then a new stub manager is created for the object.
2730 HRESULT WINAPI CoLockObjectExternal(
2733 BOOL fLastUnlockReleases)
2735 struct stub_manager *stubmgr;
2736 struct apartment *apt;
2738 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2739 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2741 apt = COM_CurrentApt();
2742 if (!apt) return CO_E_NOTINITIALIZED;
2744 stubmgr = get_stub_manager_from_object(apt, pUnk);
2749 stub_manager_ext_addref(stubmgr, 1, FALSE);
2751 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2753 stub_manager_int_release(stubmgr);
2759 stubmgr = new_stub_manager(apt, pUnk);
2763 stub_manager_ext_addref(stubmgr, 1, FALSE);
2764 stub_manager_int_release(stubmgr);
2771 WARN("stub object not found %p\n", pUnk);
2772 /* Note: native is pretty broken here because it just silently
2773 * fails, without returning an appropriate error code, making apps
2774 * think that the object was disconnected, when it actually wasn't */
2779 /***********************************************************************
2780 * CoInitializeWOW (OLE32.@)
2782 * WOW equivalent of CoInitialize?
2791 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2793 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2797 /***********************************************************************
2798 * CoGetState [OLE32.@]
2800 * Retrieves the thread state object previously stored by CoSetState().
2803 * ppv [I] Address where pointer to object will be stored.
2807 * Failure: E_OUTOFMEMORY.
2810 * Crashes on all invalid ppv addresses, including NULL.
2811 * If the function returns a non-NULL object then the caller must release its
2812 * reference on the object when the object is no longer required.
2817 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2819 struct oletls *info = COM_CurrentInfo();
2820 if (!info) return E_OUTOFMEMORY;
2826 IUnknown_AddRef(info->state);
2828 TRACE("apt->state=%p\n", info->state);
2834 /***********************************************************************
2835 * CoSetState [OLE32.@]
2837 * Sets the thread state object.
2840 * pv [I] Pointer to state object to be stored.
2843 * The system keeps a reference on the object while the object stored.
2847 * Failure: E_OUTOFMEMORY.
2849 HRESULT WINAPI CoSetState(IUnknown * pv)
2851 struct oletls *info = COM_CurrentInfo();
2852 if (!info) return E_OUTOFMEMORY;
2854 if (pv) IUnknown_AddRef(pv);
2858 TRACE("-- release %p now\n", info->state);
2859 IUnknown_Release(info->state);
2868 /******************************************************************************
2869 * CoTreatAsClass [OLE32.@]
2871 * Sets the TreatAs value of a class.
2874 * clsidOld [I] Class to set TreatAs value on.
2875 * clsidNew [I] The class the clsidOld should be treated as.
2879 * Failure: HRESULT code.
2884 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2886 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2887 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2889 WCHAR szClsidNew[CHARS_IN_GUID];
2891 WCHAR auto_treat_as[CHARS_IN_GUID];
2892 LONG auto_treat_as_size = sizeof(auto_treat_as);
2895 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2898 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2900 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2901 CLSIDFromString(auto_treat_as, &id) == S_OK)
2903 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2905 res = REGDB_E_WRITEREGDB;
2911 RegDeleteKeyW(hkey, wszTreatAs);
2915 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2916 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2918 res = REGDB_E_WRITEREGDB;
2923 if (hkey) RegCloseKey(hkey);
2927 /******************************************************************************
2928 * CoGetTreatAsClass [OLE32.@]
2930 * Gets the TreatAs value of a class.
2933 * clsidOld [I] Class to get the TreatAs value of.
2934 * clsidNew [I] The class the clsidOld should be treated as.
2938 * Failure: HRESULT code.
2943 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2945 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2947 WCHAR szClsidNew[CHARS_IN_GUID];
2949 LONG len = sizeof(szClsidNew);
2951 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2952 *clsidNew = *clsidOld; /* copy over old value */
2954 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2960 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2965 res = CLSIDFromString(szClsidNew,clsidNew);
2967 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2969 if (hkey) RegCloseKey(hkey);
2973 /******************************************************************************
2974 * CoGetCurrentProcess [OLE32.@]
2976 * Gets the current process ID.
2979 * The current process ID.
2982 * Is DWORD really the correct return type for this function?
2984 DWORD WINAPI CoGetCurrentProcess(void)
2986 return GetCurrentProcessId();
2989 /******************************************************************************
2990 * CoRegisterMessageFilter [OLE32.@]
2992 * Registers a message filter.
2995 * lpMessageFilter [I] Pointer to interface.
2996 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3000 * Failure: HRESULT code.
3003 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3004 * lpMessageFilter removes the message filter.
3006 * If lplpMessageFilter is not NULL the previous message filter will be
3007 * returned in the memory pointer to this parameter and the caller is
3008 * responsible for releasing the object.
3010 * The current thread be in an apartment otherwise the function will crash.
3012 HRESULT WINAPI CoRegisterMessageFilter(
3013 LPMESSAGEFILTER lpMessageFilter,
3014 LPMESSAGEFILTER *lplpMessageFilter)
3016 struct apartment *apt;
3017 IMessageFilter *lpOldMessageFilter;
3019 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3021 apt = COM_CurrentApt();
3023 /* can't set a message filter in a multi-threaded apartment */
3024 if (!apt || apt->multi_threaded)
3026 WARN("can't set message filter in MTA or uninitialized apt\n");
3027 return CO_E_NOT_SUPPORTED;
3030 if (lpMessageFilter)
3031 IMessageFilter_AddRef(lpMessageFilter);
3033 EnterCriticalSection(&apt->cs);
3035 lpOldMessageFilter = apt->filter;
3036 apt->filter = lpMessageFilter;
3038 LeaveCriticalSection(&apt->cs);
3040 if (lplpMessageFilter)
3041 *lplpMessageFilter = lpOldMessageFilter;
3042 else if (lpOldMessageFilter)
3043 IMessageFilter_Release(lpOldMessageFilter);
3048 /***********************************************************************
3049 * CoIsOle1Class [OLE32.@]
3051 * Determines whether the specified class an OLE v1 class.
3054 * clsid [I] Class to test.
3057 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3059 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3061 FIXME("%s\n", debugstr_guid(clsid));
3065 /***********************************************************************
3066 * IsEqualGUID [OLE32.@]
3068 * Compares two Unique Identifiers.
3071 * rguid1 [I] The first GUID to compare.
3072 * rguid2 [I] The other GUID to compare.
3078 BOOL WINAPI IsEqualGUID(
3082 return !memcmp(rguid1,rguid2,sizeof(GUID));
3085 /***********************************************************************
3086 * CoInitializeSecurity [OLE32.@]
3088 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3089 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3090 void* pReserved1, DWORD dwAuthnLevel,
3091 DWORD dwImpLevel, void* pReserved2,
3092 DWORD dwCapabilities, void* pReserved3)
3094 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3095 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3096 dwCapabilities, pReserved3);
3100 /***********************************************************************
3101 * CoSuspendClassObjects [OLE32.@]
3103 * Suspends all registered class objects to prevent further requests coming in
3104 * for those objects.
3108 * Failure: HRESULT code.
3110 HRESULT WINAPI CoSuspendClassObjects(void)
3116 /***********************************************************************
3117 * CoAddRefServerProcess [OLE32.@]
3119 * Helper function for incrementing the reference count of a local-server
3123 * New reference count.
3126 * CoReleaseServerProcess().
3128 ULONG WINAPI CoAddRefServerProcess(void)
3134 EnterCriticalSection(&csRegisteredClassList);
3135 refs = ++s_COMServerProcessReferences;
3136 LeaveCriticalSection(&csRegisteredClassList);
3138 TRACE("refs before: %d\n", refs - 1);
3143 /***********************************************************************
3144 * CoReleaseServerProcess [OLE32.@]
3146 * Helper function for decrementing the reference count of a local-server
3150 * New reference count.
3153 * When reference count reaches 0, this function suspends all registered
3154 * classes so no new connections are accepted.
3157 * CoAddRefServerProcess(), CoSuspendClassObjects().
3159 ULONG WINAPI CoReleaseServerProcess(void)
3165 EnterCriticalSection(&csRegisteredClassList);
3167 refs = --s_COMServerProcessReferences;
3168 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3170 LeaveCriticalSection(&csRegisteredClassList);
3172 TRACE("refs after: %d\n", refs);
3177 /***********************************************************************
3178 * CoIsHandlerConnected [OLE32.@]
3180 * Determines whether a proxy is connected to a remote stub.
3183 * pUnk [I] Pointer to object that may or may not be connected.
3186 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3189 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3191 FIXME("%p\n", pUnk);
3196 /***********************************************************************
3197 * CoAllowSetForegroundWindow [OLE32.@]
3200 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3202 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3206 /***********************************************************************
3207 * CoQueryProxyBlanket [OLE32.@]
3209 * Retrieves the security settings being used by a proxy.
3212 * pProxy [I] Pointer to the proxy object.
3213 * pAuthnSvc [O] The type of authentication service.
3214 * pAuthzSvc [O] The type of authorization service.
3215 * ppServerPrincName [O] Optional. The server prinicple name.
3216 * pAuthnLevel [O] The authentication level.
3217 * pImpLevel [O] The impersonation level.
3218 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3219 * pCapabilities [O] Flags affecting the security behaviour.
3223 * Failure: HRESULT code.
3226 * CoCopyProxy, CoSetProxyBlanket.
3228 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3229 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3230 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3232 IClientSecurity *pCliSec;
3235 TRACE("%p\n", pProxy);
3237 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3240 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3241 pAuthzSvc, ppServerPrincName,
3242 pAuthnLevel, pImpLevel, ppAuthInfo,
3244 IClientSecurity_Release(pCliSec);
3247 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3251 /***********************************************************************
3252 * CoSetProxyBlanket [OLE32.@]
3254 * Sets the security settings for a proxy.
3257 * pProxy [I] Pointer to the proxy object.
3258 * AuthnSvc [I] The type of authentication service.
3259 * AuthzSvc [I] The type of authorization service.
3260 * pServerPrincName [I] The server prinicple name.
3261 * AuthnLevel [I] The authentication level.
3262 * ImpLevel [I] The impersonation level.
3263 * pAuthInfo [I] Information specific to the authorization/authentication service.
3264 * Capabilities [I] Flags affecting the security behaviour.
3268 * Failure: HRESULT code.
3271 * CoQueryProxyBlanket, CoCopyProxy.
3273 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3274 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3275 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3277 IClientSecurity *pCliSec;
3280 TRACE("%p\n", pProxy);
3282 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3285 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3286 AuthzSvc, pServerPrincName,
3287 AuthnLevel, ImpLevel, pAuthInfo,
3289 IClientSecurity_Release(pCliSec);
3292 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3296 /***********************************************************************
3297 * CoCopyProxy [OLE32.@]
3302 * pProxy [I] Pointer to the proxy object.
3303 * ppCopy [O] Copy of the proxy.
3307 * Failure: HRESULT code.
3310 * CoQueryProxyBlanket, CoSetProxyBlanket.
3312 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3314 IClientSecurity *pCliSec;
3317 TRACE("%p\n", pProxy);
3319 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3322 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3323 IClientSecurity_Release(pCliSec);
3326 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3331 /***********************************************************************
3332 * CoGetCallContext [OLE32.@]
3334 * Gets the context of the currently executing server call in the current
3338 * riid [I] Context interface to return.
3339 * ppv [O] Pointer to memory that will receive the context on return.
3343 * Failure: HRESULT code.
3345 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3347 struct oletls *info = COM_CurrentInfo();
3349 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3352 return E_OUTOFMEMORY;
3354 if (!info->call_state)
3355 return RPC_E_CALL_COMPLETE;
3357 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3360 /***********************************************************************
3361 * CoSwitchCallContext [OLE32.@]
3363 * Switches the context of the currently executing server call in the current
3367 * pObject [I] Pointer to new context object
3368 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3372 * Failure: HRESULT code.
3374 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3376 struct oletls *info = COM_CurrentInfo();
3378 TRACE("(%p, %p)\n", pObject, ppOldObject);
3381 return E_OUTOFMEMORY;
3383 *ppOldObject = info->call_state;
3384 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3389 /***********************************************************************
3390 * CoQueryClientBlanket [OLE32.@]
3392 * Retrieves the authentication information about the client of the currently
3393 * executing server call in the current thread.
3396 * pAuthnSvc [O] Optional. The type of authentication service.
3397 * pAuthzSvc [O] Optional. The type of authorization service.
3398 * pServerPrincName [O] Optional. The server prinicple name.
3399 * pAuthnLevel [O] Optional. The authentication level.
3400 * pImpLevel [O] Optional. The impersonation level.
3401 * pPrivs [O] Optional. Information about the privileges of the client.
3402 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3406 * Failure: HRESULT code.
3409 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3411 HRESULT WINAPI CoQueryClientBlanket(
3414 OLECHAR **pServerPrincName,
3417 RPC_AUTHZ_HANDLE *pPrivs,
3418 DWORD *pCapabilities)
3420 IServerSecurity *pSrvSec;
3423 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3424 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3425 pPrivs, pCapabilities);
3427 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3430 hr = IServerSecurity_QueryBlanket(
3431 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3432 pImpLevel, pPrivs, pCapabilities);
3433 IServerSecurity_Release(pSrvSec);
3439 /***********************************************************************
3440 * CoImpersonateClient [OLE32.@]
3442 * Impersonates the client of the currently executing server call in the
3450 * Failure: HRESULT code.
3453 * If this function fails then the current thread will not be impersonating
3454 * the client and all actions will take place on behalf of the server.
3455 * Therefore, it is important to check the return value from this function.
3458 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3460 HRESULT WINAPI CoImpersonateClient(void)
3462 IServerSecurity *pSrvSec;
3467 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3470 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3471 IServerSecurity_Release(pSrvSec);
3477 /***********************************************************************
3478 * CoRevertToSelf [OLE32.@]
3480 * Ends the impersonation of the client of the currently executing server
3481 * call in the current thread.
3488 * Failure: HRESULT code.
3491 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3493 HRESULT WINAPI CoRevertToSelf(void)
3495 IServerSecurity *pSrvSec;
3500 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3503 hr = IServerSecurity_RevertToSelf(pSrvSec);
3504 IServerSecurity_Release(pSrvSec);
3510 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3512 /* first try to retrieve messages for incoming COM calls to the apartment window */
3513 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3514 /* next retrieve other messages necessary for the app to remain responsive */
3515 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3516 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3519 /***********************************************************************
3520 * CoWaitForMultipleHandles [OLE32.@]
3522 * Waits for one or more handles to become signaled.
3525 * dwFlags [I] Flags. See notes.
3526 * dwTimeout [I] Timeout in milliseconds.
3527 * cHandles [I] Number of handles pointed to by pHandles.
3528 * pHandles [I] Handles to wait for.
3529 * lpdwindex [O] Index of handle that was signaled.
3533 * Failure: RPC_S_CALLPENDING on timeout.
3537 * The dwFlags parameter can be zero or more of the following:
3538 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3539 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3542 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3544 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3545 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3548 DWORD start_time = GetTickCount();
3549 APARTMENT *apt = COM_CurrentApt();
3550 BOOL message_loop = apt && !apt->multi_threaded;
3552 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3553 pHandles, lpdwindex);
3557 DWORD now = GetTickCount();
3560 if (now - start_time > dwTimeout)
3562 hr = RPC_S_CALLPENDING;
3568 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3569 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3571 TRACE("waiting for rpc completion or window message\n");
3573 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3574 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3575 QS_ALLINPUT, wait_flags);
3577 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3581 /* call message filter */
3583 if (COM_CurrentApt()->filter)
3585 PENDINGTYPE pendingtype =
3586 COM_CurrentInfo()->pending_call_count_server ?
3587 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3588 DWORD be_handled = IMessageFilter_MessagePending(
3589 COM_CurrentApt()->filter, 0 /* FIXME */,
3590 now - start_time, pendingtype);
3591 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3594 case PENDINGMSG_CANCELCALL:
3595 WARN("call canceled\n");
3596 hr = RPC_E_CALL_CANCELED;
3598 case PENDINGMSG_WAITNOPROCESS:
3599 case PENDINGMSG_WAITDEFPROCESS:
3601 /* FIXME: MSDN is very vague about the difference
3602 * between WAITNOPROCESS and WAITDEFPROCESS - there
3603 * appears to be none, so it is possibly a left-over
3604 * from the 16-bit world. */
3609 /* note: using "if" here instead of "while" might seem less
3610 * efficient, but only if we are optimising for quick delivery
3611 * of pending messages, rather than quick completion of the
3613 if (COM_PeekMessage(apt, &msg))
3615 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3616 TranslateMessage(&msg);
3617 DispatchMessageW(&msg);
3618 if (msg.message == WM_QUIT)
3620 TRACE("resending WM_QUIT to outer message loop\n");
3621 PostQuitMessage(msg.wParam);
3622 /* no longer need to process messages */
3623 message_loop = FALSE;
3631 TRACE("waiting for rpc completion\n");
3633 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3634 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3635 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3636 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3639 if (res < WAIT_OBJECT_0 + cHandles)
3641 /* handle signaled, store index */
3642 *lpdwindex = (res - WAIT_OBJECT_0);
3645 else if (res == WAIT_TIMEOUT)
3647 hr = RPC_S_CALLPENDING;
3652 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3657 TRACE("-- 0x%08x\n", hr);
3662 /***********************************************************************
3663 * CoGetObject [OLE32.@]
3665 * Gets the object named by converting the name to a moniker and binding to it.
3668 * pszName [I] String representing the object.
3669 * pBindOptions [I] Parameters affecting the binding to the named object.
3670 * riid [I] Interface to bind to on the objecct.
3671 * ppv [O] On output, the interface riid of the object represented
3676 * Failure: HRESULT code.
3679 * MkParseDisplayName.
3681 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3682 REFIID riid, void **ppv)
3689 hr = CreateBindCtx(0, &pbc);
3693 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3700 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3703 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3704 IMoniker_Release(pmk);
3708 IBindCtx_Release(pbc);
3713 /***********************************************************************
3714 * CoRegisterChannelHook [OLE32.@]
3716 * Registers a process-wide hook that is called during ORPC calls.
3719 * guidExtension [I] GUID of the channel hook to register.
3720 * pChannelHook [I] Channel hook object to register.
3724 * Failure: HRESULT code.
3726 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3728 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3730 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3733 typedef struct Context
3735 const IComThreadingInfoVtbl *lpVtbl;
3736 const IContextCallbackVtbl *lpCallbackVtbl;
3737 const IObjContextVtbl *lpContextVtbl;
3742 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3744 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3747 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3749 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3752 static inline Context *impl_from_IObjContext( IObjContext *iface )
3754 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl));
3757 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3761 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3762 IsEqualIID(riid, &IID_IUnknown))
3764 *ppv = &iface->lpVtbl;
3766 else if (IsEqualIID(riid, &IID_IContextCallback))
3768 *ppv = &iface->lpCallbackVtbl;
3770 else if (IsEqualIID(riid, &IID_IObjContext))
3772 *ppv = &iface->lpContextVtbl;
3777 IUnknown_AddRef((IUnknown*)*ppv);
3781 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3782 return E_NOINTERFACE;
3785 static ULONG Context_AddRef(Context *This)
3787 return InterlockedIncrement(&This->refs);
3790 static ULONG Context_Release(Context *This)
3792 ULONG refs = InterlockedDecrement(&This->refs);
3794 HeapFree(GetProcessHeap(), 0, This);
3798 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3800 Context *This = impl_from_IComThreadingInfo(iface);
3801 return Context_QueryInterface(This, riid, ppv);
3804 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3806 Context *This = impl_from_IComThreadingInfo(iface);
3807 return Context_AddRef(This);
3810 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3812 Context *This = impl_from_IComThreadingInfo(iface);
3813 return Context_Release(This);
3816 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3818 Context *This = impl_from_IComThreadingInfo(iface);
3820 TRACE("(%p)\n", apttype);
3822 *apttype = This->apttype;
3826 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3828 Context *This = impl_from_IComThreadingInfo(iface);
3830 TRACE("(%p)\n", thdtype);
3832 switch (This->apttype)
3835 case APTTYPE_MAINSTA:
3836 *thdtype = THDTYPE_PROCESSMESSAGES;
3839 *thdtype = THDTYPE_BLOCKMESSAGES;
3845 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3847 FIXME("(%p): stub\n", logical_thread_id);
3851 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3853 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3857 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3859 Context_CTI_QueryInterface,
3861 Context_CTI_Release,
3862 Context_CTI_GetCurrentApartmentType,
3863 Context_CTI_GetCurrentThreadType,
3864 Context_CTI_GetCurrentLogicalThreadId,
3865 Context_CTI_SetCurrentLogicalThreadId
3868 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3870 Context *This = impl_from_IContextCallback(iface);
3871 return Context_QueryInterface(This, riid, ppv);
3874 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3876 Context *This = impl_from_IContextCallback(iface);
3877 return Context_AddRef(This);
3880 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3882 Context *This = impl_from_IContextCallback(iface);
3883 return Context_Release(This);
3886 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3887 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3889 Context *This = impl_from_IContextCallback(iface);
3891 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3895 static const IContextCallbackVtbl Context_Callback_Vtbl =
3897 Context_CC_QueryInterface,
3900 Context_CC_ContextCallback
3903 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3905 Context *This = impl_from_IObjContext(iface);
3906 return Context_QueryInterface(This, riid, ppv);
3909 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3911 Context *This = impl_from_IObjContext(iface);
3912 return Context_AddRef(This);
3915 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3917 Context *This = impl_from_IObjContext(iface);
3918 return Context_Release(This);
3921 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3923 Context *This = impl_from_IObjContext(iface);
3925 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3929 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3931 Context *This = impl_from_IObjContext(iface);
3933 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3937 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3939 Context *This = impl_from_IObjContext(iface);
3941 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3945 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
3947 Context *This = impl_from_IObjContext(iface);
3949 FIXME("(%p/%p)->(%p)\n", This, iface, props);
3953 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
3955 Context *This = impl_from_IObjContext(iface);
3956 FIXME("(%p/%p)\n", This, iface);
3959 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
3961 Context *This = impl_from_IObjContext(iface);
3962 FIXME("(%p/%p)\n", This, iface);
3965 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
3967 Context *This = impl_from_IObjContext(iface);
3968 FIXME("(%p/%p)\n", This, iface);
3971 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
3973 Context *This = impl_from_IObjContext(iface);
3974 FIXME("(%p/%p)\n", This, iface);
3977 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
3979 Context *This = impl_from_IObjContext(iface);
3980 FIXME("(%p/%p)\n", This, iface);
3983 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
3985 Context *This = impl_from_IObjContext(iface);
3986 FIXME("(%p/%p)\n", This, iface);
3989 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
3991 Context *This = impl_from_IObjContext(iface);
3992 FIXME("(%p/%p)\n", This, iface);
3995 static const IObjContextVtbl Context_Object_Vtbl =
3997 Context_OC_QueryInterface,
4000 Context_OC_SetProperty,
4001 Context_OC_RemoveProperty,
4002 Context_OC_GetProperty,
4003 Context_OC_EnumContextProps,
4004 Context_OC_Reserved1,
4005 Context_OC_Reserved2,
4006 Context_OC_Reserved3,
4007 Context_OC_Reserved4,
4008 Context_OC_Reserved5,
4009 Context_OC_Reserved6,
4010 Context_OC_Reserved7
4013 /***********************************************************************
4014 * CoGetObjectContext [OLE32.@]
4016 * Retrieves an object associated with the current context (i.e. apartment).
4019 * riid [I] ID of the interface of the object to retrieve.
4020 * ppv [O] Address where object will be stored on return.
4024 * Failure: HRESULT code.
4026 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4028 APARTMENT *apt = COM_CurrentApt();
4032 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4037 if (!(apt = apartment_find_multi_threaded()))
4039 ERR("apartment not initialised\n");
4040 return CO_E_NOTINITIALIZED;
4042 apartment_release(apt);
4045 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4047 return E_OUTOFMEMORY;
4049 context->lpVtbl = &Context_Threading_Vtbl;
4050 context->lpCallbackVtbl = &Context_Callback_Vtbl;
4051 context->lpContextVtbl = &Context_Object_Vtbl;
4053 if (apt->multi_threaded)
4054 context->apttype = APTTYPE_MTA;
4056 context->apttype = APTTYPE_MAINSTA;
4058 context->apttype = APTTYPE_STA;
4060 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
4061 IUnknown_Release((IUnknown *)&context->lpVtbl);
4067 /***********************************************************************
4068 * CoGetContextToken [OLE32.@]
4070 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4072 struct oletls *info = COM_CurrentInfo();
4074 TRACE("(%p)\n", token);
4077 return E_OUTOFMEMORY;
4082 if (!(apt = apartment_find_multi_threaded()))
4084 ERR("apartment not initialised\n");
4085 return CO_E_NOTINITIALIZED;
4087 apartment_release(apt);
4093 if (!info->context_token)
4098 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4099 if (FAILED(hr)) return hr;
4100 info->context_token = ctx;
4103 *token = (ULONG_PTR)info->context_token;
4104 TRACE("apt->context_token=%p\n", info->context_token);
4109 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4111 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4115 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4116 if (SUCCEEDED(hres))
4118 WCHAR dllpath[MAX_PATH+1];
4120 if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4122 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4123 if (!strcmpiW(dllpath, wszOle32))
4126 return HandlerCF_Create(rclsid, riid, ppv);
4130 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4134 return CLASS_E_CLASSNOTAVAILABLE;
4137 /***********************************************************************
4140 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4142 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4145 case DLL_PROCESS_ATTACH:
4146 hProxyDll = hinstDLL;
4147 COMPOBJ_InitProcess();
4148 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
4151 case DLL_PROCESS_DETACH:
4152 if (TRACE_ON(ole)) CoRevokeMallocSpy();
4153 OLEDD_UnInitialize();
4154 COMPOBJ_UninitProcess();
4155 RPC_UnregisterAllChannelHooks();
4156 COMPOBJ_DllList_Free();
4159 case DLL_THREAD_DETACH:
4166 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */