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
59 #include "compobj_private.h"
61 #include "wine/unicode.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
66 HINSTANCE OLE32_hInstance = 0;
68 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
75 DWORD dwClsContext, LPUNKNOWN* ppUnk);
76 static void COM_RevokeAllClasses(const struct apartment *apt);
77 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
119 CLSID classIdentifier;
121 LPUNKNOWN classObject;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /*****************************************************************************
141 * This section contains OpenDllList definitions
143 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
144 * other functions that do LoadLibrary _without_ giving back a HMODULE.
145 * Without this list these handles would never be freed.
147 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
148 * next unload-call but not before 600 sec.
151 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
152 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
154 typedef struct tagOpenDll
159 DllGetClassObjectFunc DllGetClassObject;
160 DllCanUnloadNowFunc DllCanUnloadNow;
164 static struct list openDllList = LIST_INIT(openDllList);
166 static CRITICAL_SECTION csOpenDllList;
167 static CRITICAL_SECTION_DEBUG dll_cs_debug =
169 0, 0, &csOpenDllList,
170 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
171 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
173 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
175 struct apartment_loaded_dll
183 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',' ',
184 '0','x','#','#','#','#','#','#','#','#',' ',0};
185 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
187 BOOL apartment_threaded,
188 REFCLSID rclsid, REFIID riid, void **ppv);
189 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
191 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
193 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
195 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
197 static void COMPOBJ_InitProcess( void )
201 /* Dispatching to the correct thread in an apartment is done through
202 * window messages rather than RPC transports. When an interface is
203 * marshalled into another apartment in the same process, a window of the
204 * following class is created. The *caller* of CoMarshalInterface (i.e., the
205 * application) is responsible for pumping the message loop in that thread.
206 * The WM_USER messages which point to the RPCs are then dispatched to
207 * apartment_wndproc by the user's code from the apartment in which the
208 * interface was unmarshalled.
210 memset(&wclass, 0, sizeof(wclass));
211 wclass.lpfnWndProc = apartment_wndproc;
212 wclass.hInstance = OLE32_hInstance;
213 wclass.lpszClassName = wszAptWinClass;
214 RegisterClassW(&wclass);
217 static void COMPOBJ_UninitProcess( void )
219 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
222 static void COM_TlsDestroy(void)
224 struct oletls *info = NtCurrentTeb()->ReservedForOle;
227 if (info->apt) apartment_release(info->apt);
228 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
229 if (info->state) IUnknown_Release(info->state);
230 HeapFree(GetProcessHeap(), 0, info);
231 NtCurrentTeb()->ReservedForOle = NULL;
235 /******************************************************************************
239 /* allocates memory and fills in the necessary fields for a new apartment
240 * object. must be called inside apartment cs */
241 static APARTMENT *apartment_construct(DWORD model)
245 TRACE("creating new apartment, model=%d\n", model);
247 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
248 apt->tid = GetCurrentThreadId();
250 list_init(&apt->proxies);
251 list_init(&apt->stubmgrs);
252 list_init(&apt->psclsids);
253 list_init(&apt->loaded_dlls);
256 apt->remunk_exported = FALSE;
258 InitializeCriticalSection(&apt->cs);
259 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
261 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
263 if (apt->multi_threaded)
265 /* FIXME: should be randomly generated by in an RPC call to rpcss */
266 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
270 /* FIXME: should be randomly generated by in an RPC call to rpcss */
271 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
281 /* gets and existing apartment if one exists or otherwise creates an apartment
282 * structure which stores OLE apartment-local information and stores a pointer
283 * to it in the thread-local storage */
284 static APARTMENT *apartment_get_or_create(DWORD model)
286 APARTMENT *apt = COM_CurrentApt();
290 if (model & COINIT_APARTMENTTHREADED)
292 EnterCriticalSection(&csApartment);
294 apt = apartment_construct(model);
299 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
302 LeaveCriticalSection(&csApartment);
305 apartment_createwindowifneeded(apt);
309 EnterCriticalSection(&csApartment);
311 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
312 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
316 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
317 apartment_addref(MTA);
320 MTA = apartment_construct(model);
324 LeaveCriticalSection(&csApartment);
326 COM_CurrentInfo()->apt = apt;
332 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
334 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
337 DWORD apartment_addref(struct apartment *apt)
339 DWORD refs = InterlockedIncrement(&apt->refs);
340 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
344 DWORD apartment_release(struct apartment *apt)
348 EnterCriticalSection(&csApartment);
350 ret = InterlockedDecrement(&apt->refs);
351 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
352 /* destruction stuff that needs to happen under csApartment CS */
355 if (apt == MTA) MTA = NULL;
356 else if (apt == MainApartment) MainApartment = NULL;
357 list_remove(&apt->entry);
360 LeaveCriticalSection(&csApartment);
364 struct list *cursor, *cursor2;
366 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
368 /* Release the references to the registered class objects */
369 COM_RevokeAllClasses(apt);
371 /* no locking is needed for this apartment, because no other thread
372 * can access it at this point */
374 apartment_disconnectproxies(apt);
376 if (apt->win) DestroyWindow(apt->win);
377 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
379 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
381 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
382 /* release the implicit reference given by the fact that the
383 * stub has external references (it must do since it is in the
384 * stub manager list in the apartment and all non-apartment users
385 * must have a ref on the apartment and so it cannot be destroyed).
387 stub_manager_int_release(stubmgr);
390 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
392 struct registered_psclsid *registered_psclsid =
393 LIST_ENTRY(cursor, struct registered_psclsid, entry);
395 list_remove(®istered_psclsid->entry);
396 HeapFree(GetProcessHeap(), 0, registered_psclsid);
399 /* if this assert fires, then another thread took a reference to a
400 * stub manager without taking a reference to the containing
401 * apartment, which it must do. */
402 assert(list_empty(&apt->stubmgrs));
404 if (apt->filter) IUnknown_Release(apt->filter);
406 /* free as many unused libraries as possible... */
407 apartment_freeunusedlibraries(apt, 0);
409 /* ... and free the memory for the apartment loaded dll entry and
410 * release the dll list reference without freeing the library for the
412 while ((cursor = list_head(&apt->loaded_dlls)))
414 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
415 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
417 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
420 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
421 DeleteCriticalSection(&apt->cs);
423 HeapFree(GetProcessHeap(), 0, apt);
429 /* The given OXID must be local to this process:
431 * The ref parameter is here mostly to ensure people remember that
432 * they get one, you should normally take a ref for thread safety.
434 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
436 APARTMENT *result = NULL;
439 EnterCriticalSection(&csApartment);
440 LIST_FOR_EACH( cursor, &apts )
442 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
443 if (apt->oxid == oxid)
446 if (ref) apartment_addref(result);
450 LeaveCriticalSection(&csApartment);
455 /* gets the apartment which has a given creator thread ID. The caller must
456 * release the reference from the apartment as soon as the apartment pointer
457 * is no longer required. */
458 APARTMENT *apartment_findfromtid(DWORD tid)
460 APARTMENT *result = NULL;
463 EnterCriticalSection(&csApartment);
464 LIST_FOR_EACH( cursor, &apts )
466 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
470 apartment_addref(result);
474 LeaveCriticalSection(&csApartment);
479 /* gets the main apartment if it exists. The caller must
480 * release the reference from the apartment as soon as the apartment pointer
481 * is no longer required. */
482 static APARTMENT *apartment_findmain(void)
486 EnterCriticalSection(&csApartment);
488 result = MainApartment;
489 if (result) apartment_addref(result);
491 LeaveCriticalSection(&csApartment);
496 struct host_object_params
499 CLSID clsid; /* clsid of object to marshal */
500 IID iid; /* interface to marshal */
501 HANDLE event; /* event signalling when ready for multi-threaded case */
502 HRESULT hr; /* result for multi-threaded case */
503 IStream *stream; /* stream that the object will be marshaled into */
504 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
507 static HRESULT apartment_hostobject(struct apartment *apt,
508 const struct host_object_params *params)
512 static const LARGE_INTEGER llZero;
513 WCHAR dllpath[MAX_PATH+1];
515 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
517 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
519 /* failure: CLSID is not found in registry */
520 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
521 return REGDB_E_CLASSNOTREG;
524 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
525 ¶ms->clsid, ¶ms->iid, (void **)&object);
529 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
531 IUnknown_Release(object);
532 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
537 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
542 RPC_ExecuteCall((struct dispatch_params *)lParam);
545 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
547 return DefWindowProcW(hWnd, msg, wParam, lParam);
551 struct host_thread_params
553 COINIT threading_model;
558 /* thread for hosting an object to allow an object to appear to be created in
559 * an apartment with an incompatible threading model */
560 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
562 struct host_thread_params *params = p;
565 struct apartment *apt;
569 hr = CoInitializeEx(NULL, params->threading_model);
570 if (FAILED(hr)) return hr;
572 apt = COM_CurrentApt();
573 if (params->threading_model == COINIT_APARTMENTTHREADED)
575 apartment_createwindowifneeded(apt);
576 params->apartment_hwnd = apartment_getwindow(apt);
579 params->apartment_hwnd = NULL;
581 /* force the message queue to be created before signaling parent thread */
582 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
584 SetEvent(params->ready_event);
585 params = NULL; /* can't touch params after here as it may be invalid */
587 while (GetMessageW(&msg, NULL, 0, 0))
589 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
591 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
592 obj_params->hr = apartment_hostobject(apt, obj_params);
593 SetEvent(obj_params->event);
597 TranslateMessage(&msg);
598 DispatchMessageW(&msg);
609 /* finds or creates a host apartment, creates the object inside it and returns
610 * a proxy to it so that the object can be used in the apartment of the
611 * caller of this function */
612 static HRESULT apartment_hostobject_in_hostapt(
613 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
614 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
616 struct host_object_params params;
617 HWND apartment_hwnd = NULL;
618 DWORD apartment_tid = 0;
621 if (!multi_threaded && main_apartment)
623 APARTMENT *host_apt = apartment_findmain();
626 apartment_hwnd = apartment_getwindow(host_apt);
627 apartment_release(host_apt);
633 EnterCriticalSection(&apt->cs);
635 if (!apt->host_apt_tid)
637 struct host_thread_params thread_params;
641 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
642 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
643 thread_params.apartment_hwnd = NULL;
644 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
647 CloseHandle(handles[0]);
648 LeaveCriticalSection(&apt->cs);
649 return E_OUTOFMEMORY;
651 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
652 CloseHandle(handles[0]);
653 CloseHandle(handles[1]);
654 if (wait_value == WAIT_OBJECT_0)
655 apt->host_apt_hwnd = thread_params.apartment_hwnd;
658 LeaveCriticalSection(&apt->cs);
659 return E_OUTOFMEMORY;
663 if (multi_threaded || !main_apartment)
665 apartment_hwnd = apt->host_apt_hwnd;
666 apartment_tid = apt->host_apt_tid;
669 LeaveCriticalSection(&apt->cs);
672 /* another thread may have become the main apartment in the time it took
673 * us to create the thread for the host apartment */
674 if (!apartment_hwnd && !multi_threaded && main_apartment)
676 APARTMENT *host_apt = apartment_findmain();
679 apartment_hwnd = apartment_getwindow(host_apt);
680 apartment_release(host_apt);
684 params.hkeydll = hkeydll;
685 params.clsid = *rclsid;
687 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
690 params.apartment_threaded = !multi_threaded;
694 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
695 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
699 WaitForSingleObject(params.event, INFINITE);
702 CloseHandle(params.event);
708 ERR("host apartment didn't create window\n");
712 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
715 hr = CoUnmarshalInterface(params.stream, riid, ppv);
716 IStream_Release(params.stream);
720 /* create a window for the apartment or return the current one if one has
721 * already been created */
722 HRESULT apartment_createwindowifneeded(struct apartment *apt)
724 if (apt->multi_threaded)
729 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
731 HWND_MESSAGE, 0, OLE32_hInstance, NULL);
734 ERR("CreateWindow failed with error %d\n", GetLastError());
735 return HRESULT_FROM_WIN32(GetLastError());
737 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
738 /* someone beat us to it */
745 /* retrieves the window for the main- or apartment-threaded apartment */
746 HWND apartment_getwindow(const struct apartment *apt)
748 assert(!apt->multi_threaded);
752 void apartment_joinmta(void)
754 apartment_addref(MTA);
755 COM_CurrentInfo()->apt = MTA;
758 /* gets the specified class object by loading the appropriate DLL, if
759 * necessary and calls the DllGetClassObject function for the DLL */
760 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
761 BOOL apartment_threaded,
762 REFCLSID rclsid, REFIID riid, void **ppv)
764 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
767 struct apartment_loaded_dll *apartment_loaded_dll;
769 if (!strcmpiW(dllpath, wszOle32))
771 /* we don't need to control the lifetime of this dll, so use the local
772 * implementation of DllGetClassObject directly */
773 TRACE("calling ole32!DllGetClassObject\n");
774 hr = DllGetClassObject(rclsid, riid, ppv);
777 ERR("DllGetClassObject returned error 0x%08x\n", hr);
782 EnterCriticalSection(&apt->cs);
784 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
785 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
787 TRACE("found %s already loaded\n", debugstr_w(dllpath));
794 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
795 if (!apartment_loaded_dll)
799 apartment_loaded_dll->unload_time = 0;
800 apartment_loaded_dll->multi_threaded = FALSE;
801 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
803 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
807 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
808 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
812 LeaveCriticalSection(&apt->cs);
816 /* one component being multi-threaded overrides any number of
817 * apartment-threaded components */
818 if (!apartment_threaded)
819 apartment_loaded_dll->multi_threaded = TRUE;
821 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
822 /* OK: get the ClassObject */
823 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
826 ERR("DllGetClassObject returned error 0x%08x\n", hr);
832 /* frees unused libraries loaded by apartment_getclassobject by calling the
833 * DLL's DllCanUnloadNow entry point */
834 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
836 struct apartment_loaded_dll *entry, *next;
837 EnterCriticalSection(&apt->cs);
838 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
840 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
842 DWORD real_delay = delay;
844 if (real_delay == INFINITE)
846 /* DLLs that return multi-threaded objects aren't unloaded
847 * straight away to cope for programs that have races between
848 * last object destruction and threads in the DLLs that haven't
849 * finished, despite DllCanUnloadNow returning S_OK */
850 if (entry->multi_threaded)
851 real_delay = 10 * 60 * 1000; /* 10 minutes */
856 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
858 list_remove(&entry->entry);
859 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
860 HeapFree(GetProcessHeap(), 0, entry);
863 entry->unload_time = GetTickCount() + real_delay;
865 else if (entry->unload_time)
866 entry->unload_time = 0;
868 LeaveCriticalSection(&apt->cs);
871 /*****************************************************************************
872 * This section contains OpenDllList implementation
875 /* caller must ensure that library_name is not already in the open dll list */
876 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
882 DllCanUnloadNowFunc DllCanUnloadNow;
883 DllGetClassObjectFunc DllGetClassObject;
887 *ret = COMPOBJ_DllList_Get(library_name);
888 if (*ret) return S_OK;
890 /* do this outside the csOpenDllList to avoid creating a lock dependency on
892 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
895 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
896 /* failure: DLL could not be loaded */
897 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
900 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
901 /* Note: failing to find DllCanUnloadNow is not a failure */
902 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
903 if (!DllGetClassObject)
905 /* failure: the dll did not export DllGetClassObject */
906 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
907 FreeLibrary(hLibrary);
908 return CO_E_DLLNOTFOUND;
911 EnterCriticalSection( &csOpenDllList );
913 *ret = COMPOBJ_DllList_Get(library_name);
916 /* another caller to this function already added the dll while we
917 * weren't in the critical section */
918 FreeLibrary(hLibrary);
922 len = strlenW(library_name);
923 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
925 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
926 if (entry && entry->library_name)
928 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
929 entry->library = hLibrary;
931 entry->DllCanUnloadNow = DllCanUnloadNow;
932 entry->DllGetClassObject = DllGetClassObject;
933 list_add_tail(&openDllList, &entry->entry);
938 FreeLibrary(hLibrary);
943 LeaveCriticalSection( &csOpenDllList );
948 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
952 EnterCriticalSection(&csOpenDllList);
953 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
955 if (!strcmpiW(library_name, ptr->library_name) &&
956 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
962 LeaveCriticalSection(&csOpenDllList);
966 /* pass FALSE for free_entry to release a reference without destroying the
967 * entry if it reaches zero or TRUE otherwise */
968 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
970 if (!InterlockedDecrement(&entry->refs) && free_entry)
972 EnterCriticalSection(&csOpenDllList);
973 list_remove(&entry->entry);
974 LeaveCriticalSection(&csOpenDllList);
976 TRACE("freeing %p\n", entry->library);
977 FreeLibrary(entry->library);
979 HeapFree(GetProcessHeap(), 0, entry->library_name);
980 HeapFree(GetProcessHeap(), 0, entry);
984 /* frees memory associated with active dll list */
985 static void COMPOBJ_DllList_Free(void)
987 OpenDll *entry, *cursor2;
988 EnterCriticalSection(&csOpenDllList);
989 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
991 list_remove(&entry->entry);
993 HeapFree(GetProcessHeap(), 0, entry->library_name);
994 HeapFree(GetProcessHeap(), 0, entry);
996 LeaveCriticalSection(&csOpenDllList);
999 /******************************************************************************
1000 * CoBuildVersion [OLE32.@]
1001 * CoBuildVersion [COMPOBJ.1]
1003 * Gets the build version of the DLL.
1008 * Current build version, hiword is majornumber, loword is minornumber
1010 DWORD WINAPI CoBuildVersion(void)
1012 TRACE("Returning version %d, build %d.\n", rmm, rup);
1013 return (rmm<<16)+rup;
1016 /******************************************************************************
1017 * CoRegisterInitializeSpy [OLE32.@]
1019 * Add a Spy that watches CoInitializeEx calls
1022 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1023 * cookie [II] cookie receiver
1026 * Success: S_OK if not already initialized, S_FALSE otherwise.
1027 * Failure: HRESULT code.
1032 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1034 struct oletls *info = COM_CurrentInfo();
1037 TRACE("(%p, %p)\n", spy, cookie);
1039 if (!spy || !cookie || !info)
1042 WARN("Could not allocate tls\n");
1043 return E_INVALIDARG;
1048 FIXME("Already registered?\n");
1049 return E_UNEXPECTED;
1052 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1055 cookie->QuadPart = (DWORD_PTR)spy;
1061 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1063 struct oletls *info = COM_CurrentInfo();
1064 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1066 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1067 return E_INVALIDARG;
1069 IUnknown_Release(info->spy);
1074 /******************************************************************************
1075 * CoInitialize [OLE32.@]
1077 * Initializes the COM libraries by calling CoInitializeEx with
1078 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1081 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1084 * Success: S_OK if not already initialized, S_FALSE otherwise.
1085 * Failure: HRESULT code.
1090 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1093 * Just delegate to the newer method.
1095 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1098 /******************************************************************************
1099 * CoInitializeEx [OLE32.@]
1101 * Initializes the COM libraries.
1104 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1105 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1108 * S_OK if successful,
1109 * S_FALSE if this function was called already.
1110 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1115 * The behavior used to set the IMalloc used for memory management is
1117 * The dwCoInit parameter must specify one of the following apartment
1119 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1120 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1121 * The parameter may also specify zero or more of the following flags:
1122 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1123 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1128 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1130 struct oletls *info = COM_CurrentInfo();
1134 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1136 if (lpReserved!=NULL)
1138 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1142 * Check the lock count. If this is the first time going through the initialize
1143 * process, we have to initialize the libraries.
1145 * And crank-up that lock count.
1147 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1150 * Initialize the various COM libraries and data structures.
1152 TRACE("() - Initializing the COM libraries\n");
1154 /* we may need to defer this until after apartment initialisation */
1155 RunningObjectTableImpl_Initialize();
1159 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1161 if (!(apt = info->apt))
1163 apt = apartment_get_or_create(dwCoInit);
1164 if (!apt) return E_OUTOFMEMORY;
1166 else if (!apartment_is_model(apt, dwCoInit))
1168 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1169 code then we are probably using the wrong threading model to implement that API. */
1170 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1171 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1172 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1173 return RPC_E_CHANGED_MODE;
1181 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1186 /***********************************************************************
1187 * CoUninitialize [OLE32.@]
1189 * This method will decrement the refcount on the current apartment, freeing
1190 * the resources associated with it if it is the last thread in the apartment.
1191 * If the last apartment is freed, the function will additionally release
1192 * any COM resources associated with the process.
1202 void WINAPI CoUninitialize(void)
1204 struct oletls * info = COM_CurrentInfo();
1209 /* will only happen on OOM */
1213 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1218 ERR("Mismatched CoUninitialize\n");
1221 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1227 apartment_release(info->apt);
1232 * Decrease the reference count.
1233 * If we are back to 0 locks on the COM library, make sure we free
1234 * all the associated data structures.
1236 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1239 TRACE("() - Releasing the COM libraries\n");
1241 RunningObjectTableImpl_UnInitialize();
1243 else if (lCOMRefCnt<1) {
1244 ERR( "CoUninitialize() - not CoInitialized.\n" );
1245 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1248 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1251 /******************************************************************************
1252 * CoDisconnectObject [OLE32.@]
1254 * Disconnects all connections to this object from remote processes. Dispatches
1255 * pending RPCs while blocking new RPCs from occurring, and then calls
1256 * IMarshal::DisconnectObject on the given object.
1258 * Typically called when the object server is forced to shut down, for instance by
1262 * lpUnk [I] The object whose stub should be disconnected.
1263 * reserved [I] Reserved. Should be set to 0.
1267 * Failure: HRESULT code.
1270 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1272 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1278 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1280 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1283 hr = IMarshal_DisconnectObject(marshal, reserved);
1284 IMarshal_Release(marshal);
1288 apt = COM_CurrentApt();
1290 return CO_E_NOTINITIALIZED;
1292 apartment_disconnectobject(apt, lpUnk);
1294 /* Note: native is pretty broken here because it just silently
1295 * fails, without returning an appropriate error code if the object was
1296 * not found, making apps think that the object was disconnected, when
1297 * it actually wasn't */
1302 /******************************************************************************
1303 * CoCreateGuid [OLE32.@]
1304 * CoCreateGuid [COMPOBJ.73]
1306 * Simply forwards to UuidCreate in RPCRT4.
1309 * pguid [O] Points to the GUID to initialize.
1313 * Failure: HRESULT code.
1318 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1320 DWORD status = UuidCreate(pguid);
1321 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1322 return HRESULT_FROM_WIN32( status );
1325 /******************************************************************************
1326 * CLSIDFromString [OLE32.@]
1327 * IIDFromString [OLE32.@]
1329 * Converts a unique identifier from its string representation into
1333 * idstr [I] The string representation of the GUID.
1334 * id [O] GUID converted from the string.
1338 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1343 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1349 memset( id, 0, sizeof (CLSID) );
1353 /* validate the CLSID string */
1354 if (strlenW(s) != 38)
1355 return CO_E_CLASSSTRING;
1357 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1358 return CO_E_CLASSSTRING;
1360 for (i=1; i<37; i++) {
1361 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1362 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1363 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1364 ((s[i] >= 'A') && (s[i] <= 'F'))))
1365 return CO_E_CLASSSTRING;
1368 TRACE("%s -> %p\n", debugstr_w(s), id);
1370 /* quick lookup table */
1371 memset(table, 0, 256);
1373 for (i = 0; i < 10; i++) {
1376 for (i = 0; i < 6; i++) {
1377 table['A' + i] = i+10;
1378 table['a' + i] = i+10;
1381 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1383 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1384 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1385 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1386 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1388 /* these are just sequential bytes */
1389 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1390 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1391 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1392 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1393 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1394 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1395 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1396 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1401 /*****************************************************************************/
1403 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1408 return E_INVALIDARG;
1410 ret = __CLSIDFromString(idstr, id);
1411 if(ret != S_OK) { /* It appears a ProgID is also valid */
1412 ret = CLSIDFromProgID(idstr, id);
1417 /* Converts a GUID into the respective string representation. */
1418 HRESULT WINE_StringFromCLSID(
1419 const CLSID *id, /* [in] GUID to be converted */
1420 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1422 static const char hex[] = "0123456789ABCDEF";
1427 { ERR("called with id=Null\n");
1432 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1433 id->Data1, id->Data2, id->Data3,
1434 id->Data4[0], id->Data4[1]);
1438 for (i = 2; i < 8; i++) {
1439 *s++ = hex[id->Data4[i]>>4];
1440 *s++ = hex[id->Data4[i] & 0xf];
1446 TRACE("%p->%s\n", id, idstr);
1452 /******************************************************************************
1453 * StringFromCLSID [OLE32.@]
1454 * StringFromIID [OLE32.@]
1456 * Converts a GUID into the respective string representation.
1457 * The target string is allocated using the OLE IMalloc.
1460 * id [I] the GUID to be converted.
1461 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1468 * StringFromGUID2, CLSIDFromString
1470 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1476 if ((ret = CoGetMalloc(0,&mllc)))
1479 ret=WINE_StringFromCLSID(id,buf);
1481 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1482 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1483 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1488 /******************************************************************************
1489 * StringFromGUID2 [OLE32.@]
1490 * StringFromGUID2 [COMPOBJ.76]
1492 * Modified version of StringFromCLSID that allows you to specify max
1496 * id [I] GUID to convert to string.
1497 * str [O] Buffer where the result will be stored.
1498 * cmax [I] Size of the buffer in characters.
1501 * Success: The length of the resulting string in characters.
1504 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1508 if (WINE_StringFromCLSID(id,xguid))
1510 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1513 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1514 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1516 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1517 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1521 strcpyW(path, wszCLSIDSlash);
1522 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1523 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1524 if (res == ERROR_FILE_NOT_FOUND)
1525 return REGDB_E_CLASSNOTREG;
1526 else if (res != ERROR_SUCCESS)
1527 return REGDB_E_READREGDB;
1535 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1537 if (res == ERROR_FILE_NOT_FOUND)
1538 return REGDB_E_KEYMISSING;
1539 else if (res != ERROR_SUCCESS)
1540 return REGDB_E_READREGDB;
1545 /* open HKCR\\AppId\\{string form of appid clsid} key */
1546 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1548 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1549 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1551 WCHAR buf[CHARS_IN_GUID];
1552 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1558 /* read the AppID value under the class's key */
1559 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1564 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1566 if (res == ERROR_FILE_NOT_FOUND)
1567 return REGDB_E_KEYMISSING;
1568 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1569 return REGDB_E_READREGDB;
1571 strcpyW(keyname, szAppIdKey);
1572 strcatW(keyname, buf);
1573 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1574 if (res == ERROR_FILE_NOT_FOUND)
1575 return REGDB_E_KEYMISSING;
1576 else if (res != ERROR_SUCCESS)
1577 return REGDB_E_READREGDB;
1582 /******************************************************************************
1583 * ProgIDFromCLSID [OLE32.@]
1585 * Converts a class id into the respective program ID.
1588 * clsid [I] Class ID, as found in registry.
1589 * ppszProgID [O] Associated ProgID.
1594 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1596 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1598 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1605 ERR("ppszProgId isn't optional\n");
1606 return E_INVALIDARG;
1610 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1614 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1615 ret = REGDB_E_CLASSNOTREG;
1619 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1622 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1623 ret = REGDB_E_CLASSNOTREG;
1626 ret = E_OUTOFMEMORY;
1633 /******************************************************************************
1634 * CLSIDFromProgID [OLE32.@]
1636 * Converts a program id into the respective GUID.
1639 * progid [I] Unicode program ID, as found in registry.
1640 * clsid [O] Associated CLSID.
1644 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1646 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1648 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1649 WCHAR buf2[CHARS_IN_GUID];
1650 LONG buf2len = sizeof(buf2);
1654 if (!progid || !clsid)
1656 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1657 return E_INVALIDARG;
1660 /* initialise clsid in case of failure */
1661 memset(clsid, 0, sizeof(*clsid));
1663 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1664 strcpyW( buf, progid );
1665 strcatW( buf, clsidW );
1666 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1668 HeapFree(GetProcessHeap(),0,buf);
1669 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1670 return CO_E_CLASSSTRING;
1672 HeapFree(GetProcessHeap(),0,buf);
1674 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1677 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1678 return CO_E_CLASSSTRING;
1681 return CLSIDFromString(buf2,clsid);
1685 /*****************************************************************************
1686 * CoGetPSClsid [OLE32.@]
1688 * Retrieves the CLSID of the proxy/stub factory that implements
1689 * IPSFactoryBuffer for the specified interface.
1692 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1693 * pclsid [O] Where to store returned proxy/stub CLSID.
1698 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1702 * The standard marshaller activates the object with the CLSID
1703 * returned and uses the CreateProxy and CreateStub methods on its
1704 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1707 * CoGetPSClsid determines this CLSID by searching the
1708 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1709 * in the registry and any interface id registered by
1710 * CoRegisterPSClsid within the current process.
1714 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1715 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1716 * considered a bug in native unless an application depends on this (unlikely).
1719 * CoRegisterPSClsid.
1721 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1723 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1724 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1725 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1726 WCHAR value[CHARS_IN_GUID];
1729 APARTMENT *apt = COM_CurrentApt();
1730 struct registered_psclsid *registered_psclsid;
1732 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1736 ERR("apartment not initialised\n");
1737 return CO_E_NOTINITIALIZED;
1742 ERR("pclsid isn't optional\n");
1743 return E_INVALIDARG;
1746 EnterCriticalSection(&apt->cs);
1748 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1749 if (IsEqualIID(®istered_psclsid->iid, riid))
1751 *pclsid = registered_psclsid->clsid;
1752 LeaveCriticalSection(&apt->cs);
1756 LeaveCriticalSection(&apt->cs);
1758 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1759 strcpyW(path, wszInterface);
1760 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1761 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1763 /* Open the key.. */
1764 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1766 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1767 return REGDB_E_IIDNOTREG;
1770 /* ... Once we have the key, query the registry to get the
1771 value of CLSID as a string, and convert it into a
1772 proper CLSID structure to be passed back to the app */
1773 len = sizeof(value);
1774 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1777 return REGDB_E_IIDNOTREG;
1781 /* We have the CLSID we want back from the registry as a string, so
1782 let's convert it into a CLSID structure */
1783 if (CLSIDFromString(value, pclsid) != NOERROR)
1784 return REGDB_E_IIDNOTREG;
1786 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1790 /*****************************************************************************
1791 * CoRegisterPSClsid [OLE32.@]
1793 * Register a proxy/stub CLSID for the given interface in the current process
1797 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1798 * rclsid [I] CLSID of the proxy/stub.
1802 * Failure: E_OUTOFMEMORY
1806 * This function does not add anything to the registry and the effects are
1807 * limited to the lifetime of the current process.
1812 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1814 APARTMENT *apt = COM_CurrentApt();
1815 struct registered_psclsid *registered_psclsid;
1817 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1821 ERR("apartment not initialised\n");
1822 return CO_E_NOTINITIALIZED;
1825 EnterCriticalSection(&apt->cs);
1827 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1828 if (IsEqualIID(®istered_psclsid->iid, riid))
1830 registered_psclsid->clsid = *rclsid;
1831 LeaveCriticalSection(&apt->cs);
1835 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1836 if (!registered_psclsid)
1838 LeaveCriticalSection(&apt->cs);
1839 return E_OUTOFMEMORY;
1842 registered_psclsid->iid = *riid;
1843 registered_psclsid->clsid = *rclsid;
1844 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1846 LeaveCriticalSection(&apt->cs);
1853 * COM_GetRegisteredClassObject
1855 * This internal method is used to scan the registered class list to
1856 * find a class object.
1859 * rclsid Class ID of the class to find.
1860 * dwClsContext Class context to match.
1861 * ppv [out] returns a pointer to the class object. Complying
1862 * to normal COM usage, this method will increase the
1863 * reference count on this object.
1865 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1866 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1868 HRESULT hr = S_FALSE;
1869 RegisteredClass *curClass;
1871 EnterCriticalSection( &csRegisteredClassList );
1873 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1876 * Check if we have a match on the class ID and context.
1878 if ((apt->oxid == curClass->apartment_id) &&
1879 (dwClsContext & curClass->runContext) &&
1880 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1883 * We have a match, return the pointer to the class object.
1885 *ppUnk = curClass->classObject;
1887 IUnknown_AddRef(curClass->classObject);
1894 LeaveCriticalSection( &csRegisteredClassList );
1899 /******************************************************************************
1900 * CoRegisterClassObject [OLE32.@]
1902 * Registers the class object for a given class ID. Servers housed in EXE
1903 * files use this method instead of exporting DllGetClassObject to allow
1904 * other code to connect to their objects.
1907 * rclsid [I] CLSID of the object to register.
1908 * pUnk [I] IUnknown of the object.
1909 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1910 * flags [I] REGCLS flags indicating how connections are made.
1911 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1915 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1916 * CO_E_OBJISREG if the object is already registered. We should not return this.
1919 * CoRevokeClassObject, CoGetClassObject
1922 * In-process objects are only registered for the current apartment.
1923 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1924 * in other apartments.
1927 * MSDN claims that multiple interface registrations are legal, but we
1928 * can't do that with our current implementation.
1930 HRESULT WINAPI CoRegisterClassObject(
1935 LPDWORD lpdwRegister)
1937 RegisteredClass* newClass;
1938 LPUNKNOWN foundObject;
1942 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1943 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1945 if ( (lpdwRegister==0) || (pUnk==0) )
1946 return E_INVALIDARG;
1948 apt = COM_CurrentApt();
1951 ERR("COM was not initialized\n");
1952 return CO_E_NOTINITIALIZED;
1957 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1958 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1959 if (flags & REGCLS_MULTIPLEUSE)
1960 dwClsContext |= CLSCTX_INPROC_SERVER;
1963 * First, check if the class is already registered.
1964 * If it is, this should cause an error.
1966 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1968 if (flags & REGCLS_MULTIPLEUSE) {
1969 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1970 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1971 IUnknown_Release(foundObject);
1974 IUnknown_Release(foundObject);
1975 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1976 return CO_E_OBJISREG;
1979 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1980 if ( newClass == NULL )
1981 return E_OUTOFMEMORY;
1983 newClass->classIdentifier = *rclsid;
1984 newClass->apartment_id = apt->oxid;
1985 newClass->runContext = dwClsContext;
1986 newClass->connectFlags = flags;
1987 newClass->pMarshaledData = NULL;
1988 newClass->RpcRegistration = NULL;
1991 * Use the address of the chain node as the cookie since we are sure it's
1992 * unique. FIXME: not on 64-bit platforms.
1994 newClass->dwCookie = (DWORD)newClass;
1997 * Since we're making a copy of the object pointer, we have to increase its
2000 newClass->classObject = pUnk;
2001 IUnknown_AddRef(newClass->classObject);
2003 EnterCriticalSection( &csRegisteredClassList );
2004 list_add_tail(&RegisteredClassList, &newClass->entry);
2005 LeaveCriticalSection( &csRegisteredClassList );
2007 *lpdwRegister = newClass->dwCookie;
2009 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2010 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2012 FIXME("Failed to create stream on hglobal, %x\n", hr);
2015 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2016 newClass->classObject, MSHCTX_LOCAL, NULL,
2017 MSHLFLAGS_TABLESTRONG);
2019 FIXME("CoMarshalInterface failed, %x!\n",hr);
2023 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2024 newClass->pMarshaledData,
2025 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2026 &newClass->RpcRegistration);
2031 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
2033 list_remove(&curClass->entry);
2035 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
2036 RPC_StopLocalServer(curClass->RpcRegistration);
2039 * Release the reference to the class object.
2041 IUnknown_Release(curClass->classObject);
2043 if (curClass->pMarshaledData)
2046 memset(&zero, 0, sizeof(zero));
2047 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
2048 CoReleaseMarshalData(curClass->pMarshaledData);
2049 IStream_Release(curClass->pMarshaledData);
2052 HeapFree(GetProcessHeap(), 0, curClass);
2055 static void COM_RevokeAllClasses(const struct apartment *apt)
2057 RegisteredClass *curClass, *cursor;
2059 EnterCriticalSection( &csRegisteredClassList );
2061 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
2063 if (curClass->apartment_id == apt->oxid)
2064 COM_RevokeRegisteredClassObject(curClass);
2067 LeaveCriticalSection( &csRegisteredClassList );
2070 /***********************************************************************
2071 * CoRevokeClassObject [OLE32.@]
2073 * Removes a class object from the class registry.
2076 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2080 * Failure: HRESULT code.
2083 * Must be called from the same apartment that called CoRegisterClassObject(),
2084 * otherwise it will fail with RPC_E_WRONG_THREAD.
2087 * CoRegisterClassObject
2089 HRESULT WINAPI CoRevokeClassObject(
2092 HRESULT hr = E_INVALIDARG;
2093 RegisteredClass *curClass;
2096 TRACE("(%08x)\n",dwRegister);
2098 apt = COM_CurrentApt();
2101 ERR("COM was not initialized\n");
2102 return CO_E_NOTINITIALIZED;
2105 EnterCriticalSection( &csRegisteredClassList );
2107 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2110 * Check if we have a match on the cookie.
2112 if (curClass->dwCookie == dwRegister)
2114 if (curClass->apartment_id == apt->oxid)
2116 COM_RevokeRegisteredClassObject(curClass);
2121 ERR("called from wrong apartment, should be called from %s\n",
2122 wine_dbgstr_longlong(curClass->apartment_id));
2123 hr = RPC_E_WRONG_THREAD;
2129 LeaveCriticalSection( &csRegisteredClassList );
2134 /***********************************************************************
2135 * COM_RegReadPath [internal]
2137 * Reads a registry value and expands it when necessary
2139 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2144 WCHAR src[MAX_PATH];
2145 DWORD dwLength = dstlen * sizeof(WCHAR);
2147 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2148 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2149 if (keytype == REG_EXPAND_SZ) {
2150 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2152 lstrcpynW(dst, src, dstlen);
2160 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2162 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2165 DWORD dwLength = len * sizeof(WCHAR);
2167 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2168 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2172 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2173 REFCLSID rclsid, REFIID riid,
2174 BOOL hostifnecessary, void **ppv)
2176 WCHAR dllpath[MAX_PATH+1];
2177 BOOL apartment_threaded;
2179 if (hostifnecessary)
2181 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2182 static const WCHAR wszFree[] = {'F','r','e','e',0};
2183 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2184 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2186 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2188 if (!strcmpiW(threading_model, wszApartment))
2190 apartment_threaded = TRUE;
2191 if (apt->multi_threaded)
2192 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2195 else if (!strcmpiW(threading_model, wszFree))
2197 apartment_threaded = FALSE;
2198 if (!apt->multi_threaded)
2199 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2201 /* everything except "Apartment", "Free" and "Both" */
2202 else if (strcmpiW(threading_model, wszBoth))
2204 apartment_threaded = TRUE;
2205 /* everything else is main-threaded */
2206 if (threading_model[0])
2207 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2208 debugstr_w(threading_model), debugstr_guid(rclsid));
2210 if (apt->multi_threaded || !apt->main)
2211 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2214 apartment_threaded = FALSE;
2217 apartment_threaded = !apt->multi_threaded;
2219 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2221 /* failure: CLSID is not found in registry */
2222 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2223 return REGDB_E_CLASSNOTREG;
2226 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2230 /***********************************************************************
2231 * CoGetClassObject [OLE32.@]
2233 * Creates an object of the specified class.
2236 * rclsid [I] Class ID to create an instance of.
2237 * dwClsContext [I] Flags to restrict the location of the created instance.
2238 * pServerInfo [I] Optional. Details for connecting to a remote server.
2239 * iid [I] The ID of the interface of the instance to return.
2240 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2244 * Failure: HRESULT code.
2247 * The dwClsContext parameter can be one or more of the following:
2248 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2249 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2250 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2251 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2254 * CoCreateInstance()
2256 HRESULT WINAPI CoGetClassObject(
2257 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2258 REFIID iid, LPVOID *ppv)
2260 LPUNKNOWN regClassObject;
2261 HRESULT hres = E_UNEXPECTED;
2264 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2267 return E_INVALIDARG;
2271 apt = COM_CurrentApt();
2274 ERR("apartment not initialised\n");
2275 return CO_E_NOTINITIALIZED;
2279 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2280 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2284 * First, try and see if we can't match the class ID with one of the
2285 * registered classes.
2287 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2290 /* Get the required interface from the retrieved pointer. */
2291 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2294 * Since QI got another reference on the pointer, we want to release the
2295 * one we already have. If QI was unsuccessful, this will release the object. This
2296 * is good since we are not returning it in the "out" parameter.
2298 IUnknown_Release(regClassObject);
2303 /* First try in-process server */
2304 if (CLSCTX_INPROC_SERVER & dwClsContext)
2306 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2309 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2310 return FTMarshalCF_Create(iid, ppv);
2312 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2315 if (hres == REGDB_E_CLASSNOTREG)
2316 ERR("class %s not registered\n", debugstr_guid(rclsid));
2317 else if (hres == REGDB_E_KEYMISSING)
2319 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2320 hres = REGDB_E_CLASSNOTREG;
2324 if (SUCCEEDED(hres))
2326 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2327 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2331 /* return if we got a class, otherwise fall through to one of the
2333 if (SUCCEEDED(hres))
2337 /* Next try in-process handler */
2338 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2340 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2343 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2346 if (hres == REGDB_E_CLASSNOTREG)
2347 ERR("class %s not registered\n", debugstr_guid(rclsid));
2348 else if (hres == REGDB_E_KEYMISSING)
2350 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2351 hres = REGDB_E_CLASSNOTREG;
2355 if (SUCCEEDED(hres))
2357 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2358 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2362 /* return if we got a class, otherwise fall through to one of the
2364 if (SUCCEEDED(hres))
2368 /* Next try out of process */
2369 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2371 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2372 if (SUCCEEDED(hres))
2376 /* Finally try remote: this requires networked DCOM (a lot of work) */
2377 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2379 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2380 hres = E_NOINTERFACE;
2384 ERR("no class object %s could be created for context 0x%x\n",
2385 debugstr_guid(rclsid), dwClsContext);
2389 /***********************************************************************
2390 * CoResumeClassObjects (OLE32.@)
2392 * Resumes all class objects registered with REGCLS_SUSPENDED.
2396 * Failure: HRESULT code.
2398 HRESULT WINAPI CoResumeClassObjects(void)
2404 /***********************************************************************
2405 * CoCreateInstance [OLE32.@]
2407 * Creates an instance of the specified class.
2410 * rclsid [I] Class ID to create an instance of.
2411 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2412 * dwClsContext [I] Flags to restrict the location of the created instance.
2413 * iid [I] The ID of the interface of the instance to return.
2414 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2418 * Failure: HRESULT code.
2421 * The dwClsContext parameter can be one or more of the following:
2422 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2423 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2424 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2425 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2427 * Aggregation is the concept of deferring the IUnknown of an object to another
2428 * object. This allows a separate object to behave as though it was part of
2429 * the object and to allow this the pUnkOuter parameter can be set. Note that
2430 * not all objects support having an outer of unknown.
2433 * CoGetClassObject()
2435 HRESULT WINAPI CoCreateInstance(
2437 LPUNKNOWN pUnkOuter,
2443 LPCLASSFACTORY lpclf = 0;
2445 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2446 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2455 * Initialize the "out" parameter
2459 if (!COM_CurrentApt())
2461 ERR("apartment not initialised\n");
2462 return CO_E_NOTINITIALIZED;
2466 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2467 * Rather than create a class factory, we can just check for it here
2469 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2470 if (StdGlobalInterfaceTableInstance == NULL)
2471 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2472 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2473 if (hres) return hres;
2475 TRACE("Retrieved GIT (%p)\n", *ppv);
2480 * Get a class factory to construct the object we want.
2482 hres = CoGetClassObject(rclsid,
2492 * Create the object and don't forget to release the factory
2494 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2495 IClassFactory_Release(lpclf);
2498 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2499 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2501 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2507 /***********************************************************************
2508 * CoCreateInstanceEx [OLE32.@]
2510 HRESULT WINAPI CoCreateInstanceEx(
2512 LPUNKNOWN pUnkOuter,
2514 COSERVERINFO* pServerInfo,
2518 IUnknown* pUnk = NULL;
2521 ULONG successCount = 0;
2526 if ( (cmq==0) || (pResults==NULL))
2527 return E_INVALIDARG;
2529 if (pServerInfo!=NULL)
2530 FIXME("() non-NULL pServerInfo not supported!\n");
2533 * Initialize all the "out" parameters.
2535 for (index = 0; index < cmq; index++)
2537 pResults[index].pItf = NULL;
2538 pResults[index].hr = E_NOINTERFACE;
2542 * Get the object and get its IUnknown pointer.
2544 hr = CoCreateInstance(rclsid,
2554 * Then, query for all the interfaces requested.
2556 for (index = 0; index < cmq; index++)
2558 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2559 pResults[index].pIID,
2560 (VOID**)&(pResults[index].pItf));
2562 if (pResults[index].hr == S_OK)
2567 * Release our temporary unknown pointer.
2569 IUnknown_Release(pUnk);
2571 if (successCount == 0)
2572 return E_NOINTERFACE;
2574 if (successCount!=cmq)
2575 return CO_S_NOTALLINTERFACES;
2580 /***********************************************************************
2581 * CoLoadLibrary (OLE32.@)
2586 * lpszLibName [I] Path to library.
2587 * bAutoFree [I] Whether the library should automatically be freed.
2590 * Success: Handle to loaded library.
2594 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2596 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2598 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2600 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2603 /***********************************************************************
2604 * CoFreeLibrary [OLE32.@]
2606 * Unloads a library from memory.
2609 * hLibrary [I] Handle to library to unload.
2615 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2617 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2619 FreeLibrary(hLibrary);
2623 /***********************************************************************
2624 * CoFreeAllLibraries [OLE32.@]
2626 * Function for backwards compatibility only. Does nothing.
2632 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2634 void WINAPI CoFreeAllLibraries(void)
2639 /***********************************************************************
2640 * CoFreeUnusedLibrariesEx [OLE32.@]
2642 * Frees any previously unused libraries whose delay has expired and marks
2643 * currently unused libraries for unloading. Unused are identified as those that
2644 * return S_OK from their DllCanUnloadNow function.
2647 * dwUnloadDelay [I] Unload delay in milliseconds.
2648 * dwReserved [I] Reserved. Set to 0.
2654 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2656 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2658 struct apartment *apt = COM_CurrentApt();
2661 ERR("apartment not initialised\n");
2665 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2668 /***********************************************************************
2669 * CoFreeUnusedLibraries [OLE32.@]
2670 * CoFreeUnusedLibraries [COMPOBJ.17]
2672 * Frees any unused libraries. Unused are identified as those that return
2673 * S_OK from their DllCanUnloadNow function.
2679 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2681 void WINAPI CoFreeUnusedLibraries(void)
2683 CoFreeUnusedLibrariesEx(INFINITE, 0);
2686 /***********************************************************************
2687 * CoFileTimeNow [OLE32.@]
2688 * CoFileTimeNow [COMPOBJ.82]
2690 * Retrieves the current time in FILETIME format.
2693 * lpFileTime [O] The current time.
2698 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2700 GetSystemTimeAsFileTime( lpFileTime );
2704 /******************************************************************************
2705 * CoLockObjectExternal [OLE32.@]
2707 * Increments or decrements the external reference count of a stub object.
2710 * pUnk [I] Stub object.
2711 * fLock [I] If TRUE then increments the external ref-count,
2712 * otherwise decrements.
2713 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2714 * calling CoDisconnectObject.
2718 * Failure: HRESULT code.
2721 * If fLock is TRUE and an object is passed in that doesn't have a stub
2722 * manager then a new stub manager is created for the object.
2724 HRESULT WINAPI CoLockObjectExternal(
2727 BOOL fLastUnlockReleases)
2729 struct stub_manager *stubmgr;
2730 struct apartment *apt;
2732 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2733 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2735 apt = COM_CurrentApt();
2736 if (!apt) return CO_E_NOTINITIALIZED;
2738 stubmgr = get_stub_manager_from_object(apt, pUnk);
2743 stub_manager_ext_addref(stubmgr, 1, FALSE);
2745 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2747 stub_manager_int_release(stubmgr);
2753 stubmgr = new_stub_manager(apt, pUnk);
2757 stub_manager_ext_addref(stubmgr, 1, FALSE);
2758 stub_manager_int_release(stubmgr);
2765 WARN("stub object not found %p\n", pUnk);
2766 /* Note: native is pretty broken here because it just silently
2767 * fails, without returning an appropriate error code, making apps
2768 * think that the object was disconnected, when it actually wasn't */
2773 /***********************************************************************
2774 * CoInitializeWOW (OLE32.@)
2776 * WOW equivalent of CoInitialize?
2785 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2787 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2791 /***********************************************************************
2792 * CoGetState [OLE32.@]
2794 * Retrieves the thread state object previously stored by CoSetState().
2797 * ppv [I] Address where pointer to object will be stored.
2801 * Failure: E_OUTOFMEMORY.
2804 * Crashes on all invalid ppv addresses, including NULL.
2805 * If the function returns a non-NULL object then the caller must release its
2806 * reference on the object when the object is no longer required.
2811 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2813 struct oletls *info = COM_CurrentInfo();
2814 if (!info) return E_OUTOFMEMORY;
2820 IUnknown_AddRef(info->state);
2822 TRACE("apt->state=%p\n", info->state);
2828 /***********************************************************************
2829 * CoSetState [OLE32.@]
2831 * Sets the thread state object.
2834 * pv [I] Pointer to state object to be stored.
2837 * The system keeps a reference on the object while the object stored.
2841 * Failure: E_OUTOFMEMORY.
2843 HRESULT WINAPI CoSetState(IUnknown * pv)
2845 struct oletls *info = COM_CurrentInfo();
2846 if (!info) return E_OUTOFMEMORY;
2848 if (pv) IUnknown_AddRef(pv);
2852 TRACE("-- release %p now\n", info->state);
2853 IUnknown_Release(info->state);
2862 /******************************************************************************
2863 * CoTreatAsClass [OLE32.@]
2865 * Sets the TreatAs value of a class.
2868 * clsidOld [I] Class to set TreatAs value on.
2869 * clsidNew [I] The class the clsidOld should be treated as.
2873 * Failure: HRESULT code.
2878 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2880 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2881 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2883 WCHAR szClsidNew[CHARS_IN_GUID];
2885 WCHAR auto_treat_as[CHARS_IN_GUID];
2886 LONG auto_treat_as_size = sizeof(auto_treat_as);
2889 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2892 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2894 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2895 CLSIDFromString(auto_treat_as, &id) == S_OK)
2897 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2899 res = REGDB_E_WRITEREGDB;
2905 RegDeleteKeyW(hkey, wszTreatAs);
2909 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2910 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2912 res = REGDB_E_WRITEREGDB;
2917 if (hkey) RegCloseKey(hkey);
2921 /******************************************************************************
2922 * CoGetTreatAsClass [OLE32.@]
2924 * Gets the TreatAs value of a class.
2927 * clsidOld [I] Class to get the TreatAs value of.
2928 * clsidNew [I] The class the clsidOld should be treated as.
2932 * Failure: HRESULT code.
2937 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2939 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2941 WCHAR szClsidNew[CHARS_IN_GUID];
2943 LONG len = sizeof(szClsidNew);
2945 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2946 *clsidNew = *clsidOld; /* copy over old value */
2948 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2951 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2956 res = CLSIDFromString(szClsidNew,clsidNew);
2958 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2960 if (hkey) RegCloseKey(hkey);
2964 /******************************************************************************
2965 * CoGetCurrentProcess [OLE32.@]
2966 * CoGetCurrentProcess [COMPOBJ.34]
2968 * Gets the current process ID.
2971 * The current process ID.
2974 * Is DWORD really the correct return type for this function?
2976 DWORD WINAPI CoGetCurrentProcess(void)
2978 return GetCurrentProcessId();
2981 /******************************************************************************
2982 * CoRegisterMessageFilter [OLE32.@]
2984 * Registers a message filter.
2987 * lpMessageFilter [I] Pointer to interface.
2988 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2992 * Failure: HRESULT code.
2995 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2996 * lpMessageFilter removes the message filter.
2998 * If lplpMessageFilter is not NULL the previous message filter will be
2999 * returned in the memory pointer to this parameter and the caller is
3000 * responsible for releasing the object.
3002 * The current thread be in an apartment otherwise the function will crash.
3004 HRESULT WINAPI CoRegisterMessageFilter(
3005 LPMESSAGEFILTER lpMessageFilter,
3006 LPMESSAGEFILTER *lplpMessageFilter)
3008 struct apartment *apt;
3009 IMessageFilter *lpOldMessageFilter;
3011 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3013 apt = COM_CurrentApt();
3015 /* can't set a message filter in a multi-threaded apartment */
3016 if (!apt || apt->multi_threaded)
3018 WARN("can't set message filter in MTA or uninitialized apt\n");
3019 return CO_E_NOT_SUPPORTED;
3022 if (lpMessageFilter)
3023 IMessageFilter_AddRef(lpMessageFilter);
3025 EnterCriticalSection(&apt->cs);
3027 lpOldMessageFilter = apt->filter;
3028 apt->filter = lpMessageFilter;
3030 LeaveCriticalSection(&apt->cs);
3032 if (lplpMessageFilter)
3033 *lplpMessageFilter = lpOldMessageFilter;
3034 else if (lpOldMessageFilter)
3035 IMessageFilter_Release(lpOldMessageFilter);
3040 /***********************************************************************
3041 * CoIsOle1Class [OLE32.@]
3043 * Determines whether the specified class an OLE v1 class.
3046 * clsid [I] Class to test.
3049 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3051 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3053 FIXME("%s\n", debugstr_guid(clsid));
3057 /***********************************************************************
3058 * IsEqualGUID [OLE32.@]
3060 * Compares two Unique Identifiers.
3063 * rguid1 [I] The first GUID to compare.
3064 * rguid2 [I] The other GUID to compare.
3070 BOOL WINAPI IsEqualGUID(
3074 return !memcmp(rguid1,rguid2,sizeof(GUID));
3077 /***********************************************************************
3078 * CoInitializeSecurity [OLE32.@]
3080 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3081 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3082 void* pReserved1, DWORD dwAuthnLevel,
3083 DWORD dwImpLevel, void* pReserved2,
3084 DWORD dwCapabilities, void* pReserved3)
3086 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3087 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3088 dwCapabilities, pReserved3);
3092 /***********************************************************************
3093 * CoSuspendClassObjects [OLE32.@]
3095 * Suspends all registered class objects to prevent further requests coming in
3096 * for those objects.
3100 * Failure: HRESULT code.
3102 HRESULT WINAPI CoSuspendClassObjects(void)
3108 /***********************************************************************
3109 * CoAddRefServerProcess [OLE32.@]
3111 * Helper function for incrementing the reference count of a local-server
3115 * New reference count.
3118 * CoReleaseServerProcess().
3120 ULONG WINAPI CoAddRefServerProcess(void)
3126 EnterCriticalSection(&csRegisteredClassList);
3127 refs = ++s_COMServerProcessReferences;
3128 LeaveCriticalSection(&csRegisteredClassList);
3130 TRACE("refs before: %d\n", refs - 1);
3135 /***********************************************************************
3136 * CoReleaseServerProcess [OLE32.@]
3138 * Helper function for decrementing the reference count of a local-server
3142 * New reference count.
3145 * When reference count reaches 0, this function suspends all registered
3146 * classes so no new connections are accepted.
3149 * CoAddRefServerProcess(), CoSuspendClassObjects().
3151 ULONG WINAPI CoReleaseServerProcess(void)
3157 EnterCriticalSection(&csRegisteredClassList);
3159 refs = --s_COMServerProcessReferences;
3160 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3162 LeaveCriticalSection(&csRegisteredClassList);
3164 TRACE("refs after: %d\n", refs);
3169 /***********************************************************************
3170 * CoIsHandlerConnected [OLE32.@]
3172 * Determines whether a proxy is connected to a remote stub.
3175 * pUnk [I] Pointer to object that may or may not be connected.
3178 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3181 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3183 FIXME("%p\n", pUnk);
3188 /***********************************************************************
3189 * CoAllowSetForegroundWindow [OLE32.@]
3192 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3194 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3198 /***********************************************************************
3199 * CoQueryProxyBlanket [OLE32.@]
3201 * Retrieves the security settings being used by a proxy.
3204 * pProxy [I] Pointer to the proxy object.
3205 * pAuthnSvc [O] The type of authentication service.
3206 * pAuthzSvc [O] The type of authorization service.
3207 * ppServerPrincName [O] Optional. The server prinicple name.
3208 * pAuthnLevel [O] The authentication level.
3209 * pImpLevel [O] The impersonation level.
3210 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3211 * pCapabilities [O] Flags affecting the security behaviour.
3215 * Failure: HRESULT code.
3218 * CoCopyProxy, CoSetProxyBlanket.
3220 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3221 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3222 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3224 IClientSecurity *pCliSec;
3227 TRACE("%p\n", pProxy);
3229 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3232 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3233 pAuthzSvc, ppServerPrincName,
3234 pAuthnLevel, pImpLevel, ppAuthInfo,
3236 IClientSecurity_Release(pCliSec);
3239 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3243 /***********************************************************************
3244 * CoSetProxyBlanket [OLE32.@]
3246 * Sets the security settings for a proxy.
3249 * pProxy [I] Pointer to the proxy object.
3250 * AuthnSvc [I] The type of authentication service.
3251 * AuthzSvc [I] The type of authorization service.
3252 * pServerPrincName [I] The server prinicple name.
3253 * AuthnLevel [I] The authentication level.
3254 * ImpLevel [I] The impersonation level.
3255 * pAuthInfo [I] Information specific to the authorization/authentication service.
3256 * Capabilities [I] Flags affecting the security behaviour.
3260 * Failure: HRESULT code.
3263 * CoQueryProxyBlanket, CoCopyProxy.
3265 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3266 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3267 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3269 IClientSecurity *pCliSec;
3272 TRACE("%p\n", pProxy);
3274 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3277 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3278 AuthzSvc, pServerPrincName,
3279 AuthnLevel, ImpLevel, pAuthInfo,
3281 IClientSecurity_Release(pCliSec);
3284 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3288 /***********************************************************************
3289 * CoCopyProxy [OLE32.@]
3294 * pProxy [I] Pointer to the proxy object.
3295 * ppCopy [O] Copy of the proxy.
3299 * Failure: HRESULT code.
3302 * CoQueryProxyBlanket, CoSetProxyBlanket.
3304 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3306 IClientSecurity *pCliSec;
3309 TRACE("%p\n", pProxy);
3311 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3314 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3315 IClientSecurity_Release(pCliSec);
3318 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3323 /***********************************************************************
3324 * CoGetCallContext [OLE32.@]
3326 * Gets the context of the currently executing server call in the current
3330 * riid [I] Context interface to return.
3331 * ppv [O] Pointer to memory that will receive the context on return.
3335 * Failure: HRESULT code.
3337 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3339 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3342 return E_NOINTERFACE;
3345 /***********************************************************************
3346 * CoQueryClientBlanket [OLE32.@]
3348 * Retrieves the authentication information about the client of the currently
3349 * executing server call in the current thread.
3352 * pAuthnSvc [O] Optional. The type of authentication service.
3353 * pAuthzSvc [O] Optional. The type of authorization service.
3354 * pServerPrincName [O] Optional. The server prinicple name.
3355 * pAuthnLevel [O] Optional. The authentication level.
3356 * pImpLevel [O] Optional. The impersonation level.
3357 * pPrivs [O] Optional. Information about the privileges of the client.
3358 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3362 * Failure: HRESULT code.
3365 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3367 HRESULT WINAPI CoQueryClientBlanket(
3370 OLECHAR **pServerPrincName,
3373 RPC_AUTHZ_HANDLE *pPrivs,
3374 DWORD *pCapabilities)
3376 IServerSecurity *pSrvSec;
3379 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3380 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3381 pPrivs, pCapabilities);
3383 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3386 hr = IServerSecurity_QueryBlanket(
3387 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3388 pImpLevel, pPrivs, pCapabilities);
3389 IServerSecurity_Release(pSrvSec);
3395 /***********************************************************************
3396 * CoImpersonateClient [OLE32.@]
3398 * Impersonates the client of the currently executing server call in the
3406 * Failure: HRESULT code.
3409 * If this function fails then the current thread will not be impersonating
3410 * the client and all actions will take place on behalf of the server.
3411 * Therefore, it is important to check the return value from this function.
3414 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3416 HRESULT WINAPI CoImpersonateClient(void)
3418 IServerSecurity *pSrvSec;
3423 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3426 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3427 IServerSecurity_Release(pSrvSec);
3433 /***********************************************************************
3434 * CoRevertToSelf [OLE32.@]
3436 * Ends the impersonation of the client of the currently executing server
3437 * call in the current thread.
3444 * Failure: HRESULT code.
3447 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3449 HRESULT WINAPI CoRevertToSelf(void)
3451 IServerSecurity *pSrvSec;
3456 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3459 hr = IServerSecurity_RevertToSelf(pSrvSec);
3460 IServerSecurity_Release(pSrvSec);
3466 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3468 /* first try to retrieve messages for incoming COM calls to the apartment window */
3469 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3470 /* next retrieve other messages necessary for the app to remain responsive */
3471 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3474 /***********************************************************************
3475 * CoWaitForMultipleHandles [OLE32.@]
3477 * Waits for one or more handles to become signaled.
3480 * dwFlags [I] Flags. See notes.
3481 * dwTimeout [I] Timeout in milliseconds.
3482 * cHandles [I] Number of handles pointed to by pHandles.
3483 * pHandles [I] Handles to wait for.
3484 * lpdwindex [O] Index of handle that was signaled.
3488 * Failure: RPC_S_CALLPENDING on timeout.
3492 * The dwFlags parameter can be zero or more of the following:
3493 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3494 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3497 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3499 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3500 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3503 DWORD start_time = GetTickCount();
3504 APARTMENT *apt = COM_CurrentApt();
3505 BOOL message_loop = apt && !apt->multi_threaded;
3507 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3508 pHandles, lpdwindex);
3512 DWORD now = GetTickCount();
3515 if (now - start_time > dwTimeout)
3517 hr = RPC_S_CALLPENDING;
3523 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3524 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3526 TRACE("waiting for rpc completion or window message\n");
3528 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3529 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3530 QS_ALLINPUT, wait_flags);
3532 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3536 /* call message filter */
3538 if (COM_CurrentApt()->filter)
3540 PENDINGTYPE pendingtype =
3541 COM_CurrentInfo()->pending_call_count_server ?
3542 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3543 DWORD be_handled = IMessageFilter_MessagePending(
3544 COM_CurrentApt()->filter, 0 /* FIXME */,
3545 now - start_time, pendingtype);
3546 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3549 case PENDINGMSG_CANCELCALL:
3550 WARN("call canceled\n");
3551 hr = RPC_E_CALL_CANCELED;
3553 case PENDINGMSG_WAITNOPROCESS:
3554 case PENDINGMSG_WAITDEFPROCESS:
3556 /* FIXME: MSDN is very vague about the difference
3557 * between WAITNOPROCESS and WAITDEFPROCESS - there
3558 * appears to be none, so it is possibly a left-over
3559 * from the 16-bit world. */
3564 /* note: using "if" here instead of "while" might seem less
3565 * efficient, but only if we are optimising for quick delivery
3566 * of pending messages, rather than quick completion of the
3568 if (COM_PeekMessage(apt, &msg))
3570 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3571 TranslateMessage(&msg);
3572 DispatchMessageW(&msg);
3573 if (msg.message == WM_QUIT)
3575 TRACE("resending WM_QUIT to outer message loop\n");
3576 PostQuitMessage(msg.wParam);
3577 /* no longer need to process messages */
3578 message_loop = FALSE;
3586 TRACE("waiting for rpc completion\n");
3588 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3589 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3590 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3591 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3594 if (res < WAIT_OBJECT_0 + cHandles)
3596 /* handle signaled, store index */
3597 *lpdwindex = (res - WAIT_OBJECT_0);
3600 else if (res == WAIT_TIMEOUT)
3602 hr = RPC_S_CALLPENDING;
3607 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3612 TRACE("-- 0x%08x\n", hr);
3617 /***********************************************************************
3618 * CoGetObject [OLE32.@]
3620 * Gets the object named by converting the name to a moniker and binding to it.
3623 * pszName [I] String representing the object.
3624 * pBindOptions [I] Parameters affecting the binding to the named object.
3625 * riid [I] Interface to bind to on the objecct.
3626 * ppv [O] On output, the interface riid of the object represented
3631 * Failure: HRESULT code.
3634 * MkParseDisplayName.
3636 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3637 REFIID riid, void **ppv)
3644 hr = CreateBindCtx(0, &pbc);
3648 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3655 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3658 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3659 IMoniker_Release(pmk);
3663 IBindCtx_Release(pbc);
3668 /***********************************************************************
3669 * CoRegisterChannelHook [OLE32.@]
3671 * Registers a process-wide hook that is called during ORPC calls.
3674 * guidExtension [I] GUID of the channel hook to register.
3675 * pChannelHook [I] Channel hook object to register.
3679 * Failure: HRESULT code.
3681 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3683 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3685 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3688 typedef struct Context
3690 const IComThreadingInfoVtbl *lpVtbl;
3695 static HRESULT WINAPI Context_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3699 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3700 IsEqualIID(riid, &IID_IUnknown))
3703 IUnknown_AddRef(iface);
3707 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3708 return E_NOINTERFACE;
3711 static ULONG WINAPI Context_AddRef(IComThreadingInfo *iface)
3713 Context *This = (Context *)iface;
3714 return InterlockedIncrement(&This->refs);
3717 static ULONG WINAPI Context_Release(IComThreadingInfo *iface)
3719 Context *This = (Context *)iface;
3720 ULONG refs = InterlockedDecrement(&This->refs);
3722 HeapFree(GetProcessHeap(), 0, This);
3726 static HRESULT WINAPI Context_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3728 Context *This = (Context *)iface;
3730 TRACE("(%p)\n", apttype);
3732 *apttype = This->apttype;
3736 static HRESULT WINAPI Context_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3738 Context *This = (Context *)iface;
3740 TRACE("(%p)\n", thdtype);
3742 switch (This->apttype)
3745 case APTTYPE_MAINSTA:
3746 *thdtype = THDTYPE_PROCESSMESSAGES;
3749 *thdtype = THDTYPE_BLOCKMESSAGES;
3755 static HRESULT WINAPI Context_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3757 FIXME("(%p): stub\n", logical_thread_id);
3761 static HRESULT WINAPI Context_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3763 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3767 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3769 Context_QueryInterface,
3772 Context_GetCurrentApartmentType,
3773 Context_GetCurrentThreadType,
3774 Context_GetCurrentLogicalThreadId,
3775 Context_SetCurrentLogicalThreadId
3778 /***********************************************************************
3779 * CoGetObjectContext [OLE32.@]
3781 * Retrieves an object associated with the current context (i.e. apartment).
3784 * riid [I] ID of the interface of the object to retrieve.
3785 * ppv [O] Address where object will be stored on return.
3789 * Failure: HRESULT code.
3791 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
3793 APARTMENT *apt = COM_CurrentApt();
3797 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3802 ERR("apartment not initialised\n");
3803 return CO_E_NOTINITIALIZED;
3806 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
3808 return E_OUTOFMEMORY;
3810 context->lpVtbl = &Context_Threading_Vtbl;
3812 if (apt->multi_threaded)
3813 context->apttype = APTTYPE_MTA;
3815 context->apttype = APTTYPE_MAINSTA;
3817 context->apttype = APTTYPE_STA;
3819 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
3820 IUnknown_Release((IUnknown *)&context->lpVtbl);
3826 /***********************************************************************
3827 * CoGetContextToken [OLE32.@]
3829 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
3832 if(!(calls++)) FIXME( "stub\n" );
3833 if (token) *token = 0;
3838 /***********************************************************************
3841 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3843 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3846 case DLL_PROCESS_ATTACH:
3847 OLE32_hInstance = hinstDLL;
3848 COMPOBJ_InitProcess();
3849 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3852 case DLL_PROCESS_DETACH:
3853 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3854 OLEDD_UnInitialize();
3855 COMPOBJ_UninitProcess();
3856 RPC_UnregisterAllChannelHooks();
3857 COMPOBJ_DllList_Free();
3858 OLE32_hInstance = 0;
3861 case DLL_THREAD_DETACH:
3868 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */