ole32: Convert the remaining RegCreateKey and RegOpenKey calls to the wrappers.
[wine.git] / dlls / ole32 / compobj.c
blobaf5b0fe1e9a753d45f3a99227f95312c7d6f8529
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 "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winuser.h"
57 #define USE_COM_CONTEXT_DEF
58 #include "objbase.h"
59 #include "ole2.h"
60 #include "ole2ver.h"
61 #include "ctxtcall.h"
62 #include "dde.h"
64 #include "initguid.h"
65 #include "compobj_private.h"
66 #include "moniker.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
94 struct list entry;
95 IID iid;
96 CLSID clsid;
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
118 struct list entry;
119 CLSID classIdentifier;
120 OXID apartment_id;
121 LPUNKNOWN classObject;
122 DWORD runContext;
123 DWORD connectFlags;
124 DWORD dwCookie;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
127 } RegisteredClass;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /* wrapper for NtCreateKey that creates the key recursively if necessary */
141 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
143 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
145 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
147 HANDLE subkey, root = attr->RootDirectory;
148 WCHAR *buffer = attr->ObjectName->Buffer;
149 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
150 UNICODE_STRING str;
152 while (i < len && buffer[i] != '\\') i++;
153 if (i == len) return status;
155 attrs = attr->Attributes;
156 attr->ObjectName = &str;
158 while (i < len)
160 str.Buffer = buffer + pos;
161 str.Length = (i - pos) * sizeof(WCHAR);
162 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
163 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
164 if (status) return status;
165 attr->RootDirectory = subkey;
166 while (i < len && buffer[i] == '\\') i++;
167 pos = i;
168 while (i < len && buffer[i] != '\\') i++;
170 str.Buffer = buffer + pos;
171 str.Length = (i - pos) * sizeof(WCHAR);
172 attr->Attributes = attrs;
173 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
174 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
176 return status;
179 static const WCHAR classes_rootW[] =
180 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
182 static HKEY classes_root_hkey;
184 /* create the special HKEY_CLASSES_ROOT key */
185 static HKEY create_classes_root_hkey(void)
187 HKEY hkey, ret = 0;
188 OBJECT_ATTRIBUTES attr;
189 UNICODE_STRING name;
191 attr.Length = sizeof(attr);
192 attr.RootDirectory = 0;
193 attr.ObjectName = &name;
194 attr.Attributes = 0;
195 attr.SecurityDescriptor = NULL;
196 attr.SecurityQualityOfService = NULL;
197 RtlInitUnicodeString( &name, classes_rootW );
198 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
199 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
201 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
202 ret = hkey;
203 else
204 NtClose( hkey ); /* somebody beat us to it */
205 return ret;
208 /* map the hkey from special root to normal key if necessary */
209 static inline HKEY get_classes_root_hkey( HKEY hkey )
211 HKEY ret = hkey;
213 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
214 ret = create_classes_root_hkey();
216 return ret;
219 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
221 OBJECT_ATTRIBUTES attr;
222 UNICODE_STRING nameW;
224 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
226 attr.Length = sizeof(attr);
227 attr.RootDirectory = hkey;
228 attr.ObjectName = &nameW;
229 attr.Attributes = 0;
230 attr.SecurityDescriptor = NULL;
231 attr.SecurityQualityOfService = NULL;
232 RtlInitUnicodeString( &nameW, name );
234 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
237 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
239 OBJECT_ATTRIBUTES attr;
240 UNICODE_STRING nameW;
242 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
244 attr.Length = sizeof(attr);
245 attr.RootDirectory = hkey;
246 attr.ObjectName = &nameW;
247 attr.Attributes = 0;
248 attr.SecurityDescriptor = NULL;
249 attr.SecurityQualityOfService = NULL;
250 RtlInitUnicodeString( &nameW, name );
252 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
255 /*****************************************************************************
256 * This section contains OpenDllList definitions
258 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
259 * other functions that do LoadLibrary _without_ giving back a HMODULE.
260 * Without this list these handles would never be freed.
262 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
263 * next unload-call but not before 600 sec.
266 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
267 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
269 typedef struct tagOpenDll
271 LONG refs;
272 LPWSTR library_name;
273 HANDLE library;
274 DllGetClassObjectFunc DllGetClassObject;
275 DllCanUnloadNowFunc DllCanUnloadNow;
276 struct list entry;
277 } OpenDll;
279 static struct list openDllList = LIST_INIT(openDllList);
281 static CRITICAL_SECTION csOpenDllList;
282 static CRITICAL_SECTION_DEBUG dll_cs_debug =
284 0, 0, &csOpenDllList,
285 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
286 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
288 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
290 struct apartment_loaded_dll
292 struct list entry;
293 OpenDll *dll;
294 DWORD unload_time;
295 BOOL multi_threaded;
298 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
299 '0','x','#','#','#','#','#','#','#','#',' ',0};
301 /*****************************************************************************
302 * This section contains OpenDllList implementation
305 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
307 OpenDll *ptr;
308 OpenDll *ret = NULL;
309 EnterCriticalSection(&csOpenDllList);
310 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
312 if (!strcmpiW(library_name, ptr->library_name) &&
313 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
315 ret = ptr;
316 break;
319 LeaveCriticalSection(&csOpenDllList);
320 return ret;
323 /* caller must ensure that library_name is not already in the open dll list */
324 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
326 OpenDll *entry;
327 int len;
328 HRESULT hr = S_OK;
329 HANDLE hLibrary;
330 DllCanUnloadNowFunc DllCanUnloadNow;
331 DllGetClassObjectFunc DllGetClassObject;
333 TRACE("\n");
335 *ret = COMPOBJ_DllList_Get(library_name);
336 if (*ret) return S_OK;
338 /* do this outside the csOpenDllList to avoid creating a lock dependency on
339 * the loader lock */
340 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
341 if (!hLibrary)
343 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
344 /* failure: DLL could not be loaded */
345 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
348 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
349 /* Note: failing to find DllCanUnloadNow is not a failure */
350 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
351 if (!DllGetClassObject)
353 /* failure: the dll did not export DllGetClassObject */
354 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
355 FreeLibrary(hLibrary);
356 return CO_E_DLLNOTFOUND;
359 EnterCriticalSection( &csOpenDllList );
361 *ret = COMPOBJ_DllList_Get(library_name);
362 if (*ret)
364 /* another caller to this function already added the dll while we
365 * weren't in the critical section */
366 FreeLibrary(hLibrary);
368 else
370 len = strlenW(library_name);
371 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
372 if (entry)
373 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
374 if (entry && entry->library_name)
376 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
377 entry->library = hLibrary;
378 entry->refs = 1;
379 entry->DllCanUnloadNow = DllCanUnloadNow;
380 entry->DllGetClassObject = DllGetClassObject;
381 list_add_tail(&openDllList, &entry->entry);
383 else
385 HeapFree(GetProcessHeap(), 0, entry);
386 hr = E_OUTOFMEMORY;
387 FreeLibrary(hLibrary);
389 *ret = entry;
392 LeaveCriticalSection( &csOpenDllList );
394 return hr;
397 /* pass FALSE for free_entry to release a reference without destroying the
398 * entry if it reaches zero or TRUE otherwise */
399 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
401 if (!InterlockedDecrement(&entry->refs) && free_entry)
403 EnterCriticalSection(&csOpenDllList);
404 list_remove(&entry->entry);
405 LeaveCriticalSection(&csOpenDllList);
407 TRACE("freeing %p\n", entry->library);
408 FreeLibrary(entry->library);
410 HeapFree(GetProcessHeap(), 0, entry->library_name);
411 HeapFree(GetProcessHeap(), 0, entry);
415 /* frees memory associated with active dll list */
416 static void COMPOBJ_DllList_Free(void)
418 OpenDll *entry, *cursor2;
419 EnterCriticalSection(&csOpenDllList);
420 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
422 list_remove(&entry->entry);
424 HeapFree(GetProcessHeap(), 0, entry->library_name);
425 HeapFree(GetProcessHeap(), 0, entry);
427 LeaveCriticalSection(&csOpenDllList);
428 DeleteCriticalSection(&csOpenDllList);
431 /******************************************************************************
432 * Manage apartments.
435 static DWORD apartment_addref(struct apartment *apt)
437 DWORD refs = InterlockedIncrement(&apt->refs);
438 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
439 return refs;
442 /* allocates memory and fills in the necessary fields for a new apartment
443 * object. must be called inside apartment cs */
444 static APARTMENT *apartment_construct(DWORD model)
446 APARTMENT *apt;
448 TRACE("creating new apartment, model=%d\n", model);
450 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
451 apt->tid = GetCurrentThreadId();
453 list_init(&apt->proxies);
454 list_init(&apt->stubmgrs);
455 list_init(&apt->psclsids);
456 list_init(&apt->loaded_dlls);
457 apt->ipidc = 0;
458 apt->refs = 1;
459 apt->remunk_exported = FALSE;
460 apt->oidc = 1;
461 InitializeCriticalSection(&apt->cs);
462 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
464 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
466 if (apt->multi_threaded)
468 /* FIXME: should be randomly generated by in an RPC call to rpcss */
469 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
471 else
473 /* FIXME: should be randomly generated by in an RPC call to rpcss */
474 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
477 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
479 list_add_head(&apts, &apt->entry);
481 return apt;
484 /* gets and existing apartment if one exists or otherwise creates an apartment
485 * structure which stores OLE apartment-local information and stores a pointer
486 * to it in the thread-local storage */
487 static APARTMENT *apartment_get_or_create(DWORD model)
489 APARTMENT *apt = COM_CurrentApt();
491 if (!apt)
493 if (model & COINIT_APARTMENTTHREADED)
495 EnterCriticalSection(&csApartment);
497 apt = apartment_construct(model);
498 if (!MainApartment)
500 MainApartment = apt;
501 apt->main = TRUE;
502 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
505 LeaveCriticalSection(&csApartment);
507 if (apt->main)
508 apartment_createwindowifneeded(apt);
510 else
512 EnterCriticalSection(&csApartment);
514 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
515 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
516 * in a process */
517 if (MTA)
519 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
520 apartment_addref(MTA);
522 else
523 MTA = apartment_construct(model);
525 apt = MTA;
527 LeaveCriticalSection(&csApartment);
529 COM_CurrentInfo()->apt = apt;
532 return apt;
535 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
537 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
540 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
542 list_remove(&curClass->entry);
544 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
545 RPC_StopLocalServer(curClass->RpcRegistration);
548 * Release the reference to the class object.
550 IUnknown_Release(curClass->classObject);
552 if (curClass->pMarshaledData)
554 LARGE_INTEGER zero;
555 memset(&zero, 0, sizeof(zero));
556 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
557 CoReleaseMarshalData(curClass->pMarshaledData);
558 IStream_Release(curClass->pMarshaledData);
561 HeapFree(GetProcessHeap(), 0, curClass);
564 static void COM_RevokeAllClasses(const struct apartment *apt)
566 RegisteredClass *curClass, *cursor;
568 EnterCriticalSection( &csRegisteredClassList );
570 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
572 if (curClass->apartment_id == apt->oxid)
573 COM_RevokeRegisteredClassObject(curClass);
576 LeaveCriticalSection( &csRegisteredClassList );
579 /******************************************************************************
580 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
583 typedef struct ManualResetEvent {
584 ISynchronize ISynchronize_iface;
585 ISynchronizeHandle ISynchronizeHandle_iface;
586 LONG ref;
587 HANDLE event;
588 } MREImpl;
590 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
592 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
595 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
597 MREImpl *This = impl_from_ISynchronize(iface);
599 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
601 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
602 *ppv = &This->ISynchronize_iface;
603 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
604 *ppv = &This->ISynchronizeHandle_iface;
605 }else {
606 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
607 *ppv = NULL;
608 return E_NOINTERFACE;
611 IUnknown_AddRef((IUnknown*)*ppv);
612 return S_OK;
615 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
617 MREImpl *This = impl_from_ISynchronize(iface);
618 LONG ref = InterlockedIncrement(&This->ref);
619 TRACE("%p - ref %d\n", This, ref);
621 return ref;
624 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
626 MREImpl *This = impl_from_ISynchronize(iface);
627 LONG ref = InterlockedDecrement(&This->ref);
628 TRACE("%p - ref %d\n", This, ref);
630 if(!ref)
632 CloseHandle(This->event);
633 HeapFree(GetProcessHeap(), 0, This);
636 return ref;
639 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
641 MREImpl *This = impl_from_ISynchronize(iface);
642 UINT index;
643 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
644 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
647 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
649 MREImpl *This = impl_from_ISynchronize(iface);
650 TRACE("%p\n", This);
651 SetEvent(This->event);
652 return S_OK;
655 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
657 MREImpl *This = impl_from_ISynchronize(iface);
658 TRACE("%p\n", This);
659 ResetEvent(This->event);
660 return S_OK;
663 static ISynchronizeVtbl vt_ISynchronize = {
664 ISynchronize_fnQueryInterface,
665 ISynchronize_fnAddRef,
666 ISynchronize_fnRelease,
667 ISynchronize_fnWait,
668 ISynchronize_fnSignal,
669 ISynchronize_fnReset
672 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
674 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
677 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
679 MREImpl *This = impl_from_ISynchronizeHandle(iface);
680 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
683 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
685 MREImpl *This = impl_from_ISynchronizeHandle(iface);
686 return ISynchronize_AddRef(&This->ISynchronize_iface);
689 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
691 MREImpl *This = impl_from_ISynchronizeHandle(iface);
692 return ISynchronize_Release(&This->ISynchronize_iface);
695 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
697 MREImpl *This = impl_from_ISynchronizeHandle(iface);
699 *ph = This->event;
700 return S_OK;
703 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
704 SynchronizeHandle_QueryInterface,
705 SynchronizeHandle_AddRef,
706 SynchronizeHandle_Release,
707 SynchronizeHandle_GetHandle
710 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
712 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
713 HRESULT hr;
715 if(punkouter)
716 FIXME("Aggregation not implemented.\n");
718 This->ref = 1;
719 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
720 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
721 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
723 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
724 ISynchronize_Release(&This->ISynchronize_iface);
725 return hr;
728 /***********************************************************************
729 * CoRevokeClassObject [OLE32.@]
731 * Removes a class object from the class registry.
733 * PARAMS
734 * dwRegister [I] Cookie returned from CoRegisterClassObject().
736 * RETURNS
737 * Success: S_OK.
738 * Failure: HRESULT code.
740 * NOTES
741 * Must be called from the same apartment that called CoRegisterClassObject(),
742 * otherwise it will fail with RPC_E_WRONG_THREAD.
744 * SEE ALSO
745 * CoRegisterClassObject
747 HRESULT WINAPI CoRevokeClassObject(
748 DWORD dwRegister)
750 HRESULT hr = E_INVALIDARG;
751 RegisteredClass *curClass;
752 APARTMENT *apt;
754 TRACE("(%08x)\n",dwRegister);
756 apt = COM_CurrentApt();
757 if (!apt)
759 ERR("COM was not initialized\n");
760 return CO_E_NOTINITIALIZED;
763 EnterCriticalSection( &csRegisteredClassList );
765 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
768 * Check if we have a match on the cookie.
770 if (curClass->dwCookie == dwRegister)
772 if (curClass->apartment_id == apt->oxid)
774 COM_RevokeRegisteredClassObject(curClass);
775 hr = S_OK;
777 else
779 ERR("called from wrong apartment, should be called from %s\n",
780 wine_dbgstr_longlong(curClass->apartment_id));
781 hr = RPC_E_WRONG_THREAD;
783 break;
787 LeaveCriticalSection( &csRegisteredClassList );
789 return hr;
792 /* frees unused libraries loaded by apartment_getclassobject by calling the
793 * DLL's DllCanUnloadNow entry point */
794 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
796 struct apartment_loaded_dll *entry, *next;
797 EnterCriticalSection(&apt->cs);
798 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
800 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
802 DWORD real_delay = delay;
804 if (real_delay == INFINITE)
806 /* DLLs that return multi-threaded objects aren't unloaded
807 * straight away to cope for programs that have races between
808 * last object destruction and threads in the DLLs that haven't
809 * finished, despite DllCanUnloadNow returning S_OK */
810 if (entry->multi_threaded)
811 real_delay = 10 * 60 * 1000; /* 10 minutes */
812 else
813 real_delay = 0;
816 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
818 list_remove(&entry->entry);
819 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
820 HeapFree(GetProcessHeap(), 0, entry);
822 else
823 entry->unload_time = GetTickCount() + real_delay;
825 else if (entry->unload_time)
826 entry->unload_time = 0;
828 LeaveCriticalSection(&apt->cs);
831 DWORD apartment_release(struct apartment *apt)
833 DWORD ret;
835 EnterCriticalSection(&csApartment);
837 ret = InterlockedDecrement(&apt->refs);
838 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
839 /* destruction stuff that needs to happen under csApartment CS */
840 if (ret == 0)
842 if (apt == MTA) MTA = NULL;
843 else if (apt == MainApartment) MainApartment = NULL;
844 list_remove(&apt->entry);
847 LeaveCriticalSection(&csApartment);
849 if (ret == 0)
851 struct list *cursor, *cursor2;
853 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
855 /* Release the references to the registered class objects */
856 COM_RevokeAllClasses(apt);
858 /* no locking is needed for this apartment, because no other thread
859 * can access it at this point */
861 apartment_disconnectproxies(apt);
863 if (apt->win) DestroyWindow(apt->win);
864 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
866 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
868 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
869 /* release the implicit reference given by the fact that the
870 * stub has external references (it must do since it is in the
871 * stub manager list in the apartment and all non-apartment users
872 * must have a ref on the apartment and so it cannot be destroyed).
874 stub_manager_int_release(stubmgr);
877 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
879 struct registered_psclsid *registered_psclsid =
880 LIST_ENTRY(cursor, struct registered_psclsid, entry);
882 list_remove(&registered_psclsid->entry);
883 HeapFree(GetProcessHeap(), 0, registered_psclsid);
886 /* if this assert fires, then another thread took a reference to a
887 * stub manager without taking a reference to the containing
888 * apartment, which it must do. */
889 assert(list_empty(&apt->stubmgrs));
891 if (apt->filter) IMessageFilter_Release(apt->filter);
893 /* free as many unused libraries as possible... */
894 apartment_freeunusedlibraries(apt, 0);
896 /* ... and free the memory for the apartment loaded dll entry and
897 * release the dll list reference without freeing the library for the
898 * rest */
899 while ((cursor = list_head(&apt->loaded_dlls)))
901 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
902 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
903 list_remove(cursor);
904 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
907 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
908 DeleteCriticalSection(&apt->cs);
910 HeapFree(GetProcessHeap(), 0, apt);
913 return ret;
916 /* The given OXID must be local to this process:
918 * The ref parameter is here mostly to ensure people remember that
919 * they get one, you should normally take a ref for thread safety.
921 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
923 APARTMENT *result = NULL;
924 struct list *cursor;
926 EnterCriticalSection(&csApartment);
927 LIST_FOR_EACH( cursor, &apts )
929 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
930 if (apt->oxid == oxid)
932 result = apt;
933 if (ref) apartment_addref(result);
934 break;
937 LeaveCriticalSection(&csApartment);
939 return result;
942 /* gets the apartment which has a given creator thread ID. The caller must
943 * release the reference from the apartment as soon as the apartment pointer
944 * is no longer required. */
945 APARTMENT *apartment_findfromtid(DWORD tid)
947 APARTMENT *result = NULL;
948 struct list *cursor;
950 EnterCriticalSection(&csApartment);
951 LIST_FOR_EACH( cursor, &apts )
953 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
954 if (apt->tid == tid)
956 result = apt;
957 apartment_addref(result);
958 break;
961 LeaveCriticalSection(&csApartment);
963 return result;
966 /* gets the main apartment if it exists. The caller must
967 * release the reference from the apartment as soon as the apartment pointer
968 * is no longer required. */
969 static APARTMENT *apartment_findmain(void)
971 APARTMENT *result;
973 EnterCriticalSection(&csApartment);
975 result = MainApartment;
976 if (result) apartment_addref(result);
978 LeaveCriticalSection(&csApartment);
980 return result;
983 /* gets the multi-threaded apartment if it exists. The caller must
984 * release the reference from the apartment as soon as the apartment pointer
985 * is no longer required. */
986 static APARTMENT *apartment_find_multi_threaded(void)
988 APARTMENT *result = NULL;
989 struct list *cursor;
991 EnterCriticalSection(&csApartment);
993 LIST_FOR_EACH( cursor, &apts )
995 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
996 if (apt->multi_threaded)
998 result = apt;
999 apartment_addref(result);
1000 break;
1004 LeaveCriticalSection(&csApartment);
1005 return result;
1008 /* gets the specified class object by loading the appropriate DLL, if
1009 * necessary and calls the DllGetClassObject function for the DLL */
1010 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1011 BOOL apartment_threaded,
1012 REFCLSID rclsid, REFIID riid, void **ppv)
1014 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1015 HRESULT hr = S_OK;
1016 BOOL found = FALSE;
1017 struct apartment_loaded_dll *apartment_loaded_dll;
1019 if (!strcmpiW(dllpath, wszOle32))
1021 /* we don't need to control the lifetime of this dll, so use the local
1022 * implementation of DllGetClassObject directly */
1023 TRACE("calling ole32!DllGetClassObject\n");
1024 hr = DllGetClassObject(rclsid, riid, ppv);
1026 if (hr != S_OK)
1027 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1029 return hr;
1032 EnterCriticalSection(&apt->cs);
1034 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1035 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1037 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1038 found = TRUE;
1039 break;
1042 if (!found)
1044 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1045 if (!apartment_loaded_dll)
1046 hr = E_OUTOFMEMORY;
1047 if (SUCCEEDED(hr))
1049 apartment_loaded_dll->unload_time = 0;
1050 apartment_loaded_dll->multi_threaded = FALSE;
1051 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1052 if (FAILED(hr))
1053 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1055 if (SUCCEEDED(hr))
1057 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1058 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1062 LeaveCriticalSection(&apt->cs);
1064 if (SUCCEEDED(hr))
1066 /* one component being multi-threaded overrides any number of
1067 * apartment-threaded components */
1068 if (!apartment_threaded)
1069 apartment_loaded_dll->multi_threaded = TRUE;
1071 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1072 /* OK: get the ClassObject */
1073 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1075 if (hr != S_OK)
1076 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1079 return hr;
1082 /***********************************************************************
1083 * COM_RegReadPath [internal]
1085 * Reads a registry value and expands it when necessary
1087 static DWORD COM_RegReadPath(HKEY hkeyroot, WCHAR * dst, DWORD dstlen)
1089 DWORD ret;
1090 DWORD keytype;
1091 WCHAR src[MAX_PATH];
1092 DWORD dwLength = dstlen * sizeof(WCHAR);
1094 if( (ret = RegQueryValueExW(hkeyroot, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1095 if (keytype == REG_EXPAND_SZ) {
1096 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1097 } else {
1098 const WCHAR *quote_start;
1099 quote_start = strchrW(src, '\"');
1100 if (quote_start) {
1101 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1102 if (quote_end) {
1103 memmove(src, quote_start + 1,
1104 (quote_end - quote_start - 1) * sizeof(WCHAR));
1105 src[quote_end - quote_start - 1] = '\0';
1108 lstrcpynW(dst, src, dstlen);
1111 return ret;
1114 struct host_object_params
1116 HKEY hkeydll;
1117 CLSID clsid; /* clsid of object to marshal */
1118 IID iid; /* interface to marshal */
1119 HANDLE event; /* event signalling when ready for multi-threaded case */
1120 HRESULT hr; /* result for multi-threaded case */
1121 IStream *stream; /* stream that the object will be marshaled into */
1122 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1125 static HRESULT apartment_hostobject(struct apartment *apt,
1126 const struct host_object_params *params)
1128 IUnknown *object;
1129 HRESULT hr;
1130 static const LARGE_INTEGER llZero;
1131 WCHAR dllpath[MAX_PATH+1];
1133 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1135 if (COM_RegReadPath(params->hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1137 /* failure: CLSID is not found in registry */
1138 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1139 return REGDB_E_CLASSNOTREG;
1142 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1143 &params->clsid, &params->iid, (void **)&object);
1144 if (FAILED(hr))
1145 return hr;
1147 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1148 if (FAILED(hr))
1149 IUnknown_Release(object);
1150 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1152 return hr;
1155 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1157 switch (msg)
1159 case DM_EXECUTERPC:
1160 RPC_ExecuteCall((struct dispatch_params *)lParam);
1161 return 0;
1162 case DM_HOSTOBJECT:
1163 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1164 default:
1165 return DefWindowProcW(hWnd, msg, wParam, lParam);
1169 struct host_thread_params
1171 COINIT threading_model;
1172 HANDLE ready_event;
1173 HWND apartment_hwnd;
1176 /* thread for hosting an object to allow an object to appear to be created in
1177 * an apartment with an incompatible threading model */
1178 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1180 struct host_thread_params *params = p;
1181 MSG msg;
1182 HRESULT hr;
1183 struct apartment *apt;
1185 TRACE("\n");
1187 hr = CoInitializeEx(NULL, params->threading_model);
1188 if (FAILED(hr)) return hr;
1190 apt = COM_CurrentApt();
1191 if (params->threading_model == COINIT_APARTMENTTHREADED)
1193 apartment_createwindowifneeded(apt);
1194 params->apartment_hwnd = apartment_getwindow(apt);
1196 else
1197 params->apartment_hwnd = NULL;
1199 /* force the message queue to be created before signaling parent thread */
1200 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1202 SetEvent(params->ready_event);
1203 params = NULL; /* can't touch params after here as it may be invalid */
1205 while (GetMessageW(&msg, NULL, 0, 0))
1207 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1209 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1210 obj_params->hr = apartment_hostobject(apt, obj_params);
1211 SetEvent(obj_params->event);
1213 else
1215 TranslateMessage(&msg);
1216 DispatchMessageW(&msg);
1220 TRACE("exiting\n");
1222 CoUninitialize();
1224 return S_OK;
1227 /* finds or creates a host apartment, creates the object inside it and returns
1228 * a proxy to it so that the object can be used in the apartment of the
1229 * caller of this function */
1230 static HRESULT apartment_hostobject_in_hostapt(
1231 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1232 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1234 struct host_object_params params;
1235 HWND apartment_hwnd = NULL;
1236 DWORD apartment_tid = 0;
1237 HRESULT hr;
1239 if (!multi_threaded && main_apartment)
1241 APARTMENT *host_apt = apartment_findmain();
1242 if (host_apt)
1244 apartment_hwnd = apartment_getwindow(host_apt);
1245 apartment_release(host_apt);
1249 if (!apartment_hwnd)
1251 EnterCriticalSection(&apt->cs);
1253 if (!apt->host_apt_tid)
1255 struct host_thread_params thread_params;
1256 HANDLE handles[2];
1257 DWORD wait_value;
1259 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1260 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1261 thread_params.apartment_hwnd = NULL;
1262 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1263 if (!handles[1])
1265 CloseHandle(handles[0]);
1266 LeaveCriticalSection(&apt->cs);
1267 return E_OUTOFMEMORY;
1269 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1270 CloseHandle(handles[0]);
1271 CloseHandle(handles[1]);
1272 if (wait_value == WAIT_OBJECT_0)
1273 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1274 else
1276 LeaveCriticalSection(&apt->cs);
1277 return E_OUTOFMEMORY;
1281 if (multi_threaded || !main_apartment)
1283 apartment_hwnd = apt->host_apt_hwnd;
1284 apartment_tid = apt->host_apt_tid;
1287 LeaveCriticalSection(&apt->cs);
1290 /* another thread may have become the main apartment in the time it took
1291 * us to create the thread for the host apartment */
1292 if (!apartment_hwnd && !multi_threaded && main_apartment)
1294 APARTMENT *host_apt = apartment_findmain();
1295 if (host_apt)
1297 apartment_hwnd = apartment_getwindow(host_apt);
1298 apartment_release(host_apt);
1302 params.hkeydll = hkeydll;
1303 params.clsid = *rclsid;
1304 params.iid = *riid;
1305 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1306 if (FAILED(hr))
1307 return hr;
1308 params.apartment_threaded = !multi_threaded;
1309 if (multi_threaded)
1311 params.hr = S_OK;
1312 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1313 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1314 hr = E_OUTOFMEMORY;
1315 else
1317 WaitForSingleObject(params.event, INFINITE);
1318 hr = params.hr;
1320 CloseHandle(params.event);
1322 else
1324 if (!apartment_hwnd)
1326 ERR("host apartment didn't create window\n");
1327 hr = E_OUTOFMEMORY;
1329 else
1330 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1332 if (SUCCEEDED(hr))
1333 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1334 IStream_Release(params.stream);
1335 return hr;
1338 /* create a window for the apartment or return the current one if one has
1339 * already been created */
1340 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1342 if (apt->multi_threaded)
1343 return S_OK;
1345 if (!apt->win)
1347 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1348 0, 0, 0, 0,
1349 HWND_MESSAGE, 0, hProxyDll, NULL);
1350 if (!hwnd)
1352 ERR("CreateWindow failed with error %d\n", GetLastError());
1353 return HRESULT_FROM_WIN32(GetLastError());
1355 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1356 /* someone beat us to it */
1357 DestroyWindow(hwnd);
1360 return S_OK;
1363 /* retrieves the window for the main- or apartment-threaded apartment */
1364 HWND apartment_getwindow(const struct apartment *apt)
1366 assert(!apt->multi_threaded);
1367 return apt->win;
1370 void apartment_joinmta(void)
1372 apartment_addref(MTA);
1373 COM_CurrentInfo()->apt = MTA;
1376 static void COMPOBJ_InitProcess( void )
1378 WNDCLASSW wclass;
1380 /* Dispatching to the correct thread in an apartment is done through
1381 * window messages rather than RPC transports. When an interface is
1382 * marshalled into another apartment in the same process, a window of the
1383 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1384 * application) is responsible for pumping the message loop in that thread.
1385 * The WM_USER messages which point to the RPCs are then dispatched to
1386 * apartment_wndproc by the user's code from the apartment in which the
1387 * interface was unmarshalled.
1389 memset(&wclass, 0, sizeof(wclass));
1390 wclass.lpfnWndProc = apartment_wndproc;
1391 wclass.hInstance = hProxyDll;
1392 wclass.lpszClassName = wszAptWinClass;
1393 RegisterClassW(&wclass);
1396 static void COMPOBJ_UninitProcess( void )
1398 UnregisterClassW(wszAptWinClass, hProxyDll);
1401 static void COM_TlsDestroy(void)
1403 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1404 if (info)
1406 if (info->apt) apartment_release(info->apt);
1407 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1408 if (info->state) IUnknown_Release(info->state);
1409 if (info->spy) IInitializeSpy_Release(info->spy);
1410 if (info->context_token) IObjContext_Release(info->context_token);
1411 HeapFree(GetProcessHeap(), 0, info);
1412 NtCurrentTeb()->ReservedForOle = NULL;
1416 /******************************************************************************
1417 * CoBuildVersion [OLE32.@]
1419 * Gets the build version of the DLL.
1421 * PARAMS
1423 * RETURNS
1424 * Current build version, hiword is majornumber, loword is minornumber
1426 DWORD WINAPI CoBuildVersion(void)
1428 TRACE("Returning version %d, build %d.\n", rmm, rup);
1429 return (rmm<<16)+rup;
1432 /******************************************************************************
1433 * CoRegisterInitializeSpy [OLE32.@]
1435 * Add a Spy that watches CoInitializeEx calls
1437 * PARAMS
1438 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1439 * cookie [II] cookie receiver
1441 * RETURNS
1442 * Success: S_OK if not already initialized, S_FALSE otherwise.
1443 * Failure: HRESULT code.
1445 * SEE ALSO
1446 * CoInitializeEx
1448 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1450 struct oletls *info = COM_CurrentInfo();
1451 HRESULT hr;
1453 TRACE("(%p, %p)\n", spy, cookie);
1455 if (!spy || !cookie || !info)
1457 if (!info)
1458 WARN("Could not allocate tls\n");
1459 return E_INVALIDARG;
1462 if (info->spy)
1464 FIXME("Already registered?\n");
1465 return E_UNEXPECTED;
1468 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1469 if (SUCCEEDED(hr))
1471 cookie->QuadPart = (DWORD_PTR)spy;
1472 return S_OK;
1474 return hr;
1477 /******************************************************************************
1478 * CoRevokeInitializeSpy [OLE32.@]
1480 * Remove a spy that previously watched CoInitializeEx calls
1482 * PARAMS
1483 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1485 * RETURNS
1486 * Success: S_OK if a spy is removed
1487 * Failure: E_INVALIDARG
1489 * SEE ALSO
1490 * CoInitializeEx
1492 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1494 struct oletls *info = COM_CurrentInfo();
1495 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1497 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1498 return E_INVALIDARG;
1500 IInitializeSpy_Release(info->spy);
1501 info->spy = NULL;
1502 return S_OK;
1506 /******************************************************************************
1507 * CoInitialize [OLE32.@]
1509 * Initializes the COM libraries by calling CoInitializeEx with
1510 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1512 * PARAMS
1513 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1515 * RETURNS
1516 * Success: S_OK if not already initialized, S_FALSE otherwise.
1517 * Failure: HRESULT code.
1519 * SEE ALSO
1520 * CoInitializeEx
1522 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1525 * Just delegate to the newer method.
1527 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1530 /******************************************************************************
1531 * CoInitializeEx [OLE32.@]
1533 * Initializes the COM libraries.
1535 * PARAMS
1536 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1537 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1539 * RETURNS
1540 * S_OK if successful,
1541 * S_FALSE if this function was called already.
1542 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1543 * threading model.
1545 * NOTES
1547 * The behavior used to set the IMalloc used for memory management is
1548 * obsolete.
1549 * The dwCoInit parameter must specify one of the following apartment
1550 * threading models:
1551 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1552 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1553 * The parameter may also specify zero or more of the following flags:
1554 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1555 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1557 * SEE ALSO
1558 * CoUninitialize
1560 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1562 struct oletls *info = COM_CurrentInfo();
1563 HRESULT hr = S_OK;
1564 APARTMENT *apt;
1566 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1568 if (lpReserved!=NULL)
1570 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1574 * Check the lock count. If this is the first time going through the initialize
1575 * process, we have to initialize the libraries.
1577 * And crank-up that lock count.
1579 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1582 * Initialize the various COM libraries and data structures.
1584 TRACE("() - Initializing the COM libraries\n");
1586 /* we may need to defer this until after apartment initialisation */
1587 RunningObjectTableImpl_Initialize();
1590 if (info->spy)
1591 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1593 if (!(apt = info->apt))
1595 apt = apartment_get_or_create(dwCoInit);
1596 if (!apt) return E_OUTOFMEMORY;
1598 else if (!apartment_is_model(apt, dwCoInit))
1600 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1601 code then we are probably using the wrong threading model to implement that API. */
1602 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1603 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1604 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1605 return RPC_E_CHANGED_MODE;
1607 else
1608 hr = S_FALSE;
1610 info->inits++;
1612 if (info->spy)
1613 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1615 return hr;
1618 /***********************************************************************
1619 * CoUninitialize [OLE32.@]
1621 * This method will decrement the refcount on the current apartment, freeing
1622 * the resources associated with it if it is the last thread in the apartment.
1623 * If the last apartment is freed, the function will additionally release
1624 * any COM resources associated with the process.
1626 * PARAMS
1628 * RETURNS
1629 * Nothing.
1631 * SEE ALSO
1632 * CoInitializeEx
1634 void WINAPI CoUninitialize(void)
1636 struct oletls * info = COM_CurrentInfo();
1637 LONG lCOMRefCnt;
1639 TRACE("()\n");
1641 /* will only happen on OOM */
1642 if (!info) return;
1644 if (info->spy)
1645 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1647 /* sanity check */
1648 if (!info->inits)
1650 ERR("Mismatched CoUninitialize\n");
1652 if (info->spy)
1653 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1654 return;
1657 if (!--info->inits)
1659 apartment_release(info->apt);
1660 info->apt = NULL;
1664 * Decrease the reference count.
1665 * If we are back to 0 locks on the COM library, make sure we free
1666 * all the associated data structures.
1668 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1669 if (lCOMRefCnt==1)
1671 TRACE("() - Releasing the COM libraries\n");
1673 RunningObjectTableImpl_UnInitialize();
1675 else if (lCOMRefCnt<1) {
1676 ERR( "CoUninitialize() - not CoInitialized.\n" );
1677 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1679 if (info->spy)
1680 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1683 /******************************************************************************
1684 * CoDisconnectObject [OLE32.@]
1686 * Disconnects all connections to this object from remote processes. Dispatches
1687 * pending RPCs while blocking new RPCs from occurring, and then calls
1688 * IMarshal::DisconnectObject on the given object.
1690 * Typically called when the object server is forced to shut down, for instance by
1691 * the user.
1693 * PARAMS
1694 * lpUnk [I] The object whose stub should be disconnected.
1695 * reserved [I] Reserved. Should be set to 0.
1697 * RETURNS
1698 * Success: S_OK.
1699 * Failure: HRESULT code.
1701 * SEE ALSO
1702 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1704 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1706 HRESULT hr;
1707 IMarshal *marshal;
1708 APARTMENT *apt;
1710 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1712 if (!lpUnk) return E_INVALIDARG;
1714 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1715 if (hr == S_OK)
1717 hr = IMarshal_DisconnectObject(marshal, reserved);
1718 IMarshal_Release(marshal);
1719 return hr;
1722 apt = COM_CurrentApt();
1723 if (!apt)
1724 return CO_E_NOTINITIALIZED;
1726 apartment_disconnectobject(apt, lpUnk);
1728 /* Note: native is pretty broken here because it just silently
1729 * fails, without returning an appropriate error code if the object was
1730 * not found, making apps think that the object was disconnected, when
1731 * it actually wasn't */
1733 return S_OK;
1736 /******************************************************************************
1737 * CoCreateGuid [OLE32.@]
1739 * Simply forwards to UuidCreate in RPCRT4.
1741 * PARAMS
1742 * pguid [O] Points to the GUID to initialize.
1744 * RETURNS
1745 * Success: S_OK.
1746 * Failure: HRESULT code.
1748 * SEE ALSO
1749 * UuidCreate
1751 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1753 DWORD status = UuidCreate(pguid);
1754 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1755 return HRESULT_FROM_WIN32( status );
1758 static inline BOOL is_valid_hex(WCHAR c)
1760 if (!(((c >= '0') && (c <= '9')) ||
1761 ((c >= 'a') && (c <= 'f')) ||
1762 ((c >= 'A') && (c <= 'F'))))
1763 return FALSE;
1764 return TRUE;
1767 /******************************************************************************
1768 * CLSIDFromString [OLE32.@]
1769 * IIDFromString [OLE32.@]
1771 * Converts a unique identifier from its string representation into
1772 * the GUID struct.
1774 * PARAMS
1775 * idstr [I] The string representation of the GUID.
1776 * id [O] GUID converted from the string.
1778 * RETURNS
1779 * S_OK on success
1780 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1782 * SEE ALSO
1783 * StringFromCLSID
1785 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1787 int i;
1788 BYTE table[256];
1790 if (!s || s[0]!='{') {
1791 memset( id, 0, sizeof (CLSID) );
1792 if(!s) return S_OK;
1793 return CO_E_CLASSSTRING;
1796 TRACE("%s -> %p\n", debugstr_w(s), id);
1798 /* quick lookup table */
1799 memset(table, 0, 256);
1801 for (i = 0; i < 10; i++) {
1802 table['0' + i] = i;
1804 for (i = 0; i < 6; i++) {
1805 table['A' + i] = i+10;
1806 table['a' + i] = i+10;
1809 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1811 id->Data1 = 0;
1812 for (i = 1; i < 9; i++) {
1813 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1814 id->Data1 = (id->Data1 << 4) | table[s[i]];
1816 if (s[9]!='-') return CO_E_CLASSSTRING;
1818 id->Data2 = 0;
1819 for (i = 10; i < 14; i++) {
1820 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1821 id->Data2 = (id->Data2 << 4) | table[s[i]];
1823 if (s[14]!='-') return CO_E_CLASSSTRING;
1825 id->Data3 = 0;
1826 for (i = 15; i < 19; i++) {
1827 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1828 id->Data3 = (id->Data3 << 4) | table[s[i]];
1830 if (s[19]!='-') return CO_E_CLASSSTRING;
1832 for (i = 20; i < 37; i+=2) {
1833 if (i == 24) {
1834 if (s[i]!='-') return CO_E_CLASSSTRING;
1835 i++;
1837 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1838 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1841 if (s[37] == '}' && s[38] == '\0')
1842 return S_OK;
1844 return CO_E_CLASSSTRING;
1847 /*****************************************************************************/
1849 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1851 HRESULT ret;
1853 if (!id)
1854 return E_INVALIDARG;
1856 ret = __CLSIDFromString(idstr, id);
1857 if(ret != S_OK) { /* It appears a ProgID is also valid */
1858 CLSID tmp_id;
1859 ret = CLSIDFromProgID(idstr, &tmp_id);
1860 if(SUCCEEDED(ret))
1861 *id = tmp_id;
1863 return ret;
1867 /******************************************************************************
1868 * StringFromCLSID [OLE32.@]
1869 * StringFromIID [OLE32.@]
1871 * Converts a GUID into the respective string representation.
1872 * The target string is allocated using the OLE IMalloc.
1874 * PARAMS
1875 * id [I] the GUID to be converted.
1876 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1878 * RETURNS
1879 * S_OK
1880 * E_FAIL
1882 * SEE ALSO
1883 * StringFromGUID2, CLSIDFromString
1885 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1887 HRESULT ret;
1888 LPMALLOC mllc;
1890 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1891 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1892 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1893 return S_OK;
1896 /******************************************************************************
1897 * StringFromGUID2 [OLE32.@]
1899 * Modified version of StringFromCLSID that allows you to specify max
1900 * buffer size.
1902 * PARAMS
1903 * id [I] GUID to convert to string.
1904 * str [O] Buffer where the result will be stored.
1905 * cmax [I] Size of the buffer in characters.
1907 * RETURNS
1908 * Success: The length of the resulting string in characters.
1909 * Failure: 0.
1911 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1913 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1914 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1915 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1916 '%','0','2','X','%','0','2','X','}',0 };
1917 if (!id || cmax < CHARS_IN_GUID) return 0;
1918 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1919 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1920 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1921 return CHARS_IN_GUID;
1924 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1925 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1927 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1928 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1929 LONG res;
1930 HKEY key;
1932 strcpyW(path, wszCLSIDSlash);
1933 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1934 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
1935 if (res == ERROR_FILE_NOT_FOUND)
1936 return REGDB_E_CLASSNOTREG;
1937 else if (res != ERROR_SUCCESS)
1938 return REGDB_E_READREGDB;
1940 if (!keyname)
1942 *subkey = key;
1943 return S_OK;
1946 res = open_classes_key(key, keyname, access, subkey);
1947 RegCloseKey(key);
1948 if (res == ERROR_FILE_NOT_FOUND)
1949 return REGDB_E_KEYMISSING;
1950 else if (res != ERROR_SUCCESS)
1951 return REGDB_E_READREGDB;
1953 return S_OK;
1956 /* open HKCR\\AppId\\{string form of appid clsid} key */
1957 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1959 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1960 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1961 DWORD res;
1962 WCHAR buf[CHARS_IN_GUID];
1963 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1964 DWORD size;
1965 HKEY hkey;
1966 DWORD type;
1967 HRESULT hr;
1969 /* read the AppID value under the class's key */
1970 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1971 if (FAILED(hr))
1972 return hr;
1974 size = sizeof(buf);
1975 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1976 RegCloseKey(hkey);
1977 if (res == ERROR_FILE_NOT_FOUND)
1978 return REGDB_E_KEYMISSING;
1979 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1980 return REGDB_E_READREGDB;
1982 strcpyW(keyname, szAppIdKey);
1983 strcatW(keyname, buf);
1984 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
1985 if (res == ERROR_FILE_NOT_FOUND)
1986 return REGDB_E_KEYMISSING;
1987 else if (res != ERROR_SUCCESS)
1988 return REGDB_E_READREGDB;
1990 return S_OK;
1993 /******************************************************************************
1994 * ProgIDFromCLSID [OLE32.@]
1996 * Converts a class id into the respective program ID.
1998 * PARAMS
1999 * clsid [I] Class ID, as found in registry.
2000 * ppszProgID [O] Associated ProgID.
2002 * RETURNS
2003 * S_OK
2004 * E_OUTOFMEMORY
2005 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2007 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2009 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2010 HKEY hkey;
2011 HRESULT ret;
2012 LONG progidlen = 0;
2014 if (!ppszProgID)
2016 ERR("ppszProgId isn't optional\n");
2017 return E_INVALIDARG;
2020 *ppszProgID = NULL;
2021 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2022 if (FAILED(ret))
2023 return ret;
2025 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2026 ret = REGDB_E_CLASSNOTREG;
2028 if (ret == S_OK)
2030 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2031 if (*ppszProgID)
2033 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
2034 ret = REGDB_E_CLASSNOTREG;
2036 else
2037 ret = E_OUTOFMEMORY;
2040 RegCloseKey(hkey);
2041 return ret;
2044 /******************************************************************************
2045 * CLSIDFromProgID [OLE32.@]
2047 * Converts a program id into the respective GUID.
2049 * PARAMS
2050 * progid [I] Unicode program ID, as found in registry.
2051 * clsid [O] Associated CLSID.
2053 * RETURNS
2054 * Success: S_OK
2055 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2057 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2059 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2060 WCHAR buf2[CHARS_IN_GUID];
2061 LONG buf2len = sizeof(buf2);
2062 HKEY xhkey;
2063 WCHAR *buf;
2065 if (!progid || !clsid)
2067 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2068 return E_INVALIDARG;
2071 /* initialise clsid in case of failure */
2072 memset(clsid, 0, sizeof(*clsid));
2074 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2075 strcpyW( buf, progid );
2076 strcatW( buf, clsidW );
2077 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2079 HeapFree(GetProcessHeap(),0,buf);
2080 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2081 return CO_E_CLASSSTRING;
2083 HeapFree(GetProcessHeap(),0,buf);
2085 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2087 RegCloseKey(xhkey);
2088 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2089 return CO_E_CLASSSTRING;
2091 RegCloseKey(xhkey);
2092 return __CLSIDFromString(buf2,clsid);
2096 /*****************************************************************************
2097 * CoGetPSClsid [OLE32.@]
2099 * Retrieves the CLSID of the proxy/stub factory that implements
2100 * IPSFactoryBuffer for the specified interface.
2102 * PARAMS
2103 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2104 * pclsid [O] Where to store returned proxy/stub CLSID.
2106 * RETURNS
2107 * S_OK
2108 * E_OUTOFMEMORY
2109 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2111 * NOTES
2113 * The standard marshaller activates the object with the CLSID
2114 * returned and uses the CreateProxy and CreateStub methods on its
2115 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2116 * given object.
2118 * CoGetPSClsid determines this CLSID by searching the
2119 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2120 * in the registry and any interface id registered by
2121 * CoRegisterPSClsid within the current process.
2123 * BUGS
2125 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2126 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2127 * considered a bug in native unless an application depends on this (unlikely).
2129 * SEE ALSO
2130 * CoRegisterPSClsid.
2132 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2134 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2135 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2136 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2137 WCHAR value[CHARS_IN_GUID];
2138 LONG len;
2139 HKEY hkey;
2140 APARTMENT *apt = COM_CurrentApt();
2141 struct registered_psclsid *registered_psclsid;
2143 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2145 if (!apt)
2147 ERR("apartment not initialised\n");
2148 return CO_E_NOTINITIALIZED;
2151 if (!pclsid)
2153 ERR("pclsid isn't optional\n");
2154 return E_INVALIDARG;
2157 EnterCriticalSection(&apt->cs);
2159 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2160 if (IsEqualIID(&registered_psclsid->iid, riid))
2162 *pclsid = registered_psclsid->clsid;
2163 LeaveCriticalSection(&apt->cs);
2164 return S_OK;
2167 LeaveCriticalSection(&apt->cs);
2169 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2170 strcpyW(path, wszInterface);
2171 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2172 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2174 /* Open the key.. */
2175 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2177 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2178 return REGDB_E_IIDNOTREG;
2181 /* ... Once we have the key, query the registry to get the
2182 value of CLSID as a string, and convert it into a
2183 proper CLSID structure to be passed back to the app */
2184 len = sizeof(value);
2185 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2187 RegCloseKey(hkey);
2188 return REGDB_E_IIDNOTREG;
2190 RegCloseKey(hkey);
2192 /* We have the CLSID we want back from the registry as a string, so
2193 let's convert it into a CLSID structure */
2194 if (CLSIDFromString(value, pclsid) != NOERROR)
2195 return REGDB_E_IIDNOTREG;
2197 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2198 return S_OK;
2201 /*****************************************************************************
2202 * CoRegisterPSClsid [OLE32.@]
2204 * Register a proxy/stub CLSID for the given interface in the current process
2205 * only.
2207 * PARAMS
2208 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2209 * rclsid [I] CLSID of the proxy/stub.
2211 * RETURNS
2212 * Success: S_OK
2213 * Failure: E_OUTOFMEMORY
2215 * NOTES
2217 * This function does not add anything to the registry and the effects are
2218 * limited to the lifetime of the current process.
2220 * SEE ALSO
2221 * CoGetPSClsid.
2223 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2225 APARTMENT *apt = COM_CurrentApt();
2226 struct registered_psclsid *registered_psclsid;
2228 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2230 if (!apt)
2232 ERR("apartment not initialised\n");
2233 return CO_E_NOTINITIALIZED;
2236 EnterCriticalSection(&apt->cs);
2238 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2239 if (IsEqualIID(&registered_psclsid->iid, riid))
2241 registered_psclsid->clsid = *rclsid;
2242 LeaveCriticalSection(&apt->cs);
2243 return S_OK;
2246 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2247 if (!registered_psclsid)
2249 LeaveCriticalSection(&apt->cs);
2250 return E_OUTOFMEMORY;
2253 registered_psclsid->iid = *riid;
2254 registered_psclsid->clsid = *rclsid;
2255 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2257 LeaveCriticalSection(&apt->cs);
2259 return S_OK;
2263 /***
2264 * COM_GetRegisteredClassObject
2266 * This internal method is used to scan the registered class list to
2267 * find a class object.
2269 * Params:
2270 * rclsid Class ID of the class to find.
2271 * dwClsContext Class context to match.
2272 * ppv [out] returns a pointer to the class object. Complying
2273 * to normal COM usage, this method will increase the
2274 * reference count on this object.
2276 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2277 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2279 HRESULT hr = S_FALSE;
2280 RegisteredClass *curClass;
2282 EnterCriticalSection( &csRegisteredClassList );
2284 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2287 * Check if we have a match on the class ID and context.
2289 if ((apt->oxid == curClass->apartment_id) &&
2290 (dwClsContext & curClass->runContext) &&
2291 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2294 * We have a match, return the pointer to the class object.
2296 *ppUnk = curClass->classObject;
2298 IUnknown_AddRef(curClass->classObject);
2300 hr = S_OK;
2301 break;
2305 LeaveCriticalSection( &csRegisteredClassList );
2307 return hr;
2310 /******************************************************************************
2311 * CoRegisterClassObject [OLE32.@]
2313 * Registers the class object for a given class ID. Servers housed in EXE
2314 * files use this method instead of exporting DllGetClassObject to allow
2315 * other code to connect to their objects.
2317 * PARAMS
2318 * rclsid [I] CLSID of the object to register.
2319 * pUnk [I] IUnknown of the object.
2320 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2321 * flags [I] REGCLS flags indicating how connections are made.
2322 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2324 * RETURNS
2325 * S_OK on success,
2326 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2327 * CO_E_OBJISREG if the object is already registered. We should not return this.
2329 * SEE ALSO
2330 * CoRevokeClassObject, CoGetClassObject
2332 * NOTES
2333 * In-process objects are only registered for the current apartment.
2334 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2335 * in other apartments.
2337 * BUGS
2338 * MSDN claims that multiple interface registrations are legal, but we
2339 * can't do that with our current implementation.
2341 HRESULT WINAPI CoRegisterClassObject(
2342 REFCLSID rclsid,
2343 LPUNKNOWN pUnk,
2344 DWORD dwClsContext,
2345 DWORD flags,
2346 LPDWORD lpdwRegister)
2348 static LONG next_cookie;
2349 RegisteredClass* newClass;
2350 LPUNKNOWN foundObject;
2351 HRESULT hr;
2352 APARTMENT *apt;
2354 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2355 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2357 if ( (lpdwRegister==0) || (pUnk==0) )
2358 return E_INVALIDARG;
2360 apt = COM_CurrentApt();
2361 if (!apt)
2363 ERR("COM was not initialized\n");
2364 return CO_E_NOTINITIALIZED;
2367 *lpdwRegister = 0;
2369 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2370 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2371 if (flags & REGCLS_MULTIPLEUSE)
2372 dwClsContext |= CLSCTX_INPROC_SERVER;
2375 * First, check if the class is already registered.
2376 * If it is, this should cause an error.
2378 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2379 if (hr == S_OK) {
2380 if (flags & REGCLS_MULTIPLEUSE) {
2381 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2382 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2383 IUnknown_Release(foundObject);
2384 return hr;
2386 IUnknown_Release(foundObject);
2387 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2388 return CO_E_OBJISREG;
2391 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2392 if ( newClass == NULL )
2393 return E_OUTOFMEMORY;
2395 newClass->classIdentifier = *rclsid;
2396 newClass->apartment_id = apt->oxid;
2397 newClass->runContext = dwClsContext;
2398 newClass->connectFlags = flags;
2399 newClass->pMarshaledData = NULL;
2400 newClass->RpcRegistration = NULL;
2402 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2403 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2406 * Since we're making a copy of the object pointer, we have to increase its
2407 * reference count.
2409 newClass->classObject = pUnk;
2410 IUnknown_AddRef(newClass->classObject);
2412 EnterCriticalSection( &csRegisteredClassList );
2413 list_add_tail(&RegisteredClassList, &newClass->entry);
2414 LeaveCriticalSection( &csRegisteredClassList );
2416 *lpdwRegister = newClass->dwCookie;
2418 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2419 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2420 if (hr) {
2421 FIXME("Failed to create stream on hglobal, %x\n", hr);
2422 return hr;
2424 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2425 newClass->classObject, MSHCTX_LOCAL, NULL,
2426 MSHLFLAGS_TABLESTRONG);
2427 if (hr) {
2428 FIXME("CoMarshalInterface failed, %x!\n",hr);
2429 return hr;
2432 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2433 newClass->pMarshaledData,
2434 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2435 &newClass->RpcRegistration);
2437 return S_OK;
2440 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2442 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2443 DWORD keytype;
2444 DWORD ret;
2445 DWORD dwLength = len * sizeof(WCHAR);
2447 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2448 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2449 value[0] = '\0';
2452 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2453 REFCLSID rclsid, REFIID riid,
2454 BOOL hostifnecessary, void **ppv)
2456 WCHAR dllpath[MAX_PATH+1];
2457 BOOL apartment_threaded;
2459 if (hostifnecessary)
2461 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2462 static const WCHAR wszFree[] = {'F','r','e','e',0};
2463 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2464 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2466 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2467 /* "Apartment" */
2468 if (!strcmpiW(threading_model, wszApartment))
2470 apartment_threaded = TRUE;
2471 if (apt->multi_threaded)
2472 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2474 /* "Free" */
2475 else if (!strcmpiW(threading_model, wszFree))
2477 apartment_threaded = FALSE;
2478 if (!apt->multi_threaded)
2479 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2481 /* everything except "Apartment", "Free" and "Both" */
2482 else if (strcmpiW(threading_model, wszBoth))
2484 apartment_threaded = TRUE;
2485 /* everything else is main-threaded */
2486 if (threading_model[0])
2487 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2488 debugstr_w(threading_model), debugstr_guid(rclsid));
2490 if (apt->multi_threaded || !apt->main)
2491 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2493 else
2494 apartment_threaded = FALSE;
2496 else
2497 apartment_threaded = !apt->multi_threaded;
2499 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2501 /* failure: CLSID is not found in registry */
2502 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2503 return REGDB_E_CLASSNOTREG;
2506 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2507 rclsid, riid, ppv);
2510 /***********************************************************************
2511 * CoGetClassObject [OLE32.@]
2513 * Creates an object of the specified class.
2515 * PARAMS
2516 * rclsid [I] Class ID to create an instance of.
2517 * dwClsContext [I] Flags to restrict the location of the created instance.
2518 * pServerInfo [I] Optional. Details for connecting to a remote server.
2519 * iid [I] The ID of the interface of the instance to return.
2520 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2522 * RETURNS
2523 * Success: S_OK
2524 * Failure: HRESULT code.
2526 * NOTES
2527 * The dwClsContext parameter can be one or more of the following:
2528 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2529 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2530 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2531 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2533 * SEE ALSO
2534 * CoCreateInstance()
2536 HRESULT WINAPI CoGetClassObject(
2537 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2538 REFIID iid, LPVOID *ppv)
2540 LPUNKNOWN regClassObject;
2541 HRESULT hres = E_UNEXPECTED;
2542 APARTMENT *apt;
2543 BOOL release_apt = FALSE;
2545 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2547 if (!ppv)
2548 return E_INVALIDARG;
2550 *ppv = NULL;
2552 if (!(apt = COM_CurrentApt()))
2554 if (!(apt = apartment_find_multi_threaded()))
2556 ERR("apartment not initialised\n");
2557 return CO_E_NOTINITIALIZED;
2559 release_apt = TRUE;
2562 if (pServerInfo) {
2563 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2564 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2568 * First, try and see if we can't match the class ID with one of the
2569 * registered classes.
2571 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2572 &regClassObject))
2574 /* Get the required interface from the retrieved pointer. */
2575 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2578 * Since QI got another reference on the pointer, we want to release the
2579 * one we already have. If QI was unsuccessful, this will release the object. This
2580 * is good since we are not returning it in the "out" parameter.
2582 IUnknown_Release(regClassObject);
2583 if (release_apt) apartment_release(apt);
2584 return hres;
2587 /* First try in-process server */
2588 if (CLSCTX_INPROC_SERVER & dwClsContext)
2590 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2591 HKEY hkey;
2593 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2595 if (release_apt) apartment_release(apt);
2596 return FTMarshalCF_Create(iid, ppv);
2599 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2600 if (FAILED(hres))
2602 if (hres == REGDB_E_CLASSNOTREG)
2603 ERR("class %s not registered\n", debugstr_guid(rclsid));
2604 else if (hres == REGDB_E_KEYMISSING)
2606 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2607 hres = REGDB_E_CLASSNOTREG;
2611 if (SUCCEEDED(hres))
2613 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2614 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2615 RegCloseKey(hkey);
2618 /* return if we got a class, otherwise fall through to one of the
2619 * other types */
2620 if (SUCCEEDED(hres))
2622 if (release_apt) apartment_release(apt);
2623 return hres;
2627 /* Next try in-process handler */
2628 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2630 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2631 HKEY hkey;
2633 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2634 if (FAILED(hres))
2636 if (hres == REGDB_E_CLASSNOTREG)
2637 ERR("class %s not registered\n", debugstr_guid(rclsid));
2638 else if (hres == REGDB_E_KEYMISSING)
2640 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2641 hres = REGDB_E_CLASSNOTREG;
2645 if (SUCCEEDED(hres))
2647 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2648 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2649 RegCloseKey(hkey);
2652 /* return if we got a class, otherwise fall through to one of the
2653 * other types */
2654 if (SUCCEEDED(hres))
2656 if (release_apt) apartment_release(apt);
2657 return hres;
2660 if (release_apt) apartment_release(apt);
2662 /* Next try out of process */
2663 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2665 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2666 if (SUCCEEDED(hres))
2667 return hres;
2670 /* Finally try remote: this requires networked DCOM (a lot of work) */
2671 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2673 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2674 hres = REGDB_E_CLASSNOTREG;
2677 if (FAILED(hres))
2678 ERR("no class object %s could be created for context 0x%x\n",
2679 debugstr_guid(rclsid), dwClsContext);
2680 return hres;
2683 /***********************************************************************
2684 * CoResumeClassObjects (OLE32.@)
2686 * Resumes all class objects registered with REGCLS_SUSPENDED.
2688 * RETURNS
2689 * Success: S_OK.
2690 * Failure: HRESULT code.
2692 HRESULT WINAPI CoResumeClassObjects(void)
2694 FIXME("stub\n");
2695 return S_OK;
2698 /***********************************************************************
2699 * CoCreateInstance [OLE32.@]
2701 * Creates an instance of the specified class.
2703 * PARAMS
2704 * rclsid [I] Class ID to create an instance of.
2705 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2706 * dwClsContext [I] Flags to restrict the location of the created instance.
2707 * iid [I] The ID of the interface of the instance to return.
2708 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2710 * RETURNS
2711 * Success: S_OK
2712 * Failure: HRESULT code.
2714 * NOTES
2715 * The dwClsContext parameter can be one or more of the following:
2716 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2717 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2718 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2719 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2721 * Aggregation is the concept of deferring the IUnknown of an object to another
2722 * object. This allows a separate object to behave as though it was part of
2723 * the object and to allow this the pUnkOuter parameter can be set. Note that
2724 * not all objects support having an outer of unknown.
2726 * SEE ALSO
2727 * CoGetClassObject()
2729 HRESULT WINAPI CoCreateInstance(
2730 REFCLSID rclsid,
2731 LPUNKNOWN pUnkOuter,
2732 DWORD dwClsContext,
2733 REFIID iid,
2734 LPVOID *ppv)
2736 HRESULT hres;
2737 LPCLASSFACTORY lpclf = 0;
2738 APARTMENT *apt;
2740 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2741 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2744 * Sanity check
2746 if (ppv==0)
2747 return E_POINTER;
2750 * Initialize the "out" parameter
2752 *ppv = 0;
2754 if (!(apt = COM_CurrentApt()))
2756 if (!(apt = apartment_find_multi_threaded()))
2758 ERR("apartment not initialised\n");
2759 return CO_E_NOTINITIALIZED;
2761 apartment_release(apt);
2765 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2766 * Rather than create a class factory, we can just check for it here
2768 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2769 if (StdGlobalInterfaceTableInstance == NULL)
2770 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2771 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2772 if (hres) return hres;
2774 TRACE("Retrieved GIT (%p)\n", *ppv);
2775 return S_OK;
2778 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2779 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2782 * Get a class factory to construct the object we want.
2784 hres = CoGetClassObject(rclsid,
2785 dwClsContext,
2786 NULL,
2787 &IID_IClassFactory,
2788 (LPVOID)&lpclf);
2790 if (FAILED(hres))
2791 return hres;
2794 * Create the object and don't forget to release the factory
2796 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2797 IClassFactory_Release(lpclf);
2798 if(FAILED(hres))
2800 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2801 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2802 else
2803 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2806 return hres;
2809 /***********************************************************************
2810 * CoCreateInstanceEx [OLE32.@]
2812 HRESULT WINAPI CoCreateInstanceEx(
2813 REFCLSID rclsid,
2814 LPUNKNOWN pUnkOuter,
2815 DWORD dwClsContext,
2816 COSERVERINFO* pServerInfo,
2817 ULONG cmq,
2818 MULTI_QI* pResults)
2820 IUnknown* pUnk = NULL;
2821 HRESULT hr;
2822 ULONG index;
2823 ULONG successCount = 0;
2826 * Sanity check
2828 if ( (cmq==0) || (pResults==NULL))
2829 return E_INVALIDARG;
2831 if (pServerInfo!=NULL)
2832 FIXME("() non-NULL pServerInfo not supported!\n");
2835 * Initialize all the "out" parameters.
2837 for (index = 0; index < cmq; index++)
2839 pResults[index].pItf = NULL;
2840 pResults[index].hr = E_NOINTERFACE;
2844 * Get the object and get its IUnknown pointer.
2846 hr = CoCreateInstance(rclsid,
2847 pUnkOuter,
2848 dwClsContext,
2849 &IID_IUnknown,
2850 (VOID**)&pUnk);
2852 if (hr)
2853 return hr;
2856 * Then, query for all the interfaces requested.
2858 for (index = 0; index < cmq; index++)
2860 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2861 pResults[index].pIID,
2862 (VOID**)&(pResults[index].pItf));
2864 if (pResults[index].hr == S_OK)
2865 successCount++;
2869 * Release our temporary unknown pointer.
2871 IUnknown_Release(pUnk);
2873 if (successCount == 0)
2874 return E_NOINTERFACE;
2876 if (successCount!=cmq)
2877 return CO_S_NOTALLINTERFACES;
2879 return S_OK;
2882 /***********************************************************************
2883 * CoLoadLibrary (OLE32.@)
2885 * Loads a library.
2887 * PARAMS
2888 * lpszLibName [I] Path to library.
2889 * bAutoFree [I] Whether the library should automatically be freed.
2891 * RETURNS
2892 * Success: Handle to loaded library.
2893 * Failure: NULL.
2895 * SEE ALSO
2896 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2898 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2900 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2902 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2905 /***********************************************************************
2906 * CoFreeLibrary [OLE32.@]
2908 * Unloads a library from memory.
2910 * PARAMS
2911 * hLibrary [I] Handle to library to unload.
2913 * RETURNS
2914 * Nothing
2916 * SEE ALSO
2917 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2919 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2921 FreeLibrary(hLibrary);
2925 /***********************************************************************
2926 * CoFreeAllLibraries [OLE32.@]
2928 * Function for backwards compatibility only. Does nothing.
2930 * RETURNS
2931 * Nothing.
2933 * SEE ALSO
2934 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2936 void WINAPI CoFreeAllLibraries(void)
2938 /* NOP */
2941 /***********************************************************************
2942 * CoFreeUnusedLibrariesEx [OLE32.@]
2944 * Frees any previously unused libraries whose delay has expired and marks
2945 * currently unused libraries for unloading. Unused are identified as those that
2946 * return S_OK from their DllCanUnloadNow function.
2948 * PARAMS
2949 * dwUnloadDelay [I] Unload delay in milliseconds.
2950 * dwReserved [I] Reserved. Set to 0.
2952 * RETURNS
2953 * Nothing.
2955 * SEE ALSO
2956 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2958 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2960 struct apartment *apt = COM_CurrentApt();
2961 if (!apt)
2963 ERR("apartment not initialised\n");
2964 return;
2967 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2970 /***********************************************************************
2971 * CoFreeUnusedLibraries [OLE32.@]
2973 * Frees any unused libraries. Unused are identified as those that return
2974 * S_OK from their DllCanUnloadNow function.
2976 * RETURNS
2977 * Nothing.
2979 * SEE ALSO
2980 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2982 void WINAPI CoFreeUnusedLibraries(void)
2984 CoFreeUnusedLibrariesEx(INFINITE, 0);
2987 /***********************************************************************
2988 * CoFileTimeNow [OLE32.@]
2990 * Retrieves the current time in FILETIME format.
2992 * PARAMS
2993 * lpFileTime [O] The current time.
2995 * RETURNS
2996 * S_OK.
2998 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3000 GetSystemTimeAsFileTime( lpFileTime );
3001 return S_OK;
3004 /******************************************************************************
3005 * CoLockObjectExternal [OLE32.@]
3007 * Increments or decrements the external reference count of a stub object.
3009 * PARAMS
3010 * pUnk [I] Stub object.
3011 * fLock [I] If TRUE then increments the external ref-count,
3012 * otherwise decrements.
3013 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3014 * calling CoDisconnectObject.
3016 * RETURNS
3017 * Success: S_OK.
3018 * Failure: HRESULT code.
3020 * NOTES
3021 * If fLock is TRUE and an object is passed in that doesn't have a stub
3022 * manager then a new stub manager is created for the object.
3024 HRESULT WINAPI CoLockObjectExternal(
3025 LPUNKNOWN pUnk,
3026 BOOL fLock,
3027 BOOL fLastUnlockReleases)
3029 struct stub_manager *stubmgr;
3030 struct apartment *apt;
3032 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3033 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3035 apt = COM_CurrentApt();
3036 if (!apt) return CO_E_NOTINITIALIZED;
3038 stubmgr = get_stub_manager_from_object(apt, pUnk);
3040 if (stubmgr)
3042 if (fLock)
3043 stub_manager_ext_addref(stubmgr, 1, FALSE);
3044 else
3045 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3047 stub_manager_int_release(stubmgr);
3049 return S_OK;
3051 else if (fLock)
3053 stubmgr = new_stub_manager(apt, pUnk);
3055 if (stubmgr)
3057 stub_manager_ext_addref(stubmgr, 1, FALSE);
3058 stub_manager_int_release(stubmgr);
3061 return S_OK;
3063 else
3065 WARN("stub object not found %p\n", pUnk);
3066 /* Note: native is pretty broken here because it just silently
3067 * fails, without returning an appropriate error code, making apps
3068 * think that the object was disconnected, when it actually wasn't */
3069 return S_OK;
3073 /***********************************************************************
3074 * CoInitializeWOW (OLE32.@)
3076 * WOW equivalent of CoInitialize?
3078 * PARAMS
3079 * x [I] Unknown.
3080 * y [I] Unknown.
3082 * RETURNS
3083 * Unknown.
3085 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3087 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3088 return 0;
3091 /***********************************************************************
3092 * CoGetState [OLE32.@]
3094 * Retrieves the thread state object previously stored by CoSetState().
3096 * PARAMS
3097 * ppv [I] Address where pointer to object will be stored.
3099 * RETURNS
3100 * Success: S_OK.
3101 * Failure: E_OUTOFMEMORY.
3103 * NOTES
3104 * Crashes on all invalid ppv addresses, including NULL.
3105 * If the function returns a non-NULL object then the caller must release its
3106 * reference on the object when the object is no longer required.
3108 * SEE ALSO
3109 * CoSetState().
3111 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3113 struct oletls *info = COM_CurrentInfo();
3114 if (!info) return E_OUTOFMEMORY;
3116 *ppv = NULL;
3118 if (info->state)
3120 IUnknown_AddRef(info->state);
3121 *ppv = info->state;
3122 TRACE("apt->state=%p\n", info->state);
3125 return S_OK;
3128 /***********************************************************************
3129 * CoSetState [OLE32.@]
3131 * Sets the thread state object.
3133 * PARAMS
3134 * pv [I] Pointer to state object to be stored.
3136 * NOTES
3137 * The system keeps a reference on the object while the object stored.
3139 * RETURNS
3140 * Success: S_OK.
3141 * Failure: E_OUTOFMEMORY.
3143 HRESULT WINAPI CoSetState(IUnknown * pv)
3145 struct oletls *info = COM_CurrentInfo();
3146 if (!info) return E_OUTOFMEMORY;
3148 if (pv) IUnknown_AddRef(pv);
3150 if (info->state)
3152 TRACE("-- release %p now\n", info->state);
3153 IUnknown_Release(info->state);
3156 info->state = pv;
3158 return S_OK;
3162 /******************************************************************************
3163 * CoTreatAsClass [OLE32.@]
3165 * Sets the TreatAs value of a class.
3167 * PARAMS
3168 * clsidOld [I] Class to set TreatAs value on.
3169 * clsidNew [I] The class the clsidOld should be treated as.
3171 * RETURNS
3172 * Success: S_OK.
3173 * Failure: HRESULT code.
3175 * SEE ALSO
3176 * CoGetTreatAsClass
3178 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3180 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3181 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3182 HKEY hkey = NULL;
3183 WCHAR szClsidNew[CHARS_IN_GUID];
3184 HRESULT res = S_OK;
3185 WCHAR auto_treat_as[CHARS_IN_GUID];
3186 LONG auto_treat_as_size = sizeof(auto_treat_as);
3187 CLSID id;
3189 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3190 if (FAILED(res))
3191 goto done;
3192 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3194 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3195 CLSIDFromString(auto_treat_as, &id) == S_OK)
3197 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3199 res = REGDB_E_WRITEREGDB;
3200 goto done;
3203 else
3205 RegDeleteKeyW(hkey, wszTreatAs);
3206 goto done;
3209 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3210 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3212 res = REGDB_E_WRITEREGDB;
3213 goto done;
3216 done:
3217 if (hkey) RegCloseKey(hkey);
3218 return res;
3221 /******************************************************************************
3222 * CoGetTreatAsClass [OLE32.@]
3224 * Gets the TreatAs value of a class.
3226 * PARAMS
3227 * clsidOld [I] Class to get the TreatAs value of.
3228 * clsidNew [I] The class the clsidOld should be treated as.
3230 * RETURNS
3231 * Success: S_OK.
3232 * Failure: HRESULT code.
3234 * SEE ALSO
3235 * CoSetTreatAsClass
3237 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3239 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3240 HKEY hkey = NULL;
3241 WCHAR szClsidNew[CHARS_IN_GUID];
3242 HRESULT res = S_OK;
3243 LONG len = sizeof(szClsidNew);
3245 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3246 *clsidNew = *clsidOld; /* copy over old value */
3248 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3249 if (FAILED(res))
3251 res = S_FALSE;
3252 goto done;
3254 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3256 res = S_FALSE;
3257 goto done;
3259 res = CLSIDFromString(szClsidNew,clsidNew);
3260 if (FAILED(res))
3261 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3262 done:
3263 if (hkey) RegCloseKey(hkey);
3264 return res;
3267 /******************************************************************************
3268 * CoGetCurrentProcess [OLE32.@]
3270 * Gets the current process ID.
3272 * RETURNS
3273 * The current process ID.
3275 * NOTES
3276 * Is DWORD really the correct return type for this function?
3278 DWORD WINAPI CoGetCurrentProcess(void)
3280 return GetCurrentProcessId();
3283 /******************************************************************************
3284 * CoRegisterMessageFilter [OLE32.@]
3286 * Registers a message filter.
3288 * PARAMS
3289 * lpMessageFilter [I] Pointer to interface.
3290 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3292 * RETURNS
3293 * Success: S_OK.
3294 * Failure: HRESULT code.
3296 * NOTES
3297 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3298 * lpMessageFilter removes the message filter.
3300 * If lplpMessageFilter is not NULL the previous message filter will be
3301 * returned in the memory pointer to this parameter and the caller is
3302 * responsible for releasing the object.
3304 * The current thread be in an apartment otherwise the function will crash.
3306 HRESULT WINAPI CoRegisterMessageFilter(
3307 LPMESSAGEFILTER lpMessageFilter,
3308 LPMESSAGEFILTER *lplpMessageFilter)
3310 struct apartment *apt;
3311 IMessageFilter *lpOldMessageFilter;
3313 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3315 apt = COM_CurrentApt();
3317 /* can't set a message filter in a multi-threaded apartment */
3318 if (!apt || apt->multi_threaded)
3320 WARN("can't set message filter in MTA or uninitialized apt\n");
3321 return CO_E_NOT_SUPPORTED;
3324 if (lpMessageFilter)
3325 IMessageFilter_AddRef(lpMessageFilter);
3327 EnterCriticalSection(&apt->cs);
3329 lpOldMessageFilter = apt->filter;
3330 apt->filter = lpMessageFilter;
3332 LeaveCriticalSection(&apt->cs);
3334 if (lplpMessageFilter)
3335 *lplpMessageFilter = lpOldMessageFilter;
3336 else if (lpOldMessageFilter)
3337 IMessageFilter_Release(lpOldMessageFilter);
3339 return S_OK;
3342 /***********************************************************************
3343 * CoIsOle1Class [OLE32.@]
3345 * Determines whether the specified class an OLE v1 class.
3347 * PARAMS
3348 * clsid [I] Class to test.
3350 * RETURNS
3351 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3353 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3355 FIXME("%s\n", debugstr_guid(clsid));
3356 return FALSE;
3359 /***********************************************************************
3360 * IsEqualGUID [OLE32.@]
3362 * Compares two Unique Identifiers.
3364 * PARAMS
3365 * rguid1 [I] The first GUID to compare.
3366 * rguid2 [I] The other GUID to compare.
3368 * RETURNS
3369 * TRUE if equal
3371 #undef IsEqualGUID
3372 BOOL WINAPI IsEqualGUID(
3373 REFGUID rguid1,
3374 REFGUID rguid2)
3376 return !memcmp(rguid1,rguid2,sizeof(GUID));
3379 /***********************************************************************
3380 * CoInitializeSecurity [OLE32.@]
3382 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3383 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3384 void* pReserved1, DWORD dwAuthnLevel,
3385 DWORD dwImpLevel, void* pReserved2,
3386 DWORD dwCapabilities, void* pReserved3)
3388 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3389 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3390 dwCapabilities, pReserved3);
3391 return S_OK;
3394 /***********************************************************************
3395 * CoSuspendClassObjects [OLE32.@]
3397 * Suspends all registered class objects to prevent further requests coming in
3398 * for those objects.
3400 * RETURNS
3401 * Success: S_OK.
3402 * Failure: HRESULT code.
3404 HRESULT WINAPI CoSuspendClassObjects(void)
3406 FIXME("\n");
3407 return S_OK;
3410 /***********************************************************************
3411 * CoAddRefServerProcess [OLE32.@]
3413 * Helper function for incrementing the reference count of a local-server
3414 * process.
3416 * RETURNS
3417 * New reference count.
3419 * SEE ALSO
3420 * CoReleaseServerProcess().
3422 ULONG WINAPI CoAddRefServerProcess(void)
3424 ULONG refs;
3426 TRACE("\n");
3428 EnterCriticalSection(&csRegisteredClassList);
3429 refs = ++s_COMServerProcessReferences;
3430 LeaveCriticalSection(&csRegisteredClassList);
3432 TRACE("refs before: %d\n", refs - 1);
3434 return refs;
3437 /***********************************************************************
3438 * CoReleaseServerProcess [OLE32.@]
3440 * Helper function for decrementing the reference count of a local-server
3441 * process.
3443 * RETURNS
3444 * New reference count.
3446 * NOTES
3447 * When reference count reaches 0, this function suspends all registered
3448 * classes so no new connections are accepted.
3450 * SEE ALSO
3451 * CoAddRefServerProcess(), CoSuspendClassObjects().
3453 ULONG WINAPI CoReleaseServerProcess(void)
3455 ULONG refs;
3457 TRACE("\n");
3459 EnterCriticalSection(&csRegisteredClassList);
3461 refs = --s_COMServerProcessReferences;
3462 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3464 LeaveCriticalSection(&csRegisteredClassList);
3466 TRACE("refs after: %d\n", refs);
3468 return refs;
3471 /***********************************************************************
3472 * CoIsHandlerConnected [OLE32.@]
3474 * Determines whether a proxy is connected to a remote stub.
3476 * PARAMS
3477 * pUnk [I] Pointer to object that may or may not be connected.
3479 * RETURNS
3480 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3481 * FALSE otherwise.
3483 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3485 FIXME("%p\n", pUnk);
3487 return TRUE;
3490 /***********************************************************************
3491 * CoAllowSetForegroundWindow [OLE32.@]
3494 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3496 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3497 return S_OK;
3500 /***********************************************************************
3501 * CoQueryProxyBlanket [OLE32.@]
3503 * Retrieves the security settings being used by a proxy.
3505 * PARAMS
3506 * pProxy [I] Pointer to the proxy object.
3507 * pAuthnSvc [O] The type of authentication service.
3508 * pAuthzSvc [O] The type of authorization service.
3509 * ppServerPrincName [O] Optional. The server prinicple name.
3510 * pAuthnLevel [O] The authentication level.
3511 * pImpLevel [O] The impersonation level.
3512 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3513 * pCapabilities [O] Flags affecting the security behaviour.
3515 * RETURNS
3516 * Success: S_OK.
3517 * Failure: HRESULT code.
3519 * SEE ALSO
3520 * CoCopyProxy, CoSetProxyBlanket.
3522 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3523 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3524 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3526 IClientSecurity *pCliSec;
3527 HRESULT hr;
3529 TRACE("%p\n", pProxy);
3531 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3532 if (SUCCEEDED(hr))
3534 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3535 pAuthzSvc, ppServerPrincName,
3536 pAuthnLevel, pImpLevel, ppAuthInfo,
3537 pCapabilities);
3538 IClientSecurity_Release(pCliSec);
3541 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3542 return hr;
3545 /***********************************************************************
3546 * CoSetProxyBlanket [OLE32.@]
3548 * Sets the security settings for a proxy.
3550 * PARAMS
3551 * pProxy [I] Pointer to the proxy object.
3552 * AuthnSvc [I] The type of authentication service.
3553 * AuthzSvc [I] The type of authorization service.
3554 * pServerPrincName [I] The server prinicple name.
3555 * AuthnLevel [I] The authentication level.
3556 * ImpLevel [I] The impersonation level.
3557 * pAuthInfo [I] Information specific to the authorization/authentication service.
3558 * Capabilities [I] Flags affecting the security behaviour.
3560 * RETURNS
3561 * Success: S_OK.
3562 * Failure: HRESULT code.
3564 * SEE ALSO
3565 * CoQueryProxyBlanket, CoCopyProxy.
3567 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3568 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3569 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3571 IClientSecurity *pCliSec;
3572 HRESULT hr;
3574 TRACE("%p\n", pProxy);
3576 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3577 if (SUCCEEDED(hr))
3579 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3580 AuthzSvc, pServerPrincName,
3581 AuthnLevel, ImpLevel, pAuthInfo,
3582 Capabilities);
3583 IClientSecurity_Release(pCliSec);
3586 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3587 return hr;
3590 /***********************************************************************
3591 * CoCopyProxy [OLE32.@]
3593 * Copies a proxy.
3595 * PARAMS
3596 * pProxy [I] Pointer to the proxy object.
3597 * ppCopy [O] Copy of the proxy.
3599 * RETURNS
3600 * Success: S_OK.
3601 * Failure: HRESULT code.
3603 * SEE ALSO
3604 * CoQueryProxyBlanket, CoSetProxyBlanket.
3606 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3608 IClientSecurity *pCliSec;
3609 HRESULT hr;
3611 TRACE("%p\n", pProxy);
3613 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3614 if (SUCCEEDED(hr))
3616 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3617 IClientSecurity_Release(pCliSec);
3620 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3621 return hr;
3625 /***********************************************************************
3626 * CoGetCallContext [OLE32.@]
3628 * Gets the context of the currently executing server call in the current
3629 * thread.
3631 * PARAMS
3632 * riid [I] Context interface to return.
3633 * ppv [O] Pointer to memory that will receive the context on return.
3635 * RETURNS
3636 * Success: S_OK.
3637 * Failure: HRESULT code.
3639 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3641 struct oletls *info = COM_CurrentInfo();
3643 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3645 if (!info)
3646 return E_OUTOFMEMORY;
3648 if (!info->call_state)
3649 return RPC_E_CALL_COMPLETE;
3651 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3654 /***********************************************************************
3655 * CoSwitchCallContext [OLE32.@]
3657 * Switches the context of the currently executing server call in the current
3658 * thread.
3660 * PARAMS
3661 * pObject [I] Pointer to new context object
3662 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3664 * RETURNS
3665 * Success: S_OK.
3666 * Failure: HRESULT code.
3668 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3670 struct oletls *info = COM_CurrentInfo();
3672 TRACE("(%p, %p)\n", pObject, ppOldObject);
3674 if (!info)
3675 return E_OUTOFMEMORY;
3677 *ppOldObject = info->call_state;
3678 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3680 return S_OK;
3683 /***********************************************************************
3684 * CoQueryClientBlanket [OLE32.@]
3686 * Retrieves the authentication information about the client of the currently
3687 * executing server call in the current thread.
3689 * PARAMS
3690 * pAuthnSvc [O] Optional. The type of authentication service.
3691 * pAuthzSvc [O] Optional. The type of authorization service.
3692 * pServerPrincName [O] Optional. The server prinicple name.
3693 * pAuthnLevel [O] Optional. The authentication level.
3694 * pImpLevel [O] Optional. The impersonation level.
3695 * pPrivs [O] Optional. Information about the privileges of the client.
3696 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3698 * RETURNS
3699 * Success: S_OK.
3700 * Failure: HRESULT code.
3702 * SEE ALSO
3703 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3705 HRESULT WINAPI CoQueryClientBlanket(
3706 DWORD *pAuthnSvc,
3707 DWORD *pAuthzSvc,
3708 OLECHAR **pServerPrincName,
3709 DWORD *pAuthnLevel,
3710 DWORD *pImpLevel,
3711 RPC_AUTHZ_HANDLE *pPrivs,
3712 DWORD *pCapabilities)
3714 IServerSecurity *pSrvSec;
3715 HRESULT hr;
3717 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3718 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3719 pPrivs, pCapabilities);
3721 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3722 if (SUCCEEDED(hr))
3724 hr = IServerSecurity_QueryBlanket(
3725 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3726 pImpLevel, pPrivs, pCapabilities);
3727 IServerSecurity_Release(pSrvSec);
3730 return hr;
3733 /***********************************************************************
3734 * CoImpersonateClient [OLE32.@]
3736 * Impersonates the client of the currently executing server call in the
3737 * current thread.
3739 * PARAMS
3740 * None.
3742 * RETURNS
3743 * Success: S_OK.
3744 * Failure: HRESULT code.
3746 * NOTES
3747 * If this function fails then the current thread will not be impersonating
3748 * the client and all actions will take place on behalf of the server.
3749 * Therefore, it is important to check the return value from this function.
3751 * SEE ALSO
3752 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3754 HRESULT WINAPI CoImpersonateClient(void)
3756 IServerSecurity *pSrvSec;
3757 HRESULT hr;
3759 TRACE("\n");
3761 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3762 if (SUCCEEDED(hr))
3764 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3765 IServerSecurity_Release(pSrvSec);
3768 return hr;
3771 /***********************************************************************
3772 * CoRevertToSelf [OLE32.@]
3774 * Ends the impersonation of the client of the currently executing server
3775 * call in the current thread.
3777 * PARAMS
3778 * None.
3780 * RETURNS
3781 * Success: S_OK.
3782 * Failure: HRESULT code.
3784 * SEE ALSO
3785 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3787 HRESULT WINAPI CoRevertToSelf(void)
3789 IServerSecurity *pSrvSec;
3790 HRESULT hr;
3792 TRACE("\n");
3794 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3795 if (SUCCEEDED(hr))
3797 hr = IServerSecurity_RevertToSelf(pSrvSec);
3798 IServerSecurity_Release(pSrvSec);
3801 return hr;
3804 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3806 /* first try to retrieve messages for incoming COM calls to the apartment window */
3807 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3808 /* next retrieve other messages necessary for the app to remain responsive */
3809 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3810 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3813 /***********************************************************************
3814 * CoWaitForMultipleHandles [OLE32.@]
3816 * Waits for one or more handles to become signaled.
3818 * PARAMS
3819 * dwFlags [I] Flags. See notes.
3820 * dwTimeout [I] Timeout in milliseconds.
3821 * cHandles [I] Number of handles pointed to by pHandles.
3822 * pHandles [I] Handles to wait for.
3823 * lpdwindex [O] Index of handle that was signaled.
3825 * RETURNS
3826 * Success: S_OK.
3827 * Failure: RPC_S_CALLPENDING on timeout.
3829 * NOTES
3831 * The dwFlags parameter can be zero or more of the following:
3832 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3833 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3835 * SEE ALSO
3836 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3838 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3839 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3841 HRESULT hr = S_OK;
3842 DWORD start_time = GetTickCount();
3843 APARTMENT *apt = COM_CurrentApt();
3844 BOOL message_loop = apt && !apt->multi_threaded;
3846 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3847 pHandles, lpdwindex);
3849 while (TRUE)
3851 DWORD now = GetTickCount();
3852 DWORD res;
3854 if (now - start_time > dwTimeout)
3856 hr = RPC_S_CALLPENDING;
3857 break;
3860 if (message_loop)
3862 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3863 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3865 TRACE("waiting for rpc completion or window message\n");
3867 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3868 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3869 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
3871 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3873 MSG msg;
3875 /* call message filter */
3877 if (COM_CurrentApt()->filter)
3879 PENDINGTYPE pendingtype =
3880 COM_CurrentInfo()->pending_call_count_server ?
3881 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3882 DWORD be_handled = IMessageFilter_MessagePending(
3883 COM_CurrentApt()->filter, 0 /* FIXME */,
3884 now - start_time, pendingtype);
3885 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3886 switch (be_handled)
3888 case PENDINGMSG_CANCELCALL:
3889 WARN("call canceled\n");
3890 hr = RPC_E_CALL_CANCELED;
3891 break;
3892 case PENDINGMSG_WAITNOPROCESS:
3893 case PENDINGMSG_WAITDEFPROCESS:
3894 default:
3895 /* FIXME: MSDN is very vague about the difference
3896 * between WAITNOPROCESS and WAITDEFPROCESS - there
3897 * appears to be none, so it is possibly a left-over
3898 * from the 16-bit world. */
3899 break;
3903 while (COM_PeekMessage(apt, &msg))
3905 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3906 TranslateMessage(&msg);
3907 DispatchMessageW(&msg);
3908 if (msg.message == WM_QUIT)
3910 TRACE("resending WM_QUIT to outer message loop\n");
3911 PostQuitMessage(msg.wParam);
3912 /* no longer need to process messages */
3913 message_loop = FALSE;
3914 break;
3917 continue;
3920 else
3922 TRACE("waiting for rpc completion\n");
3924 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
3925 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3926 (dwFlags & COWAIT_ALERTABLE) != 0);
3929 switch (res)
3931 case WAIT_TIMEOUT:
3932 hr = RPC_S_CALLPENDING;
3933 break;
3934 case WAIT_FAILED:
3935 hr = HRESULT_FROM_WIN32( GetLastError() );
3936 break;
3937 default:
3938 *lpdwindex = res;
3939 break;
3941 break;
3943 TRACE("-- 0x%08x\n", hr);
3944 return hr;
3948 /***********************************************************************
3949 * CoGetObject [OLE32.@]
3951 * Gets the object named by converting the name to a moniker and binding to it.
3953 * PARAMS
3954 * pszName [I] String representing the object.
3955 * pBindOptions [I] Parameters affecting the binding to the named object.
3956 * riid [I] Interface to bind to on the objecct.
3957 * ppv [O] On output, the interface riid of the object represented
3958 * by pszName.
3960 * RETURNS
3961 * Success: S_OK.
3962 * Failure: HRESULT code.
3964 * SEE ALSO
3965 * MkParseDisplayName.
3967 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3968 REFIID riid, void **ppv)
3970 IBindCtx *pbc;
3971 HRESULT hr;
3973 *ppv = NULL;
3975 hr = CreateBindCtx(0, &pbc);
3976 if (SUCCEEDED(hr))
3978 if (pBindOptions)
3979 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3981 if (SUCCEEDED(hr))
3983 ULONG chEaten;
3984 IMoniker *pmk;
3986 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3987 if (SUCCEEDED(hr))
3989 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3990 IMoniker_Release(pmk);
3994 IBindCtx_Release(pbc);
3996 return hr;
3999 /***********************************************************************
4000 * CoRegisterChannelHook [OLE32.@]
4002 * Registers a process-wide hook that is called during ORPC calls.
4004 * PARAMS
4005 * guidExtension [I] GUID of the channel hook to register.
4006 * pChannelHook [I] Channel hook object to register.
4008 * RETURNS
4009 * Success: S_OK.
4010 * Failure: HRESULT code.
4012 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4014 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4016 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4019 typedef struct Context
4021 IComThreadingInfo IComThreadingInfo_iface;
4022 IContextCallback IContextCallback_iface;
4023 IObjContext IObjContext_iface;
4024 LONG refs;
4025 APTTYPE apttype;
4026 } Context;
4028 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4030 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4033 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4035 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4038 static inline Context *impl_from_IObjContext( IObjContext *iface )
4040 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4043 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4045 *ppv = NULL;
4047 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4048 IsEqualIID(riid, &IID_IUnknown))
4050 *ppv = &iface->IComThreadingInfo_iface;
4052 else if (IsEqualIID(riid, &IID_IContextCallback))
4054 *ppv = &iface->IContextCallback_iface;
4056 else if (IsEqualIID(riid, &IID_IObjContext))
4058 *ppv = &iface->IObjContext_iface;
4061 if (*ppv)
4063 IUnknown_AddRef((IUnknown*)*ppv);
4064 return S_OK;
4067 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4068 return E_NOINTERFACE;
4071 static ULONG Context_AddRef(Context *This)
4073 return InterlockedIncrement(&This->refs);
4076 static ULONG Context_Release(Context *This)
4078 ULONG refs = InterlockedDecrement(&This->refs);
4079 if (!refs)
4080 HeapFree(GetProcessHeap(), 0, This);
4081 return refs;
4084 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4086 Context *This = impl_from_IComThreadingInfo(iface);
4087 return Context_QueryInterface(This, riid, ppv);
4090 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4092 Context *This = impl_from_IComThreadingInfo(iface);
4093 return Context_AddRef(This);
4096 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4098 Context *This = impl_from_IComThreadingInfo(iface);
4099 return Context_Release(This);
4102 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4104 Context *This = impl_from_IComThreadingInfo(iface);
4106 TRACE("(%p)\n", apttype);
4108 *apttype = This->apttype;
4109 return S_OK;
4112 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4114 Context *This = impl_from_IComThreadingInfo(iface);
4116 TRACE("(%p)\n", thdtype);
4118 switch (This->apttype)
4120 case APTTYPE_STA:
4121 case APTTYPE_MAINSTA:
4122 *thdtype = THDTYPE_PROCESSMESSAGES;
4123 break;
4124 default:
4125 *thdtype = THDTYPE_BLOCKMESSAGES;
4126 break;
4128 return S_OK;
4131 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4133 FIXME("(%p): stub\n", logical_thread_id);
4134 return E_NOTIMPL;
4137 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4139 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4140 return E_NOTIMPL;
4143 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4145 Context_CTI_QueryInterface,
4146 Context_CTI_AddRef,
4147 Context_CTI_Release,
4148 Context_CTI_GetCurrentApartmentType,
4149 Context_CTI_GetCurrentThreadType,
4150 Context_CTI_GetCurrentLogicalThreadId,
4151 Context_CTI_SetCurrentLogicalThreadId
4154 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4156 Context *This = impl_from_IContextCallback(iface);
4157 return Context_QueryInterface(This, riid, ppv);
4160 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4162 Context *This = impl_from_IContextCallback(iface);
4163 return Context_AddRef(This);
4166 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4168 Context *This = impl_from_IContextCallback(iface);
4169 return Context_Release(This);
4172 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4173 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4175 Context *This = impl_from_IContextCallback(iface);
4177 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4178 return E_NOTIMPL;
4181 static const IContextCallbackVtbl Context_Callback_Vtbl =
4183 Context_CC_QueryInterface,
4184 Context_CC_AddRef,
4185 Context_CC_Release,
4186 Context_CC_ContextCallback
4189 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4191 Context *This = impl_from_IObjContext(iface);
4192 return Context_QueryInterface(This, riid, ppv);
4195 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4197 Context *This = impl_from_IObjContext(iface);
4198 return Context_AddRef(This);
4201 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4203 Context *This = impl_from_IObjContext(iface);
4204 return Context_Release(This);
4207 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4209 Context *This = impl_from_IObjContext(iface);
4211 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4212 return E_NOTIMPL;
4215 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4217 Context *This = impl_from_IObjContext(iface);
4219 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4220 return E_NOTIMPL;
4223 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4225 Context *This = impl_from_IObjContext(iface);
4227 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4228 return E_NOTIMPL;
4231 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4233 Context *This = impl_from_IObjContext(iface);
4235 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4236 return E_NOTIMPL;
4239 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4241 Context *This = impl_from_IObjContext(iface);
4242 FIXME("(%p/%p)\n", This, iface);
4245 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4247 Context *This = impl_from_IObjContext(iface);
4248 FIXME("(%p/%p)\n", This, iface);
4251 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4253 Context *This = impl_from_IObjContext(iface);
4254 FIXME("(%p/%p)\n", This, iface);
4257 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4259 Context *This = impl_from_IObjContext(iface);
4260 FIXME("(%p/%p)\n", This, iface);
4263 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4265 Context *This = impl_from_IObjContext(iface);
4266 FIXME("(%p/%p)\n", This, iface);
4269 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4271 Context *This = impl_from_IObjContext(iface);
4272 FIXME("(%p/%p)\n", This, iface);
4275 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4277 Context *This = impl_from_IObjContext(iface);
4278 FIXME("(%p/%p)\n", This, iface);
4281 static const IObjContextVtbl Context_Object_Vtbl =
4283 Context_OC_QueryInterface,
4284 Context_OC_AddRef,
4285 Context_OC_Release,
4286 Context_OC_SetProperty,
4287 Context_OC_RemoveProperty,
4288 Context_OC_GetProperty,
4289 Context_OC_EnumContextProps,
4290 Context_OC_Reserved1,
4291 Context_OC_Reserved2,
4292 Context_OC_Reserved3,
4293 Context_OC_Reserved4,
4294 Context_OC_Reserved5,
4295 Context_OC_Reserved6,
4296 Context_OC_Reserved7
4299 /***********************************************************************
4300 * CoGetObjectContext [OLE32.@]
4302 * Retrieves an object associated with the current context (i.e. apartment).
4304 * PARAMS
4305 * riid [I] ID of the interface of the object to retrieve.
4306 * ppv [O] Address where object will be stored on return.
4308 * RETURNS
4309 * Success: S_OK.
4310 * Failure: HRESULT code.
4312 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4314 APARTMENT *apt = COM_CurrentApt();
4315 Context *context;
4316 HRESULT hr;
4318 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4320 *ppv = NULL;
4321 if (!apt)
4323 if (!(apt = apartment_find_multi_threaded()))
4325 ERR("apartment not initialised\n");
4326 return CO_E_NOTINITIALIZED;
4328 apartment_release(apt);
4331 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4332 if (!context)
4333 return E_OUTOFMEMORY;
4335 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4336 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4337 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4338 context->refs = 1;
4339 if (apt->multi_threaded)
4340 context->apttype = APTTYPE_MTA;
4341 else if (apt->main)
4342 context->apttype = APTTYPE_MAINSTA;
4343 else
4344 context->apttype = APTTYPE_STA;
4346 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4347 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4349 return hr;
4353 /***********************************************************************
4354 * CoGetContextToken [OLE32.@]
4356 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4358 struct oletls *info = COM_CurrentInfo();
4360 TRACE("(%p)\n", token);
4362 if (!info)
4363 return E_OUTOFMEMORY;
4365 if (!info->apt)
4367 APARTMENT *apt;
4368 if (!(apt = apartment_find_multi_threaded()))
4370 ERR("apartment not initialised\n");
4371 return CO_E_NOTINITIALIZED;
4373 apartment_release(apt);
4376 if (!token)
4377 return E_POINTER;
4379 if (!info->context_token)
4381 HRESULT hr;
4382 IObjContext *ctx;
4384 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4385 if (FAILED(hr)) return hr;
4386 info->context_token = ctx;
4389 *token = (ULONG_PTR)info->context_token;
4390 TRACE("apt->context_token=%p\n", info->context_token);
4392 return S_OK;
4395 /***********************************************************************
4396 * CoGetDefaultContext [OLE32.@]
4398 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4400 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4401 return E_NOINTERFACE;
4404 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4406 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4407 HKEY hkey;
4408 HRESULT hres;
4410 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4411 if (SUCCEEDED(hres))
4413 WCHAR dllpath[MAX_PATH+1];
4415 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4417 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4418 if (!strcmpiW(dllpath, wszOle32))
4420 RegCloseKey(hkey);
4421 return HandlerCF_Create(rclsid, riid, ppv);
4424 else
4425 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4426 RegCloseKey(hkey);
4429 return CLASS_E_CLASSNOTAVAILABLE;
4432 /***********************************************************************
4433 * DllMain (OLE32.@)
4435 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4437 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4439 switch(fdwReason) {
4440 case DLL_PROCESS_ATTACH:
4441 hProxyDll = hinstDLL;
4442 COMPOBJ_InitProcess();
4443 break;
4445 case DLL_PROCESS_DETACH:
4446 COMPOBJ_UninitProcess();
4447 RPC_UnregisterAllChannelHooks();
4448 COMPOBJ_DllList_Free();
4449 DeleteCriticalSection(&csRegisteredClassList);
4450 DeleteCriticalSection(&csApartment);
4451 break;
4453 case DLL_THREAD_DETACH:
4454 COM_TlsDestroy();
4455 break;
4457 return TRUE;
4460 /***********************************************************************
4461 * DllRegisterServer (OLE32.@)
4463 HRESULT WINAPI DllRegisterServer(void)
4465 return OLE32_DllRegisterServer();
4468 /***********************************************************************
4469 * DllUnregisterServer (OLE32.@)
4471 HRESULT WINAPI DllUnregisterServer(void)
4473 return OLE32_DllUnregisterServer();