gdi32: Add support for non-rgb colorrefs.
[wine.git] / dlls / ole32 / compobj.c
blob28e5da153d16124f5b490e6ad2e75869e1748356
1 /*
2 * COMPOBJ library
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
26 * Note
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
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #define USE_COM_CONTEXT_DEF
56 #include "objbase.h"
57 #include "ole2.h"
58 #include "ole2ver.h"
59 #include "ctxtcall.h"
60 #include "dde.h"
62 #include "initguid.h"
63 #include "compobj_private.h"
64 #include "moniker.h"
66 #include "wine/unicode.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
77 static APARTMENT *MTA; /* protected by csApartment */
78 static APARTMENT *MainApartment; /* the first STA apartment */
79 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
81 static CRITICAL_SECTION csApartment;
82 static CRITICAL_SECTION_DEBUG critsect_debug =
84 0, 0, &csApartment,
85 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
88 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
90 struct registered_psclsid
92 struct list entry;
93 IID iid;
94 CLSID clsid;
98 * This lock count counts the number of times CoInitialize is called. It is
99 * decreased every time CoUninitialize is called. When it hits 0, the COM
100 * libraries are freed
102 static LONG s_COMLockCount = 0;
103 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
104 static LONG s_COMServerProcessReferences = 0;
107 * This linked list contains the list of registered class objects. These
108 * are mostly used to register the factories for out-of-proc servers of OLE
109 * objects.
111 * TODO: Make this data structure aware of inter-process communication. This
112 * means that parts of this will be exported to rpcss.
114 typedef struct tagRegisteredClass
116 struct list entry;
117 CLSID classIdentifier;
118 OXID apartment_id;
119 LPUNKNOWN classObject;
120 DWORD runContext;
121 DWORD connectFlags;
122 DWORD dwCookie;
123 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124 void *RpcRegistration;
125 } RegisteredClass;
127 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
129 static CRITICAL_SECTION csRegisteredClassList;
130 static CRITICAL_SECTION_DEBUG class_cs_debug =
132 0, 0, &csRegisteredClassList,
133 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
136 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
138 /*****************************************************************************
139 * This section contains OpenDllList definitions
141 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
142 * other functions that do LoadLibrary _without_ giving back a HMODULE.
143 * Without this list these handles would never be freed.
145 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
146 * next unload-call but not before 600 sec.
149 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
150 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
152 typedef struct tagOpenDll
154 LONG refs;
155 LPWSTR library_name;
156 HANDLE library;
157 DllGetClassObjectFunc DllGetClassObject;
158 DllCanUnloadNowFunc DllCanUnloadNow;
159 struct list entry;
160 } OpenDll;
162 static struct list openDllList = LIST_INIT(openDllList);
164 static CRITICAL_SECTION csOpenDllList;
165 static CRITICAL_SECTION_DEBUG dll_cs_debug =
167 0, 0, &csOpenDllList,
168 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
169 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
171 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
173 struct apartment_loaded_dll
175 struct list entry;
176 OpenDll *dll;
177 DWORD unload_time;
178 BOOL multi_threaded;
181 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',' ',
182 '0','x','#','#','#','#','#','#','#','#',' ',0};
184 /*****************************************************************************
185 * This section contains OpenDllList implementation
188 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
190 OpenDll *ptr;
191 OpenDll *ret = NULL;
192 EnterCriticalSection(&csOpenDllList);
193 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
195 if (!strcmpiW(library_name, ptr->library_name) &&
196 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
198 ret = ptr;
199 break;
202 LeaveCriticalSection(&csOpenDllList);
203 return ret;
206 /* caller must ensure that library_name is not already in the open dll list */
207 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
209 OpenDll *entry;
210 int len;
211 HRESULT hr = S_OK;
212 HANDLE hLibrary;
213 DllCanUnloadNowFunc DllCanUnloadNow;
214 DllGetClassObjectFunc DllGetClassObject;
216 TRACE("\n");
218 *ret = COMPOBJ_DllList_Get(library_name);
219 if (*ret) return S_OK;
221 /* do this outside the csOpenDllList to avoid creating a lock dependency on
222 * the loader lock */
223 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
224 if (!hLibrary)
226 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
227 /* failure: DLL could not be loaded */
228 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
231 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
232 /* Note: failing to find DllCanUnloadNow is not a failure */
233 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
234 if (!DllGetClassObject)
236 /* failure: the dll did not export DllGetClassObject */
237 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
238 FreeLibrary(hLibrary);
239 return CO_E_DLLNOTFOUND;
242 EnterCriticalSection( &csOpenDllList );
244 *ret = COMPOBJ_DllList_Get(library_name);
245 if (*ret)
247 /* another caller to this function already added the dll while we
248 * weren't in the critical section */
249 FreeLibrary(hLibrary);
251 else
253 len = strlenW(library_name);
254 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
255 if (entry)
256 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
257 if (entry && entry->library_name)
259 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
260 entry->library = hLibrary;
261 entry->refs = 1;
262 entry->DllCanUnloadNow = DllCanUnloadNow;
263 entry->DllGetClassObject = DllGetClassObject;
264 list_add_tail(&openDllList, &entry->entry);
266 else
268 HeapFree(GetProcessHeap(), 0, entry);
269 hr = E_OUTOFMEMORY;
270 FreeLibrary(hLibrary);
272 *ret = entry;
275 LeaveCriticalSection( &csOpenDllList );
277 return hr;
280 /* pass FALSE for free_entry to release a reference without destroying the
281 * entry if it reaches zero or TRUE otherwise */
282 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
284 if (!InterlockedDecrement(&entry->refs) && free_entry)
286 EnterCriticalSection(&csOpenDllList);
287 list_remove(&entry->entry);
288 LeaveCriticalSection(&csOpenDllList);
290 TRACE("freeing %p\n", entry->library);
291 FreeLibrary(entry->library);
293 HeapFree(GetProcessHeap(), 0, entry->library_name);
294 HeapFree(GetProcessHeap(), 0, entry);
298 /* frees memory associated with active dll list */
299 static void COMPOBJ_DllList_Free(void)
301 OpenDll *entry, *cursor2;
302 EnterCriticalSection(&csOpenDllList);
303 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
305 list_remove(&entry->entry);
307 HeapFree(GetProcessHeap(), 0, entry->library_name);
308 HeapFree(GetProcessHeap(), 0, entry);
310 LeaveCriticalSection(&csOpenDllList);
313 /******************************************************************************
314 * Manage apartments.
317 static DWORD apartment_addref(struct apartment *apt)
319 DWORD refs = InterlockedIncrement(&apt->refs);
320 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
321 return refs;
324 /* allocates memory and fills in the necessary fields for a new apartment
325 * object. must be called inside apartment cs */
326 static APARTMENT *apartment_construct(DWORD model)
328 APARTMENT *apt;
330 TRACE("creating new apartment, model=%d\n", model);
332 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
333 apt->tid = GetCurrentThreadId();
335 list_init(&apt->proxies);
336 list_init(&apt->stubmgrs);
337 list_init(&apt->psclsids);
338 list_init(&apt->loaded_dlls);
339 apt->ipidc = 0;
340 apt->refs = 1;
341 apt->remunk_exported = FALSE;
342 apt->oidc = 1;
343 InitializeCriticalSection(&apt->cs);
344 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
346 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
348 if (apt->multi_threaded)
350 /* FIXME: should be randomly generated by in an RPC call to rpcss */
351 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
353 else
355 /* FIXME: should be randomly generated by in an RPC call to rpcss */
356 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
359 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
361 list_add_head(&apts, &apt->entry);
363 return apt;
366 /* gets and existing apartment if one exists or otherwise creates an apartment
367 * structure which stores OLE apartment-local information and stores a pointer
368 * to it in the thread-local storage */
369 static APARTMENT *apartment_get_or_create(DWORD model)
371 APARTMENT *apt = COM_CurrentApt();
373 if (!apt)
375 if (model & COINIT_APARTMENTTHREADED)
377 EnterCriticalSection(&csApartment);
379 apt = apartment_construct(model);
380 if (!MainApartment)
382 MainApartment = apt;
383 apt->main = TRUE;
384 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
387 LeaveCriticalSection(&csApartment);
389 if (apt->main)
390 apartment_createwindowifneeded(apt);
392 else
394 EnterCriticalSection(&csApartment);
396 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
397 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
398 * in a process */
399 if (MTA)
401 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
402 apartment_addref(MTA);
404 else
405 MTA = apartment_construct(model);
407 apt = MTA;
409 LeaveCriticalSection(&csApartment);
411 COM_CurrentInfo()->apt = apt;
414 return apt;
417 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
419 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
422 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
424 list_remove(&curClass->entry);
426 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
427 RPC_StopLocalServer(curClass->RpcRegistration);
430 * Release the reference to the class object.
432 IUnknown_Release(curClass->classObject);
434 if (curClass->pMarshaledData)
436 LARGE_INTEGER zero;
437 memset(&zero, 0, sizeof(zero));
438 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
439 CoReleaseMarshalData(curClass->pMarshaledData);
440 IStream_Release(curClass->pMarshaledData);
443 HeapFree(GetProcessHeap(), 0, curClass);
446 static void COM_RevokeAllClasses(const struct apartment *apt)
448 RegisteredClass *curClass, *cursor;
450 EnterCriticalSection( &csRegisteredClassList );
452 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
454 if (curClass->apartment_id == apt->oxid)
455 COM_RevokeRegisteredClassObject(curClass);
458 LeaveCriticalSection( &csRegisteredClassList );
461 /******************************************************************************
462 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
465 typedef struct ManualResetEvent {
466 ISynchronize ISynchronize_iface;
467 LONG ref;
468 HANDLE event;
469 } MREImpl;
471 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
473 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
476 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
478 MREImpl *This = impl_from_ISynchronize(iface);
479 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
481 *ppv = NULL;
482 if(IsEqualGUID(riid, &IID_IUnknown) ||
483 IsEqualGUID(riid, &IID_ISynchronize))
484 *ppv = This;
485 else
486 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
488 if(*ppv)
490 IUnknown_AddRef((IUnknown*)*ppv);
491 return S_OK;
494 return E_NOINTERFACE;
497 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
499 MREImpl *This = impl_from_ISynchronize(iface);
500 LONG ref = InterlockedIncrement(&This->ref);
501 TRACE("%p - ref %d\n", This, ref);
503 return ref;
506 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
508 MREImpl *This = impl_from_ISynchronize(iface);
509 LONG ref = InterlockedDecrement(&This->ref);
510 TRACE("%p - ref %d\n", This, ref);
512 if(!ref)
514 CloseHandle(This->event);
515 HeapFree(GetProcessHeap(), 0, This);
518 return ref;
521 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
523 MREImpl *This = impl_from_ISynchronize(iface);
524 UINT index;
525 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
526 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
529 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
531 MREImpl *This = impl_from_ISynchronize(iface);
532 TRACE("%p\n", This);
533 SetEvent(This->event);
534 return S_OK;
537 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
539 MREImpl *This = impl_from_ISynchronize(iface);
540 TRACE("%p\n", This);
541 ResetEvent(This->event);
542 return S_OK;
545 static ISynchronizeVtbl vt_ISynchronize = {
546 ISynchronize_fnQueryInterface,
547 ISynchronize_fnAddRef,
548 ISynchronize_fnRelease,
549 ISynchronize_fnWait,
550 ISynchronize_fnSignal,
551 ISynchronize_fnReset
554 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
556 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
557 HRESULT hr;
559 if(punkouter)
560 FIXME("Aggregation not implemented.\n");
562 This->ref = 1;
563 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
564 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
566 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
567 ISynchronize_Release(&This->ISynchronize_iface);
568 return hr;
571 /***********************************************************************
572 * CoRevokeClassObject [OLE32.@]
574 * Removes a class object from the class registry.
576 * PARAMS
577 * dwRegister [I] Cookie returned from CoRegisterClassObject().
579 * RETURNS
580 * Success: S_OK.
581 * Failure: HRESULT code.
583 * NOTES
584 * Must be called from the same apartment that called CoRegisterClassObject(),
585 * otherwise it will fail with RPC_E_WRONG_THREAD.
587 * SEE ALSO
588 * CoRegisterClassObject
590 HRESULT WINAPI CoRevokeClassObject(
591 DWORD dwRegister)
593 HRESULT hr = E_INVALIDARG;
594 RegisteredClass *curClass;
595 APARTMENT *apt;
597 TRACE("(%08x)\n",dwRegister);
599 apt = COM_CurrentApt();
600 if (!apt)
602 ERR("COM was not initialized\n");
603 return CO_E_NOTINITIALIZED;
606 EnterCriticalSection( &csRegisteredClassList );
608 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
611 * Check if we have a match on the cookie.
613 if (curClass->dwCookie == dwRegister)
615 if (curClass->apartment_id == apt->oxid)
617 COM_RevokeRegisteredClassObject(curClass);
618 hr = S_OK;
620 else
622 ERR("called from wrong apartment, should be called from %s\n",
623 wine_dbgstr_longlong(curClass->apartment_id));
624 hr = RPC_E_WRONG_THREAD;
626 break;
630 LeaveCriticalSection( &csRegisteredClassList );
632 return hr;
635 /* frees unused libraries loaded by apartment_getclassobject by calling the
636 * DLL's DllCanUnloadNow entry point */
637 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
639 struct apartment_loaded_dll *entry, *next;
640 EnterCriticalSection(&apt->cs);
641 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
643 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
645 DWORD real_delay = delay;
647 if (real_delay == INFINITE)
649 /* DLLs that return multi-threaded objects aren't unloaded
650 * straight away to cope for programs that have races between
651 * last object destruction and threads in the DLLs that haven't
652 * finished, despite DllCanUnloadNow returning S_OK */
653 if (entry->multi_threaded)
654 real_delay = 10 * 60 * 1000; /* 10 minutes */
655 else
656 real_delay = 0;
659 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
661 list_remove(&entry->entry);
662 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
663 HeapFree(GetProcessHeap(), 0, entry);
665 else
666 entry->unload_time = GetTickCount() + real_delay;
668 else if (entry->unload_time)
669 entry->unload_time = 0;
671 LeaveCriticalSection(&apt->cs);
674 DWORD apartment_release(struct apartment *apt)
676 DWORD ret;
678 EnterCriticalSection(&csApartment);
680 ret = InterlockedDecrement(&apt->refs);
681 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
682 /* destruction stuff that needs to happen under csApartment CS */
683 if (ret == 0)
685 if (apt == MTA) MTA = NULL;
686 else if (apt == MainApartment) MainApartment = NULL;
687 list_remove(&apt->entry);
690 LeaveCriticalSection(&csApartment);
692 if (ret == 0)
694 struct list *cursor, *cursor2;
696 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
698 /* Release the references to the registered class objects */
699 COM_RevokeAllClasses(apt);
701 /* no locking is needed for this apartment, because no other thread
702 * can access it at this point */
704 apartment_disconnectproxies(apt);
706 if (apt->win) DestroyWindow(apt->win);
707 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
709 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
711 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
712 /* release the implicit reference given by the fact that the
713 * stub has external references (it must do since it is in the
714 * stub manager list in the apartment and all non-apartment users
715 * must have a ref on the apartment and so it cannot be destroyed).
717 stub_manager_int_release(stubmgr);
720 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
722 struct registered_psclsid *registered_psclsid =
723 LIST_ENTRY(cursor, struct registered_psclsid, entry);
725 list_remove(&registered_psclsid->entry);
726 HeapFree(GetProcessHeap(), 0, registered_psclsid);
729 /* if this assert fires, then another thread took a reference to a
730 * stub manager without taking a reference to the containing
731 * apartment, which it must do. */
732 assert(list_empty(&apt->stubmgrs));
734 if (apt->filter) IUnknown_Release(apt->filter);
736 /* free as many unused libraries as possible... */
737 apartment_freeunusedlibraries(apt, 0);
739 /* ... and free the memory for the apartment loaded dll entry and
740 * release the dll list reference without freeing the library for the
741 * rest */
742 while ((cursor = list_head(&apt->loaded_dlls)))
744 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
745 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
746 list_remove(cursor);
747 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
750 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
751 DeleteCriticalSection(&apt->cs);
753 HeapFree(GetProcessHeap(), 0, apt);
756 return ret;
759 /* The given OXID must be local to this process:
761 * The ref parameter is here mostly to ensure people remember that
762 * they get one, you should normally take a ref for thread safety.
764 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
766 APARTMENT *result = NULL;
767 struct list *cursor;
769 EnterCriticalSection(&csApartment);
770 LIST_FOR_EACH( cursor, &apts )
772 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
773 if (apt->oxid == oxid)
775 result = apt;
776 if (ref) apartment_addref(result);
777 break;
780 LeaveCriticalSection(&csApartment);
782 return result;
785 /* gets the apartment which has a given creator thread ID. The caller must
786 * release the reference from the apartment as soon as the apartment pointer
787 * is no longer required. */
788 APARTMENT *apartment_findfromtid(DWORD tid)
790 APARTMENT *result = NULL;
791 struct list *cursor;
793 EnterCriticalSection(&csApartment);
794 LIST_FOR_EACH( cursor, &apts )
796 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
797 if (apt->tid == tid)
799 result = apt;
800 apartment_addref(result);
801 break;
804 LeaveCriticalSection(&csApartment);
806 return result;
809 /* gets the main apartment if it exists. The caller must
810 * release the reference from the apartment as soon as the apartment pointer
811 * is no longer required. */
812 static APARTMENT *apartment_findmain(void)
814 APARTMENT *result;
816 EnterCriticalSection(&csApartment);
818 result = MainApartment;
819 if (result) apartment_addref(result);
821 LeaveCriticalSection(&csApartment);
823 return result;
826 /* gets the multi-threaded apartment if it exists. The caller must
827 * release the reference from the apartment as soon as the apartment pointer
828 * is no longer required. */
829 static APARTMENT *apartment_find_multi_threaded(void)
831 APARTMENT *result = NULL;
832 struct list *cursor;
834 EnterCriticalSection(&csApartment);
836 LIST_FOR_EACH( cursor, &apts )
838 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
839 if (apt->multi_threaded)
841 result = apt;
842 apartment_addref(result);
843 break;
847 LeaveCriticalSection(&csApartment);
848 return result;
851 /* gets the specified class object by loading the appropriate DLL, if
852 * necessary and calls the DllGetClassObject function for the DLL */
853 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
854 BOOL apartment_threaded,
855 REFCLSID rclsid, REFIID riid, void **ppv)
857 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
858 HRESULT hr = S_OK;
859 BOOL found = FALSE;
860 struct apartment_loaded_dll *apartment_loaded_dll;
862 if (!strcmpiW(dllpath, wszOle32))
864 /* we don't need to control the lifetime of this dll, so use the local
865 * implementation of DllGetClassObject directly */
866 TRACE("calling ole32!DllGetClassObject\n");
867 hr = DllGetClassObject(rclsid, riid, ppv);
869 if (hr != S_OK)
870 ERR("DllGetClassObject returned error 0x%08x\n", hr);
872 return hr;
875 EnterCriticalSection(&apt->cs);
877 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
878 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
880 TRACE("found %s already loaded\n", debugstr_w(dllpath));
881 found = TRUE;
882 break;
885 if (!found)
887 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
888 if (!apartment_loaded_dll)
889 hr = E_OUTOFMEMORY;
890 if (SUCCEEDED(hr))
892 apartment_loaded_dll->unload_time = 0;
893 apartment_loaded_dll->multi_threaded = FALSE;
894 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
895 if (FAILED(hr))
896 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
898 if (SUCCEEDED(hr))
900 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
901 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
905 LeaveCriticalSection(&apt->cs);
907 if (SUCCEEDED(hr))
909 /* one component being multi-threaded overrides any number of
910 * apartment-threaded components */
911 if (!apartment_threaded)
912 apartment_loaded_dll->multi_threaded = TRUE;
914 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
915 /* OK: get the ClassObject */
916 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
918 if (hr != S_OK)
919 ERR("DllGetClassObject returned error 0x%08x\n", hr);
922 return hr;
925 /***********************************************************************
926 * COM_RegReadPath [internal]
928 * Reads a registry value and expands it when necessary
930 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
932 DWORD ret;
933 HKEY key;
934 DWORD keytype;
935 WCHAR src[MAX_PATH];
936 DWORD dwLength = dstlen * sizeof(WCHAR);
938 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
939 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
940 if (keytype == REG_EXPAND_SZ) {
941 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
942 } else {
943 const WCHAR *quote_start;
944 quote_start = strchrW(src, '\"');
945 if (quote_start) {
946 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
947 if (quote_end) {
948 memmove(src, quote_start + 1,
949 (quote_end - quote_start - 1) * sizeof(WCHAR));
950 src[quote_end - quote_start - 1] = '\0';
953 lstrcpynW(dst, src, dstlen);
956 RegCloseKey (key);
958 return ret;
961 struct host_object_params
963 HKEY hkeydll;
964 CLSID clsid; /* clsid of object to marshal */
965 IID iid; /* interface to marshal */
966 HANDLE event; /* event signalling when ready for multi-threaded case */
967 HRESULT hr; /* result for multi-threaded case */
968 IStream *stream; /* stream that the object will be marshaled into */
969 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
972 static HRESULT apartment_hostobject(struct apartment *apt,
973 const struct host_object_params *params)
975 IUnknown *object;
976 HRESULT hr;
977 static const LARGE_INTEGER llZero;
978 WCHAR dllpath[MAX_PATH+1];
980 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
982 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
984 /* failure: CLSID is not found in registry */
985 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
986 return REGDB_E_CLASSNOTREG;
989 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
990 &params->clsid, &params->iid, (void **)&object);
991 if (FAILED(hr))
992 return hr;
994 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
995 if (FAILED(hr))
996 IUnknown_Release(object);
997 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
999 return hr;
1002 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1004 switch (msg)
1006 case DM_EXECUTERPC:
1007 RPC_ExecuteCall((struct dispatch_params *)lParam);
1008 return 0;
1009 case DM_HOSTOBJECT:
1010 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1011 default:
1012 return DefWindowProcW(hWnd, msg, wParam, lParam);
1016 struct host_thread_params
1018 COINIT threading_model;
1019 HANDLE ready_event;
1020 HWND apartment_hwnd;
1023 /* thread for hosting an object to allow an object to appear to be created in
1024 * an apartment with an incompatible threading model */
1025 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1027 struct host_thread_params *params = p;
1028 MSG msg;
1029 HRESULT hr;
1030 struct apartment *apt;
1032 TRACE("\n");
1034 hr = CoInitializeEx(NULL, params->threading_model);
1035 if (FAILED(hr)) return hr;
1037 apt = COM_CurrentApt();
1038 if (params->threading_model == COINIT_APARTMENTTHREADED)
1040 apartment_createwindowifneeded(apt);
1041 params->apartment_hwnd = apartment_getwindow(apt);
1043 else
1044 params->apartment_hwnd = NULL;
1046 /* force the message queue to be created before signaling parent thread */
1047 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1049 SetEvent(params->ready_event);
1050 params = NULL; /* can't touch params after here as it may be invalid */
1052 while (GetMessageW(&msg, NULL, 0, 0))
1054 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1056 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1057 obj_params->hr = apartment_hostobject(apt, obj_params);
1058 SetEvent(obj_params->event);
1060 else
1062 TranslateMessage(&msg);
1063 DispatchMessageW(&msg);
1067 TRACE("exiting\n");
1069 CoUninitialize();
1071 return S_OK;
1074 /* finds or creates a host apartment, creates the object inside it and returns
1075 * a proxy to it so that the object can be used in the apartment of the
1076 * caller of this function */
1077 static HRESULT apartment_hostobject_in_hostapt(
1078 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1079 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1081 struct host_object_params params;
1082 HWND apartment_hwnd = NULL;
1083 DWORD apartment_tid = 0;
1084 HRESULT hr;
1086 if (!multi_threaded && main_apartment)
1088 APARTMENT *host_apt = apartment_findmain();
1089 if (host_apt)
1091 apartment_hwnd = apartment_getwindow(host_apt);
1092 apartment_release(host_apt);
1096 if (!apartment_hwnd)
1098 EnterCriticalSection(&apt->cs);
1100 if (!apt->host_apt_tid)
1102 struct host_thread_params thread_params;
1103 HANDLE handles[2];
1104 DWORD wait_value;
1106 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1107 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1108 thread_params.apartment_hwnd = NULL;
1109 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1110 if (!handles[1])
1112 CloseHandle(handles[0]);
1113 LeaveCriticalSection(&apt->cs);
1114 return E_OUTOFMEMORY;
1116 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1117 CloseHandle(handles[0]);
1118 CloseHandle(handles[1]);
1119 if (wait_value == WAIT_OBJECT_0)
1120 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1121 else
1123 LeaveCriticalSection(&apt->cs);
1124 return E_OUTOFMEMORY;
1128 if (multi_threaded || !main_apartment)
1130 apartment_hwnd = apt->host_apt_hwnd;
1131 apartment_tid = apt->host_apt_tid;
1134 LeaveCriticalSection(&apt->cs);
1137 /* another thread may have become the main apartment in the time it took
1138 * us to create the thread for the host apartment */
1139 if (!apartment_hwnd && !multi_threaded && main_apartment)
1141 APARTMENT *host_apt = apartment_findmain();
1142 if (host_apt)
1144 apartment_hwnd = apartment_getwindow(host_apt);
1145 apartment_release(host_apt);
1149 params.hkeydll = hkeydll;
1150 params.clsid = *rclsid;
1151 params.iid = *riid;
1152 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1153 if (FAILED(hr))
1154 return hr;
1155 params.apartment_threaded = !multi_threaded;
1156 if (multi_threaded)
1158 params.hr = S_OK;
1159 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1160 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1161 hr = E_OUTOFMEMORY;
1162 else
1164 WaitForSingleObject(params.event, INFINITE);
1165 hr = params.hr;
1167 CloseHandle(params.event);
1169 else
1171 if (!apartment_hwnd)
1173 ERR("host apartment didn't create window\n");
1174 hr = E_OUTOFMEMORY;
1176 else
1177 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1179 if (SUCCEEDED(hr))
1180 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1181 IStream_Release(params.stream);
1182 return hr;
1185 /* create a window for the apartment or return the current one if one has
1186 * already been created */
1187 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1189 if (apt->multi_threaded)
1190 return S_OK;
1192 if (!apt->win)
1194 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1195 0, 0, 0, 0,
1196 HWND_MESSAGE, 0, hProxyDll, NULL);
1197 if (!hwnd)
1199 ERR("CreateWindow failed with error %d\n", GetLastError());
1200 return HRESULT_FROM_WIN32(GetLastError());
1202 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1203 /* someone beat us to it */
1204 DestroyWindow(hwnd);
1207 return S_OK;
1210 /* retrieves the window for the main- or apartment-threaded apartment */
1211 HWND apartment_getwindow(const struct apartment *apt)
1213 assert(!apt->multi_threaded);
1214 return apt->win;
1217 void apartment_joinmta(void)
1219 apartment_addref(MTA);
1220 COM_CurrentInfo()->apt = MTA;
1223 static void COMPOBJ_InitProcess( void )
1225 WNDCLASSW wclass;
1227 /* Dispatching to the correct thread in an apartment is done through
1228 * window messages rather than RPC transports. When an interface is
1229 * marshalled into another apartment in the same process, a window of the
1230 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1231 * application) is responsible for pumping the message loop in that thread.
1232 * The WM_USER messages which point to the RPCs are then dispatched to
1233 * apartment_wndproc by the user's code from the apartment in which the
1234 * interface was unmarshalled.
1236 memset(&wclass, 0, sizeof(wclass));
1237 wclass.lpfnWndProc = apartment_wndproc;
1238 wclass.hInstance = hProxyDll;
1239 wclass.lpszClassName = wszAptWinClass;
1240 RegisterClassW(&wclass);
1243 static void COMPOBJ_UninitProcess( void )
1245 UnregisterClassW(wszAptWinClass, hProxyDll);
1248 static void COM_TlsDestroy(void)
1250 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1251 if (info)
1253 if (info->apt) apartment_release(info->apt);
1254 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1255 if (info->state) IUnknown_Release(info->state);
1256 if (info->spy) IUnknown_Release(info->spy);
1257 if (info->context_token) IObjContext_Release(info->context_token);
1258 HeapFree(GetProcessHeap(), 0, info);
1259 NtCurrentTeb()->ReservedForOle = NULL;
1263 /******************************************************************************
1264 * CoBuildVersion [OLE32.@]
1266 * Gets the build version of the DLL.
1268 * PARAMS
1270 * RETURNS
1271 * Current build version, hiword is majornumber, loword is minornumber
1273 DWORD WINAPI CoBuildVersion(void)
1275 TRACE("Returning version %d, build %d.\n", rmm, rup);
1276 return (rmm<<16)+rup;
1279 /******************************************************************************
1280 * CoRegisterInitializeSpy [OLE32.@]
1282 * Add a Spy that watches CoInitializeEx calls
1284 * PARAMS
1285 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1286 * cookie [II] cookie receiver
1288 * RETURNS
1289 * Success: S_OK if not already initialized, S_FALSE otherwise.
1290 * Failure: HRESULT code.
1292 * SEE ALSO
1293 * CoInitializeEx
1295 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1297 struct oletls *info = COM_CurrentInfo();
1298 HRESULT hr;
1300 TRACE("(%p, %p)\n", spy, cookie);
1302 if (!spy || !cookie || !info)
1304 if (!info)
1305 WARN("Could not allocate tls\n");
1306 return E_INVALIDARG;
1309 if (info->spy)
1311 FIXME("Already registered?\n");
1312 return E_UNEXPECTED;
1315 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1316 if (SUCCEEDED(hr))
1318 cookie->QuadPart = (DWORD_PTR)spy;
1319 return S_OK;
1321 return hr;
1324 /******************************************************************************
1325 * CoRevokeInitializeSpy [OLE32.@]
1327 * Remove a spy that previously watched CoInitializeEx calls
1329 * PARAMS
1330 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1332 * RETURNS
1333 * Success: S_OK if a spy is removed
1334 * Failure: E_INVALIDARG
1336 * SEE ALSO
1337 * CoInitializeEx
1339 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1341 struct oletls *info = COM_CurrentInfo();
1342 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1344 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1345 return E_INVALIDARG;
1347 IUnknown_Release(info->spy);
1348 info->spy = NULL;
1349 return S_OK;
1353 /******************************************************************************
1354 * CoInitialize [OLE32.@]
1356 * Initializes the COM libraries by calling CoInitializeEx with
1357 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1359 * PARAMS
1360 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1362 * RETURNS
1363 * Success: S_OK if not already initialized, S_FALSE otherwise.
1364 * Failure: HRESULT code.
1366 * SEE ALSO
1367 * CoInitializeEx
1369 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1372 * Just delegate to the newer method.
1374 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1377 /******************************************************************************
1378 * CoInitializeEx [OLE32.@]
1380 * Initializes the COM libraries.
1382 * PARAMS
1383 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1384 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1386 * RETURNS
1387 * S_OK if successful,
1388 * S_FALSE if this function was called already.
1389 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1390 * threading model.
1392 * NOTES
1394 * The behavior used to set the IMalloc used for memory management is
1395 * obsolete.
1396 * The dwCoInit parameter must specify one of the following apartment
1397 * threading models:
1398 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1399 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1400 * The parameter may also specify zero or more of the following flags:
1401 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1402 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1404 * SEE ALSO
1405 * CoUninitialize
1407 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1409 struct oletls *info = COM_CurrentInfo();
1410 HRESULT hr = S_OK;
1411 APARTMENT *apt;
1413 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1415 if (lpReserved!=NULL)
1417 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1421 * Check the lock count. If this is the first time going through the initialize
1422 * process, we have to initialize the libraries.
1424 * And crank-up that lock count.
1426 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1429 * Initialize the various COM libraries and data structures.
1431 TRACE("() - Initializing the COM libraries\n");
1433 /* we may need to defer this until after apartment initialisation */
1434 RunningObjectTableImpl_Initialize();
1437 if (info->spy)
1438 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1440 if (!(apt = info->apt))
1442 apt = apartment_get_or_create(dwCoInit);
1443 if (!apt) return E_OUTOFMEMORY;
1445 else if (!apartment_is_model(apt, dwCoInit))
1447 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1448 code then we are probably using the wrong threading model to implement that API. */
1449 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1450 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1451 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1452 return RPC_E_CHANGED_MODE;
1454 else
1455 hr = S_FALSE;
1457 info->inits++;
1459 if (info->spy)
1460 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1462 return hr;
1465 /***********************************************************************
1466 * CoUninitialize [OLE32.@]
1468 * This method will decrement the refcount on the current apartment, freeing
1469 * the resources associated with it if it is the last thread in the apartment.
1470 * If the last apartment is freed, the function will additionally release
1471 * any COM resources associated with the process.
1473 * PARAMS
1475 * RETURNS
1476 * Nothing.
1478 * SEE ALSO
1479 * CoInitializeEx
1481 void WINAPI CoUninitialize(void)
1483 struct oletls * info = COM_CurrentInfo();
1484 LONG lCOMRefCnt;
1486 TRACE("()\n");
1488 /* will only happen on OOM */
1489 if (!info) return;
1491 if (info->spy)
1492 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1494 /* sanity check */
1495 if (!info->inits)
1497 ERR("Mismatched CoUninitialize\n");
1499 if (info->spy)
1500 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1501 return;
1504 if (!--info->inits)
1506 apartment_release(info->apt);
1507 info->apt = NULL;
1511 * Decrease the reference count.
1512 * If we are back to 0 locks on the COM library, make sure we free
1513 * all the associated data structures.
1515 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1516 if (lCOMRefCnt==1)
1518 TRACE("() - Releasing the COM libraries\n");
1520 RunningObjectTableImpl_UnInitialize();
1522 else if (lCOMRefCnt<1) {
1523 ERR( "CoUninitialize() - not CoInitialized.\n" );
1524 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1526 if (info->spy)
1527 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1530 /******************************************************************************
1531 * CoDisconnectObject [OLE32.@]
1533 * Disconnects all connections to this object from remote processes. Dispatches
1534 * pending RPCs while blocking new RPCs from occurring, and then calls
1535 * IMarshal::DisconnectObject on the given object.
1537 * Typically called when the object server is forced to shut down, for instance by
1538 * the user.
1540 * PARAMS
1541 * lpUnk [I] The object whose stub should be disconnected.
1542 * reserved [I] Reserved. Should be set to 0.
1544 * RETURNS
1545 * Success: S_OK.
1546 * Failure: HRESULT code.
1548 * SEE ALSO
1549 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1551 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1553 HRESULT hr;
1554 IMarshal *marshal;
1555 APARTMENT *apt;
1557 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1559 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1560 if (hr == S_OK)
1562 hr = IMarshal_DisconnectObject(marshal, reserved);
1563 IMarshal_Release(marshal);
1564 return hr;
1567 apt = COM_CurrentApt();
1568 if (!apt)
1569 return CO_E_NOTINITIALIZED;
1571 apartment_disconnectobject(apt, lpUnk);
1573 /* Note: native is pretty broken here because it just silently
1574 * fails, without returning an appropriate error code if the object was
1575 * not found, making apps think that the object was disconnected, when
1576 * it actually wasn't */
1578 return S_OK;
1581 /******************************************************************************
1582 * CoCreateGuid [OLE32.@]
1584 * Simply forwards to UuidCreate in RPCRT4.
1586 * PARAMS
1587 * pguid [O] Points to the GUID to initialize.
1589 * RETURNS
1590 * Success: S_OK.
1591 * Failure: HRESULT code.
1593 * SEE ALSO
1594 * UuidCreate
1596 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1598 DWORD status = UuidCreate(pguid);
1599 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1600 return HRESULT_FROM_WIN32( status );
1603 static inline BOOL is_valid_hex(WCHAR c)
1605 if (!(((c >= '0') && (c <= '9')) ||
1606 ((c >= 'a') && (c <= 'f')) ||
1607 ((c >= 'A') && (c <= 'F'))))
1608 return FALSE;
1609 return TRUE;
1612 /******************************************************************************
1613 * CLSIDFromString [OLE32.@]
1614 * IIDFromString [OLE32.@]
1616 * Converts a unique identifier from its string representation into
1617 * the GUID struct.
1619 * PARAMS
1620 * idstr [I] The string representation of the GUID.
1621 * id [O] GUID converted from the string.
1623 * RETURNS
1624 * S_OK on success
1625 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1627 * SEE ALSO
1628 * StringFromCLSID
1630 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1632 int i;
1633 BYTE table[256];
1635 if (!s || s[0]!='{') {
1636 memset( id, 0, sizeof (CLSID) );
1637 if(!s) return S_OK;
1638 return CO_E_CLASSSTRING;
1641 TRACE("%s -> %p\n", debugstr_w(s), id);
1643 /* quick lookup table */
1644 memset(table, 0, 256);
1646 for (i = 0; i < 10; i++) {
1647 table['0' + i] = i;
1649 for (i = 0; i < 6; i++) {
1650 table['A' + i] = i+10;
1651 table['a' + i] = i+10;
1654 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1656 id->Data1 = 0;
1657 for (i = 1; i < 9; i++) {
1658 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1659 id->Data1 = (id->Data1 << 4) | table[s[i]];
1661 if (s[9]!='-') return CO_E_CLASSSTRING;
1663 id->Data2 = 0;
1664 for (i = 10; i < 14; i++) {
1665 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1666 id->Data2 = (id->Data2 << 4) | table[s[i]];
1668 if (s[14]!='-') return CO_E_CLASSSTRING;
1670 id->Data3 = 0;
1671 for (i = 15; i < 19; i++) {
1672 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1673 id->Data3 = (id->Data3 << 4) | table[s[i]];
1675 if (s[19]!='-') return CO_E_CLASSSTRING;
1677 for (i = 20; i < 37; i+=2) {
1678 if (i == 24) {
1679 if (s[i]!='-') return CO_E_CLASSSTRING;
1680 i++;
1682 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1683 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1686 if (s[37] == '}' && s[38] == '\0')
1687 return S_OK;
1689 return CO_E_CLASSSTRING;
1692 /*****************************************************************************/
1694 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1696 HRESULT ret;
1698 if (!id)
1699 return E_INVALIDARG;
1701 ret = __CLSIDFromString(idstr, id);
1702 if(ret != S_OK) { /* It appears a ProgID is also valid */
1703 CLSID tmp_id;
1704 ret = CLSIDFromProgID(idstr, &tmp_id);
1705 if(SUCCEEDED(ret))
1706 *id = tmp_id;
1708 return ret;
1712 /******************************************************************************
1713 * StringFromCLSID [OLE32.@]
1714 * StringFromIID [OLE32.@]
1716 * Converts a GUID into the respective string representation.
1717 * The target string is allocated using the OLE IMalloc.
1719 * PARAMS
1720 * id [I] the GUID to be converted.
1721 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1723 * RETURNS
1724 * S_OK
1725 * E_FAIL
1727 * SEE ALSO
1728 * StringFromGUID2, CLSIDFromString
1730 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1732 HRESULT ret;
1733 LPMALLOC mllc;
1735 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1736 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1737 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1738 return S_OK;
1741 /******************************************************************************
1742 * StringFromGUID2 [OLE32.@]
1744 * Modified version of StringFromCLSID that allows you to specify max
1745 * buffer size.
1747 * PARAMS
1748 * id [I] GUID to convert to string.
1749 * str [O] Buffer where the result will be stored.
1750 * cmax [I] Size of the buffer in characters.
1752 * RETURNS
1753 * Success: The length of the resulting string in characters.
1754 * Failure: 0.
1756 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1758 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1759 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1760 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1761 '%','0','2','X','%','0','2','X','}',0 };
1762 if (!id || cmax < CHARS_IN_GUID) return 0;
1763 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1764 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1765 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1766 return CHARS_IN_GUID;
1769 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1770 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1772 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1773 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1774 LONG res;
1775 HKEY key;
1777 strcpyW(path, wszCLSIDSlash);
1778 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1779 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1780 if (res == ERROR_FILE_NOT_FOUND)
1781 return REGDB_E_CLASSNOTREG;
1782 else if (res != ERROR_SUCCESS)
1783 return REGDB_E_READREGDB;
1785 if (!keyname)
1787 *subkey = key;
1788 return S_OK;
1791 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1792 RegCloseKey(key);
1793 if (res == ERROR_FILE_NOT_FOUND)
1794 return REGDB_E_KEYMISSING;
1795 else if (res != ERROR_SUCCESS)
1796 return REGDB_E_READREGDB;
1798 return S_OK;
1801 /* open HKCR\\AppId\\{string form of appid clsid} key */
1802 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1804 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1805 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1806 DWORD res;
1807 WCHAR buf[CHARS_IN_GUID];
1808 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1809 DWORD size;
1810 HKEY hkey;
1811 DWORD type;
1812 HRESULT hr;
1814 /* read the AppID value under the class's key */
1815 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1816 if (FAILED(hr))
1817 return hr;
1819 size = sizeof(buf);
1820 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1821 RegCloseKey(hkey);
1822 if (res == ERROR_FILE_NOT_FOUND)
1823 return REGDB_E_KEYMISSING;
1824 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1825 return REGDB_E_READREGDB;
1827 strcpyW(keyname, szAppIdKey);
1828 strcatW(keyname, buf);
1829 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1830 if (res == ERROR_FILE_NOT_FOUND)
1831 return REGDB_E_KEYMISSING;
1832 else if (res != ERROR_SUCCESS)
1833 return REGDB_E_READREGDB;
1835 return S_OK;
1838 /******************************************************************************
1839 * ProgIDFromCLSID [OLE32.@]
1841 * Converts a class id into the respective program ID.
1843 * PARAMS
1844 * clsid [I] Class ID, as found in registry.
1845 * ppszProgID [O] Associated ProgID.
1847 * RETURNS
1848 * S_OK
1849 * E_OUTOFMEMORY
1850 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1852 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1854 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1855 HKEY hkey;
1856 HRESULT ret;
1857 LONG progidlen = 0;
1859 if (!ppszProgID)
1861 ERR("ppszProgId isn't optional\n");
1862 return E_INVALIDARG;
1865 *ppszProgID = NULL;
1866 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1867 if (FAILED(ret))
1868 return ret;
1870 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1871 ret = REGDB_E_CLASSNOTREG;
1873 if (ret == S_OK)
1875 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1876 if (*ppszProgID)
1878 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1879 ret = REGDB_E_CLASSNOTREG;
1881 else
1882 ret = E_OUTOFMEMORY;
1885 RegCloseKey(hkey);
1886 return ret;
1889 /******************************************************************************
1890 * CLSIDFromProgID [OLE32.@]
1892 * Converts a program id into the respective GUID.
1894 * PARAMS
1895 * progid [I] Unicode program ID, as found in registry.
1896 * clsid [O] Associated CLSID.
1898 * RETURNS
1899 * Success: S_OK
1900 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1902 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1904 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1905 WCHAR buf2[CHARS_IN_GUID];
1906 LONG buf2len = sizeof(buf2);
1907 HKEY xhkey;
1908 WCHAR *buf;
1910 if (!progid || !clsid)
1912 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1913 return E_INVALIDARG;
1916 /* initialise clsid in case of failure */
1917 memset(clsid, 0, sizeof(*clsid));
1919 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1920 strcpyW( buf, progid );
1921 strcatW( buf, clsidW );
1922 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1924 HeapFree(GetProcessHeap(),0,buf);
1925 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1926 return CO_E_CLASSSTRING;
1928 HeapFree(GetProcessHeap(),0,buf);
1930 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1932 RegCloseKey(xhkey);
1933 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1934 return CO_E_CLASSSTRING;
1936 RegCloseKey(xhkey);
1937 return __CLSIDFromString(buf2,clsid);
1941 /*****************************************************************************
1942 * CoGetPSClsid [OLE32.@]
1944 * Retrieves the CLSID of the proxy/stub factory that implements
1945 * IPSFactoryBuffer for the specified interface.
1947 * PARAMS
1948 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1949 * pclsid [O] Where to store returned proxy/stub CLSID.
1951 * RETURNS
1952 * S_OK
1953 * E_OUTOFMEMORY
1954 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1956 * NOTES
1958 * The standard marshaller activates the object with the CLSID
1959 * returned and uses the CreateProxy and CreateStub methods on its
1960 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1961 * given object.
1963 * CoGetPSClsid determines this CLSID by searching the
1964 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1965 * in the registry and any interface id registered by
1966 * CoRegisterPSClsid within the current process.
1968 * BUGS
1970 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1971 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1972 * considered a bug in native unless an application depends on this (unlikely).
1974 * SEE ALSO
1975 * CoRegisterPSClsid.
1977 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1979 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1980 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1981 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1982 WCHAR value[CHARS_IN_GUID];
1983 LONG len;
1984 HKEY hkey;
1985 APARTMENT *apt = COM_CurrentApt();
1986 struct registered_psclsid *registered_psclsid;
1988 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1990 if (!apt)
1992 ERR("apartment not initialised\n");
1993 return CO_E_NOTINITIALIZED;
1996 if (!pclsid)
1998 ERR("pclsid isn't optional\n");
1999 return E_INVALIDARG;
2002 EnterCriticalSection(&apt->cs);
2004 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2005 if (IsEqualIID(&registered_psclsid->iid, riid))
2007 *pclsid = registered_psclsid->clsid;
2008 LeaveCriticalSection(&apt->cs);
2009 return S_OK;
2012 LeaveCriticalSection(&apt->cs);
2014 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2015 strcpyW(path, wszInterface);
2016 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2017 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2019 /* Open the key.. */
2020 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
2022 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2023 return REGDB_E_IIDNOTREG;
2026 /* ... Once we have the key, query the registry to get the
2027 value of CLSID as a string, and convert it into a
2028 proper CLSID structure to be passed back to the app */
2029 len = sizeof(value);
2030 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2032 RegCloseKey(hkey);
2033 return REGDB_E_IIDNOTREG;
2035 RegCloseKey(hkey);
2037 /* We have the CLSID we want back from the registry as a string, so
2038 let's convert it into a CLSID structure */
2039 if (CLSIDFromString(value, pclsid) != NOERROR)
2040 return REGDB_E_IIDNOTREG;
2042 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2043 return S_OK;
2046 /*****************************************************************************
2047 * CoRegisterPSClsid [OLE32.@]
2049 * Register a proxy/stub CLSID for the given interface in the current process
2050 * only.
2052 * PARAMS
2053 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2054 * rclsid [I] CLSID of the proxy/stub.
2056 * RETURNS
2057 * Success: S_OK
2058 * Failure: E_OUTOFMEMORY
2060 * NOTES
2062 * This function does not add anything to the registry and the effects are
2063 * limited to the lifetime of the current process.
2065 * SEE ALSO
2066 * CoGetPSClsid.
2068 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2070 APARTMENT *apt = COM_CurrentApt();
2071 struct registered_psclsid *registered_psclsid;
2073 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2075 if (!apt)
2077 ERR("apartment not initialised\n");
2078 return CO_E_NOTINITIALIZED;
2081 EnterCriticalSection(&apt->cs);
2083 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2084 if (IsEqualIID(&registered_psclsid->iid, riid))
2086 registered_psclsid->clsid = *rclsid;
2087 LeaveCriticalSection(&apt->cs);
2088 return S_OK;
2091 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2092 if (!registered_psclsid)
2094 LeaveCriticalSection(&apt->cs);
2095 return E_OUTOFMEMORY;
2098 registered_psclsid->iid = *riid;
2099 registered_psclsid->clsid = *rclsid;
2100 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2102 LeaveCriticalSection(&apt->cs);
2104 return S_OK;
2108 /***
2109 * COM_GetRegisteredClassObject
2111 * This internal method is used to scan the registered class list to
2112 * find a class object.
2114 * Params:
2115 * rclsid Class ID of the class to find.
2116 * dwClsContext Class context to match.
2117 * ppv [out] returns a pointer to the class object. Complying
2118 * to normal COM usage, this method will increase the
2119 * reference count on this object.
2121 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2122 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2124 HRESULT hr = S_FALSE;
2125 RegisteredClass *curClass;
2127 EnterCriticalSection( &csRegisteredClassList );
2129 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2132 * Check if we have a match on the class ID and context.
2134 if ((apt->oxid == curClass->apartment_id) &&
2135 (dwClsContext & curClass->runContext) &&
2136 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2139 * We have a match, return the pointer to the class object.
2141 *ppUnk = curClass->classObject;
2143 IUnknown_AddRef(curClass->classObject);
2145 hr = S_OK;
2146 break;
2150 LeaveCriticalSection( &csRegisteredClassList );
2152 return hr;
2155 /******************************************************************************
2156 * CoRegisterClassObject [OLE32.@]
2158 * Registers the class object for a given class ID. Servers housed in EXE
2159 * files use this method instead of exporting DllGetClassObject to allow
2160 * other code to connect to their objects.
2162 * PARAMS
2163 * rclsid [I] CLSID of the object to register.
2164 * pUnk [I] IUnknown of the object.
2165 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2166 * flags [I] REGCLS flags indicating how connections are made.
2167 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2169 * RETURNS
2170 * S_OK on success,
2171 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2172 * CO_E_OBJISREG if the object is already registered. We should not return this.
2174 * SEE ALSO
2175 * CoRevokeClassObject, CoGetClassObject
2177 * NOTES
2178 * In-process objects are only registered for the current apartment.
2179 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2180 * in other apartments.
2182 * BUGS
2183 * MSDN claims that multiple interface registrations are legal, but we
2184 * can't do that with our current implementation.
2186 HRESULT WINAPI CoRegisterClassObject(
2187 REFCLSID rclsid,
2188 LPUNKNOWN pUnk,
2189 DWORD dwClsContext,
2190 DWORD flags,
2191 LPDWORD lpdwRegister)
2193 static LONG next_cookie;
2194 RegisteredClass* newClass;
2195 LPUNKNOWN foundObject;
2196 HRESULT hr;
2197 APARTMENT *apt;
2199 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2200 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2202 if ( (lpdwRegister==0) || (pUnk==0) )
2203 return E_INVALIDARG;
2205 apt = COM_CurrentApt();
2206 if (!apt)
2208 ERR("COM was not initialized\n");
2209 return CO_E_NOTINITIALIZED;
2212 *lpdwRegister = 0;
2214 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2215 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2216 if (flags & REGCLS_MULTIPLEUSE)
2217 dwClsContext |= CLSCTX_INPROC_SERVER;
2220 * First, check if the class is already registered.
2221 * If it is, this should cause an error.
2223 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2224 if (hr == S_OK) {
2225 if (flags & REGCLS_MULTIPLEUSE) {
2226 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2227 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2228 IUnknown_Release(foundObject);
2229 return hr;
2231 IUnknown_Release(foundObject);
2232 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2233 return CO_E_OBJISREG;
2236 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2237 if ( newClass == NULL )
2238 return E_OUTOFMEMORY;
2240 newClass->classIdentifier = *rclsid;
2241 newClass->apartment_id = apt->oxid;
2242 newClass->runContext = dwClsContext;
2243 newClass->connectFlags = flags;
2244 newClass->pMarshaledData = NULL;
2245 newClass->RpcRegistration = NULL;
2247 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2248 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2251 * Since we're making a copy of the object pointer, we have to increase its
2252 * reference count.
2254 newClass->classObject = pUnk;
2255 IUnknown_AddRef(newClass->classObject);
2257 EnterCriticalSection( &csRegisteredClassList );
2258 list_add_tail(&RegisteredClassList, &newClass->entry);
2259 LeaveCriticalSection( &csRegisteredClassList );
2261 *lpdwRegister = newClass->dwCookie;
2263 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2264 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2265 if (hr) {
2266 FIXME("Failed to create stream on hglobal, %x\n", hr);
2267 return hr;
2269 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2270 newClass->classObject, MSHCTX_LOCAL, NULL,
2271 MSHLFLAGS_TABLESTRONG);
2272 if (hr) {
2273 FIXME("CoMarshalInterface failed, %x!\n",hr);
2274 return hr;
2277 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2278 newClass->pMarshaledData,
2279 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2280 &newClass->RpcRegistration);
2282 return S_OK;
2285 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2287 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2288 DWORD keytype;
2289 DWORD ret;
2290 DWORD dwLength = len * sizeof(WCHAR);
2292 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2293 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2294 value[0] = '\0';
2297 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2298 REFCLSID rclsid, REFIID riid,
2299 BOOL hostifnecessary, void **ppv)
2301 WCHAR dllpath[MAX_PATH+1];
2302 BOOL apartment_threaded;
2304 if (hostifnecessary)
2306 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2307 static const WCHAR wszFree[] = {'F','r','e','e',0};
2308 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2309 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2311 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2312 /* "Apartment" */
2313 if (!strcmpiW(threading_model, wszApartment))
2315 apartment_threaded = TRUE;
2316 if (apt->multi_threaded)
2317 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2319 /* "Free" */
2320 else if (!strcmpiW(threading_model, wszFree))
2322 apartment_threaded = FALSE;
2323 if (!apt->multi_threaded)
2324 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2326 /* everything except "Apartment", "Free" and "Both" */
2327 else if (strcmpiW(threading_model, wszBoth))
2329 apartment_threaded = TRUE;
2330 /* everything else is main-threaded */
2331 if (threading_model[0])
2332 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2333 debugstr_w(threading_model), debugstr_guid(rclsid));
2335 if (apt->multi_threaded || !apt->main)
2336 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2338 else
2339 apartment_threaded = FALSE;
2341 else
2342 apartment_threaded = !apt->multi_threaded;
2344 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2346 /* failure: CLSID is not found in registry */
2347 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2348 return REGDB_E_CLASSNOTREG;
2351 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2352 rclsid, riid, ppv);
2355 /***********************************************************************
2356 * CoGetClassObject [OLE32.@]
2358 * Creates an object of the specified class.
2360 * PARAMS
2361 * rclsid [I] Class ID to create an instance of.
2362 * dwClsContext [I] Flags to restrict the location of the created instance.
2363 * pServerInfo [I] Optional. Details for connecting to a remote server.
2364 * iid [I] The ID of the interface of the instance to return.
2365 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2367 * RETURNS
2368 * Success: S_OK
2369 * Failure: HRESULT code.
2371 * NOTES
2372 * The dwClsContext parameter can be one or more of the following:
2373 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2374 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2375 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2376 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2378 * SEE ALSO
2379 * CoCreateInstance()
2381 HRESULT WINAPI CoGetClassObject(
2382 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2383 REFIID iid, LPVOID *ppv)
2385 LPUNKNOWN regClassObject;
2386 HRESULT hres = E_UNEXPECTED;
2387 APARTMENT *apt;
2388 BOOL release_apt = FALSE;
2390 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2392 if (!ppv)
2393 return E_INVALIDARG;
2395 *ppv = NULL;
2397 if (!(apt = COM_CurrentApt()))
2399 if (!(apt = apartment_find_multi_threaded()))
2401 ERR("apartment not initialised\n");
2402 return CO_E_NOTINITIALIZED;
2404 release_apt = TRUE;
2407 if (pServerInfo) {
2408 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2409 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2413 * First, try and see if we can't match the class ID with one of the
2414 * registered classes.
2416 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2417 &regClassObject))
2419 /* Get the required interface from the retrieved pointer. */
2420 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2423 * Since QI got another reference on the pointer, we want to release the
2424 * one we already have. If QI was unsuccessful, this will release the object. This
2425 * is good since we are not returning it in the "out" parameter.
2427 IUnknown_Release(regClassObject);
2428 if (release_apt) apartment_release(apt);
2429 return hres;
2432 /* First try in-process server */
2433 if (CLSCTX_INPROC_SERVER & dwClsContext)
2435 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2436 HKEY hkey;
2438 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2440 if (release_apt) apartment_release(apt);
2441 return FTMarshalCF_Create(iid, ppv);
2444 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2445 if (FAILED(hres))
2447 if (hres == REGDB_E_CLASSNOTREG)
2448 ERR("class %s not registered\n", debugstr_guid(rclsid));
2449 else if (hres == REGDB_E_KEYMISSING)
2451 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2452 hres = REGDB_E_CLASSNOTREG;
2456 if (SUCCEEDED(hres))
2458 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2459 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2460 RegCloseKey(hkey);
2463 /* return if we got a class, otherwise fall through to one of the
2464 * other types */
2465 if (SUCCEEDED(hres))
2467 if (release_apt) apartment_release(apt);
2468 return hres;
2472 /* Next try in-process handler */
2473 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2475 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2476 HKEY hkey;
2478 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2479 if (FAILED(hres))
2481 if (hres == REGDB_E_CLASSNOTREG)
2482 ERR("class %s not registered\n", debugstr_guid(rclsid));
2483 else if (hres == REGDB_E_KEYMISSING)
2485 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2486 hres = REGDB_E_CLASSNOTREG;
2490 if (SUCCEEDED(hres))
2492 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2493 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2494 RegCloseKey(hkey);
2497 /* return if we got a class, otherwise fall through to one of the
2498 * other types */
2499 if (SUCCEEDED(hres))
2501 if (release_apt) apartment_release(apt);
2502 return hres;
2505 if (release_apt) apartment_release(apt);
2507 /* Next try out of process */
2508 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2510 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2511 if (SUCCEEDED(hres))
2512 return hres;
2515 /* Finally try remote: this requires networked DCOM (a lot of work) */
2516 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2518 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2519 hres = REGDB_E_CLASSNOTREG;
2522 if (FAILED(hres))
2523 ERR("no class object %s could be created for context 0x%x\n",
2524 debugstr_guid(rclsid), dwClsContext);
2525 return hres;
2528 /***********************************************************************
2529 * CoResumeClassObjects (OLE32.@)
2531 * Resumes all class objects registered with REGCLS_SUSPENDED.
2533 * RETURNS
2534 * Success: S_OK.
2535 * Failure: HRESULT code.
2537 HRESULT WINAPI CoResumeClassObjects(void)
2539 FIXME("stub\n");
2540 return S_OK;
2543 /***********************************************************************
2544 * CoCreateInstance [OLE32.@]
2546 * Creates an instance of the specified class.
2548 * PARAMS
2549 * rclsid [I] Class ID to create an instance of.
2550 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2551 * dwClsContext [I] Flags to restrict the location of the created instance.
2552 * iid [I] The ID of the interface of the instance to return.
2553 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2555 * RETURNS
2556 * Success: S_OK
2557 * Failure: HRESULT code.
2559 * NOTES
2560 * The dwClsContext parameter can be one or more of the following:
2561 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2562 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2563 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2564 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2566 * Aggregation is the concept of deferring the IUnknown of an object to another
2567 * object. This allows a separate object to behave as though it was part of
2568 * the object and to allow this the pUnkOuter parameter can be set. Note that
2569 * not all objects support having an outer of unknown.
2571 * SEE ALSO
2572 * CoGetClassObject()
2574 HRESULT WINAPI CoCreateInstance(
2575 REFCLSID rclsid,
2576 LPUNKNOWN pUnkOuter,
2577 DWORD dwClsContext,
2578 REFIID iid,
2579 LPVOID *ppv)
2581 HRESULT hres;
2582 LPCLASSFACTORY lpclf = 0;
2583 APARTMENT *apt;
2585 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2586 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2589 * Sanity check
2591 if (ppv==0)
2592 return E_POINTER;
2595 * Initialize the "out" parameter
2597 *ppv = 0;
2599 if (!(apt = COM_CurrentApt()))
2601 if (!(apt = apartment_find_multi_threaded()))
2603 ERR("apartment not initialised\n");
2604 return CO_E_NOTINITIALIZED;
2606 apartment_release(apt);
2610 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2611 * Rather than create a class factory, we can just check for it here
2613 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2614 if (StdGlobalInterfaceTableInstance == NULL)
2615 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2616 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2617 if (hres) return hres;
2619 TRACE("Retrieved GIT (%p)\n", *ppv);
2620 return S_OK;
2623 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2624 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2627 * Get a class factory to construct the object we want.
2629 hres = CoGetClassObject(rclsid,
2630 dwClsContext,
2631 NULL,
2632 &IID_IClassFactory,
2633 (LPVOID)&lpclf);
2635 if (FAILED(hres))
2636 return hres;
2639 * Create the object and don't forget to release the factory
2641 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2642 IClassFactory_Release(lpclf);
2643 if(FAILED(hres))
2645 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2646 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2647 else
2648 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2651 return hres;
2654 /***********************************************************************
2655 * CoCreateInstanceEx [OLE32.@]
2657 HRESULT WINAPI CoCreateInstanceEx(
2658 REFCLSID rclsid,
2659 LPUNKNOWN pUnkOuter,
2660 DWORD dwClsContext,
2661 COSERVERINFO* pServerInfo,
2662 ULONG cmq,
2663 MULTI_QI* pResults)
2665 IUnknown* pUnk = NULL;
2666 HRESULT hr;
2667 ULONG index;
2668 ULONG successCount = 0;
2671 * Sanity check
2673 if ( (cmq==0) || (pResults==NULL))
2674 return E_INVALIDARG;
2676 if (pServerInfo!=NULL)
2677 FIXME("() non-NULL pServerInfo not supported!\n");
2680 * Initialize all the "out" parameters.
2682 for (index = 0; index < cmq; index++)
2684 pResults[index].pItf = NULL;
2685 pResults[index].hr = E_NOINTERFACE;
2689 * Get the object and get its IUnknown pointer.
2691 hr = CoCreateInstance(rclsid,
2692 pUnkOuter,
2693 dwClsContext,
2694 &IID_IUnknown,
2695 (VOID**)&pUnk);
2697 if (hr)
2698 return hr;
2701 * Then, query for all the interfaces requested.
2703 for (index = 0; index < cmq; index++)
2705 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2706 pResults[index].pIID,
2707 (VOID**)&(pResults[index].pItf));
2709 if (pResults[index].hr == S_OK)
2710 successCount++;
2714 * Release our temporary unknown pointer.
2716 IUnknown_Release(pUnk);
2718 if (successCount == 0)
2719 return E_NOINTERFACE;
2721 if (successCount!=cmq)
2722 return CO_S_NOTALLINTERFACES;
2724 return S_OK;
2727 /***********************************************************************
2728 * CoLoadLibrary (OLE32.@)
2730 * Loads a library.
2732 * PARAMS
2733 * lpszLibName [I] Path to library.
2734 * bAutoFree [I] Whether the library should automatically be freed.
2736 * RETURNS
2737 * Success: Handle to loaded library.
2738 * Failure: NULL.
2740 * SEE ALSO
2741 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2743 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2745 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2747 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2750 /***********************************************************************
2751 * CoFreeLibrary [OLE32.@]
2753 * Unloads a library from memory.
2755 * PARAMS
2756 * hLibrary [I] Handle to library to unload.
2758 * RETURNS
2759 * Nothing
2761 * SEE ALSO
2762 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2764 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2766 FreeLibrary(hLibrary);
2770 /***********************************************************************
2771 * CoFreeAllLibraries [OLE32.@]
2773 * Function for backwards compatibility only. Does nothing.
2775 * RETURNS
2776 * Nothing.
2778 * SEE ALSO
2779 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2781 void WINAPI CoFreeAllLibraries(void)
2783 /* NOP */
2786 /***********************************************************************
2787 * CoFreeUnusedLibrariesEx [OLE32.@]
2789 * Frees any previously unused libraries whose delay has expired and marks
2790 * currently unused libraries for unloading. Unused are identified as those that
2791 * return S_OK from their DllCanUnloadNow function.
2793 * PARAMS
2794 * dwUnloadDelay [I] Unload delay in milliseconds.
2795 * dwReserved [I] Reserved. Set to 0.
2797 * RETURNS
2798 * Nothing.
2800 * SEE ALSO
2801 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2803 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2805 struct apartment *apt = COM_CurrentApt();
2806 if (!apt)
2808 ERR("apartment not initialised\n");
2809 return;
2812 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2815 /***********************************************************************
2816 * CoFreeUnusedLibraries [OLE32.@]
2818 * Frees any unused libraries. Unused are identified as those that return
2819 * S_OK from their DllCanUnloadNow function.
2821 * RETURNS
2822 * Nothing.
2824 * SEE ALSO
2825 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2827 void WINAPI CoFreeUnusedLibraries(void)
2829 CoFreeUnusedLibrariesEx(INFINITE, 0);
2832 /***********************************************************************
2833 * CoFileTimeNow [OLE32.@]
2835 * Retrieves the current time in FILETIME format.
2837 * PARAMS
2838 * lpFileTime [O] The current time.
2840 * RETURNS
2841 * S_OK.
2843 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2845 GetSystemTimeAsFileTime( lpFileTime );
2846 return S_OK;
2849 /******************************************************************************
2850 * CoLockObjectExternal [OLE32.@]
2852 * Increments or decrements the external reference count of a stub object.
2854 * PARAMS
2855 * pUnk [I] Stub object.
2856 * fLock [I] If TRUE then increments the external ref-count,
2857 * otherwise decrements.
2858 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2859 * calling CoDisconnectObject.
2861 * RETURNS
2862 * Success: S_OK.
2863 * Failure: HRESULT code.
2865 * NOTES
2866 * If fLock is TRUE and an object is passed in that doesn't have a stub
2867 * manager then a new stub manager is created for the object.
2869 HRESULT WINAPI CoLockObjectExternal(
2870 LPUNKNOWN pUnk,
2871 BOOL fLock,
2872 BOOL fLastUnlockReleases)
2874 struct stub_manager *stubmgr;
2875 struct apartment *apt;
2877 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2878 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2880 apt = COM_CurrentApt();
2881 if (!apt) return CO_E_NOTINITIALIZED;
2883 stubmgr = get_stub_manager_from_object(apt, pUnk);
2885 if (stubmgr)
2887 if (fLock)
2888 stub_manager_ext_addref(stubmgr, 1, FALSE);
2889 else
2890 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2892 stub_manager_int_release(stubmgr);
2894 return S_OK;
2896 else if (fLock)
2898 stubmgr = new_stub_manager(apt, pUnk);
2900 if (stubmgr)
2902 stub_manager_ext_addref(stubmgr, 1, FALSE);
2903 stub_manager_int_release(stubmgr);
2906 return S_OK;
2908 else
2910 WARN("stub object not found %p\n", pUnk);
2911 /* Note: native is pretty broken here because it just silently
2912 * fails, without returning an appropriate error code, making apps
2913 * think that the object was disconnected, when it actually wasn't */
2914 return S_OK;
2918 /***********************************************************************
2919 * CoInitializeWOW (OLE32.@)
2921 * WOW equivalent of CoInitialize?
2923 * PARAMS
2924 * x [I] Unknown.
2925 * y [I] Unknown.
2927 * RETURNS
2928 * Unknown.
2930 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2932 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2933 return 0;
2936 /***********************************************************************
2937 * CoGetState [OLE32.@]
2939 * Retrieves the thread state object previously stored by CoSetState().
2941 * PARAMS
2942 * ppv [I] Address where pointer to object will be stored.
2944 * RETURNS
2945 * Success: S_OK.
2946 * Failure: E_OUTOFMEMORY.
2948 * NOTES
2949 * Crashes on all invalid ppv addresses, including NULL.
2950 * If the function returns a non-NULL object then the caller must release its
2951 * reference on the object when the object is no longer required.
2953 * SEE ALSO
2954 * CoSetState().
2956 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2958 struct oletls *info = COM_CurrentInfo();
2959 if (!info) return E_OUTOFMEMORY;
2961 *ppv = NULL;
2963 if (info->state)
2965 IUnknown_AddRef(info->state);
2966 *ppv = info->state;
2967 TRACE("apt->state=%p\n", info->state);
2970 return S_OK;
2973 /***********************************************************************
2974 * CoSetState [OLE32.@]
2976 * Sets the thread state object.
2978 * PARAMS
2979 * pv [I] Pointer to state object to be stored.
2981 * NOTES
2982 * The system keeps a reference on the object while the object stored.
2984 * RETURNS
2985 * Success: S_OK.
2986 * Failure: E_OUTOFMEMORY.
2988 HRESULT WINAPI CoSetState(IUnknown * pv)
2990 struct oletls *info = COM_CurrentInfo();
2991 if (!info) return E_OUTOFMEMORY;
2993 if (pv) IUnknown_AddRef(pv);
2995 if (info->state)
2997 TRACE("-- release %p now\n", info->state);
2998 IUnknown_Release(info->state);
3001 info->state = pv;
3003 return S_OK;
3007 /******************************************************************************
3008 * CoTreatAsClass [OLE32.@]
3010 * Sets the TreatAs value of a class.
3012 * PARAMS
3013 * clsidOld [I] Class to set TreatAs value on.
3014 * clsidNew [I] The class the clsidOld should be treated as.
3016 * RETURNS
3017 * Success: S_OK.
3018 * Failure: HRESULT code.
3020 * SEE ALSO
3021 * CoGetTreatAsClass
3023 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3025 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3026 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3027 HKEY hkey = NULL;
3028 WCHAR szClsidNew[CHARS_IN_GUID];
3029 HRESULT res = S_OK;
3030 WCHAR auto_treat_as[CHARS_IN_GUID];
3031 LONG auto_treat_as_size = sizeof(auto_treat_as);
3032 CLSID id;
3034 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3035 if (FAILED(res))
3036 goto done;
3037 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3039 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3040 CLSIDFromString(auto_treat_as, &id) == S_OK)
3042 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3044 res = REGDB_E_WRITEREGDB;
3045 goto done;
3048 else
3050 RegDeleteKeyW(hkey, wszTreatAs);
3051 goto done;
3054 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3055 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3057 res = REGDB_E_WRITEREGDB;
3058 goto done;
3061 done:
3062 if (hkey) RegCloseKey(hkey);
3063 return res;
3066 /******************************************************************************
3067 * CoGetTreatAsClass [OLE32.@]
3069 * Gets the TreatAs value of a class.
3071 * PARAMS
3072 * clsidOld [I] Class to get the TreatAs value of.
3073 * clsidNew [I] The class the clsidOld should be treated as.
3075 * RETURNS
3076 * Success: S_OK.
3077 * Failure: HRESULT code.
3079 * SEE ALSO
3080 * CoSetTreatAsClass
3082 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3084 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3085 HKEY hkey = NULL;
3086 WCHAR szClsidNew[CHARS_IN_GUID];
3087 HRESULT res = S_OK;
3088 LONG len = sizeof(szClsidNew);
3090 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3091 *clsidNew = *clsidOld; /* copy over old value */
3093 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3094 if (FAILED(res))
3096 res = S_FALSE;
3097 goto done;
3099 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3101 res = S_FALSE;
3102 goto done;
3104 res = CLSIDFromString(szClsidNew,clsidNew);
3105 if (FAILED(res))
3106 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3107 done:
3108 if (hkey) RegCloseKey(hkey);
3109 return res;
3112 /******************************************************************************
3113 * CoGetCurrentProcess [OLE32.@]
3115 * Gets the current process ID.
3117 * RETURNS
3118 * The current process ID.
3120 * NOTES
3121 * Is DWORD really the correct return type for this function?
3123 DWORD WINAPI CoGetCurrentProcess(void)
3125 return GetCurrentProcessId();
3128 /******************************************************************************
3129 * CoRegisterMessageFilter [OLE32.@]
3131 * Registers a message filter.
3133 * PARAMS
3134 * lpMessageFilter [I] Pointer to interface.
3135 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3137 * RETURNS
3138 * Success: S_OK.
3139 * Failure: HRESULT code.
3141 * NOTES
3142 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3143 * lpMessageFilter removes the message filter.
3145 * If lplpMessageFilter is not NULL the previous message filter will be
3146 * returned in the memory pointer to this parameter and the caller is
3147 * responsible for releasing the object.
3149 * The current thread be in an apartment otherwise the function will crash.
3151 HRESULT WINAPI CoRegisterMessageFilter(
3152 LPMESSAGEFILTER lpMessageFilter,
3153 LPMESSAGEFILTER *lplpMessageFilter)
3155 struct apartment *apt;
3156 IMessageFilter *lpOldMessageFilter;
3158 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3160 apt = COM_CurrentApt();
3162 /* can't set a message filter in a multi-threaded apartment */
3163 if (!apt || apt->multi_threaded)
3165 WARN("can't set message filter in MTA or uninitialized apt\n");
3166 return CO_E_NOT_SUPPORTED;
3169 if (lpMessageFilter)
3170 IMessageFilter_AddRef(lpMessageFilter);
3172 EnterCriticalSection(&apt->cs);
3174 lpOldMessageFilter = apt->filter;
3175 apt->filter = lpMessageFilter;
3177 LeaveCriticalSection(&apt->cs);
3179 if (lplpMessageFilter)
3180 *lplpMessageFilter = lpOldMessageFilter;
3181 else if (lpOldMessageFilter)
3182 IMessageFilter_Release(lpOldMessageFilter);
3184 return S_OK;
3187 /***********************************************************************
3188 * CoIsOle1Class [OLE32.@]
3190 * Determines whether the specified class an OLE v1 class.
3192 * PARAMS
3193 * clsid [I] Class to test.
3195 * RETURNS
3196 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3198 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3200 FIXME("%s\n", debugstr_guid(clsid));
3201 return FALSE;
3204 /***********************************************************************
3205 * IsEqualGUID [OLE32.@]
3207 * Compares two Unique Identifiers.
3209 * PARAMS
3210 * rguid1 [I] The first GUID to compare.
3211 * rguid2 [I] The other GUID to compare.
3213 * RETURNS
3214 * TRUE if equal
3216 #undef IsEqualGUID
3217 BOOL WINAPI IsEqualGUID(
3218 REFGUID rguid1,
3219 REFGUID rguid2)
3221 return !memcmp(rguid1,rguid2,sizeof(GUID));
3224 /***********************************************************************
3225 * CoInitializeSecurity [OLE32.@]
3227 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3228 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3229 void* pReserved1, DWORD dwAuthnLevel,
3230 DWORD dwImpLevel, void* pReserved2,
3231 DWORD dwCapabilities, void* pReserved3)
3233 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3234 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3235 dwCapabilities, pReserved3);
3236 return S_OK;
3239 /***********************************************************************
3240 * CoSuspendClassObjects [OLE32.@]
3242 * Suspends all registered class objects to prevent further requests coming in
3243 * for those objects.
3245 * RETURNS
3246 * Success: S_OK.
3247 * Failure: HRESULT code.
3249 HRESULT WINAPI CoSuspendClassObjects(void)
3251 FIXME("\n");
3252 return S_OK;
3255 /***********************************************************************
3256 * CoAddRefServerProcess [OLE32.@]
3258 * Helper function for incrementing the reference count of a local-server
3259 * process.
3261 * RETURNS
3262 * New reference count.
3264 * SEE ALSO
3265 * CoReleaseServerProcess().
3267 ULONG WINAPI CoAddRefServerProcess(void)
3269 ULONG refs;
3271 TRACE("\n");
3273 EnterCriticalSection(&csRegisteredClassList);
3274 refs = ++s_COMServerProcessReferences;
3275 LeaveCriticalSection(&csRegisteredClassList);
3277 TRACE("refs before: %d\n", refs - 1);
3279 return refs;
3282 /***********************************************************************
3283 * CoReleaseServerProcess [OLE32.@]
3285 * Helper function for decrementing the reference count of a local-server
3286 * process.
3288 * RETURNS
3289 * New reference count.
3291 * NOTES
3292 * When reference count reaches 0, this function suspends all registered
3293 * classes so no new connections are accepted.
3295 * SEE ALSO
3296 * CoAddRefServerProcess(), CoSuspendClassObjects().
3298 ULONG WINAPI CoReleaseServerProcess(void)
3300 ULONG refs;
3302 TRACE("\n");
3304 EnterCriticalSection(&csRegisteredClassList);
3306 refs = --s_COMServerProcessReferences;
3307 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3309 LeaveCriticalSection(&csRegisteredClassList);
3311 TRACE("refs after: %d\n", refs);
3313 return refs;
3316 /***********************************************************************
3317 * CoIsHandlerConnected [OLE32.@]
3319 * Determines whether a proxy is connected to a remote stub.
3321 * PARAMS
3322 * pUnk [I] Pointer to object that may or may not be connected.
3324 * RETURNS
3325 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3326 * FALSE otherwise.
3328 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3330 FIXME("%p\n", pUnk);
3332 return TRUE;
3335 /***********************************************************************
3336 * CoAllowSetForegroundWindow [OLE32.@]
3339 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3341 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3342 return S_OK;
3345 /***********************************************************************
3346 * CoQueryProxyBlanket [OLE32.@]
3348 * Retrieves the security settings being used by a proxy.
3350 * PARAMS
3351 * pProxy [I] Pointer to the proxy object.
3352 * pAuthnSvc [O] The type of authentication service.
3353 * pAuthzSvc [O] The type of authorization service.
3354 * ppServerPrincName [O] Optional. The server prinicple name.
3355 * pAuthnLevel [O] The authentication level.
3356 * pImpLevel [O] The impersonation level.
3357 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3358 * pCapabilities [O] Flags affecting the security behaviour.
3360 * RETURNS
3361 * Success: S_OK.
3362 * Failure: HRESULT code.
3364 * SEE ALSO
3365 * CoCopyProxy, CoSetProxyBlanket.
3367 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3368 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3369 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3371 IClientSecurity *pCliSec;
3372 HRESULT hr;
3374 TRACE("%p\n", pProxy);
3376 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3377 if (SUCCEEDED(hr))
3379 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3380 pAuthzSvc, ppServerPrincName,
3381 pAuthnLevel, pImpLevel, ppAuthInfo,
3382 pCapabilities);
3383 IClientSecurity_Release(pCliSec);
3386 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3387 return hr;
3390 /***********************************************************************
3391 * CoSetProxyBlanket [OLE32.@]
3393 * Sets the security settings for a proxy.
3395 * PARAMS
3396 * pProxy [I] Pointer to the proxy object.
3397 * AuthnSvc [I] The type of authentication service.
3398 * AuthzSvc [I] The type of authorization service.
3399 * pServerPrincName [I] The server prinicple name.
3400 * AuthnLevel [I] The authentication level.
3401 * ImpLevel [I] The impersonation level.
3402 * pAuthInfo [I] Information specific to the authorization/authentication service.
3403 * Capabilities [I] Flags affecting the security behaviour.
3405 * RETURNS
3406 * Success: S_OK.
3407 * Failure: HRESULT code.
3409 * SEE ALSO
3410 * CoQueryProxyBlanket, CoCopyProxy.
3412 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3413 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3414 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3416 IClientSecurity *pCliSec;
3417 HRESULT hr;
3419 TRACE("%p\n", pProxy);
3421 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3422 if (SUCCEEDED(hr))
3424 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3425 AuthzSvc, pServerPrincName,
3426 AuthnLevel, ImpLevel, pAuthInfo,
3427 Capabilities);
3428 IClientSecurity_Release(pCliSec);
3431 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3432 return hr;
3435 /***********************************************************************
3436 * CoCopyProxy [OLE32.@]
3438 * Copies a proxy.
3440 * PARAMS
3441 * pProxy [I] Pointer to the proxy object.
3442 * ppCopy [O] Copy of the proxy.
3444 * RETURNS
3445 * Success: S_OK.
3446 * Failure: HRESULT code.
3448 * SEE ALSO
3449 * CoQueryProxyBlanket, CoSetProxyBlanket.
3451 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3453 IClientSecurity *pCliSec;
3454 HRESULT hr;
3456 TRACE("%p\n", pProxy);
3458 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3459 if (SUCCEEDED(hr))
3461 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3462 IClientSecurity_Release(pCliSec);
3465 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3466 return hr;
3470 /***********************************************************************
3471 * CoGetCallContext [OLE32.@]
3473 * Gets the context of the currently executing server call in the current
3474 * thread.
3476 * PARAMS
3477 * riid [I] Context interface to return.
3478 * ppv [O] Pointer to memory that will receive the context on return.
3480 * RETURNS
3481 * Success: S_OK.
3482 * Failure: HRESULT code.
3484 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3486 struct oletls *info = COM_CurrentInfo();
3488 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3490 if (!info)
3491 return E_OUTOFMEMORY;
3493 if (!info->call_state)
3494 return RPC_E_CALL_COMPLETE;
3496 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3499 /***********************************************************************
3500 * CoSwitchCallContext [OLE32.@]
3502 * Switches the context of the currently executing server call in the current
3503 * thread.
3505 * PARAMS
3506 * pObject [I] Pointer to new context object
3507 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3509 * RETURNS
3510 * Success: S_OK.
3511 * Failure: HRESULT code.
3513 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3515 struct oletls *info = COM_CurrentInfo();
3517 TRACE("(%p, %p)\n", pObject, ppOldObject);
3519 if (!info)
3520 return E_OUTOFMEMORY;
3522 *ppOldObject = info->call_state;
3523 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3525 return S_OK;
3528 /***********************************************************************
3529 * CoQueryClientBlanket [OLE32.@]
3531 * Retrieves the authentication information about the client of the currently
3532 * executing server call in the current thread.
3534 * PARAMS
3535 * pAuthnSvc [O] Optional. The type of authentication service.
3536 * pAuthzSvc [O] Optional. The type of authorization service.
3537 * pServerPrincName [O] Optional. The server prinicple name.
3538 * pAuthnLevel [O] Optional. The authentication level.
3539 * pImpLevel [O] Optional. The impersonation level.
3540 * pPrivs [O] Optional. Information about the privileges of the client.
3541 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3543 * RETURNS
3544 * Success: S_OK.
3545 * Failure: HRESULT code.
3547 * SEE ALSO
3548 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3550 HRESULT WINAPI CoQueryClientBlanket(
3551 DWORD *pAuthnSvc,
3552 DWORD *pAuthzSvc,
3553 OLECHAR **pServerPrincName,
3554 DWORD *pAuthnLevel,
3555 DWORD *pImpLevel,
3556 RPC_AUTHZ_HANDLE *pPrivs,
3557 DWORD *pCapabilities)
3559 IServerSecurity *pSrvSec;
3560 HRESULT hr;
3562 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3563 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3564 pPrivs, pCapabilities);
3566 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3567 if (SUCCEEDED(hr))
3569 hr = IServerSecurity_QueryBlanket(
3570 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3571 pImpLevel, pPrivs, pCapabilities);
3572 IServerSecurity_Release(pSrvSec);
3575 return hr;
3578 /***********************************************************************
3579 * CoImpersonateClient [OLE32.@]
3581 * Impersonates the client of the currently executing server call in the
3582 * current thread.
3584 * PARAMS
3585 * None.
3587 * RETURNS
3588 * Success: S_OK.
3589 * Failure: HRESULT code.
3591 * NOTES
3592 * If this function fails then the current thread will not be impersonating
3593 * the client and all actions will take place on behalf of the server.
3594 * Therefore, it is important to check the return value from this function.
3596 * SEE ALSO
3597 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3599 HRESULT WINAPI CoImpersonateClient(void)
3601 IServerSecurity *pSrvSec;
3602 HRESULT hr;
3604 TRACE("\n");
3606 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3607 if (SUCCEEDED(hr))
3609 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3610 IServerSecurity_Release(pSrvSec);
3613 return hr;
3616 /***********************************************************************
3617 * CoRevertToSelf [OLE32.@]
3619 * Ends the impersonation of the client of the currently executing server
3620 * call in the current thread.
3622 * PARAMS
3623 * None.
3625 * RETURNS
3626 * Success: S_OK.
3627 * Failure: HRESULT code.
3629 * SEE ALSO
3630 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3632 HRESULT WINAPI CoRevertToSelf(void)
3634 IServerSecurity *pSrvSec;
3635 HRESULT hr;
3637 TRACE("\n");
3639 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3640 if (SUCCEEDED(hr))
3642 hr = IServerSecurity_RevertToSelf(pSrvSec);
3643 IServerSecurity_Release(pSrvSec);
3646 return hr;
3649 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3651 /* first try to retrieve messages for incoming COM calls to the apartment window */
3652 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3653 /* next retrieve other messages necessary for the app to remain responsive */
3654 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3655 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3658 /***********************************************************************
3659 * CoWaitForMultipleHandles [OLE32.@]
3661 * Waits for one or more handles to become signaled.
3663 * PARAMS
3664 * dwFlags [I] Flags. See notes.
3665 * dwTimeout [I] Timeout in milliseconds.
3666 * cHandles [I] Number of handles pointed to by pHandles.
3667 * pHandles [I] Handles to wait for.
3668 * lpdwindex [O] Index of handle that was signaled.
3670 * RETURNS
3671 * Success: S_OK.
3672 * Failure: RPC_S_CALLPENDING on timeout.
3674 * NOTES
3676 * The dwFlags parameter can be zero or more of the following:
3677 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3678 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3680 * SEE ALSO
3681 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3683 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3684 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3686 HRESULT hr = S_OK;
3687 DWORD start_time = GetTickCount();
3688 APARTMENT *apt = COM_CurrentApt();
3689 BOOL message_loop = apt && !apt->multi_threaded;
3691 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3692 pHandles, lpdwindex);
3694 while (TRUE)
3696 DWORD now = GetTickCount();
3697 DWORD res;
3699 if (now - start_time > dwTimeout)
3701 hr = RPC_S_CALLPENDING;
3702 break;
3705 if (message_loop)
3707 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3708 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3710 TRACE("waiting for rpc completion or window message\n");
3712 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3713 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3714 QS_ALLINPUT, wait_flags);
3716 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3718 MSG msg;
3720 /* call message filter */
3722 if (COM_CurrentApt()->filter)
3724 PENDINGTYPE pendingtype =
3725 COM_CurrentInfo()->pending_call_count_server ?
3726 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3727 DWORD be_handled = IMessageFilter_MessagePending(
3728 COM_CurrentApt()->filter, 0 /* FIXME */,
3729 now - start_time, pendingtype);
3730 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3731 switch (be_handled)
3733 case PENDINGMSG_CANCELCALL:
3734 WARN("call canceled\n");
3735 hr = RPC_E_CALL_CANCELED;
3736 break;
3737 case PENDINGMSG_WAITNOPROCESS:
3738 case PENDINGMSG_WAITDEFPROCESS:
3739 default:
3740 /* FIXME: MSDN is very vague about the difference
3741 * between WAITNOPROCESS and WAITDEFPROCESS - there
3742 * appears to be none, so it is possibly a left-over
3743 * from the 16-bit world. */
3744 break;
3748 /* note: using "if" here instead of "while" might seem less
3749 * efficient, but only if we are optimising for quick delivery
3750 * of pending messages, rather than quick completion of the
3751 * COM call */
3752 if (COM_PeekMessage(apt, &msg))
3754 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3755 TranslateMessage(&msg);
3756 DispatchMessageW(&msg);
3757 if (msg.message == WM_QUIT)
3759 TRACE("resending WM_QUIT to outer message loop\n");
3760 PostQuitMessage(msg.wParam);
3761 /* no longer need to process messages */
3762 message_loop = FALSE;
3765 continue;
3768 else
3770 TRACE("waiting for rpc completion\n");
3772 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3773 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3774 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3775 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3778 switch (res)
3780 case WAIT_TIMEOUT:
3781 hr = RPC_S_CALLPENDING;
3782 break;
3783 case WAIT_FAILED:
3784 hr = HRESULT_FROM_WIN32( GetLastError() );
3785 break;
3786 default:
3787 *lpdwindex = res;
3788 break;
3790 break;
3792 TRACE("-- 0x%08x\n", hr);
3793 return hr;
3797 /***********************************************************************
3798 * CoGetObject [OLE32.@]
3800 * Gets the object named by converting the name to a moniker and binding to it.
3802 * PARAMS
3803 * pszName [I] String representing the object.
3804 * pBindOptions [I] Parameters affecting the binding to the named object.
3805 * riid [I] Interface to bind to on the objecct.
3806 * ppv [O] On output, the interface riid of the object represented
3807 * by pszName.
3809 * RETURNS
3810 * Success: S_OK.
3811 * Failure: HRESULT code.
3813 * SEE ALSO
3814 * MkParseDisplayName.
3816 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3817 REFIID riid, void **ppv)
3819 IBindCtx *pbc;
3820 HRESULT hr;
3822 *ppv = NULL;
3824 hr = CreateBindCtx(0, &pbc);
3825 if (SUCCEEDED(hr))
3827 if (pBindOptions)
3828 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3830 if (SUCCEEDED(hr))
3832 ULONG chEaten;
3833 IMoniker *pmk;
3835 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3836 if (SUCCEEDED(hr))
3838 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3839 IMoniker_Release(pmk);
3843 IBindCtx_Release(pbc);
3845 return hr;
3848 /***********************************************************************
3849 * CoRegisterChannelHook [OLE32.@]
3851 * Registers a process-wide hook that is called during ORPC calls.
3853 * PARAMS
3854 * guidExtension [I] GUID of the channel hook to register.
3855 * pChannelHook [I] Channel hook object to register.
3857 * RETURNS
3858 * Success: S_OK.
3859 * Failure: HRESULT code.
3861 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3863 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3865 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3868 typedef struct Context
3870 IComThreadingInfo IComThreadingInfo_iface;
3871 IContextCallback IContextCallback_iface;
3872 IObjContext IObjContext_iface;
3873 LONG refs;
3874 APTTYPE apttype;
3875 } Context;
3877 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3879 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
3882 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3884 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
3887 static inline Context *impl_from_IObjContext( IObjContext *iface )
3889 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
3892 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3894 *ppv = NULL;
3896 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3897 IsEqualIID(riid, &IID_IUnknown))
3899 *ppv = &iface->IComThreadingInfo_iface;
3901 else if (IsEqualIID(riid, &IID_IContextCallback))
3903 *ppv = &iface->IContextCallback_iface;
3905 else if (IsEqualIID(riid, &IID_IObjContext))
3907 *ppv = &iface->IObjContext_iface;
3910 if (*ppv)
3912 IUnknown_AddRef((IUnknown*)*ppv);
3913 return S_OK;
3916 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3917 return E_NOINTERFACE;
3920 static ULONG Context_AddRef(Context *This)
3922 return InterlockedIncrement(&This->refs);
3925 static ULONG Context_Release(Context *This)
3927 ULONG refs = InterlockedDecrement(&This->refs);
3928 if (!refs)
3929 HeapFree(GetProcessHeap(), 0, This);
3930 return refs;
3933 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3935 Context *This = impl_from_IComThreadingInfo(iface);
3936 return Context_QueryInterface(This, riid, ppv);
3939 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3941 Context *This = impl_from_IComThreadingInfo(iface);
3942 return Context_AddRef(This);
3945 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3947 Context *This = impl_from_IComThreadingInfo(iface);
3948 return Context_Release(This);
3951 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3953 Context *This = impl_from_IComThreadingInfo(iface);
3955 TRACE("(%p)\n", apttype);
3957 *apttype = This->apttype;
3958 return S_OK;
3961 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3963 Context *This = impl_from_IComThreadingInfo(iface);
3965 TRACE("(%p)\n", thdtype);
3967 switch (This->apttype)
3969 case APTTYPE_STA:
3970 case APTTYPE_MAINSTA:
3971 *thdtype = THDTYPE_PROCESSMESSAGES;
3972 break;
3973 default:
3974 *thdtype = THDTYPE_BLOCKMESSAGES;
3975 break;
3977 return S_OK;
3980 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3982 FIXME("(%p): stub\n", logical_thread_id);
3983 return E_NOTIMPL;
3986 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3988 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3989 return E_NOTIMPL;
3992 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3994 Context_CTI_QueryInterface,
3995 Context_CTI_AddRef,
3996 Context_CTI_Release,
3997 Context_CTI_GetCurrentApartmentType,
3998 Context_CTI_GetCurrentThreadType,
3999 Context_CTI_GetCurrentLogicalThreadId,
4000 Context_CTI_SetCurrentLogicalThreadId
4003 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4005 Context *This = impl_from_IContextCallback(iface);
4006 return Context_QueryInterface(This, riid, ppv);
4009 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4011 Context *This = impl_from_IContextCallback(iface);
4012 return Context_AddRef(This);
4015 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4017 Context *This = impl_from_IContextCallback(iface);
4018 return Context_Release(This);
4021 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4022 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4024 Context *This = impl_from_IContextCallback(iface);
4026 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4027 return E_NOTIMPL;
4030 static const IContextCallbackVtbl Context_Callback_Vtbl =
4032 Context_CC_QueryInterface,
4033 Context_CC_AddRef,
4034 Context_CC_Release,
4035 Context_CC_ContextCallback
4038 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4040 Context *This = impl_from_IObjContext(iface);
4041 return Context_QueryInterface(This, riid, ppv);
4044 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4046 Context *This = impl_from_IObjContext(iface);
4047 return Context_AddRef(This);
4050 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4052 Context *This = impl_from_IObjContext(iface);
4053 return Context_Release(This);
4056 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4058 Context *This = impl_from_IObjContext(iface);
4060 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4061 return E_NOTIMPL;
4064 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4066 Context *This = impl_from_IObjContext(iface);
4068 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4069 return E_NOTIMPL;
4072 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4074 Context *This = impl_from_IObjContext(iface);
4076 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4077 return E_NOTIMPL;
4080 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4082 Context *This = impl_from_IObjContext(iface);
4084 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4085 return E_NOTIMPL;
4088 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4090 Context *This = impl_from_IObjContext(iface);
4091 FIXME("(%p/%p)\n", This, iface);
4094 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4096 Context *This = impl_from_IObjContext(iface);
4097 FIXME("(%p/%p)\n", This, iface);
4100 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4102 Context *This = impl_from_IObjContext(iface);
4103 FIXME("(%p/%p)\n", This, iface);
4106 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4108 Context *This = impl_from_IObjContext(iface);
4109 FIXME("(%p/%p)\n", This, iface);
4112 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4114 Context *This = impl_from_IObjContext(iface);
4115 FIXME("(%p/%p)\n", This, iface);
4118 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4120 Context *This = impl_from_IObjContext(iface);
4121 FIXME("(%p/%p)\n", This, iface);
4124 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4126 Context *This = impl_from_IObjContext(iface);
4127 FIXME("(%p/%p)\n", This, iface);
4130 static const IObjContextVtbl Context_Object_Vtbl =
4132 Context_OC_QueryInterface,
4133 Context_OC_AddRef,
4134 Context_OC_Release,
4135 Context_OC_SetProperty,
4136 Context_OC_RemoveProperty,
4137 Context_OC_GetProperty,
4138 Context_OC_EnumContextProps,
4139 Context_OC_Reserved1,
4140 Context_OC_Reserved2,
4141 Context_OC_Reserved3,
4142 Context_OC_Reserved4,
4143 Context_OC_Reserved5,
4144 Context_OC_Reserved6,
4145 Context_OC_Reserved7
4148 /***********************************************************************
4149 * CoGetObjectContext [OLE32.@]
4151 * Retrieves an object associated with the current context (i.e. apartment).
4153 * PARAMS
4154 * riid [I] ID of the interface of the object to retrieve.
4155 * ppv [O] Address where object will be stored on return.
4157 * RETURNS
4158 * Success: S_OK.
4159 * Failure: HRESULT code.
4161 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4163 APARTMENT *apt = COM_CurrentApt();
4164 Context *context;
4165 HRESULT hr;
4167 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4169 *ppv = NULL;
4170 if (!apt)
4172 if (!(apt = apartment_find_multi_threaded()))
4174 ERR("apartment not initialised\n");
4175 return CO_E_NOTINITIALIZED;
4177 apartment_release(apt);
4180 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4181 if (!context)
4182 return E_OUTOFMEMORY;
4184 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4185 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4186 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4187 context->refs = 1;
4188 if (apt->multi_threaded)
4189 context->apttype = APTTYPE_MTA;
4190 else if (apt->main)
4191 context->apttype = APTTYPE_MAINSTA;
4192 else
4193 context->apttype = APTTYPE_STA;
4195 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4196 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4198 return hr;
4202 /***********************************************************************
4203 * CoGetContextToken [OLE32.@]
4205 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4207 struct oletls *info = COM_CurrentInfo();
4209 TRACE("(%p)\n", token);
4211 if (!info)
4212 return E_OUTOFMEMORY;
4214 if (!info->apt)
4216 APARTMENT *apt;
4217 if (!(apt = apartment_find_multi_threaded()))
4219 ERR("apartment not initialised\n");
4220 return CO_E_NOTINITIALIZED;
4222 apartment_release(apt);
4225 if (!token)
4226 return E_POINTER;
4228 if (!info->context_token)
4230 HRESULT hr;
4231 IObjContext *ctx;
4233 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4234 if (FAILED(hr)) return hr;
4235 info->context_token = ctx;
4238 *token = (ULONG_PTR)info->context_token;
4239 TRACE("apt->context_token=%p\n", info->context_token);
4241 return S_OK;
4244 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4246 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4247 HKEY hkey;
4248 HRESULT hres;
4250 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4251 if (SUCCEEDED(hres))
4253 WCHAR dllpath[MAX_PATH+1];
4255 if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4257 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4258 if (!strcmpiW(dllpath, wszOle32))
4260 RegCloseKey(hkey);
4261 return HandlerCF_Create(rclsid, riid, ppv);
4264 else
4265 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4266 RegCloseKey(hkey);
4269 return CLASS_E_CLASSNOTAVAILABLE;
4272 /***********************************************************************
4273 * DllMain (OLE32.@)
4275 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4277 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4279 switch(fdwReason) {
4280 case DLL_PROCESS_ATTACH:
4281 hProxyDll = hinstDLL;
4282 COMPOBJ_InitProcess();
4283 break;
4285 case DLL_PROCESS_DETACH:
4286 COMPOBJ_UninitProcess();
4287 RPC_UnregisterAllChannelHooks();
4288 COMPOBJ_DllList_Free();
4289 break;
4291 case DLL_THREAD_DETACH:
4292 COM_TlsDestroy();
4293 break;
4295 return TRUE;
4298 /***********************************************************************
4299 * DllRegisterServer (OLE32.@)
4301 HRESULT WINAPI DllRegisterServer(void)
4303 return OLE32_DllRegisterServer();
4306 /***********************************************************************
4307 * DllUnregisterServer (OLE32.@)
4309 HRESULT WINAPI DllUnregisterServer(void)
4311 return OLE32_DllUnregisterServer();