ole32: Delay registering the apartment class until needed.
[wine.git] / dlls / ole32 / compobj.c
blobdbe1b060d38c3fa3362bd8f9fc0bcf6170f0bf89
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"
63 #include "servprov.h"
65 #include "initguid.h"
66 #include "compobj_private.h"
67 #include "moniker.h"
69 #include "wine/unicode.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(ole);
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
80 static APARTMENT *MTA; /* protected by csApartment */
81 static APARTMENT *MainApartment; /* the first STA apartment */
82 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment;
85 static CRITICAL_SECTION_DEBUG critsect_debug =
87 0, 0, &csApartment,
88 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
89 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
91 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
93 struct registered_psclsid
95 struct list entry;
96 IID iid;
97 CLSID clsid;
101 * This is a marshallable object exposing registered local servers.
102 * IServiceProvider is used only because it happens meet requirements
103 * and already has proxy/stub code. If more functionality is needed,
104 * a custom interface may be used instead.
106 struct LocalServer
108 IServiceProvider IServiceProvider_iface;
109 LONG ref;
110 APARTMENT *apt;
111 IStream *marshal_stream;
115 * This lock count counts the number of times CoInitialize is called. It is
116 * decreased every time CoUninitialize is called. When it hits 0, the COM
117 * libraries are freed
119 static LONG s_COMLockCount = 0;
120 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
121 static LONG s_COMServerProcessReferences = 0;
124 * This linked list contains the list of registered class objects. These
125 * are mostly used to register the factories for out-of-proc servers of OLE
126 * objects.
128 * TODO: Make this data structure aware of inter-process communication. This
129 * means that parts of this will be exported to rpcss.
131 typedef struct tagRegisteredClass
133 struct list entry;
134 CLSID classIdentifier;
135 OXID apartment_id;
136 LPUNKNOWN classObject;
137 DWORD runContext;
138 DWORD connectFlags;
139 DWORD dwCookie;
140 void *RpcRegistration;
141 } RegisteredClass;
143 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
145 static CRITICAL_SECTION csRegisteredClassList;
146 static CRITICAL_SECTION_DEBUG class_cs_debug =
148 0, 0, &csRegisteredClassList,
149 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
150 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
152 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
154 /* wrapper for NtCreateKey that creates the key recursively if necessary */
155 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
157 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
159 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
161 HANDLE subkey, root = attr->RootDirectory;
162 WCHAR *buffer = attr->ObjectName->Buffer;
163 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
164 UNICODE_STRING str;
166 while (i < len && buffer[i] != '\\') i++;
167 if (i == len) return status;
169 attrs = attr->Attributes;
170 attr->ObjectName = &str;
172 while (i < len)
174 str.Buffer = buffer + pos;
175 str.Length = (i - pos) * sizeof(WCHAR);
176 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
177 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
178 if (status) return status;
179 attr->RootDirectory = subkey;
180 while (i < len && buffer[i] == '\\') i++;
181 pos = i;
182 while (i < len && buffer[i] != '\\') i++;
184 str.Buffer = buffer + pos;
185 str.Length = (i - pos) * sizeof(WCHAR);
186 attr->Attributes = attrs;
187 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
188 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
190 return status;
193 static const WCHAR classes_rootW[] =
194 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
196 static HKEY classes_root_hkey;
198 /* create the special HKEY_CLASSES_ROOT key */
199 static HKEY create_classes_root_hkey(void)
201 HKEY hkey, ret = 0;
202 OBJECT_ATTRIBUTES attr;
203 UNICODE_STRING name;
205 attr.Length = sizeof(attr);
206 attr.RootDirectory = 0;
207 attr.ObjectName = &name;
208 attr.Attributes = 0;
209 attr.SecurityDescriptor = NULL;
210 attr.SecurityQualityOfService = NULL;
211 RtlInitUnicodeString( &name, classes_rootW );
212 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
213 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
215 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
216 ret = hkey;
217 else
218 NtClose( hkey ); /* somebody beat us to it */
219 return ret;
222 /* map the hkey from special root to normal key if necessary */
223 static inline HKEY get_classes_root_hkey( HKEY hkey )
225 HKEY ret = hkey;
227 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
228 ret = create_classes_root_hkey();
230 return ret;
233 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
235 OBJECT_ATTRIBUTES attr;
236 UNICODE_STRING nameW;
238 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
240 attr.Length = sizeof(attr);
241 attr.RootDirectory = hkey;
242 attr.ObjectName = &nameW;
243 attr.Attributes = 0;
244 attr.SecurityDescriptor = NULL;
245 attr.SecurityQualityOfService = NULL;
246 RtlInitUnicodeString( &nameW, name );
248 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
251 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
253 OBJECT_ATTRIBUTES attr;
254 UNICODE_STRING nameW;
256 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
258 attr.Length = sizeof(attr);
259 attr.RootDirectory = hkey;
260 attr.ObjectName = &nameW;
261 attr.Attributes = 0;
262 attr.SecurityDescriptor = NULL;
263 attr.SecurityQualityOfService = NULL;
264 RtlInitUnicodeString( &nameW, name );
266 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
269 /*****************************************************************************
270 * This section contains OpenDllList definitions
272 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
273 * other functions that do LoadLibrary _without_ giving back a HMODULE.
274 * Without this list these handles would never be freed.
276 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
277 * next unload-call but not before 600 sec.
280 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
281 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
283 typedef struct tagOpenDll
285 LONG refs;
286 LPWSTR library_name;
287 HANDLE library;
288 DllGetClassObjectFunc DllGetClassObject;
289 DllCanUnloadNowFunc DllCanUnloadNow;
290 struct list entry;
291 } OpenDll;
293 static struct list openDllList = LIST_INIT(openDllList);
295 static CRITICAL_SECTION csOpenDllList;
296 static CRITICAL_SECTION_DEBUG dll_cs_debug =
298 0, 0, &csOpenDllList,
299 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
300 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
302 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
304 struct apartment_loaded_dll
306 struct list entry;
307 OpenDll *dll;
308 DWORD unload_time;
309 BOOL multi_threaded;
312 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',' ',
313 '0','x','#','#','#','#','#','#','#','#',' ',0};
315 /*****************************************************************************
316 * This section contains OpenDllList implementation
319 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
321 OpenDll *ptr;
322 OpenDll *ret = NULL;
323 EnterCriticalSection(&csOpenDllList);
324 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
326 if (!strcmpiW(library_name, ptr->library_name) &&
327 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
329 ret = ptr;
330 break;
333 LeaveCriticalSection(&csOpenDllList);
334 return ret;
337 /* caller must ensure that library_name is not already in the open dll list */
338 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
340 OpenDll *entry;
341 int len;
342 HRESULT hr = S_OK;
343 HANDLE hLibrary;
344 DllCanUnloadNowFunc DllCanUnloadNow;
345 DllGetClassObjectFunc DllGetClassObject;
347 TRACE("\n");
349 *ret = COMPOBJ_DllList_Get(library_name);
350 if (*ret) return S_OK;
352 /* do this outside the csOpenDllList to avoid creating a lock dependency on
353 * the loader lock */
354 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
355 if (!hLibrary)
357 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
358 /* failure: DLL could not be loaded */
359 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
362 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
363 /* Note: failing to find DllCanUnloadNow is not a failure */
364 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
365 if (!DllGetClassObject)
367 /* failure: the dll did not export DllGetClassObject */
368 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
369 FreeLibrary(hLibrary);
370 return CO_E_DLLNOTFOUND;
373 EnterCriticalSection( &csOpenDllList );
375 *ret = COMPOBJ_DllList_Get(library_name);
376 if (*ret)
378 /* another caller to this function already added the dll while we
379 * weren't in the critical section */
380 FreeLibrary(hLibrary);
382 else
384 len = strlenW(library_name);
385 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
386 if (entry)
387 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
388 if (entry && entry->library_name)
390 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
391 entry->library = hLibrary;
392 entry->refs = 1;
393 entry->DllCanUnloadNow = DllCanUnloadNow;
394 entry->DllGetClassObject = DllGetClassObject;
395 list_add_tail(&openDllList, &entry->entry);
396 *ret = entry;
398 else
400 HeapFree(GetProcessHeap(), 0, entry);
401 hr = E_OUTOFMEMORY;
402 FreeLibrary(hLibrary);
406 LeaveCriticalSection( &csOpenDllList );
408 return hr;
411 /* pass FALSE for free_entry to release a reference without destroying the
412 * entry if it reaches zero or TRUE otherwise */
413 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
415 if (!InterlockedDecrement(&entry->refs) && free_entry)
417 EnterCriticalSection(&csOpenDllList);
418 list_remove(&entry->entry);
419 LeaveCriticalSection(&csOpenDllList);
421 TRACE("freeing %p\n", entry->library);
422 FreeLibrary(entry->library);
424 HeapFree(GetProcessHeap(), 0, entry->library_name);
425 HeapFree(GetProcessHeap(), 0, entry);
429 /* frees memory associated with active dll list */
430 static void COMPOBJ_DllList_Free(void)
432 OpenDll *entry, *cursor2;
433 EnterCriticalSection(&csOpenDllList);
434 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
436 list_remove(&entry->entry);
438 HeapFree(GetProcessHeap(), 0, entry->library_name);
439 HeapFree(GetProcessHeap(), 0, entry);
441 LeaveCriticalSection(&csOpenDllList);
442 DeleteCriticalSection(&csOpenDllList);
445 /******************************************************************************
446 * Manage apartments.
449 static DWORD apartment_addref(struct apartment *apt)
451 DWORD refs = InterlockedIncrement(&apt->refs);
452 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
453 return refs;
456 /* allocates memory and fills in the necessary fields for a new apartment
457 * object. must be called inside apartment cs */
458 static APARTMENT *apartment_construct(DWORD model)
460 APARTMENT *apt;
462 TRACE("creating new apartment, model=%d\n", model);
464 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
465 apt->tid = GetCurrentThreadId();
467 list_init(&apt->proxies);
468 list_init(&apt->stubmgrs);
469 list_init(&apt->psclsids);
470 list_init(&apt->loaded_dlls);
471 apt->ipidc = 0;
472 apt->refs = 1;
473 apt->remunk_exported = FALSE;
474 apt->oidc = 1;
475 InitializeCriticalSection(&apt->cs);
476 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
478 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
480 if (apt->multi_threaded)
482 /* FIXME: should be randomly generated by in an RPC call to rpcss */
483 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
485 else
487 /* FIXME: should be randomly generated by in an RPC call to rpcss */
488 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
491 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
493 list_add_head(&apts, &apt->entry);
495 return apt;
498 /* gets and existing apartment if one exists or otherwise creates an apartment
499 * structure which stores OLE apartment-local information and stores a pointer
500 * to it in the thread-local storage */
501 static APARTMENT *apartment_get_or_create(DWORD model)
503 APARTMENT *apt = COM_CurrentApt();
505 if (!apt)
507 if (model & COINIT_APARTMENTTHREADED)
509 EnterCriticalSection(&csApartment);
511 apt = apartment_construct(model);
512 if (!MainApartment)
514 MainApartment = apt;
515 apt->main = TRUE;
516 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
519 LeaveCriticalSection(&csApartment);
521 if (apt->main)
522 apartment_createwindowifneeded(apt);
524 else
526 EnterCriticalSection(&csApartment);
528 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
529 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
530 * in a process */
531 if (MTA)
533 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
534 apartment_addref(MTA);
536 else
537 MTA = apartment_construct(model);
539 apt = MTA;
541 LeaveCriticalSection(&csApartment);
543 COM_CurrentInfo()->apt = apt;
546 return apt;
549 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
551 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
554 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
556 list_remove(&curClass->entry);
558 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
559 RPC_StopLocalServer(curClass->RpcRegistration);
561 IUnknown_Release(curClass->classObject);
562 HeapFree(GetProcessHeap(), 0, curClass);
565 static void COM_RevokeAllClasses(const struct apartment *apt)
567 RegisteredClass *curClass, *cursor;
569 EnterCriticalSection( &csRegisteredClassList );
571 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
573 if (curClass->apartment_id == apt->oxid)
574 COM_RevokeRegisteredClassObject(curClass);
577 LeaveCriticalSection( &csRegisteredClassList );
580 /******************************************************************************
581 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
584 typedef struct ManualResetEvent {
585 ISynchronize ISynchronize_iface;
586 ISynchronizeHandle ISynchronizeHandle_iface;
587 LONG ref;
588 HANDLE event;
589 } MREImpl;
591 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
593 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
596 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
598 MREImpl *This = impl_from_ISynchronize(iface);
600 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
602 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
603 *ppv = &This->ISynchronize_iface;
604 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
605 *ppv = &This->ISynchronizeHandle_iface;
606 }else {
607 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
608 *ppv = NULL;
609 return E_NOINTERFACE;
612 IUnknown_AddRef((IUnknown*)*ppv);
613 return S_OK;
616 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
618 MREImpl *This = impl_from_ISynchronize(iface);
619 LONG ref = InterlockedIncrement(&This->ref);
620 TRACE("%p - ref %d\n", This, ref);
622 return ref;
625 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
627 MREImpl *This = impl_from_ISynchronize(iface);
628 LONG ref = InterlockedDecrement(&This->ref);
629 TRACE("%p - ref %d\n", This, ref);
631 if(!ref)
633 CloseHandle(This->event);
634 HeapFree(GetProcessHeap(), 0, This);
637 return ref;
640 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
642 MREImpl *This = impl_from_ISynchronize(iface);
643 UINT index;
644 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
645 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
648 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
650 MREImpl *This = impl_from_ISynchronize(iface);
651 TRACE("%p\n", This);
652 SetEvent(This->event);
653 return S_OK;
656 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
658 MREImpl *This = impl_from_ISynchronize(iface);
659 TRACE("%p\n", This);
660 ResetEvent(This->event);
661 return S_OK;
664 static ISynchronizeVtbl vt_ISynchronize = {
665 ISynchronize_fnQueryInterface,
666 ISynchronize_fnAddRef,
667 ISynchronize_fnRelease,
668 ISynchronize_fnWait,
669 ISynchronize_fnSignal,
670 ISynchronize_fnReset
673 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
675 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
678 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
680 MREImpl *This = impl_from_ISynchronizeHandle(iface);
681 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
684 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
686 MREImpl *This = impl_from_ISynchronizeHandle(iface);
687 return ISynchronize_AddRef(&This->ISynchronize_iface);
690 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
692 MREImpl *This = impl_from_ISynchronizeHandle(iface);
693 return ISynchronize_Release(&This->ISynchronize_iface);
696 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
698 MREImpl *This = impl_from_ISynchronizeHandle(iface);
700 *ph = This->event;
701 return S_OK;
704 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
705 SynchronizeHandle_QueryInterface,
706 SynchronizeHandle_AddRef,
707 SynchronizeHandle_Release,
708 SynchronizeHandle_GetHandle
711 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
713 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
714 HRESULT hr;
716 if(punkouter)
717 FIXME("Aggregation not implemented.\n");
719 This->ref = 1;
720 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
721 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
722 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
724 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
725 ISynchronize_Release(&This->ISynchronize_iface);
726 return hr;
729 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
731 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
734 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
736 LocalServer *This = impl_from_IServiceProvider(iface);
738 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
740 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
741 *ppv = &This->IServiceProvider_iface;
742 }else {
743 *ppv = NULL;
744 return E_NOINTERFACE;
747 IUnknown_AddRef((IUnknown*)*ppv);
748 return S_OK;
751 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
753 LocalServer *This = impl_from_IServiceProvider(iface);
754 LONG ref = InterlockedIncrement(&This->ref);
756 TRACE("(%p) ref=%d\n", This, ref);
758 return ref;
761 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
763 LocalServer *This = impl_from_IServiceProvider(iface);
764 LONG ref = InterlockedDecrement(&This->ref);
766 TRACE("(%p) ref=%d\n", This, ref);
768 if(!ref) {
769 assert(!This->apt);
770 HeapFree(GetProcessHeap(), 0, This);
773 return ref;
776 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
778 LocalServer *This = impl_from_IServiceProvider(iface);
779 APARTMENT *apt = COM_CurrentApt();
780 RegisteredClass *iter;
781 HRESULT hres = E_FAIL;
783 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
785 if(!This->apt)
786 return E_UNEXPECTED;
788 EnterCriticalSection(&csRegisteredClassList);
790 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
791 if(iter->apartment_id == apt->oxid
792 && (iter->runContext & CLSCTX_LOCAL_SERVER)
793 && IsEqualGUID(&iter->classIdentifier, guid)) {
794 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
795 break;
799 LeaveCriticalSection( &csRegisteredClassList );
801 return hres;
804 static const IServiceProviderVtbl LocalServerVtbl = {
805 LocalServer_QueryInterface,
806 LocalServer_AddRef,
807 LocalServer_Release,
808 LocalServer_QueryService
811 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
813 HRESULT hres = S_OK;
815 EnterCriticalSection(&apt->cs);
817 if(!apt->local_server) {
818 LocalServer *obj;
820 obj = heap_alloc(sizeof(*obj));
821 if(obj) {
822 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
823 obj->ref = 1;
824 obj->apt = apt;
826 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
827 if(SUCCEEDED(hres)) {
828 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
829 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
830 if(FAILED(hres))
831 IStream_Release(obj->marshal_stream);
834 if(SUCCEEDED(hres))
835 apt->local_server = obj;
836 else
837 heap_free(obj);
838 }else {
839 hres = E_OUTOFMEMORY;
843 if(SUCCEEDED(hres))
844 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
846 LeaveCriticalSection(&apt->cs);
848 if(FAILED(hres))
849 ERR("Failed: %08x\n", hres);
850 return hres;
853 /***********************************************************************
854 * CoRevokeClassObject [OLE32.@]
856 * Removes a class object from the class registry.
858 * PARAMS
859 * dwRegister [I] Cookie returned from CoRegisterClassObject().
861 * RETURNS
862 * Success: S_OK.
863 * Failure: HRESULT code.
865 * NOTES
866 * Must be called from the same apartment that called CoRegisterClassObject(),
867 * otherwise it will fail with RPC_E_WRONG_THREAD.
869 * SEE ALSO
870 * CoRegisterClassObject
872 HRESULT WINAPI CoRevokeClassObject(
873 DWORD dwRegister)
875 HRESULT hr = E_INVALIDARG;
876 RegisteredClass *curClass;
877 APARTMENT *apt;
879 TRACE("(%08x)\n",dwRegister);
881 apt = COM_CurrentApt();
882 if (!apt)
884 ERR("COM was not initialized\n");
885 return CO_E_NOTINITIALIZED;
888 EnterCriticalSection( &csRegisteredClassList );
890 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
893 * Check if we have a match on the cookie.
895 if (curClass->dwCookie == dwRegister)
897 if (curClass->apartment_id == apt->oxid)
899 COM_RevokeRegisteredClassObject(curClass);
900 hr = S_OK;
902 else
904 ERR("called from wrong apartment, should be called from %s\n",
905 wine_dbgstr_longlong(curClass->apartment_id));
906 hr = RPC_E_WRONG_THREAD;
908 break;
912 LeaveCriticalSection( &csRegisteredClassList );
914 return hr;
917 /* frees unused libraries loaded by apartment_getclassobject by calling the
918 * DLL's DllCanUnloadNow entry point */
919 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
921 struct apartment_loaded_dll *entry, *next;
922 EnterCriticalSection(&apt->cs);
923 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
925 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
927 DWORD real_delay = delay;
929 if (real_delay == INFINITE)
931 /* DLLs that return multi-threaded objects aren't unloaded
932 * straight away to cope for programs that have races between
933 * last object destruction and threads in the DLLs that haven't
934 * finished, despite DllCanUnloadNow returning S_OK */
935 if (entry->multi_threaded)
936 real_delay = 10 * 60 * 1000; /* 10 minutes */
937 else
938 real_delay = 0;
941 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
943 list_remove(&entry->entry);
944 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
945 HeapFree(GetProcessHeap(), 0, entry);
947 else
949 entry->unload_time = GetTickCount() + real_delay;
950 if (!entry->unload_time) entry->unload_time = 1;
953 else if (entry->unload_time)
954 entry->unload_time = 0;
956 LeaveCriticalSection(&apt->cs);
959 DWORD apartment_release(struct apartment *apt)
961 DWORD ret;
963 EnterCriticalSection(&csApartment);
965 ret = InterlockedDecrement(&apt->refs);
966 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
967 /* destruction stuff that needs to happen under csApartment CS */
968 if (ret == 0)
970 if (apt == MTA) MTA = NULL;
971 else if (apt == MainApartment) MainApartment = NULL;
972 list_remove(&apt->entry);
975 LeaveCriticalSection(&csApartment);
977 if (ret == 0)
979 struct list *cursor, *cursor2;
981 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
983 if(apt->local_server) {
984 LocalServer *local_server = apt->local_server;
985 LARGE_INTEGER zero;
987 memset(&zero, 0, sizeof(zero));
988 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
989 CoReleaseMarshalData(local_server->marshal_stream);
990 IStream_Release(local_server->marshal_stream);
991 local_server->marshal_stream = NULL;
993 apt->local_server = NULL;
994 local_server->apt = NULL;
995 IServiceProvider_Release(&local_server->IServiceProvider_iface);
998 /* Release the references to the registered class objects */
999 COM_RevokeAllClasses(apt);
1001 /* no locking is needed for this apartment, because no other thread
1002 * can access it at this point */
1004 apartment_disconnectproxies(apt);
1006 if (apt->win) DestroyWindow(apt->win);
1007 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1009 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1011 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1012 /* release the implicit reference given by the fact that the
1013 * stub has external references (it must do since it is in the
1014 * stub manager list in the apartment and all non-apartment users
1015 * must have a ref on the apartment and so it cannot be destroyed).
1017 stub_manager_int_release(stubmgr);
1020 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
1022 struct registered_psclsid *registered_psclsid =
1023 LIST_ENTRY(cursor, struct registered_psclsid, entry);
1025 list_remove(&registered_psclsid->entry);
1026 HeapFree(GetProcessHeap(), 0, registered_psclsid);
1029 /* if this assert fires, then another thread took a reference to a
1030 * stub manager without taking a reference to the containing
1031 * apartment, which it must do. */
1032 assert(list_empty(&apt->stubmgrs));
1034 if (apt->filter) IMessageFilter_Release(apt->filter);
1036 /* free as many unused libraries as possible... */
1037 apartment_freeunusedlibraries(apt, 0);
1039 /* ... and free the memory for the apartment loaded dll entry and
1040 * release the dll list reference without freeing the library for the
1041 * rest */
1042 while ((cursor = list_head(&apt->loaded_dlls)))
1044 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1045 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1046 list_remove(cursor);
1047 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1050 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1051 DeleteCriticalSection(&apt->cs);
1053 HeapFree(GetProcessHeap(), 0, apt);
1056 return ret;
1059 /* The given OXID must be local to this process:
1061 * The ref parameter is here mostly to ensure people remember that
1062 * they get one, you should normally take a ref for thread safety.
1064 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1066 APARTMENT *result = NULL;
1067 struct list *cursor;
1069 EnterCriticalSection(&csApartment);
1070 LIST_FOR_EACH( cursor, &apts )
1072 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1073 if (apt->oxid == oxid)
1075 result = apt;
1076 if (ref) apartment_addref(result);
1077 break;
1080 LeaveCriticalSection(&csApartment);
1082 return result;
1085 /* gets the apartment which has a given creator thread ID. The caller must
1086 * release the reference from the apartment as soon as the apartment pointer
1087 * is no longer required. */
1088 APARTMENT *apartment_findfromtid(DWORD tid)
1090 APARTMENT *result = NULL;
1091 struct list *cursor;
1093 EnterCriticalSection(&csApartment);
1094 LIST_FOR_EACH( cursor, &apts )
1096 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1097 if (apt->tid == tid)
1099 result = apt;
1100 apartment_addref(result);
1101 break;
1104 LeaveCriticalSection(&csApartment);
1106 return result;
1109 /* gets the main apartment if it exists. The caller must
1110 * release the reference from the apartment as soon as the apartment pointer
1111 * is no longer required. */
1112 static APARTMENT *apartment_findmain(void)
1114 APARTMENT *result;
1116 EnterCriticalSection(&csApartment);
1118 result = MainApartment;
1119 if (result) apartment_addref(result);
1121 LeaveCriticalSection(&csApartment);
1123 return result;
1126 /* gets the multi-threaded apartment if it exists. The caller must
1127 * release the reference from the apartment as soon as the apartment pointer
1128 * is no longer required. */
1129 static APARTMENT *apartment_find_multi_threaded(void)
1131 APARTMENT *result = NULL;
1132 struct list *cursor;
1134 EnterCriticalSection(&csApartment);
1136 LIST_FOR_EACH( cursor, &apts )
1138 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1139 if (apt->multi_threaded)
1141 result = apt;
1142 apartment_addref(result);
1143 break;
1147 LeaveCriticalSection(&csApartment);
1148 return result;
1151 /* gets the specified class object by loading the appropriate DLL, if
1152 * necessary and calls the DllGetClassObject function for the DLL */
1153 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1154 BOOL apartment_threaded,
1155 REFCLSID rclsid, REFIID riid, void **ppv)
1157 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1158 HRESULT hr = S_OK;
1159 BOOL found = FALSE;
1160 struct apartment_loaded_dll *apartment_loaded_dll;
1162 if (!strcmpiW(dllpath, wszOle32))
1164 /* we don't need to control the lifetime of this dll, so use the local
1165 * implementation of DllGetClassObject directly */
1166 TRACE("calling ole32!DllGetClassObject\n");
1167 hr = DllGetClassObject(rclsid, riid, ppv);
1169 if (hr != S_OK)
1170 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1172 return hr;
1175 EnterCriticalSection(&apt->cs);
1177 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1178 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1180 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1181 found = TRUE;
1182 break;
1185 if (!found)
1187 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1188 if (!apartment_loaded_dll)
1189 hr = E_OUTOFMEMORY;
1190 if (SUCCEEDED(hr))
1192 apartment_loaded_dll->unload_time = 0;
1193 apartment_loaded_dll->multi_threaded = FALSE;
1194 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1195 if (FAILED(hr))
1196 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1198 if (SUCCEEDED(hr))
1200 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1201 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1205 LeaveCriticalSection(&apt->cs);
1207 if (SUCCEEDED(hr))
1209 /* one component being multi-threaded overrides any number of
1210 * apartment-threaded components */
1211 if (!apartment_threaded)
1212 apartment_loaded_dll->multi_threaded = TRUE;
1214 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1215 /* OK: get the ClassObject */
1216 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1218 if (hr != S_OK)
1219 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1222 return hr;
1225 /***********************************************************************
1226 * COM_RegReadPath [internal]
1228 * Reads a registry value and expands it when necessary
1230 static DWORD COM_RegReadPath(HKEY hkeyroot, WCHAR * dst, DWORD dstlen)
1232 DWORD ret;
1233 DWORD keytype;
1234 WCHAR src[MAX_PATH];
1235 DWORD dwLength = dstlen * sizeof(WCHAR);
1237 if( (ret = RegQueryValueExW(hkeyroot, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1238 if (keytype == REG_EXPAND_SZ) {
1239 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1240 } else {
1241 const WCHAR *quote_start;
1242 quote_start = strchrW(src, '\"');
1243 if (quote_start) {
1244 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1245 if (quote_end) {
1246 memmove(src, quote_start + 1,
1247 (quote_end - quote_start - 1) * sizeof(WCHAR));
1248 src[quote_end - quote_start - 1] = '\0';
1251 lstrcpynW(dst, src, dstlen);
1254 return ret;
1257 struct host_object_params
1259 HKEY hkeydll;
1260 CLSID clsid; /* clsid of object to marshal */
1261 IID iid; /* interface to marshal */
1262 HANDLE event; /* event signalling when ready for multi-threaded case */
1263 HRESULT hr; /* result for multi-threaded case */
1264 IStream *stream; /* stream that the object will be marshaled into */
1265 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1268 static HRESULT apartment_hostobject(struct apartment *apt,
1269 const struct host_object_params *params)
1271 IUnknown *object;
1272 HRESULT hr;
1273 static const LARGE_INTEGER llZero;
1274 WCHAR dllpath[MAX_PATH+1];
1276 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1278 if (COM_RegReadPath(params->hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1280 /* failure: CLSID is not found in registry */
1281 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1282 return REGDB_E_CLASSNOTREG;
1285 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1286 &params->clsid, &params->iid, (void **)&object);
1287 if (FAILED(hr))
1288 return hr;
1290 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1291 if (FAILED(hr))
1292 IUnknown_Release(object);
1293 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1295 return hr;
1298 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1300 switch (msg)
1302 case DM_EXECUTERPC:
1303 RPC_ExecuteCall((struct dispatch_params *)lParam);
1304 return 0;
1305 case DM_HOSTOBJECT:
1306 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1307 default:
1308 return DefWindowProcW(hWnd, msg, wParam, lParam);
1312 struct host_thread_params
1314 COINIT threading_model;
1315 HANDLE ready_event;
1316 HWND apartment_hwnd;
1319 /* thread for hosting an object to allow an object to appear to be created in
1320 * an apartment with an incompatible threading model */
1321 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1323 struct host_thread_params *params = p;
1324 MSG msg;
1325 HRESULT hr;
1326 struct apartment *apt;
1328 TRACE("\n");
1330 hr = CoInitializeEx(NULL, params->threading_model);
1331 if (FAILED(hr)) return hr;
1333 apt = COM_CurrentApt();
1334 if (params->threading_model == COINIT_APARTMENTTHREADED)
1336 apartment_createwindowifneeded(apt);
1337 params->apartment_hwnd = apartment_getwindow(apt);
1339 else
1340 params->apartment_hwnd = NULL;
1342 /* force the message queue to be created before signaling parent thread */
1343 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1345 SetEvent(params->ready_event);
1346 params = NULL; /* can't touch params after here as it may be invalid */
1348 while (GetMessageW(&msg, NULL, 0, 0))
1350 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1352 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1353 obj_params->hr = apartment_hostobject(apt, obj_params);
1354 SetEvent(obj_params->event);
1356 else
1358 TranslateMessage(&msg);
1359 DispatchMessageW(&msg);
1363 TRACE("exiting\n");
1365 CoUninitialize();
1367 return S_OK;
1370 /* finds or creates a host apartment, creates the object inside it and returns
1371 * a proxy to it so that the object can be used in the apartment of the
1372 * caller of this function */
1373 static HRESULT apartment_hostobject_in_hostapt(
1374 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1375 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1377 struct host_object_params params;
1378 HWND apartment_hwnd = NULL;
1379 DWORD apartment_tid = 0;
1380 HRESULT hr;
1382 if (!multi_threaded && main_apartment)
1384 APARTMENT *host_apt = apartment_findmain();
1385 if (host_apt)
1387 apartment_hwnd = apartment_getwindow(host_apt);
1388 apartment_release(host_apt);
1392 if (!apartment_hwnd)
1394 EnterCriticalSection(&apt->cs);
1396 if (!apt->host_apt_tid)
1398 struct host_thread_params thread_params;
1399 HANDLE handles[2];
1400 DWORD wait_value;
1402 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1403 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1404 thread_params.apartment_hwnd = NULL;
1405 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1406 if (!handles[1])
1408 CloseHandle(handles[0]);
1409 LeaveCriticalSection(&apt->cs);
1410 return E_OUTOFMEMORY;
1412 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1413 CloseHandle(handles[0]);
1414 CloseHandle(handles[1]);
1415 if (wait_value == WAIT_OBJECT_0)
1416 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1417 else
1419 LeaveCriticalSection(&apt->cs);
1420 return E_OUTOFMEMORY;
1424 if (multi_threaded || !main_apartment)
1426 apartment_hwnd = apt->host_apt_hwnd;
1427 apartment_tid = apt->host_apt_tid;
1430 LeaveCriticalSection(&apt->cs);
1433 /* another thread may have become the main apartment in the time it took
1434 * us to create the thread for the host apartment */
1435 if (!apartment_hwnd && !multi_threaded && main_apartment)
1437 APARTMENT *host_apt = apartment_findmain();
1438 if (host_apt)
1440 apartment_hwnd = apartment_getwindow(host_apt);
1441 apartment_release(host_apt);
1445 params.hkeydll = hkeydll;
1446 params.clsid = *rclsid;
1447 params.iid = *riid;
1448 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1449 if (FAILED(hr))
1450 return hr;
1451 params.apartment_threaded = !multi_threaded;
1452 if (multi_threaded)
1454 params.hr = S_OK;
1455 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1456 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1457 hr = E_OUTOFMEMORY;
1458 else
1460 WaitForSingleObject(params.event, INFINITE);
1461 hr = params.hr;
1463 CloseHandle(params.event);
1465 else
1467 if (!apartment_hwnd)
1469 ERR("host apartment didn't create window\n");
1470 hr = E_OUTOFMEMORY;
1472 else
1473 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1475 if (SUCCEEDED(hr))
1476 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1477 IStream_Release(params.stream);
1478 return hr;
1481 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1483 WNDCLASSW wclass;
1485 /* Dispatching to the correct thread in an apartment is done through
1486 * window messages rather than RPC transports. When an interface is
1487 * marshalled into another apartment in the same process, a window of the
1488 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1489 * application) is responsible for pumping the message loop in that thread.
1490 * The WM_USER messages which point to the RPCs are then dispatched to
1491 * apartment_wndproc by the user's code from the apartment in which the
1492 * interface was unmarshalled.
1494 memset(&wclass, 0, sizeof(wclass));
1495 wclass.lpfnWndProc = apartment_wndproc;
1496 wclass.hInstance = hProxyDll;
1497 wclass.lpszClassName = wszAptWinClass;
1498 RegisterClassW(&wclass);
1499 return TRUE;
1502 /* create a window for the apartment or return the current one if one has
1503 * already been created */
1504 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1506 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1508 if (apt->multi_threaded)
1509 return S_OK;
1511 if (!apt->win)
1513 HWND hwnd;
1515 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1517 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1518 HWND_MESSAGE, 0, hProxyDll, NULL);
1519 if (!hwnd)
1521 ERR("CreateWindow failed with error %d\n", GetLastError());
1522 return HRESULT_FROM_WIN32(GetLastError());
1524 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1525 /* someone beat us to it */
1526 DestroyWindow(hwnd);
1529 return S_OK;
1532 /* retrieves the window for the main- or apartment-threaded apartment */
1533 HWND apartment_getwindow(const struct apartment *apt)
1535 assert(!apt->multi_threaded);
1536 return apt->win;
1539 void apartment_joinmta(void)
1541 apartment_addref(MTA);
1542 COM_CurrentInfo()->apt = MTA;
1545 static void COM_TlsDestroy(void)
1547 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1548 if (info)
1550 if (info->apt) apartment_release(info->apt);
1551 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1552 if (info->state) IUnknown_Release(info->state);
1553 if (info->spy) IInitializeSpy_Release(info->spy);
1554 if (info->context_token) IObjContext_Release(info->context_token);
1555 HeapFree(GetProcessHeap(), 0, info);
1556 NtCurrentTeb()->ReservedForOle = NULL;
1560 /******************************************************************************
1561 * CoBuildVersion [OLE32.@]
1563 * Gets the build version of the DLL.
1565 * PARAMS
1567 * RETURNS
1568 * Current build version, hiword is majornumber, loword is minornumber
1570 DWORD WINAPI CoBuildVersion(void)
1572 TRACE("Returning version %d, build %d.\n", rmm, rup);
1573 return (rmm<<16)+rup;
1576 /******************************************************************************
1577 * CoRegisterInitializeSpy [OLE32.@]
1579 * Add a Spy that watches CoInitializeEx calls
1581 * PARAMS
1582 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1583 * cookie [II] cookie receiver
1585 * RETURNS
1586 * Success: S_OK if not already initialized, S_FALSE otherwise.
1587 * Failure: HRESULT code.
1589 * SEE ALSO
1590 * CoInitializeEx
1592 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1594 struct oletls *info = COM_CurrentInfo();
1595 HRESULT hr;
1597 TRACE("(%p, %p)\n", spy, cookie);
1599 if (!spy || !cookie || !info)
1601 if (!info)
1602 WARN("Could not allocate tls\n");
1603 return E_INVALIDARG;
1606 if (info->spy)
1608 FIXME("Already registered?\n");
1609 return E_UNEXPECTED;
1612 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1613 if (SUCCEEDED(hr))
1615 cookie->QuadPart = (DWORD_PTR)spy;
1616 return S_OK;
1618 return hr;
1621 /******************************************************************************
1622 * CoRevokeInitializeSpy [OLE32.@]
1624 * Remove a spy that previously watched CoInitializeEx calls
1626 * PARAMS
1627 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1629 * RETURNS
1630 * Success: S_OK if a spy is removed
1631 * Failure: E_INVALIDARG
1633 * SEE ALSO
1634 * CoInitializeEx
1636 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1638 struct oletls *info = COM_CurrentInfo();
1639 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1641 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1642 return E_INVALIDARG;
1644 IInitializeSpy_Release(info->spy);
1645 info->spy = NULL;
1646 return S_OK;
1650 /******************************************************************************
1651 * CoInitialize [OLE32.@]
1653 * Initializes the COM libraries by calling CoInitializeEx with
1654 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1656 * PARAMS
1657 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1659 * RETURNS
1660 * Success: S_OK if not already initialized, S_FALSE otherwise.
1661 * Failure: HRESULT code.
1663 * SEE ALSO
1664 * CoInitializeEx
1666 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1669 * Just delegate to the newer method.
1671 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1674 /******************************************************************************
1675 * CoInitializeEx [OLE32.@]
1677 * Initializes the COM libraries.
1679 * PARAMS
1680 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1681 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1683 * RETURNS
1684 * S_OK if successful,
1685 * S_FALSE if this function was called already.
1686 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1687 * threading model.
1689 * NOTES
1691 * The behavior used to set the IMalloc used for memory management is
1692 * obsolete.
1693 * The dwCoInit parameter must specify one of the following apartment
1694 * threading models:
1695 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1696 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1697 * The parameter may also specify zero or more of the following flags:
1698 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1699 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1701 * SEE ALSO
1702 * CoUninitialize
1704 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1706 struct oletls *info = COM_CurrentInfo();
1707 HRESULT hr = S_OK;
1708 APARTMENT *apt;
1710 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1712 if (lpReserved!=NULL)
1714 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1718 * Check the lock count. If this is the first time going through the initialize
1719 * process, we have to initialize the libraries.
1721 * And crank-up that lock count.
1723 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1726 * Initialize the various COM libraries and data structures.
1728 TRACE("() - Initializing the COM libraries\n");
1730 /* we may need to defer this until after apartment initialisation */
1731 RunningObjectTableImpl_Initialize();
1734 if (info->spy)
1735 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1737 if (!(apt = info->apt))
1739 apt = apartment_get_or_create(dwCoInit);
1740 if (!apt) return E_OUTOFMEMORY;
1742 else if (!apartment_is_model(apt, dwCoInit))
1744 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1745 code then we are probably using the wrong threading model to implement that API. */
1746 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1747 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1748 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1749 return RPC_E_CHANGED_MODE;
1751 else
1752 hr = S_FALSE;
1754 info->inits++;
1756 if (info->spy)
1757 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1759 return hr;
1762 /***********************************************************************
1763 * CoUninitialize [OLE32.@]
1765 * This method will decrement the refcount on the current apartment, freeing
1766 * the resources associated with it if it is the last thread in the apartment.
1767 * If the last apartment is freed, the function will additionally release
1768 * any COM resources associated with the process.
1770 * PARAMS
1772 * RETURNS
1773 * Nothing.
1775 * SEE ALSO
1776 * CoInitializeEx
1778 void WINAPI CoUninitialize(void)
1780 struct oletls * info = COM_CurrentInfo();
1781 LONG lCOMRefCnt;
1783 TRACE("()\n");
1785 /* will only happen on OOM */
1786 if (!info) return;
1788 if (info->spy)
1789 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1791 /* sanity check */
1792 if (!info->inits)
1794 ERR("Mismatched CoUninitialize\n");
1796 if (info->spy)
1797 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1798 return;
1801 if (!--info->inits)
1803 apartment_release(info->apt);
1804 info->apt = NULL;
1808 * Decrease the reference count.
1809 * If we are back to 0 locks on the COM library, make sure we free
1810 * all the associated data structures.
1812 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1813 if (lCOMRefCnt==1)
1815 TRACE("() - Releasing the COM libraries\n");
1817 RunningObjectTableImpl_UnInitialize();
1819 else if (lCOMRefCnt<1) {
1820 ERR( "CoUninitialize() - not CoInitialized.\n" );
1821 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1823 if (info->spy)
1824 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1827 /******************************************************************************
1828 * CoDisconnectObject [OLE32.@]
1830 * Disconnects all connections to this object from remote processes. Dispatches
1831 * pending RPCs while blocking new RPCs from occurring, and then calls
1832 * IMarshal::DisconnectObject on the given object.
1834 * Typically called when the object server is forced to shut down, for instance by
1835 * the user.
1837 * PARAMS
1838 * lpUnk [I] The object whose stub should be disconnected.
1839 * reserved [I] Reserved. Should be set to 0.
1841 * RETURNS
1842 * Success: S_OK.
1843 * Failure: HRESULT code.
1845 * SEE ALSO
1846 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1848 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1850 HRESULT hr;
1851 IMarshal *marshal;
1852 APARTMENT *apt;
1854 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1856 if (!lpUnk) return E_INVALIDARG;
1858 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1859 if (hr == S_OK)
1861 hr = IMarshal_DisconnectObject(marshal, reserved);
1862 IMarshal_Release(marshal);
1863 return hr;
1866 apt = COM_CurrentApt();
1867 if (!apt)
1868 return CO_E_NOTINITIALIZED;
1870 apartment_disconnectobject(apt, lpUnk);
1872 /* Note: native is pretty broken here because it just silently
1873 * fails, without returning an appropriate error code if the object was
1874 * not found, making apps think that the object was disconnected, when
1875 * it actually wasn't */
1877 return S_OK;
1880 /******************************************************************************
1881 * CoCreateGuid [OLE32.@]
1883 * Simply forwards to UuidCreate in RPCRT4.
1885 * PARAMS
1886 * pguid [O] Points to the GUID to initialize.
1888 * RETURNS
1889 * Success: S_OK.
1890 * Failure: HRESULT code.
1892 * SEE ALSO
1893 * UuidCreate
1895 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1897 DWORD status = UuidCreate(pguid);
1898 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1899 return HRESULT_FROM_WIN32( status );
1902 static inline BOOL is_valid_hex(WCHAR c)
1904 if (!(((c >= '0') && (c <= '9')) ||
1905 ((c >= 'a') && (c <= 'f')) ||
1906 ((c >= 'A') && (c <= 'F'))))
1907 return FALSE;
1908 return TRUE;
1911 /******************************************************************************
1912 * CLSIDFromString [OLE32.@]
1913 * IIDFromString [OLE32.@]
1915 * Converts a unique identifier from its string representation into
1916 * the GUID struct.
1918 * PARAMS
1919 * idstr [I] The string representation of the GUID.
1920 * id [O] GUID converted from the string.
1922 * RETURNS
1923 * S_OK on success
1924 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1926 * SEE ALSO
1927 * StringFromCLSID
1929 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1931 int i;
1932 BYTE table[256];
1934 if (!s || s[0]!='{') {
1935 memset( id, 0, sizeof (CLSID) );
1936 if(!s) return S_OK;
1937 return CO_E_CLASSSTRING;
1940 TRACE("%s -> %p\n", debugstr_w(s), id);
1942 /* quick lookup table */
1943 memset(table, 0, 256);
1945 for (i = 0; i < 10; i++) {
1946 table['0' + i] = i;
1948 for (i = 0; i < 6; i++) {
1949 table['A' + i] = i+10;
1950 table['a' + i] = i+10;
1953 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1955 id->Data1 = 0;
1956 for (i = 1; i < 9; i++) {
1957 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1958 id->Data1 = (id->Data1 << 4) | table[s[i]];
1960 if (s[9]!='-') return CO_E_CLASSSTRING;
1962 id->Data2 = 0;
1963 for (i = 10; i < 14; i++) {
1964 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1965 id->Data2 = (id->Data2 << 4) | table[s[i]];
1967 if (s[14]!='-') return CO_E_CLASSSTRING;
1969 id->Data3 = 0;
1970 for (i = 15; i < 19; i++) {
1971 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1972 id->Data3 = (id->Data3 << 4) | table[s[i]];
1974 if (s[19]!='-') return CO_E_CLASSSTRING;
1976 for (i = 20; i < 37; i+=2) {
1977 if (i == 24) {
1978 if (s[i]!='-') return CO_E_CLASSSTRING;
1979 i++;
1981 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1982 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1985 if (s[37] == '}' && s[38] == '\0')
1986 return S_OK;
1988 return CO_E_CLASSSTRING;
1991 /*****************************************************************************/
1993 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1995 HRESULT ret;
1997 if (!id)
1998 return E_INVALIDARG;
2000 ret = __CLSIDFromString(idstr, id);
2001 if(ret != S_OK) { /* It appears a ProgID is also valid */
2002 CLSID tmp_id;
2003 ret = CLSIDFromProgID(idstr, &tmp_id);
2004 if(SUCCEEDED(ret))
2005 *id = tmp_id;
2007 return ret;
2011 /******************************************************************************
2012 * StringFromCLSID [OLE32.@]
2013 * StringFromIID [OLE32.@]
2015 * Converts a GUID into the respective string representation.
2016 * The target string is allocated using the OLE IMalloc.
2018 * PARAMS
2019 * id [I] the GUID to be converted.
2020 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2022 * RETURNS
2023 * S_OK
2024 * E_FAIL
2026 * SEE ALSO
2027 * StringFromGUID2, CLSIDFromString
2029 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2031 HRESULT ret;
2032 LPMALLOC mllc;
2034 if ((ret = CoGetMalloc(0,&mllc))) return ret;
2035 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
2036 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2037 return S_OK;
2040 /******************************************************************************
2041 * StringFromGUID2 [OLE32.@]
2043 * Modified version of StringFromCLSID that allows you to specify max
2044 * buffer size.
2046 * PARAMS
2047 * id [I] GUID to convert to string.
2048 * str [O] Buffer where the result will be stored.
2049 * cmax [I] Size of the buffer in characters.
2051 * RETURNS
2052 * Success: The length of the resulting string in characters.
2053 * Failure: 0.
2055 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2057 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2058 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2059 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2060 '%','0','2','X','%','0','2','X','}',0 };
2061 if (!id || cmax < CHARS_IN_GUID) return 0;
2062 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2063 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2064 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2065 return CHARS_IN_GUID;
2068 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2069 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2071 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2072 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2073 LONG res;
2074 HKEY key;
2076 strcpyW(path, wszCLSIDSlash);
2077 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2078 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2079 if (res == ERROR_FILE_NOT_FOUND)
2080 return REGDB_E_CLASSNOTREG;
2081 else if (res != ERROR_SUCCESS)
2082 return REGDB_E_READREGDB;
2084 if (!keyname)
2086 *subkey = key;
2087 return S_OK;
2090 res = open_classes_key(key, keyname, access, subkey);
2091 RegCloseKey(key);
2092 if (res == ERROR_FILE_NOT_FOUND)
2093 return REGDB_E_KEYMISSING;
2094 else if (res != ERROR_SUCCESS)
2095 return REGDB_E_READREGDB;
2097 return S_OK;
2100 /* open HKCR\\AppId\\{string form of appid clsid} key */
2101 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2103 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2104 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2105 DWORD res;
2106 WCHAR buf[CHARS_IN_GUID];
2107 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2108 DWORD size;
2109 HKEY hkey;
2110 DWORD type;
2111 HRESULT hr;
2113 /* read the AppID value under the class's key */
2114 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2115 if (FAILED(hr))
2116 return hr;
2118 size = sizeof(buf);
2119 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2120 RegCloseKey(hkey);
2121 if (res == ERROR_FILE_NOT_FOUND)
2122 return REGDB_E_KEYMISSING;
2123 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2124 return REGDB_E_READREGDB;
2126 strcpyW(keyname, szAppIdKey);
2127 strcatW(keyname, buf);
2128 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2129 if (res == ERROR_FILE_NOT_FOUND)
2130 return REGDB_E_KEYMISSING;
2131 else if (res != ERROR_SUCCESS)
2132 return REGDB_E_READREGDB;
2134 return S_OK;
2137 /******************************************************************************
2138 * ProgIDFromCLSID [OLE32.@]
2140 * Converts a class id into the respective program ID.
2142 * PARAMS
2143 * clsid [I] Class ID, as found in registry.
2144 * ppszProgID [O] Associated ProgID.
2146 * RETURNS
2147 * S_OK
2148 * E_OUTOFMEMORY
2149 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2151 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2153 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2154 HKEY hkey;
2155 HRESULT ret;
2156 LONG progidlen = 0;
2158 if (!ppszProgID)
2160 ERR("ppszProgId isn't optional\n");
2161 return E_INVALIDARG;
2164 *ppszProgID = NULL;
2165 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2166 if (FAILED(ret))
2167 return ret;
2169 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2170 ret = REGDB_E_CLASSNOTREG;
2172 if (ret == S_OK)
2174 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2175 if (*ppszProgID)
2177 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2178 ret = REGDB_E_CLASSNOTREG;
2179 CoTaskMemFree(*ppszProgID);
2180 *ppszProgID = NULL;
2183 else
2184 ret = E_OUTOFMEMORY;
2187 RegCloseKey(hkey);
2188 return ret;
2191 /******************************************************************************
2192 * CLSIDFromProgID [OLE32.@]
2194 * Converts a program id into the respective GUID.
2196 * PARAMS
2197 * progid [I] Unicode program ID, as found in registry.
2198 * clsid [O] Associated CLSID.
2200 * RETURNS
2201 * Success: S_OK
2202 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2204 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2206 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2207 WCHAR buf2[CHARS_IN_GUID];
2208 LONG buf2len = sizeof(buf2);
2209 HKEY xhkey;
2210 WCHAR *buf;
2212 if (!progid || !clsid)
2214 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2215 return E_INVALIDARG;
2218 /* initialise clsid in case of failure */
2219 memset(clsid, 0, sizeof(*clsid));
2221 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2222 strcpyW( buf, progid );
2223 strcatW( buf, clsidW );
2224 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2226 HeapFree(GetProcessHeap(),0,buf);
2227 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2228 return CO_E_CLASSSTRING;
2230 HeapFree(GetProcessHeap(),0,buf);
2232 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2234 RegCloseKey(xhkey);
2235 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2236 return CO_E_CLASSSTRING;
2238 RegCloseKey(xhkey);
2239 return __CLSIDFromString(buf2,clsid);
2242 /******************************************************************************
2243 * CLSIDFromProgIDEx [OLE32.@]
2245 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2247 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2249 return CLSIDFromProgID(progid, clsid);
2252 /*****************************************************************************
2253 * CoGetPSClsid [OLE32.@]
2255 * Retrieves the CLSID of the proxy/stub factory that implements
2256 * IPSFactoryBuffer for the specified interface.
2258 * PARAMS
2259 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2260 * pclsid [O] Where to store returned proxy/stub CLSID.
2262 * RETURNS
2263 * S_OK
2264 * E_OUTOFMEMORY
2265 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2267 * NOTES
2269 * The standard marshaller activates the object with the CLSID
2270 * returned and uses the CreateProxy and CreateStub methods on its
2271 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2272 * given object.
2274 * CoGetPSClsid determines this CLSID by searching the
2275 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2276 * in the registry and any interface id registered by
2277 * CoRegisterPSClsid within the current process.
2279 * BUGS
2281 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2282 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2283 * considered a bug in native unless an application depends on this (unlikely).
2285 * SEE ALSO
2286 * CoRegisterPSClsid.
2288 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2290 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2291 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2292 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2293 WCHAR value[CHARS_IN_GUID];
2294 LONG len;
2295 HKEY hkey;
2296 APARTMENT *apt = COM_CurrentApt();
2297 struct registered_psclsid *registered_psclsid;
2299 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2301 if (!apt)
2303 ERR("apartment not initialised\n");
2304 return CO_E_NOTINITIALIZED;
2307 if (!pclsid)
2309 ERR("pclsid isn't optional\n");
2310 return E_INVALIDARG;
2313 EnterCriticalSection(&apt->cs);
2315 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2316 if (IsEqualIID(&registered_psclsid->iid, riid))
2318 *pclsid = registered_psclsid->clsid;
2319 LeaveCriticalSection(&apt->cs);
2320 return S_OK;
2323 LeaveCriticalSection(&apt->cs);
2325 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2326 strcpyW(path, wszInterface);
2327 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2328 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2330 /* Open the key.. */
2331 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2333 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2334 return REGDB_E_IIDNOTREG;
2337 /* ... Once we have the key, query the registry to get the
2338 value of CLSID as a string, and convert it into a
2339 proper CLSID structure to be passed back to the app */
2340 len = sizeof(value);
2341 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2343 RegCloseKey(hkey);
2344 return REGDB_E_IIDNOTREG;
2346 RegCloseKey(hkey);
2348 /* We have the CLSID we want back from the registry as a string, so
2349 let's convert it into a CLSID structure */
2350 if (CLSIDFromString(value, pclsid) != NOERROR)
2351 return REGDB_E_IIDNOTREG;
2353 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2354 return S_OK;
2357 /*****************************************************************************
2358 * CoRegisterPSClsid [OLE32.@]
2360 * Register a proxy/stub CLSID for the given interface in the current process
2361 * only.
2363 * PARAMS
2364 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2365 * rclsid [I] CLSID of the proxy/stub.
2367 * RETURNS
2368 * Success: S_OK
2369 * Failure: E_OUTOFMEMORY
2371 * NOTES
2373 * This function does not add anything to the registry and the effects are
2374 * limited to the lifetime of the current process.
2376 * SEE ALSO
2377 * CoGetPSClsid.
2379 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2381 APARTMENT *apt = COM_CurrentApt();
2382 struct registered_psclsid *registered_psclsid;
2384 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2386 if (!apt)
2388 ERR("apartment not initialised\n");
2389 return CO_E_NOTINITIALIZED;
2392 EnterCriticalSection(&apt->cs);
2394 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2395 if (IsEqualIID(&registered_psclsid->iid, riid))
2397 registered_psclsid->clsid = *rclsid;
2398 LeaveCriticalSection(&apt->cs);
2399 return S_OK;
2402 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2403 if (!registered_psclsid)
2405 LeaveCriticalSection(&apt->cs);
2406 return E_OUTOFMEMORY;
2409 registered_psclsid->iid = *riid;
2410 registered_psclsid->clsid = *rclsid;
2411 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2413 LeaveCriticalSection(&apt->cs);
2415 return S_OK;
2419 /***
2420 * COM_GetRegisteredClassObject
2422 * This internal method is used to scan the registered class list to
2423 * find a class object.
2425 * Params:
2426 * rclsid Class ID of the class to find.
2427 * dwClsContext Class context to match.
2428 * ppv [out] returns a pointer to the class object. Complying
2429 * to normal COM usage, this method will increase the
2430 * reference count on this object.
2432 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2433 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2435 HRESULT hr = S_FALSE;
2436 RegisteredClass *curClass;
2438 EnterCriticalSection( &csRegisteredClassList );
2440 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2443 * Check if we have a match on the class ID and context.
2445 if ((apt->oxid == curClass->apartment_id) &&
2446 (dwClsContext & curClass->runContext) &&
2447 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2450 * We have a match, return the pointer to the class object.
2452 *ppUnk = curClass->classObject;
2454 IUnknown_AddRef(curClass->classObject);
2456 hr = S_OK;
2457 break;
2461 LeaveCriticalSection( &csRegisteredClassList );
2463 return hr;
2466 /******************************************************************************
2467 * CoRegisterClassObject [OLE32.@]
2469 * Registers the class object for a given class ID. Servers housed in EXE
2470 * files use this method instead of exporting DllGetClassObject to allow
2471 * other code to connect to their objects.
2473 * PARAMS
2474 * rclsid [I] CLSID of the object to register.
2475 * pUnk [I] IUnknown of the object.
2476 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2477 * flags [I] REGCLS flags indicating how connections are made.
2478 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2480 * RETURNS
2481 * S_OK on success,
2482 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2483 * CO_E_OBJISREG if the object is already registered. We should not return this.
2485 * SEE ALSO
2486 * CoRevokeClassObject, CoGetClassObject
2488 * NOTES
2489 * In-process objects are only registered for the current apartment.
2490 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2491 * in other apartments.
2493 * BUGS
2494 * MSDN claims that multiple interface registrations are legal, but we
2495 * can't do that with our current implementation.
2497 HRESULT WINAPI CoRegisterClassObject(
2498 REFCLSID rclsid,
2499 LPUNKNOWN pUnk,
2500 DWORD dwClsContext,
2501 DWORD flags,
2502 LPDWORD lpdwRegister)
2504 static LONG next_cookie;
2505 RegisteredClass* newClass;
2506 LPUNKNOWN foundObject;
2507 HRESULT hr;
2508 APARTMENT *apt;
2510 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2511 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2513 if ( (lpdwRegister==0) || (pUnk==0) )
2514 return E_INVALIDARG;
2516 apt = COM_CurrentApt();
2517 if (!apt)
2519 ERR("COM was not initialized\n");
2520 return CO_E_NOTINITIALIZED;
2523 *lpdwRegister = 0;
2525 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2526 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2527 if (flags & REGCLS_MULTIPLEUSE)
2528 dwClsContext |= CLSCTX_INPROC_SERVER;
2531 * First, check if the class is already registered.
2532 * If it is, this should cause an error.
2534 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2535 if (hr == S_OK) {
2536 if (flags & REGCLS_MULTIPLEUSE) {
2537 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2538 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2539 IUnknown_Release(foundObject);
2540 return hr;
2542 IUnknown_Release(foundObject);
2543 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2544 return CO_E_OBJISREG;
2547 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2548 if ( newClass == NULL )
2549 return E_OUTOFMEMORY;
2551 newClass->classIdentifier = *rclsid;
2552 newClass->apartment_id = apt->oxid;
2553 newClass->runContext = dwClsContext;
2554 newClass->connectFlags = flags;
2555 newClass->RpcRegistration = NULL;
2557 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2558 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2561 * Since we're making a copy of the object pointer, we have to increase its
2562 * reference count.
2564 newClass->classObject = pUnk;
2565 IUnknown_AddRef(newClass->classObject);
2567 EnterCriticalSection( &csRegisteredClassList );
2568 list_add_tail(&RegisteredClassList, &newClass->entry);
2569 LeaveCriticalSection( &csRegisteredClassList );
2571 *lpdwRegister = newClass->dwCookie;
2573 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2574 IStream *marshal_stream;
2576 hr = get_local_server_stream(apt, &marshal_stream);
2577 if(FAILED(hr))
2578 return hr;
2580 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2581 marshal_stream,
2582 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2583 &newClass->RpcRegistration);
2584 IStream_Release(marshal_stream);
2586 return S_OK;
2589 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2591 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2592 DWORD keytype;
2593 DWORD ret;
2594 DWORD dwLength = len * sizeof(WCHAR);
2596 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2597 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2598 value[0] = '\0';
2601 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2602 REFCLSID rclsid, REFIID riid,
2603 BOOL hostifnecessary, void **ppv)
2605 WCHAR dllpath[MAX_PATH+1];
2606 BOOL apartment_threaded;
2608 if (hostifnecessary)
2610 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2611 static const WCHAR wszFree[] = {'F','r','e','e',0};
2612 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2613 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2615 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2616 /* "Apartment" */
2617 if (!strcmpiW(threading_model, wszApartment))
2619 apartment_threaded = TRUE;
2620 if (apt->multi_threaded)
2621 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2623 /* "Free" */
2624 else if (!strcmpiW(threading_model, wszFree))
2626 apartment_threaded = FALSE;
2627 if (!apt->multi_threaded)
2628 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2630 /* everything except "Apartment", "Free" and "Both" */
2631 else if (strcmpiW(threading_model, wszBoth))
2633 apartment_threaded = TRUE;
2634 /* everything else is main-threaded */
2635 if (threading_model[0])
2636 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2637 debugstr_w(threading_model), debugstr_guid(rclsid));
2639 if (apt->multi_threaded || !apt->main)
2640 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2642 else
2643 apartment_threaded = FALSE;
2645 else
2646 apartment_threaded = !apt->multi_threaded;
2648 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2650 /* failure: CLSID is not found in registry */
2651 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2652 return REGDB_E_CLASSNOTREG;
2655 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2656 rclsid, riid, ppv);
2659 /***********************************************************************
2660 * CoGetClassObject [OLE32.@]
2662 * Creates an object of the specified class.
2664 * PARAMS
2665 * rclsid [I] Class ID to create an instance of.
2666 * dwClsContext [I] Flags to restrict the location of the created instance.
2667 * pServerInfo [I] Optional. Details for connecting to a remote server.
2668 * iid [I] The ID of the interface of the instance to return.
2669 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2671 * RETURNS
2672 * Success: S_OK
2673 * Failure: HRESULT code.
2675 * NOTES
2676 * The dwClsContext parameter can be one or more of the following:
2677 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2678 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2679 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2680 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2682 * SEE ALSO
2683 * CoCreateInstance()
2685 HRESULT WINAPI CoGetClassObject(
2686 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2687 REFIID iid, LPVOID *ppv)
2689 LPUNKNOWN regClassObject;
2690 HRESULT hres = E_UNEXPECTED;
2691 APARTMENT *apt;
2692 BOOL release_apt = FALSE;
2694 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2696 if (!ppv)
2697 return E_INVALIDARG;
2699 *ppv = NULL;
2701 if (!(apt = COM_CurrentApt()))
2703 if (!(apt = apartment_find_multi_threaded()))
2705 ERR("apartment not initialised\n");
2706 return CO_E_NOTINITIALIZED;
2708 release_apt = TRUE;
2711 if (pServerInfo) {
2712 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2713 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2717 * First, try and see if we can't match the class ID with one of the
2718 * registered classes.
2720 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2721 &regClassObject))
2723 /* Get the required interface from the retrieved pointer. */
2724 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2727 * Since QI got another reference on the pointer, we want to release the
2728 * one we already have. If QI was unsuccessful, this will release the object. This
2729 * is good since we are not returning it in the "out" parameter.
2731 IUnknown_Release(regClassObject);
2732 if (release_apt) apartment_release(apt);
2733 return hres;
2736 /* First try in-process server */
2737 if (CLSCTX_INPROC_SERVER & dwClsContext)
2739 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2740 HKEY hkey;
2742 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2744 if (release_apt) apartment_release(apt);
2745 return FTMarshalCF_Create(iid, ppv);
2748 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2749 if (FAILED(hres))
2751 if (hres == REGDB_E_CLASSNOTREG)
2752 ERR("class %s not registered\n", debugstr_guid(rclsid));
2753 else if (hres == REGDB_E_KEYMISSING)
2755 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2756 hres = REGDB_E_CLASSNOTREG;
2760 if (SUCCEEDED(hres))
2762 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2763 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2764 RegCloseKey(hkey);
2767 /* return if we got a class, otherwise fall through to one of the
2768 * other types */
2769 if (SUCCEEDED(hres))
2771 if (release_apt) apartment_release(apt);
2772 return hres;
2776 /* Next try in-process handler */
2777 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2779 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2780 HKEY hkey;
2782 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2783 if (FAILED(hres))
2785 if (hres == REGDB_E_CLASSNOTREG)
2786 ERR("class %s not registered\n", debugstr_guid(rclsid));
2787 else if (hres == REGDB_E_KEYMISSING)
2789 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2790 hres = REGDB_E_CLASSNOTREG;
2794 if (SUCCEEDED(hres))
2796 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2797 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2798 RegCloseKey(hkey);
2801 /* return if we got a class, otherwise fall through to one of the
2802 * other types */
2803 if (SUCCEEDED(hres))
2805 if (release_apt) apartment_release(apt);
2806 return hres;
2809 if (release_apt) apartment_release(apt);
2811 /* Next try out of process */
2812 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2814 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2815 if (SUCCEEDED(hres))
2816 return hres;
2819 /* Finally try remote: this requires networked DCOM (a lot of work) */
2820 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2822 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2823 hres = REGDB_E_CLASSNOTREG;
2826 if (FAILED(hres))
2827 ERR("no class object %s could be created for context 0x%x\n",
2828 debugstr_guid(rclsid), dwClsContext);
2829 return hres;
2832 /***********************************************************************
2833 * CoResumeClassObjects (OLE32.@)
2835 * Resumes all class objects registered with REGCLS_SUSPENDED.
2837 * RETURNS
2838 * Success: S_OK.
2839 * Failure: HRESULT code.
2841 HRESULT WINAPI CoResumeClassObjects(void)
2843 FIXME("stub\n");
2844 return S_OK;
2847 /***********************************************************************
2848 * CoCreateInstance [OLE32.@]
2850 * Creates an instance of the specified class.
2852 * PARAMS
2853 * rclsid [I] Class ID to create an instance of.
2854 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2855 * dwClsContext [I] Flags to restrict the location of the created instance.
2856 * iid [I] The ID of the interface of the instance to return.
2857 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2859 * RETURNS
2860 * Success: S_OK
2861 * Failure: HRESULT code.
2863 * NOTES
2864 * The dwClsContext parameter can be one or more of the following:
2865 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2866 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2867 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2868 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2870 * Aggregation is the concept of deferring the IUnknown of an object to another
2871 * object. This allows a separate object to behave as though it was part of
2872 * the object and to allow this the pUnkOuter parameter can be set. Note that
2873 * not all objects support having an outer of unknown.
2875 * SEE ALSO
2876 * CoGetClassObject()
2878 HRESULT WINAPI CoCreateInstance(
2879 REFCLSID rclsid,
2880 LPUNKNOWN pUnkOuter,
2881 DWORD dwClsContext,
2882 REFIID iid,
2883 LPVOID *ppv)
2885 HRESULT hres;
2886 LPCLASSFACTORY lpclf = 0;
2887 APARTMENT *apt;
2889 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2890 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2892 if (ppv==0)
2893 return E_POINTER;
2895 *ppv = 0;
2897 if (!(apt = COM_CurrentApt()))
2899 if (!(apt = apartment_find_multi_threaded()))
2901 ERR("apartment not initialised\n");
2902 return CO_E_NOTINITIALIZED;
2904 apartment_release(apt);
2908 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2910 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
2912 IGlobalInterfaceTable *git = get_std_git();
2913 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
2914 if (hres != S_OK) return hres;
2916 TRACE("Retrieved GIT (%p)\n", *ppv);
2917 return S_OK;
2920 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2921 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2924 * Get a class factory to construct the object we want.
2926 hres = CoGetClassObject(rclsid,
2927 dwClsContext,
2928 NULL,
2929 &IID_IClassFactory,
2930 (LPVOID)&lpclf);
2932 if (FAILED(hres))
2933 return hres;
2936 * Create the object and don't forget to release the factory
2938 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2939 IClassFactory_Release(lpclf);
2940 if (FAILED(hres))
2942 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2943 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2944 else
2945 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2946 debugstr_guid(iid),
2947 debugstr_guid(rclsid),hres);
2950 return hres;
2953 /***********************************************************************
2954 * CoCreateInstanceEx [OLE32.@]
2956 HRESULT WINAPI CoCreateInstanceEx(
2957 REFCLSID rclsid,
2958 LPUNKNOWN pUnkOuter,
2959 DWORD dwClsContext,
2960 COSERVERINFO* pServerInfo,
2961 ULONG cmq,
2962 MULTI_QI* pResults)
2964 IUnknown* pUnk = NULL;
2965 HRESULT hr;
2966 ULONG index;
2967 ULONG successCount = 0;
2970 * Sanity check
2972 if ( (cmq==0) || (pResults==NULL))
2973 return E_INVALIDARG;
2975 if (pServerInfo!=NULL)
2976 FIXME("() non-NULL pServerInfo not supported!\n");
2979 * Initialize all the "out" parameters.
2981 for (index = 0; index < cmq; index++)
2983 pResults[index].pItf = NULL;
2984 pResults[index].hr = E_NOINTERFACE;
2988 * Get the object and get its IUnknown pointer.
2990 hr = CoCreateInstance(rclsid,
2991 pUnkOuter,
2992 dwClsContext,
2993 &IID_IUnknown,
2994 (VOID**)&pUnk);
2996 if (hr != S_OK)
2997 return hr;
3000 * Then, query for all the interfaces requested.
3002 for (index = 0; index < cmq; index++)
3004 pResults[index].hr = IUnknown_QueryInterface(pUnk,
3005 pResults[index].pIID,
3006 (VOID**)&(pResults[index].pItf));
3008 if (pResults[index].hr == S_OK)
3009 successCount++;
3013 * Release our temporary unknown pointer.
3015 IUnknown_Release(pUnk);
3017 if (successCount == 0)
3018 return E_NOINTERFACE;
3020 if (successCount!=cmq)
3021 return CO_S_NOTALLINTERFACES;
3023 return S_OK;
3026 /***********************************************************************
3027 * CoLoadLibrary (OLE32.@)
3029 * Loads a library.
3031 * PARAMS
3032 * lpszLibName [I] Path to library.
3033 * bAutoFree [I] Whether the library should automatically be freed.
3035 * RETURNS
3036 * Success: Handle to loaded library.
3037 * Failure: NULL.
3039 * SEE ALSO
3040 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3042 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3044 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3046 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3049 /***********************************************************************
3050 * CoFreeLibrary [OLE32.@]
3052 * Unloads a library from memory.
3054 * PARAMS
3055 * hLibrary [I] Handle to library to unload.
3057 * RETURNS
3058 * Nothing
3060 * SEE ALSO
3061 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3063 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3065 FreeLibrary(hLibrary);
3069 /***********************************************************************
3070 * CoFreeAllLibraries [OLE32.@]
3072 * Function for backwards compatibility only. Does nothing.
3074 * RETURNS
3075 * Nothing.
3077 * SEE ALSO
3078 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3080 void WINAPI CoFreeAllLibraries(void)
3082 /* NOP */
3085 /***********************************************************************
3086 * CoFreeUnusedLibrariesEx [OLE32.@]
3088 * Frees any previously unused libraries whose delay has expired and marks
3089 * currently unused libraries for unloading. Unused are identified as those that
3090 * return S_OK from their DllCanUnloadNow function.
3092 * PARAMS
3093 * dwUnloadDelay [I] Unload delay in milliseconds.
3094 * dwReserved [I] Reserved. Set to 0.
3096 * RETURNS
3097 * Nothing.
3099 * SEE ALSO
3100 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3102 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3104 struct apartment *apt = COM_CurrentApt();
3105 if (!apt)
3107 ERR("apartment not initialised\n");
3108 return;
3111 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3114 /***********************************************************************
3115 * CoFreeUnusedLibraries [OLE32.@]
3117 * Frees any unused libraries. Unused are identified as those that return
3118 * S_OK from their DllCanUnloadNow function.
3120 * RETURNS
3121 * Nothing.
3123 * SEE ALSO
3124 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3126 void WINAPI CoFreeUnusedLibraries(void)
3128 CoFreeUnusedLibrariesEx(INFINITE, 0);
3131 /***********************************************************************
3132 * CoFileTimeNow [OLE32.@]
3134 * Retrieves the current time in FILETIME format.
3136 * PARAMS
3137 * lpFileTime [O] The current time.
3139 * RETURNS
3140 * S_OK.
3142 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3144 GetSystemTimeAsFileTime( lpFileTime );
3145 return S_OK;
3148 /******************************************************************************
3149 * CoLockObjectExternal [OLE32.@]
3151 * Increments or decrements the external reference count of a stub object.
3153 * PARAMS
3154 * pUnk [I] Stub object.
3155 * fLock [I] If TRUE then increments the external ref-count,
3156 * otherwise decrements.
3157 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3158 * calling CoDisconnectObject.
3160 * RETURNS
3161 * Success: S_OK.
3162 * Failure: HRESULT code.
3164 * NOTES
3165 * If fLock is TRUE and an object is passed in that doesn't have a stub
3166 * manager then a new stub manager is created for the object.
3168 HRESULT WINAPI CoLockObjectExternal(
3169 LPUNKNOWN pUnk,
3170 BOOL fLock,
3171 BOOL fLastUnlockReleases)
3173 struct stub_manager *stubmgr;
3174 struct apartment *apt;
3176 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3177 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3179 apt = COM_CurrentApt();
3180 if (!apt) return CO_E_NOTINITIALIZED;
3182 stubmgr = get_stub_manager_from_object(apt, pUnk);
3184 if (stubmgr)
3186 if (fLock)
3187 stub_manager_ext_addref(stubmgr, 1, FALSE);
3188 else
3189 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3191 stub_manager_int_release(stubmgr);
3193 return S_OK;
3195 else if (fLock)
3197 stubmgr = new_stub_manager(apt, pUnk);
3199 if (stubmgr)
3201 stub_manager_ext_addref(stubmgr, 1, FALSE);
3202 stub_manager_int_release(stubmgr);
3205 return S_OK;
3207 else
3209 WARN("stub object not found %p\n", pUnk);
3210 /* Note: native is pretty broken here because it just silently
3211 * fails, without returning an appropriate error code, making apps
3212 * think that the object was disconnected, when it actually wasn't */
3213 return S_OK;
3217 /***********************************************************************
3218 * CoInitializeWOW (OLE32.@)
3220 * WOW equivalent of CoInitialize?
3222 * PARAMS
3223 * x [I] Unknown.
3224 * y [I] Unknown.
3226 * RETURNS
3227 * Unknown.
3229 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3231 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3232 return 0;
3235 /***********************************************************************
3236 * CoGetState [OLE32.@]
3238 * Retrieves the thread state object previously stored by CoSetState().
3240 * PARAMS
3241 * ppv [I] Address where pointer to object will be stored.
3243 * RETURNS
3244 * Success: S_OK.
3245 * Failure: E_OUTOFMEMORY.
3247 * NOTES
3248 * Crashes on all invalid ppv addresses, including NULL.
3249 * If the function returns a non-NULL object then the caller must release its
3250 * reference on the object when the object is no longer required.
3252 * SEE ALSO
3253 * CoSetState().
3255 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3257 struct oletls *info = COM_CurrentInfo();
3258 if (!info) return E_OUTOFMEMORY;
3260 *ppv = NULL;
3262 if (info->state)
3264 IUnknown_AddRef(info->state);
3265 *ppv = info->state;
3266 TRACE("apt->state=%p\n", info->state);
3269 return S_OK;
3272 /***********************************************************************
3273 * CoSetState [OLE32.@]
3275 * Sets the thread state object.
3277 * PARAMS
3278 * pv [I] Pointer to state object to be stored.
3280 * NOTES
3281 * The system keeps a reference on the object while the object stored.
3283 * RETURNS
3284 * Success: S_OK.
3285 * Failure: E_OUTOFMEMORY.
3287 HRESULT WINAPI CoSetState(IUnknown * pv)
3289 struct oletls *info = COM_CurrentInfo();
3290 if (!info) return E_OUTOFMEMORY;
3292 if (pv) IUnknown_AddRef(pv);
3294 if (info->state)
3296 TRACE("-- release %p now\n", info->state);
3297 IUnknown_Release(info->state);
3300 info->state = pv;
3302 return S_OK;
3306 /******************************************************************************
3307 * CoTreatAsClass [OLE32.@]
3309 * Sets the TreatAs value of a class.
3311 * PARAMS
3312 * clsidOld [I] Class to set TreatAs value on.
3313 * clsidNew [I] The class the clsidOld should be treated as.
3315 * RETURNS
3316 * Success: S_OK.
3317 * Failure: HRESULT code.
3319 * SEE ALSO
3320 * CoGetTreatAsClass
3322 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3324 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3325 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3326 HKEY hkey = NULL;
3327 WCHAR szClsidNew[CHARS_IN_GUID];
3328 HRESULT res = S_OK;
3329 WCHAR auto_treat_as[CHARS_IN_GUID];
3330 LONG auto_treat_as_size = sizeof(auto_treat_as);
3331 CLSID id;
3333 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3334 if (FAILED(res))
3335 goto done;
3336 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3338 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3339 CLSIDFromString(auto_treat_as, &id) == S_OK)
3341 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3343 res = REGDB_E_WRITEREGDB;
3344 goto done;
3347 else
3349 RegDeleteKeyW(hkey, wszTreatAs);
3350 goto done;
3353 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3354 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3356 res = REGDB_E_WRITEREGDB;
3357 goto done;
3360 done:
3361 if (hkey) RegCloseKey(hkey);
3362 return res;
3365 /******************************************************************************
3366 * CoGetTreatAsClass [OLE32.@]
3368 * Gets the TreatAs value of a class.
3370 * PARAMS
3371 * clsidOld [I] Class to get the TreatAs value of.
3372 * clsidNew [I] The class the clsidOld should be treated as.
3374 * RETURNS
3375 * Success: S_OK.
3376 * Failure: HRESULT code.
3378 * SEE ALSO
3379 * CoSetTreatAsClass
3381 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3383 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3384 HKEY hkey = NULL;
3385 WCHAR szClsidNew[CHARS_IN_GUID];
3386 HRESULT res = S_OK;
3387 LONG len = sizeof(szClsidNew);
3389 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3390 *clsidNew = *clsidOld; /* copy over old value */
3392 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3393 if (FAILED(res))
3395 res = S_FALSE;
3396 goto done;
3398 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3400 res = S_FALSE;
3401 goto done;
3403 res = CLSIDFromString(szClsidNew,clsidNew);
3404 if (FAILED(res))
3405 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3406 done:
3407 if (hkey) RegCloseKey(hkey);
3408 return res;
3411 /******************************************************************************
3412 * CoGetCurrentProcess [OLE32.@]
3414 * Gets the current process ID.
3416 * RETURNS
3417 * The current process ID.
3419 * NOTES
3420 * Is DWORD really the correct return type for this function?
3422 DWORD WINAPI CoGetCurrentProcess(void)
3424 return GetCurrentProcessId();
3427 /******************************************************************************
3428 * CoRegisterMessageFilter [OLE32.@]
3430 * Registers a message filter.
3432 * PARAMS
3433 * lpMessageFilter [I] Pointer to interface.
3434 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3436 * RETURNS
3437 * Success: S_OK.
3438 * Failure: HRESULT code.
3440 * NOTES
3441 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3442 * lpMessageFilter removes the message filter.
3444 * If lplpMessageFilter is not NULL the previous message filter will be
3445 * returned in the memory pointer to this parameter and the caller is
3446 * responsible for releasing the object.
3448 * The current thread be in an apartment otherwise the function will crash.
3450 HRESULT WINAPI CoRegisterMessageFilter(
3451 LPMESSAGEFILTER lpMessageFilter,
3452 LPMESSAGEFILTER *lplpMessageFilter)
3454 struct apartment *apt;
3455 IMessageFilter *lpOldMessageFilter;
3457 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3459 apt = COM_CurrentApt();
3461 /* can't set a message filter in a multi-threaded apartment */
3462 if (!apt || apt->multi_threaded)
3464 WARN("can't set message filter in MTA or uninitialized apt\n");
3465 return CO_E_NOT_SUPPORTED;
3468 if (lpMessageFilter)
3469 IMessageFilter_AddRef(lpMessageFilter);
3471 EnterCriticalSection(&apt->cs);
3473 lpOldMessageFilter = apt->filter;
3474 apt->filter = lpMessageFilter;
3476 LeaveCriticalSection(&apt->cs);
3478 if (lplpMessageFilter)
3479 *lplpMessageFilter = lpOldMessageFilter;
3480 else if (lpOldMessageFilter)
3481 IMessageFilter_Release(lpOldMessageFilter);
3483 return S_OK;
3486 /***********************************************************************
3487 * CoIsOle1Class [OLE32.@]
3489 * Determines whether the specified class an OLE v1 class.
3491 * PARAMS
3492 * clsid [I] Class to test.
3494 * RETURNS
3495 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3497 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3499 FIXME("%s\n", debugstr_guid(clsid));
3500 return FALSE;
3503 /***********************************************************************
3504 * IsEqualGUID [OLE32.@]
3506 * Compares two Unique Identifiers.
3508 * PARAMS
3509 * rguid1 [I] The first GUID to compare.
3510 * rguid2 [I] The other GUID to compare.
3512 * RETURNS
3513 * TRUE if equal
3515 #undef IsEqualGUID
3516 BOOL WINAPI IsEqualGUID(
3517 REFGUID rguid1,
3518 REFGUID rguid2)
3520 return !memcmp(rguid1,rguid2,sizeof(GUID));
3523 /***********************************************************************
3524 * CoInitializeSecurity [OLE32.@]
3526 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3527 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3528 void* pReserved1, DWORD dwAuthnLevel,
3529 DWORD dwImpLevel, void* pReserved2,
3530 DWORD dwCapabilities, void* pReserved3)
3532 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3533 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3534 dwCapabilities, pReserved3);
3535 return S_OK;
3538 /***********************************************************************
3539 * CoSuspendClassObjects [OLE32.@]
3541 * Suspends all registered class objects to prevent further requests coming in
3542 * for those objects.
3544 * RETURNS
3545 * Success: S_OK.
3546 * Failure: HRESULT code.
3548 HRESULT WINAPI CoSuspendClassObjects(void)
3550 FIXME("\n");
3551 return S_OK;
3554 /***********************************************************************
3555 * CoAddRefServerProcess [OLE32.@]
3557 * Helper function for incrementing the reference count of a local-server
3558 * process.
3560 * RETURNS
3561 * New reference count.
3563 * SEE ALSO
3564 * CoReleaseServerProcess().
3566 ULONG WINAPI CoAddRefServerProcess(void)
3568 ULONG refs;
3570 TRACE("\n");
3572 EnterCriticalSection(&csRegisteredClassList);
3573 refs = ++s_COMServerProcessReferences;
3574 LeaveCriticalSection(&csRegisteredClassList);
3576 TRACE("refs before: %d\n", refs - 1);
3578 return refs;
3581 /***********************************************************************
3582 * CoReleaseServerProcess [OLE32.@]
3584 * Helper function for decrementing the reference count of a local-server
3585 * process.
3587 * RETURNS
3588 * New reference count.
3590 * NOTES
3591 * When reference count reaches 0, this function suspends all registered
3592 * classes so no new connections are accepted.
3594 * SEE ALSO
3595 * CoAddRefServerProcess(), CoSuspendClassObjects().
3597 ULONG WINAPI CoReleaseServerProcess(void)
3599 ULONG refs;
3601 TRACE("\n");
3603 EnterCriticalSection(&csRegisteredClassList);
3605 refs = --s_COMServerProcessReferences;
3606 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3608 LeaveCriticalSection(&csRegisteredClassList);
3610 TRACE("refs after: %d\n", refs);
3612 return refs;
3615 /***********************************************************************
3616 * CoIsHandlerConnected [OLE32.@]
3618 * Determines whether a proxy is connected to a remote stub.
3620 * PARAMS
3621 * pUnk [I] Pointer to object that may or may not be connected.
3623 * RETURNS
3624 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3625 * FALSE otherwise.
3627 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3629 FIXME("%p\n", pUnk);
3631 return TRUE;
3634 /***********************************************************************
3635 * CoAllowSetForegroundWindow [OLE32.@]
3638 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3640 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3641 return S_OK;
3644 /***********************************************************************
3645 * CoQueryProxyBlanket [OLE32.@]
3647 * Retrieves the security settings being used by a proxy.
3649 * PARAMS
3650 * pProxy [I] Pointer to the proxy object.
3651 * pAuthnSvc [O] The type of authentication service.
3652 * pAuthzSvc [O] The type of authorization service.
3653 * ppServerPrincName [O] Optional. The server prinicple name.
3654 * pAuthnLevel [O] The authentication level.
3655 * pImpLevel [O] The impersonation level.
3656 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3657 * pCapabilities [O] Flags affecting the security behaviour.
3659 * RETURNS
3660 * Success: S_OK.
3661 * Failure: HRESULT code.
3663 * SEE ALSO
3664 * CoCopyProxy, CoSetProxyBlanket.
3666 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3667 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3668 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3670 IClientSecurity *pCliSec;
3671 HRESULT hr;
3673 TRACE("%p\n", pProxy);
3675 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3676 if (SUCCEEDED(hr))
3678 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3679 pAuthzSvc, ppServerPrincName,
3680 pAuthnLevel, pImpLevel, ppAuthInfo,
3681 pCapabilities);
3682 IClientSecurity_Release(pCliSec);
3685 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3686 return hr;
3689 /***********************************************************************
3690 * CoSetProxyBlanket [OLE32.@]
3692 * Sets the security settings for a proxy.
3694 * PARAMS
3695 * pProxy [I] Pointer to the proxy object.
3696 * AuthnSvc [I] The type of authentication service.
3697 * AuthzSvc [I] The type of authorization service.
3698 * pServerPrincName [I] The server prinicple name.
3699 * AuthnLevel [I] The authentication level.
3700 * ImpLevel [I] The impersonation level.
3701 * pAuthInfo [I] Information specific to the authorization/authentication service.
3702 * Capabilities [I] Flags affecting the security behaviour.
3704 * RETURNS
3705 * Success: S_OK.
3706 * Failure: HRESULT code.
3708 * SEE ALSO
3709 * CoQueryProxyBlanket, CoCopyProxy.
3711 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3712 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3713 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3715 IClientSecurity *pCliSec;
3716 HRESULT hr;
3718 TRACE("%p\n", pProxy);
3720 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3721 if (SUCCEEDED(hr))
3723 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3724 AuthzSvc, pServerPrincName,
3725 AuthnLevel, ImpLevel, pAuthInfo,
3726 Capabilities);
3727 IClientSecurity_Release(pCliSec);
3730 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3731 return hr;
3734 /***********************************************************************
3735 * CoCopyProxy [OLE32.@]
3737 * Copies a proxy.
3739 * PARAMS
3740 * pProxy [I] Pointer to the proxy object.
3741 * ppCopy [O] Copy of the proxy.
3743 * RETURNS
3744 * Success: S_OK.
3745 * Failure: HRESULT code.
3747 * SEE ALSO
3748 * CoQueryProxyBlanket, CoSetProxyBlanket.
3750 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3752 IClientSecurity *pCliSec;
3753 HRESULT hr;
3755 TRACE("%p\n", pProxy);
3757 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3758 if (SUCCEEDED(hr))
3760 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3761 IClientSecurity_Release(pCliSec);
3764 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3765 return hr;
3769 /***********************************************************************
3770 * CoGetCallContext [OLE32.@]
3772 * Gets the context of the currently executing server call in the current
3773 * thread.
3775 * PARAMS
3776 * riid [I] Context interface to return.
3777 * ppv [O] Pointer to memory that will receive the context on return.
3779 * RETURNS
3780 * Success: S_OK.
3781 * Failure: HRESULT code.
3783 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3785 struct oletls *info = COM_CurrentInfo();
3787 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3789 if (!info)
3790 return E_OUTOFMEMORY;
3792 if (!info->call_state)
3793 return RPC_E_CALL_COMPLETE;
3795 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3798 /***********************************************************************
3799 * CoSwitchCallContext [OLE32.@]
3801 * Switches the context of the currently executing server call in the current
3802 * thread.
3804 * PARAMS
3805 * pObject [I] Pointer to new context object
3806 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3808 * RETURNS
3809 * Success: S_OK.
3810 * Failure: HRESULT code.
3812 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3814 struct oletls *info = COM_CurrentInfo();
3816 TRACE("(%p, %p)\n", pObject, ppOldObject);
3818 if (!info)
3819 return E_OUTOFMEMORY;
3821 *ppOldObject = info->call_state;
3822 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3824 return S_OK;
3827 /***********************************************************************
3828 * CoQueryClientBlanket [OLE32.@]
3830 * Retrieves the authentication information about the client of the currently
3831 * executing server call in the current thread.
3833 * PARAMS
3834 * pAuthnSvc [O] Optional. The type of authentication service.
3835 * pAuthzSvc [O] Optional. The type of authorization service.
3836 * pServerPrincName [O] Optional. The server prinicple name.
3837 * pAuthnLevel [O] Optional. The authentication level.
3838 * pImpLevel [O] Optional. The impersonation level.
3839 * pPrivs [O] Optional. Information about the privileges of the client.
3840 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3842 * RETURNS
3843 * Success: S_OK.
3844 * Failure: HRESULT code.
3846 * SEE ALSO
3847 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3849 HRESULT WINAPI CoQueryClientBlanket(
3850 DWORD *pAuthnSvc,
3851 DWORD *pAuthzSvc,
3852 OLECHAR **pServerPrincName,
3853 DWORD *pAuthnLevel,
3854 DWORD *pImpLevel,
3855 RPC_AUTHZ_HANDLE *pPrivs,
3856 DWORD *pCapabilities)
3858 IServerSecurity *pSrvSec;
3859 HRESULT hr;
3861 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3862 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3863 pPrivs, pCapabilities);
3865 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3866 if (SUCCEEDED(hr))
3868 hr = IServerSecurity_QueryBlanket(
3869 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3870 pImpLevel, pPrivs, pCapabilities);
3871 IServerSecurity_Release(pSrvSec);
3874 return hr;
3877 /***********************************************************************
3878 * CoImpersonateClient [OLE32.@]
3880 * Impersonates the client of the currently executing server call in the
3881 * current thread.
3883 * PARAMS
3884 * None.
3886 * RETURNS
3887 * Success: S_OK.
3888 * Failure: HRESULT code.
3890 * NOTES
3891 * If this function fails then the current thread will not be impersonating
3892 * the client and all actions will take place on behalf of the server.
3893 * Therefore, it is important to check the return value from this function.
3895 * SEE ALSO
3896 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3898 HRESULT WINAPI CoImpersonateClient(void)
3900 IServerSecurity *pSrvSec;
3901 HRESULT hr;
3903 TRACE("\n");
3905 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3906 if (SUCCEEDED(hr))
3908 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3909 IServerSecurity_Release(pSrvSec);
3912 return hr;
3915 /***********************************************************************
3916 * CoRevertToSelf [OLE32.@]
3918 * Ends the impersonation of the client of the currently executing server
3919 * call in the current thread.
3921 * PARAMS
3922 * None.
3924 * RETURNS
3925 * Success: S_OK.
3926 * Failure: HRESULT code.
3928 * SEE ALSO
3929 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3931 HRESULT WINAPI CoRevertToSelf(void)
3933 IServerSecurity *pSrvSec;
3934 HRESULT hr;
3936 TRACE("\n");
3938 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3939 if (SUCCEEDED(hr))
3941 hr = IServerSecurity_RevertToSelf(pSrvSec);
3942 IServerSecurity_Release(pSrvSec);
3945 return hr;
3948 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3950 /* first try to retrieve messages for incoming COM calls to the apartment window */
3951 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3952 /* next retrieve other messages necessary for the app to remain responsive */
3953 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3954 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3957 /***********************************************************************
3958 * CoWaitForMultipleHandles [OLE32.@]
3960 * Waits for one or more handles to become signaled.
3962 * PARAMS
3963 * dwFlags [I] Flags. See notes.
3964 * dwTimeout [I] Timeout in milliseconds.
3965 * cHandles [I] Number of handles pointed to by pHandles.
3966 * pHandles [I] Handles to wait for.
3967 * lpdwindex [O] Index of handle that was signaled.
3969 * RETURNS
3970 * Success: S_OK.
3971 * Failure: RPC_S_CALLPENDING on timeout.
3973 * NOTES
3975 * The dwFlags parameter can be zero or more of the following:
3976 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3977 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3979 * SEE ALSO
3980 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3982 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3983 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3985 HRESULT hr = S_OK;
3986 DWORD start_time = GetTickCount();
3987 APARTMENT *apt = COM_CurrentApt();
3988 BOOL message_loop = apt && !apt->multi_threaded;
3990 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3991 pHandles, lpdwindex);
3993 while (TRUE)
3995 DWORD now = GetTickCount();
3996 DWORD res;
3998 if (now - start_time > dwTimeout)
4000 hr = RPC_S_CALLPENDING;
4001 break;
4004 if (message_loop)
4006 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4007 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4009 TRACE("waiting for rpc completion or window message\n");
4011 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4012 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4013 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4015 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4017 MSG msg;
4018 int count = 0;
4020 /* call message filter */
4022 if (COM_CurrentApt()->filter)
4024 PENDINGTYPE pendingtype =
4025 COM_CurrentInfo()->pending_call_count_server ?
4026 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4027 DWORD be_handled = IMessageFilter_MessagePending(
4028 COM_CurrentApt()->filter, 0 /* FIXME */,
4029 now - start_time, pendingtype);
4030 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4031 switch (be_handled)
4033 case PENDINGMSG_CANCELCALL:
4034 WARN("call canceled\n");
4035 hr = RPC_E_CALL_CANCELED;
4036 break;
4037 case PENDINGMSG_WAITNOPROCESS:
4038 case PENDINGMSG_WAITDEFPROCESS:
4039 default:
4040 /* FIXME: MSDN is very vague about the difference
4041 * between WAITNOPROCESS and WAITDEFPROCESS - there
4042 * appears to be none, so it is possibly a left-over
4043 * from the 16-bit world. */
4044 break;
4048 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4049 * so after processing 100 messages we go back to checking the wait handles */
4050 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4052 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4053 TranslateMessage(&msg);
4054 DispatchMessageW(&msg);
4055 if (msg.message == WM_QUIT)
4057 TRACE("resending WM_QUIT to outer message loop\n");
4058 PostQuitMessage(msg.wParam);
4059 /* no longer need to process messages */
4060 message_loop = FALSE;
4061 break;
4064 continue;
4067 else
4069 TRACE("waiting for rpc completion\n");
4071 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4072 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4073 (dwFlags & COWAIT_ALERTABLE) != 0);
4076 switch (res)
4078 case WAIT_TIMEOUT:
4079 hr = RPC_S_CALLPENDING;
4080 break;
4081 case WAIT_FAILED:
4082 hr = HRESULT_FROM_WIN32( GetLastError() );
4083 break;
4084 default:
4085 *lpdwindex = res;
4086 break;
4088 break;
4090 TRACE("-- 0x%08x\n", hr);
4091 return hr;
4095 /***********************************************************************
4096 * CoGetObject [OLE32.@]
4098 * Gets the object named by converting the name to a moniker and binding to it.
4100 * PARAMS
4101 * pszName [I] String representing the object.
4102 * pBindOptions [I] Parameters affecting the binding to the named object.
4103 * riid [I] Interface to bind to on the objecct.
4104 * ppv [O] On output, the interface riid of the object represented
4105 * by pszName.
4107 * RETURNS
4108 * Success: S_OK.
4109 * Failure: HRESULT code.
4111 * SEE ALSO
4112 * MkParseDisplayName.
4114 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4115 REFIID riid, void **ppv)
4117 IBindCtx *pbc;
4118 HRESULT hr;
4120 *ppv = NULL;
4122 hr = CreateBindCtx(0, &pbc);
4123 if (SUCCEEDED(hr))
4125 if (pBindOptions)
4126 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4128 if (SUCCEEDED(hr))
4130 ULONG chEaten;
4131 IMoniker *pmk;
4133 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4134 if (SUCCEEDED(hr))
4136 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4137 IMoniker_Release(pmk);
4141 IBindCtx_Release(pbc);
4143 return hr;
4146 /***********************************************************************
4147 * CoRegisterChannelHook [OLE32.@]
4149 * Registers a process-wide hook that is called during ORPC calls.
4151 * PARAMS
4152 * guidExtension [I] GUID of the channel hook to register.
4153 * pChannelHook [I] Channel hook object to register.
4155 * RETURNS
4156 * Success: S_OK.
4157 * Failure: HRESULT code.
4159 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4161 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4163 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4166 typedef struct Context
4168 IComThreadingInfo IComThreadingInfo_iface;
4169 IContextCallback IContextCallback_iface;
4170 IObjContext IObjContext_iface;
4171 LONG refs;
4172 APTTYPE apttype;
4173 } Context;
4175 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4177 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4180 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4182 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4185 static inline Context *impl_from_IObjContext( IObjContext *iface )
4187 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4190 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4192 *ppv = NULL;
4194 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4195 IsEqualIID(riid, &IID_IUnknown))
4197 *ppv = &iface->IComThreadingInfo_iface;
4199 else if (IsEqualIID(riid, &IID_IContextCallback))
4201 *ppv = &iface->IContextCallback_iface;
4203 else if (IsEqualIID(riid, &IID_IObjContext))
4205 *ppv = &iface->IObjContext_iface;
4208 if (*ppv)
4210 IUnknown_AddRef((IUnknown*)*ppv);
4211 return S_OK;
4214 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4215 return E_NOINTERFACE;
4218 static ULONG Context_AddRef(Context *This)
4220 return InterlockedIncrement(&This->refs);
4223 static ULONG Context_Release(Context *This)
4225 ULONG refs = InterlockedDecrement(&This->refs);
4226 if (!refs)
4227 HeapFree(GetProcessHeap(), 0, This);
4228 return refs;
4231 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4233 Context *This = impl_from_IComThreadingInfo(iface);
4234 return Context_QueryInterface(This, riid, ppv);
4237 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4239 Context *This = impl_from_IComThreadingInfo(iface);
4240 return Context_AddRef(This);
4243 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4245 Context *This = impl_from_IComThreadingInfo(iface);
4246 return Context_Release(This);
4249 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4251 Context *This = impl_from_IComThreadingInfo(iface);
4253 TRACE("(%p)\n", apttype);
4255 *apttype = This->apttype;
4256 return S_OK;
4259 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4261 Context *This = impl_from_IComThreadingInfo(iface);
4263 TRACE("(%p)\n", thdtype);
4265 switch (This->apttype)
4267 case APTTYPE_STA:
4268 case APTTYPE_MAINSTA:
4269 *thdtype = THDTYPE_PROCESSMESSAGES;
4270 break;
4271 default:
4272 *thdtype = THDTYPE_BLOCKMESSAGES;
4273 break;
4275 return S_OK;
4278 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4280 FIXME("(%p): stub\n", logical_thread_id);
4281 return E_NOTIMPL;
4284 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4286 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4287 return E_NOTIMPL;
4290 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4292 Context_CTI_QueryInterface,
4293 Context_CTI_AddRef,
4294 Context_CTI_Release,
4295 Context_CTI_GetCurrentApartmentType,
4296 Context_CTI_GetCurrentThreadType,
4297 Context_CTI_GetCurrentLogicalThreadId,
4298 Context_CTI_SetCurrentLogicalThreadId
4301 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4303 Context *This = impl_from_IContextCallback(iface);
4304 return Context_QueryInterface(This, riid, ppv);
4307 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4309 Context *This = impl_from_IContextCallback(iface);
4310 return Context_AddRef(This);
4313 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4315 Context *This = impl_from_IContextCallback(iface);
4316 return Context_Release(This);
4319 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4320 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4322 Context *This = impl_from_IContextCallback(iface);
4324 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4325 return E_NOTIMPL;
4328 static const IContextCallbackVtbl Context_Callback_Vtbl =
4330 Context_CC_QueryInterface,
4331 Context_CC_AddRef,
4332 Context_CC_Release,
4333 Context_CC_ContextCallback
4336 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4338 Context *This = impl_from_IObjContext(iface);
4339 return Context_QueryInterface(This, riid, ppv);
4342 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4344 Context *This = impl_from_IObjContext(iface);
4345 return Context_AddRef(This);
4348 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4350 Context *This = impl_from_IObjContext(iface);
4351 return Context_Release(This);
4354 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4356 Context *This = impl_from_IObjContext(iface);
4358 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4359 return E_NOTIMPL;
4362 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4364 Context *This = impl_from_IObjContext(iface);
4366 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4367 return E_NOTIMPL;
4370 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4372 Context *This = impl_from_IObjContext(iface);
4374 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4375 return E_NOTIMPL;
4378 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4380 Context *This = impl_from_IObjContext(iface);
4382 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4383 return E_NOTIMPL;
4386 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4388 Context *This = impl_from_IObjContext(iface);
4389 FIXME("(%p/%p)\n", This, iface);
4392 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4394 Context *This = impl_from_IObjContext(iface);
4395 FIXME("(%p/%p)\n", This, iface);
4398 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4400 Context *This = impl_from_IObjContext(iface);
4401 FIXME("(%p/%p)\n", This, iface);
4404 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4406 Context *This = impl_from_IObjContext(iface);
4407 FIXME("(%p/%p)\n", This, iface);
4410 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4412 Context *This = impl_from_IObjContext(iface);
4413 FIXME("(%p/%p)\n", This, iface);
4416 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4418 Context *This = impl_from_IObjContext(iface);
4419 FIXME("(%p/%p)\n", This, iface);
4422 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4424 Context *This = impl_from_IObjContext(iface);
4425 FIXME("(%p/%p)\n", This, iface);
4428 static const IObjContextVtbl Context_Object_Vtbl =
4430 Context_OC_QueryInterface,
4431 Context_OC_AddRef,
4432 Context_OC_Release,
4433 Context_OC_SetProperty,
4434 Context_OC_RemoveProperty,
4435 Context_OC_GetProperty,
4436 Context_OC_EnumContextProps,
4437 Context_OC_Reserved1,
4438 Context_OC_Reserved2,
4439 Context_OC_Reserved3,
4440 Context_OC_Reserved4,
4441 Context_OC_Reserved5,
4442 Context_OC_Reserved6,
4443 Context_OC_Reserved7
4446 /***********************************************************************
4447 * CoGetObjectContext [OLE32.@]
4449 * Retrieves an object associated with the current context (i.e. apartment).
4451 * PARAMS
4452 * riid [I] ID of the interface of the object to retrieve.
4453 * ppv [O] Address where object will be stored on return.
4455 * RETURNS
4456 * Success: S_OK.
4457 * Failure: HRESULT code.
4459 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4461 APARTMENT *apt = COM_CurrentApt();
4462 Context *context;
4463 HRESULT hr;
4465 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4467 *ppv = NULL;
4468 if (!apt)
4470 if (!(apt = apartment_find_multi_threaded()))
4472 ERR("apartment not initialised\n");
4473 return CO_E_NOTINITIALIZED;
4475 apartment_release(apt);
4478 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4479 if (!context)
4480 return E_OUTOFMEMORY;
4482 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4483 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4484 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4485 context->refs = 1;
4486 if (apt->multi_threaded)
4487 context->apttype = APTTYPE_MTA;
4488 else if (apt->main)
4489 context->apttype = APTTYPE_MAINSTA;
4490 else
4491 context->apttype = APTTYPE_STA;
4493 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4494 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4496 return hr;
4500 /***********************************************************************
4501 * CoGetContextToken [OLE32.@]
4503 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4505 struct oletls *info = COM_CurrentInfo();
4507 TRACE("(%p)\n", token);
4509 if (!info)
4510 return E_OUTOFMEMORY;
4512 if (!info->apt)
4514 APARTMENT *apt;
4515 if (!(apt = apartment_find_multi_threaded()))
4517 ERR("apartment not initialised\n");
4518 return CO_E_NOTINITIALIZED;
4520 apartment_release(apt);
4523 if (!token)
4524 return E_POINTER;
4526 if (!info->context_token)
4528 HRESULT hr;
4529 IObjContext *ctx;
4531 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4532 if (FAILED(hr)) return hr;
4533 info->context_token = ctx;
4536 *token = (ULONG_PTR)info->context_token;
4537 TRACE("apt->context_token=%p\n", info->context_token);
4539 return S_OK;
4542 /***********************************************************************
4543 * CoGetDefaultContext [OLE32.@]
4545 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4547 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4548 return E_NOINTERFACE;
4551 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4553 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4554 HKEY hkey;
4555 HRESULT hres;
4557 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4558 if (SUCCEEDED(hres))
4560 WCHAR dllpath[MAX_PATH+1];
4562 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4564 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4565 if (!strcmpiW(dllpath, wszOle32))
4567 RegCloseKey(hkey);
4568 return HandlerCF_Create(rclsid, riid, ppv);
4571 else
4572 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4573 RegCloseKey(hkey);
4576 return CLASS_E_CLASSNOTAVAILABLE;
4579 /***********************************************************************
4580 * DllMain (OLE32.@)
4582 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
4584 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
4586 switch(fdwReason) {
4587 case DLL_PROCESS_ATTACH:
4588 hProxyDll = hinstDLL;
4589 break;
4591 case DLL_PROCESS_DETACH:
4592 if (reserved) break;
4593 release_std_git();
4594 UnregisterClassW( wszAptWinClass, hProxyDll );
4595 RPC_UnregisterAllChannelHooks();
4596 COMPOBJ_DllList_Free();
4597 DeleteCriticalSection(&csRegisteredClassList);
4598 DeleteCriticalSection(&csApartment);
4599 break;
4601 case DLL_THREAD_DETACH:
4602 COM_TlsDestroy();
4603 break;
4605 return TRUE;
4608 /***********************************************************************
4609 * DllRegisterServer (OLE32.@)
4611 HRESULT WINAPI DllRegisterServer(void)
4613 return OLE32_DllRegisterServer();
4616 /***********************************************************************
4617 * DllUnregisterServer (OLE32.@)
4619 HRESULT WINAPI DllUnregisterServer(void)
4621 return OLE32_DllUnregisterServer();