ole32: Test HRESULT values using proper success code.
[wine.git] / dlls / ole32 / compobj.c
blob45376d10e5a167b1800dac534f45f54ae82f34fd
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 /* create a window for the apartment or return the current one if one has
1482 * already been created */
1483 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1485 if (apt->multi_threaded)
1486 return S_OK;
1488 if (!apt->win)
1490 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1491 0, 0, 0, 0,
1492 HWND_MESSAGE, 0, hProxyDll, NULL);
1493 if (!hwnd)
1495 ERR("CreateWindow failed with error %d\n", GetLastError());
1496 return HRESULT_FROM_WIN32(GetLastError());
1498 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1499 /* someone beat us to it */
1500 DestroyWindow(hwnd);
1503 return S_OK;
1506 /* retrieves the window for the main- or apartment-threaded apartment */
1507 HWND apartment_getwindow(const struct apartment *apt)
1509 assert(!apt->multi_threaded);
1510 return apt->win;
1513 void apartment_joinmta(void)
1515 apartment_addref(MTA);
1516 COM_CurrentInfo()->apt = MTA;
1519 static void COMPOBJ_InitProcess( void )
1521 WNDCLASSW wclass;
1523 /* Dispatching to the correct thread in an apartment is done through
1524 * window messages rather than RPC transports. When an interface is
1525 * marshalled into another apartment in the same process, a window of the
1526 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1527 * application) is responsible for pumping the message loop in that thread.
1528 * The WM_USER messages which point to the RPCs are then dispatched to
1529 * apartment_wndproc by the user's code from the apartment in which the
1530 * interface was unmarshalled.
1532 memset(&wclass, 0, sizeof(wclass));
1533 wclass.lpfnWndProc = apartment_wndproc;
1534 wclass.hInstance = hProxyDll;
1535 wclass.lpszClassName = wszAptWinClass;
1536 RegisterClassW(&wclass);
1539 static void COMPOBJ_UninitProcess( void )
1541 UnregisterClassW(wszAptWinClass, hProxyDll);
1544 static void COM_TlsDestroy(void)
1546 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1547 if (info)
1549 if (info->apt) apartment_release(info->apt);
1550 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1551 if (info->state) IUnknown_Release(info->state);
1552 if (info->spy) IInitializeSpy_Release(info->spy);
1553 if (info->context_token) IObjContext_Release(info->context_token);
1554 HeapFree(GetProcessHeap(), 0, info);
1555 NtCurrentTeb()->ReservedForOle = NULL;
1559 /******************************************************************************
1560 * CoBuildVersion [OLE32.@]
1562 * Gets the build version of the DLL.
1564 * PARAMS
1566 * RETURNS
1567 * Current build version, hiword is majornumber, loword is minornumber
1569 DWORD WINAPI CoBuildVersion(void)
1571 TRACE("Returning version %d, build %d.\n", rmm, rup);
1572 return (rmm<<16)+rup;
1575 /******************************************************************************
1576 * CoRegisterInitializeSpy [OLE32.@]
1578 * Add a Spy that watches CoInitializeEx calls
1580 * PARAMS
1581 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1582 * cookie [II] cookie receiver
1584 * RETURNS
1585 * Success: S_OK if not already initialized, S_FALSE otherwise.
1586 * Failure: HRESULT code.
1588 * SEE ALSO
1589 * CoInitializeEx
1591 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1593 struct oletls *info = COM_CurrentInfo();
1594 HRESULT hr;
1596 TRACE("(%p, %p)\n", spy, cookie);
1598 if (!spy || !cookie || !info)
1600 if (!info)
1601 WARN("Could not allocate tls\n");
1602 return E_INVALIDARG;
1605 if (info->spy)
1607 FIXME("Already registered?\n");
1608 return E_UNEXPECTED;
1611 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1612 if (SUCCEEDED(hr))
1614 cookie->QuadPart = (DWORD_PTR)spy;
1615 return S_OK;
1617 return hr;
1620 /******************************************************************************
1621 * CoRevokeInitializeSpy [OLE32.@]
1623 * Remove a spy that previously watched CoInitializeEx calls
1625 * PARAMS
1626 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1628 * RETURNS
1629 * Success: S_OK if a spy is removed
1630 * Failure: E_INVALIDARG
1632 * SEE ALSO
1633 * CoInitializeEx
1635 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1637 struct oletls *info = COM_CurrentInfo();
1638 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1640 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1641 return E_INVALIDARG;
1643 IInitializeSpy_Release(info->spy);
1644 info->spy = NULL;
1645 return S_OK;
1649 /******************************************************************************
1650 * CoInitialize [OLE32.@]
1652 * Initializes the COM libraries by calling CoInitializeEx with
1653 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1655 * PARAMS
1656 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1658 * RETURNS
1659 * Success: S_OK if not already initialized, S_FALSE otherwise.
1660 * Failure: HRESULT code.
1662 * SEE ALSO
1663 * CoInitializeEx
1665 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1668 * Just delegate to the newer method.
1670 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1673 /******************************************************************************
1674 * CoInitializeEx [OLE32.@]
1676 * Initializes the COM libraries.
1678 * PARAMS
1679 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1680 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1682 * RETURNS
1683 * S_OK if successful,
1684 * S_FALSE if this function was called already.
1685 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1686 * threading model.
1688 * NOTES
1690 * The behavior used to set the IMalloc used for memory management is
1691 * obsolete.
1692 * The dwCoInit parameter must specify one of the following apartment
1693 * threading models:
1694 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1695 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1696 * The parameter may also specify zero or more of the following flags:
1697 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1698 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1700 * SEE ALSO
1701 * CoUninitialize
1703 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1705 struct oletls *info = COM_CurrentInfo();
1706 HRESULT hr = S_OK;
1707 APARTMENT *apt;
1709 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1711 if (lpReserved!=NULL)
1713 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1717 * Check the lock count. If this is the first time going through the initialize
1718 * process, we have to initialize the libraries.
1720 * And crank-up that lock count.
1722 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1725 * Initialize the various COM libraries and data structures.
1727 TRACE("() - Initializing the COM libraries\n");
1729 /* we may need to defer this until after apartment initialisation */
1730 RunningObjectTableImpl_Initialize();
1733 if (info->spy)
1734 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1736 if (!(apt = info->apt))
1738 apt = apartment_get_or_create(dwCoInit);
1739 if (!apt) return E_OUTOFMEMORY;
1741 else if (!apartment_is_model(apt, dwCoInit))
1743 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1744 code then we are probably using the wrong threading model to implement that API. */
1745 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1746 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1747 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1748 return RPC_E_CHANGED_MODE;
1750 else
1751 hr = S_FALSE;
1753 info->inits++;
1755 if (info->spy)
1756 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1758 return hr;
1761 /***********************************************************************
1762 * CoUninitialize [OLE32.@]
1764 * This method will decrement the refcount on the current apartment, freeing
1765 * the resources associated with it if it is the last thread in the apartment.
1766 * If the last apartment is freed, the function will additionally release
1767 * any COM resources associated with the process.
1769 * PARAMS
1771 * RETURNS
1772 * Nothing.
1774 * SEE ALSO
1775 * CoInitializeEx
1777 void WINAPI CoUninitialize(void)
1779 struct oletls * info = COM_CurrentInfo();
1780 LONG lCOMRefCnt;
1782 TRACE("()\n");
1784 /* will only happen on OOM */
1785 if (!info) return;
1787 if (info->spy)
1788 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1790 /* sanity check */
1791 if (!info->inits)
1793 ERR("Mismatched CoUninitialize\n");
1795 if (info->spy)
1796 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1797 return;
1800 if (!--info->inits)
1802 apartment_release(info->apt);
1803 info->apt = NULL;
1807 * Decrease the reference count.
1808 * If we are back to 0 locks on the COM library, make sure we free
1809 * all the associated data structures.
1811 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1812 if (lCOMRefCnt==1)
1814 TRACE("() - Releasing the COM libraries\n");
1816 RunningObjectTableImpl_UnInitialize();
1818 else if (lCOMRefCnt<1) {
1819 ERR( "CoUninitialize() - not CoInitialized.\n" );
1820 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1822 if (info->spy)
1823 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1826 /******************************************************************************
1827 * CoDisconnectObject [OLE32.@]
1829 * Disconnects all connections to this object from remote processes. Dispatches
1830 * pending RPCs while blocking new RPCs from occurring, and then calls
1831 * IMarshal::DisconnectObject on the given object.
1833 * Typically called when the object server is forced to shut down, for instance by
1834 * the user.
1836 * PARAMS
1837 * lpUnk [I] The object whose stub should be disconnected.
1838 * reserved [I] Reserved. Should be set to 0.
1840 * RETURNS
1841 * Success: S_OK.
1842 * Failure: HRESULT code.
1844 * SEE ALSO
1845 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1847 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1849 HRESULT hr;
1850 IMarshal *marshal;
1851 APARTMENT *apt;
1853 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1855 if (!lpUnk) return E_INVALIDARG;
1857 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1858 if (hr == S_OK)
1860 hr = IMarshal_DisconnectObject(marshal, reserved);
1861 IMarshal_Release(marshal);
1862 return hr;
1865 apt = COM_CurrentApt();
1866 if (!apt)
1867 return CO_E_NOTINITIALIZED;
1869 apartment_disconnectobject(apt, lpUnk);
1871 /* Note: native is pretty broken here because it just silently
1872 * fails, without returning an appropriate error code if the object was
1873 * not found, making apps think that the object was disconnected, when
1874 * it actually wasn't */
1876 return S_OK;
1879 /******************************************************************************
1880 * CoCreateGuid [OLE32.@]
1882 * Simply forwards to UuidCreate in RPCRT4.
1884 * PARAMS
1885 * pguid [O] Points to the GUID to initialize.
1887 * RETURNS
1888 * Success: S_OK.
1889 * Failure: HRESULT code.
1891 * SEE ALSO
1892 * UuidCreate
1894 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1896 DWORD status = UuidCreate(pguid);
1897 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1898 return HRESULT_FROM_WIN32( status );
1901 static inline BOOL is_valid_hex(WCHAR c)
1903 if (!(((c >= '0') && (c <= '9')) ||
1904 ((c >= 'a') && (c <= 'f')) ||
1905 ((c >= 'A') && (c <= 'F'))))
1906 return FALSE;
1907 return TRUE;
1910 /******************************************************************************
1911 * CLSIDFromString [OLE32.@]
1912 * IIDFromString [OLE32.@]
1914 * Converts a unique identifier from its string representation into
1915 * the GUID struct.
1917 * PARAMS
1918 * idstr [I] The string representation of the GUID.
1919 * id [O] GUID converted from the string.
1921 * RETURNS
1922 * S_OK on success
1923 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1925 * SEE ALSO
1926 * StringFromCLSID
1928 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1930 int i;
1931 BYTE table[256];
1933 if (!s || s[0]!='{') {
1934 memset( id, 0, sizeof (CLSID) );
1935 if(!s) return S_OK;
1936 return CO_E_CLASSSTRING;
1939 TRACE("%s -> %p\n", debugstr_w(s), id);
1941 /* quick lookup table */
1942 memset(table, 0, 256);
1944 for (i = 0; i < 10; i++) {
1945 table['0' + i] = i;
1947 for (i = 0; i < 6; i++) {
1948 table['A' + i] = i+10;
1949 table['a' + i] = i+10;
1952 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1954 id->Data1 = 0;
1955 for (i = 1; i < 9; i++) {
1956 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1957 id->Data1 = (id->Data1 << 4) | table[s[i]];
1959 if (s[9]!='-') return CO_E_CLASSSTRING;
1961 id->Data2 = 0;
1962 for (i = 10; i < 14; i++) {
1963 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1964 id->Data2 = (id->Data2 << 4) | table[s[i]];
1966 if (s[14]!='-') return CO_E_CLASSSTRING;
1968 id->Data3 = 0;
1969 for (i = 15; i < 19; i++) {
1970 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1971 id->Data3 = (id->Data3 << 4) | table[s[i]];
1973 if (s[19]!='-') return CO_E_CLASSSTRING;
1975 for (i = 20; i < 37; i+=2) {
1976 if (i == 24) {
1977 if (s[i]!='-') return CO_E_CLASSSTRING;
1978 i++;
1980 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1981 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1984 if (s[37] == '}' && s[38] == '\0')
1985 return S_OK;
1987 return CO_E_CLASSSTRING;
1990 /*****************************************************************************/
1992 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1994 HRESULT ret;
1996 if (!id)
1997 return E_INVALIDARG;
1999 ret = __CLSIDFromString(idstr, id);
2000 if(ret != S_OK) { /* It appears a ProgID is also valid */
2001 CLSID tmp_id;
2002 ret = CLSIDFromProgID(idstr, &tmp_id);
2003 if(SUCCEEDED(ret))
2004 *id = tmp_id;
2006 return ret;
2010 /******************************************************************************
2011 * StringFromCLSID [OLE32.@]
2012 * StringFromIID [OLE32.@]
2014 * Converts a GUID into the respective string representation.
2015 * The target string is allocated using the OLE IMalloc.
2017 * PARAMS
2018 * id [I] the GUID to be converted.
2019 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2021 * RETURNS
2022 * S_OK
2023 * E_FAIL
2025 * SEE ALSO
2026 * StringFromGUID2, CLSIDFromString
2028 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2030 HRESULT ret;
2031 LPMALLOC mllc;
2033 if ((ret = CoGetMalloc(0,&mllc))) return ret;
2034 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
2035 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2036 return S_OK;
2039 /******************************************************************************
2040 * StringFromGUID2 [OLE32.@]
2042 * Modified version of StringFromCLSID that allows you to specify max
2043 * buffer size.
2045 * PARAMS
2046 * id [I] GUID to convert to string.
2047 * str [O] Buffer where the result will be stored.
2048 * cmax [I] Size of the buffer in characters.
2050 * RETURNS
2051 * Success: The length of the resulting string in characters.
2052 * Failure: 0.
2054 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2056 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2057 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2058 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2059 '%','0','2','X','%','0','2','X','}',0 };
2060 if (!id || cmax < CHARS_IN_GUID) return 0;
2061 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2062 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2063 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2064 return CHARS_IN_GUID;
2067 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2068 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2070 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2071 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2072 LONG res;
2073 HKEY key;
2075 strcpyW(path, wszCLSIDSlash);
2076 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2077 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2078 if (res == ERROR_FILE_NOT_FOUND)
2079 return REGDB_E_CLASSNOTREG;
2080 else if (res != ERROR_SUCCESS)
2081 return REGDB_E_READREGDB;
2083 if (!keyname)
2085 *subkey = key;
2086 return S_OK;
2089 res = open_classes_key(key, keyname, access, subkey);
2090 RegCloseKey(key);
2091 if (res == ERROR_FILE_NOT_FOUND)
2092 return REGDB_E_KEYMISSING;
2093 else if (res != ERROR_SUCCESS)
2094 return REGDB_E_READREGDB;
2096 return S_OK;
2099 /* open HKCR\\AppId\\{string form of appid clsid} key */
2100 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2102 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2103 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2104 DWORD res;
2105 WCHAR buf[CHARS_IN_GUID];
2106 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2107 DWORD size;
2108 HKEY hkey;
2109 DWORD type;
2110 HRESULT hr;
2112 /* read the AppID value under the class's key */
2113 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2114 if (FAILED(hr))
2115 return hr;
2117 size = sizeof(buf);
2118 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2119 RegCloseKey(hkey);
2120 if (res == ERROR_FILE_NOT_FOUND)
2121 return REGDB_E_KEYMISSING;
2122 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2123 return REGDB_E_READREGDB;
2125 strcpyW(keyname, szAppIdKey);
2126 strcatW(keyname, buf);
2127 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2128 if (res == ERROR_FILE_NOT_FOUND)
2129 return REGDB_E_KEYMISSING;
2130 else if (res != ERROR_SUCCESS)
2131 return REGDB_E_READREGDB;
2133 return S_OK;
2136 /******************************************************************************
2137 * ProgIDFromCLSID [OLE32.@]
2139 * Converts a class id into the respective program ID.
2141 * PARAMS
2142 * clsid [I] Class ID, as found in registry.
2143 * ppszProgID [O] Associated ProgID.
2145 * RETURNS
2146 * S_OK
2147 * E_OUTOFMEMORY
2148 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2150 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2152 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2153 HKEY hkey;
2154 HRESULT ret;
2155 LONG progidlen = 0;
2157 if (!ppszProgID)
2159 ERR("ppszProgId isn't optional\n");
2160 return E_INVALIDARG;
2163 *ppszProgID = NULL;
2164 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2165 if (FAILED(ret))
2166 return ret;
2168 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2169 ret = REGDB_E_CLASSNOTREG;
2171 if (ret == S_OK)
2173 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2174 if (*ppszProgID)
2176 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2177 ret = REGDB_E_CLASSNOTREG;
2178 CoTaskMemFree(*ppszProgID);
2179 *ppszProgID = NULL;
2182 else
2183 ret = E_OUTOFMEMORY;
2186 RegCloseKey(hkey);
2187 return ret;
2190 /******************************************************************************
2191 * CLSIDFromProgID [OLE32.@]
2193 * Converts a program id into the respective GUID.
2195 * PARAMS
2196 * progid [I] Unicode program ID, as found in registry.
2197 * clsid [O] Associated CLSID.
2199 * RETURNS
2200 * Success: S_OK
2201 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2203 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2205 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2206 WCHAR buf2[CHARS_IN_GUID];
2207 LONG buf2len = sizeof(buf2);
2208 HKEY xhkey;
2209 WCHAR *buf;
2211 if (!progid || !clsid)
2213 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2214 return E_INVALIDARG;
2217 /* initialise clsid in case of failure */
2218 memset(clsid, 0, sizeof(*clsid));
2220 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2221 strcpyW( buf, progid );
2222 strcatW( buf, clsidW );
2223 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2225 HeapFree(GetProcessHeap(),0,buf);
2226 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2227 return CO_E_CLASSSTRING;
2229 HeapFree(GetProcessHeap(),0,buf);
2231 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2233 RegCloseKey(xhkey);
2234 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2235 return CO_E_CLASSSTRING;
2237 RegCloseKey(xhkey);
2238 return __CLSIDFromString(buf2,clsid);
2241 /******************************************************************************
2242 * CLSIDFromProgIDEx [OLE32.@]
2244 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2246 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2248 return CLSIDFromProgID(progid, clsid);
2251 /*****************************************************************************
2252 * CoGetPSClsid [OLE32.@]
2254 * Retrieves the CLSID of the proxy/stub factory that implements
2255 * IPSFactoryBuffer for the specified interface.
2257 * PARAMS
2258 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2259 * pclsid [O] Where to store returned proxy/stub CLSID.
2261 * RETURNS
2262 * S_OK
2263 * E_OUTOFMEMORY
2264 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2266 * NOTES
2268 * The standard marshaller activates the object with the CLSID
2269 * returned and uses the CreateProxy and CreateStub methods on its
2270 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2271 * given object.
2273 * CoGetPSClsid determines this CLSID by searching the
2274 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2275 * in the registry and any interface id registered by
2276 * CoRegisterPSClsid within the current process.
2278 * BUGS
2280 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2281 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2282 * considered a bug in native unless an application depends on this (unlikely).
2284 * SEE ALSO
2285 * CoRegisterPSClsid.
2287 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2289 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2290 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2291 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2292 WCHAR value[CHARS_IN_GUID];
2293 LONG len;
2294 HKEY hkey;
2295 APARTMENT *apt = COM_CurrentApt();
2296 struct registered_psclsid *registered_psclsid;
2298 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2300 if (!apt)
2302 ERR("apartment not initialised\n");
2303 return CO_E_NOTINITIALIZED;
2306 if (!pclsid)
2308 ERR("pclsid isn't optional\n");
2309 return E_INVALIDARG;
2312 EnterCriticalSection(&apt->cs);
2314 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2315 if (IsEqualIID(&registered_psclsid->iid, riid))
2317 *pclsid = registered_psclsid->clsid;
2318 LeaveCriticalSection(&apt->cs);
2319 return S_OK;
2322 LeaveCriticalSection(&apt->cs);
2324 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2325 strcpyW(path, wszInterface);
2326 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2327 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2329 /* Open the key.. */
2330 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2332 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2333 return REGDB_E_IIDNOTREG;
2336 /* ... Once we have the key, query the registry to get the
2337 value of CLSID as a string, and convert it into a
2338 proper CLSID structure to be passed back to the app */
2339 len = sizeof(value);
2340 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2342 RegCloseKey(hkey);
2343 return REGDB_E_IIDNOTREG;
2345 RegCloseKey(hkey);
2347 /* We have the CLSID we want back from the registry as a string, so
2348 let's convert it into a CLSID structure */
2349 if (CLSIDFromString(value, pclsid) != NOERROR)
2350 return REGDB_E_IIDNOTREG;
2352 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2353 return S_OK;
2356 /*****************************************************************************
2357 * CoRegisterPSClsid [OLE32.@]
2359 * Register a proxy/stub CLSID for the given interface in the current process
2360 * only.
2362 * PARAMS
2363 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2364 * rclsid [I] CLSID of the proxy/stub.
2366 * RETURNS
2367 * Success: S_OK
2368 * Failure: E_OUTOFMEMORY
2370 * NOTES
2372 * This function does not add anything to the registry and the effects are
2373 * limited to the lifetime of the current process.
2375 * SEE ALSO
2376 * CoGetPSClsid.
2378 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2380 APARTMENT *apt = COM_CurrentApt();
2381 struct registered_psclsid *registered_psclsid;
2383 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2385 if (!apt)
2387 ERR("apartment not initialised\n");
2388 return CO_E_NOTINITIALIZED;
2391 EnterCriticalSection(&apt->cs);
2393 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2394 if (IsEqualIID(&registered_psclsid->iid, riid))
2396 registered_psclsid->clsid = *rclsid;
2397 LeaveCriticalSection(&apt->cs);
2398 return S_OK;
2401 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2402 if (!registered_psclsid)
2404 LeaveCriticalSection(&apt->cs);
2405 return E_OUTOFMEMORY;
2408 registered_psclsid->iid = *riid;
2409 registered_psclsid->clsid = *rclsid;
2410 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2412 LeaveCriticalSection(&apt->cs);
2414 return S_OK;
2418 /***
2419 * COM_GetRegisteredClassObject
2421 * This internal method is used to scan the registered class list to
2422 * find a class object.
2424 * Params:
2425 * rclsid Class ID of the class to find.
2426 * dwClsContext Class context to match.
2427 * ppv [out] returns a pointer to the class object. Complying
2428 * to normal COM usage, this method will increase the
2429 * reference count on this object.
2431 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2432 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2434 HRESULT hr = S_FALSE;
2435 RegisteredClass *curClass;
2437 EnterCriticalSection( &csRegisteredClassList );
2439 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2442 * Check if we have a match on the class ID and context.
2444 if ((apt->oxid == curClass->apartment_id) &&
2445 (dwClsContext & curClass->runContext) &&
2446 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2449 * We have a match, return the pointer to the class object.
2451 *ppUnk = curClass->classObject;
2453 IUnknown_AddRef(curClass->classObject);
2455 hr = S_OK;
2456 break;
2460 LeaveCriticalSection( &csRegisteredClassList );
2462 return hr;
2465 /******************************************************************************
2466 * CoRegisterClassObject [OLE32.@]
2468 * Registers the class object for a given class ID. Servers housed in EXE
2469 * files use this method instead of exporting DllGetClassObject to allow
2470 * other code to connect to their objects.
2472 * PARAMS
2473 * rclsid [I] CLSID of the object to register.
2474 * pUnk [I] IUnknown of the object.
2475 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2476 * flags [I] REGCLS flags indicating how connections are made.
2477 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2479 * RETURNS
2480 * S_OK on success,
2481 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2482 * CO_E_OBJISREG if the object is already registered. We should not return this.
2484 * SEE ALSO
2485 * CoRevokeClassObject, CoGetClassObject
2487 * NOTES
2488 * In-process objects are only registered for the current apartment.
2489 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2490 * in other apartments.
2492 * BUGS
2493 * MSDN claims that multiple interface registrations are legal, but we
2494 * can't do that with our current implementation.
2496 HRESULT WINAPI CoRegisterClassObject(
2497 REFCLSID rclsid,
2498 LPUNKNOWN pUnk,
2499 DWORD dwClsContext,
2500 DWORD flags,
2501 LPDWORD lpdwRegister)
2503 static LONG next_cookie;
2504 RegisteredClass* newClass;
2505 LPUNKNOWN foundObject;
2506 HRESULT hr;
2507 APARTMENT *apt;
2509 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2510 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2512 if ( (lpdwRegister==0) || (pUnk==0) )
2513 return E_INVALIDARG;
2515 apt = COM_CurrentApt();
2516 if (!apt)
2518 ERR("COM was not initialized\n");
2519 return CO_E_NOTINITIALIZED;
2522 *lpdwRegister = 0;
2524 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2525 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2526 if (flags & REGCLS_MULTIPLEUSE)
2527 dwClsContext |= CLSCTX_INPROC_SERVER;
2530 * First, check if the class is already registered.
2531 * If it is, this should cause an error.
2533 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2534 if (hr == S_OK) {
2535 if (flags & REGCLS_MULTIPLEUSE) {
2536 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2537 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2538 IUnknown_Release(foundObject);
2539 return hr;
2541 IUnknown_Release(foundObject);
2542 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2543 return CO_E_OBJISREG;
2546 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2547 if ( newClass == NULL )
2548 return E_OUTOFMEMORY;
2550 newClass->classIdentifier = *rclsid;
2551 newClass->apartment_id = apt->oxid;
2552 newClass->runContext = dwClsContext;
2553 newClass->connectFlags = flags;
2554 newClass->RpcRegistration = NULL;
2556 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2557 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2560 * Since we're making a copy of the object pointer, we have to increase its
2561 * reference count.
2563 newClass->classObject = pUnk;
2564 IUnknown_AddRef(newClass->classObject);
2566 EnterCriticalSection( &csRegisteredClassList );
2567 list_add_tail(&RegisteredClassList, &newClass->entry);
2568 LeaveCriticalSection( &csRegisteredClassList );
2570 *lpdwRegister = newClass->dwCookie;
2572 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2573 IStream *marshal_stream;
2575 hr = get_local_server_stream(apt, &marshal_stream);
2576 if(FAILED(hr))
2577 return hr;
2579 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2580 marshal_stream,
2581 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2582 &newClass->RpcRegistration);
2583 IStream_Release(marshal_stream);
2585 return S_OK;
2588 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2590 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2591 DWORD keytype;
2592 DWORD ret;
2593 DWORD dwLength = len * sizeof(WCHAR);
2595 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2596 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2597 value[0] = '\0';
2600 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2601 REFCLSID rclsid, REFIID riid,
2602 BOOL hostifnecessary, void **ppv)
2604 WCHAR dllpath[MAX_PATH+1];
2605 BOOL apartment_threaded;
2607 if (hostifnecessary)
2609 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2610 static const WCHAR wszFree[] = {'F','r','e','e',0};
2611 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2612 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2614 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2615 /* "Apartment" */
2616 if (!strcmpiW(threading_model, wszApartment))
2618 apartment_threaded = TRUE;
2619 if (apt->multi_threaded)
2620 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2622 /* "Free" */
2623 else if (!strcmpiW(threading_model, wszFree))
2625 apartment_threaded = FALSE;
2626 if (!apt->multi_threaded)
2627 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2629 /* everything except "Apartment", "Free" and "Both" */
2630 else if (strcmpiW(threading_model, wszBoth))
2632 apartment_threaded = TRUE;
2633 /* everything else is main-threaded */
2634 if (threading_model[0])
2635 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2636 debugstr_w(threading_model), debugstr_guid(rclsid));
2638 if (apt->multi_threaded || !apt->main)
2639 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2641 else
2642 apartment_threaded = FALSE;
2644 else
2645 apartment_threaded = !apt->multi_threaded;
2647 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2649 /* failure: CLSID is not found in registry */
2650 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2651 return REGDB_E_CLASSNOTREG;
2654 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2655 rclsid, riid, ppv);
2658 /***********************************************************************
2659 * CoGetClassObject [OLE32.@]
2661 * Creates an object of the specified class.
2663 * PARAMS
2664 * rclsid [I] Class ID to create an instance of.
2665 * dwClsContext [I] Flags to restrict the location of the created instance.
2666 * pServerInfo [I] Optional. Details for connecting to a remote server.
2667 * iid [I] The ID of the interface of the instance to return.
2668 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2670 * RETURNS
2671 * Success: S_OK
2672 * Failure: HRESULT code.
2674 * NOTES
2675 * The dwClsContext parameter can be one or more of the following:
2676 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2677 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2678 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2679 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2681 * SEE ALSO
2682 * CoCreateInstance()
2684 HRESULT WINAPI CoGetClassObject(
2685 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2686 REFIID iid, LPVOID *ppv)
2688 LPUNKNOWN regClassObject;
2689 HRESULT hres = E_UNEXPECTED;
2690 APARTMENT *apt;
2691 BOOL release_apt = FALSE;
2693 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2695 if (!ppv)
2696 return E_INVALIDARG;
2698 *ppv = NULL;
2700 if (!(apt = COM_CurrentApt()))
2702 if (!(apt = apartment_find_multi_threaded()))
2704 ERR("apartment not initialised\n");
2705 return CO_E_NOTINITIALIZED;
2707 release_apt = TRUE;
2710 if (pServerInfo) {
2711 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2712 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2716 * First, try and see if we can't match the class ID with one of the
2717 * registered classes.
2719 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2720 &regClassObject))
2722 /* Get the required interface from the retrieved pointer. */
2723 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2726 * Since QI got another reference on the pointer, we want to release the
2727 * one we already have. If QI was unsuccessful, this will release the object. This
2728 * is good since we are not returning it in the "out" parameter.
2730 IUnknown_Release(regClassObject);
2731 if (release_apt) apartment_release(apt);
2732 return hres;
2735 /* First try in-process server */
2736 if (CLSCTX_INPROC_SERVER & dwClsContext)
2738 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2739 HKEY hkey;
2741 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2743 if (release_apt) apartment_release(apt);
2744 return FTMarshalCF_Create(iid, ppv);
2747 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2748 if (FAILED(hres))
2750 if (hres == REGDB_E_CLASSNOTREG)
2751 ERR("class %s not registered\n", debugstr_guid(rclsid));
2752 else if (hres == REGDB_E_KEYMISSING)
2754 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2755 hres = REGDB_E_CLASSNOTREG;
2759 if (SUCCEEDED(hres))
2761 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2762 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2763 RegCloseKey(hkey);
2766 /* return if we got a class, otherwise fall through to one of the
2767 * other types */
2768 if (SUCCEEDED(hres))
2770 if (release_apt) apartment_release(apt);
2771 return hres;
2775 /* Next try in-process handler */
2776 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2778 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2779 HKEY hkey;
2781 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2782 if (FAILED(hres))
2784 if (hres == REGDB_E_CLASSNOTREG)
2785 ERR("class %s not registered\n", debugstr_guid(rclsid));
2786 else if (hres == REGDB_E_KEYMISSING)
2788 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2789 hres = REGDB_E_CLASSNOTREG;
2793 if (SUCCEEDED(hres))
2795 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2796 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2797 RegCloseKey(hkey);
2800 /* return if we got a class, otherwise fall through to one of the
2801 * other types */
2802 if (SUCCEEDED(hres))
2804 if (release_apt) apartment_release(apt);
2805 return hres;
2808 if (release_apt) apartment_release(apt);
2810 /* Next try out of process */
2811 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2813 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2814 if (SUCCEEDED(hres))
2815 return hres;
2818 /* Finally try remote: this requires networked DCOM (a lot of work) */
2819 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2821 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2822 hres = REGDB_E_CLASSNOTREG;
2825 if (FAILED(hres))
2826 ERR("no class object %s could be created for context 0x%x\n",
2827 debugstr_guid(rclsid), dwClsContext);
2828 return hres;
2831 /***********************************************************************
2832 * CoResumeClassObjects (OLE32.@)
2834 * Resumes all class objects registered with REGCLS_SUSPENDED.
2836 * RETURNS
2837 * Success: S_OK.
2838 * Failure: HRESULT code.
2840 HRESULT WINAPI CoResumeClassObjects(void)
2842 FIXME("stub\n");
2843 return S_OK;
2846 /***********************************************************************
2847 * CoCreateInstance [OLE32.@]
2849 * Creates an instance of the specified class.
2851 * PARAMS
2852 * rclsid [I] Class ID to create an instance of.
2853 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2854 * dwClsContext [I] Flags to restrict the location of the created instance.
2855 * iid [I] The ID of the interface of the instance to return.
2856 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2858 * RETURNS
2859 * Success: S_OK
2860 * Failure: HRESULT code.
2862 * NOTES
2863 * The dwClsContext parameter can be one or more of the following:
2864 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2865 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2866 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2867 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2869 * Aggregation is the concept of deferring the IUnknown of an object to another
2870 * object. This allows a separate object to behave as though it was part of
2871 * the object and to allow this the pUnkOuter parameter can be set. Note that
2872 * not all objects support having an outer of unknown.
2874 * SEE ALSO
2875 * CoGetClassObject()
2877 HRESULT WINAPI CoCreateInstance(
2878 REFCLSID rclsid,
2879 LPUNKNOWN pUnkOuter,
2880 DWORD dwClsContext,
2881 REFIID iid,
2882 LPVOID *ppv)
2884 HRESULT hres;
2885 LPCLASSFACTORY lpclf = 0;
2886 APARTMENT *apt;
2888 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2889 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2891 if (ppv==0)
2892 return E_POINTER;
2894 *ppv = 0;
2896 if (!(apt = COM_CurrentApt()))
2898 if (!(apt = apartment_find_multi_threaded()))
2900 ERR("apartment not initialised\n");
2901 return CO_E_NOTINITIALIZED;
2903 apartment_release(apt);
2907 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2909 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
2911 IGlobalInterfaceTable *git = get_std_git();
2912 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
2913 if (hres != S_OK) return hres;
2915 TRACE("Retrieved GIT (%p)\n", *ppv);
2916 return S_OK;
2919 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2920 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2923 * Get a class factory to construct the object we want.
2925 hres = CoGetClassObject(rclsid,
2926 dwClsContext,
2927 NULL,
2928 &IID_IClassFactory,
2929 (LPVOID)&lpclf);
2931 if (FAILED(hres))
2932 return hres;
2935 * Create the object and don't forget to release the factory
2937 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2938 IClassFactory_Release(lpclf);
2939 if (FAILED(hres))
2941 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2942 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2943 else
2944 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2945 debugstr_guid(iid),
2946 debugstr_guid(rclsid),hres);
2949 return hres;
2952 /***********************************************************************
2953 * CoCreateInstanceEx [OLE32.@]
2955 HRESULT WINAPI CoCreateInstanceEx(
2956 REFCLSID rclsid,
2957 LPUNKNOWN pUnkOuter,
2958 DWORD dwClsContext,
2959 COSERVERINFO* pServerInfo,
2960 ULONG cmq,
2961 MULTI_QI* pResults)
2963 IUnknown* pUnk = NULL;
2964 HRESULT hr;
2965 ULONG index;
2966 ULONG successCount = 0;
2969 * Sanity check
2971 if ( (cmq==0) || (pResults==NULL))
2972 return E_INVALIDARG;
2974 if (pServerInfo!=NULL)
2975 FIXME("() non-NULL pServerInfo not supported!\n");
2978 * Initialize all the "out" parameters.
2980 for (index = 0; index < cmq; index++)
2982 pResults[index].pItf = NULL;
2983 pResults[index].hr = E_NOINTERFACE;
2987 * Get the object and get its IUnknown pointer.
2989 hr = CoCreateInstance(rclsid,
2990 pUnkOuter,
2991 dwClsContext,
2992 &IID_IUnknown,
2993 (VOID**)&pUnk);
2995 if (hr != S_OK)
2996 return hr;
2999 * Then, query for all the interfaces requested.
3001 for (index = 0; index < cmq; index++)
3003 pResults[index].hr = IUnknown_QueryInterface(pUnk,
3004 pResults[index].pIID,
3005 (VOID**)&(pResults[index].pItf));
3007 if (pResults[index].hr == S_OK)
3008 successCount++;
3012 * Release our temporary unknown pointer.
3014 IUnknown_Release(pUnk);
3016 if (successCount == 0)
3017 return E_NOINTERFACE;
3019 if (successCount!=cmq)
3020 return CO_S_NOTALLINTERFACES;
3022 return S_OK;
3025 /***********************************************************************
3026 * CoLoadLibrary (OLE32.@)
3028 * Loads a library.
3030 * PARAMS
3031 * lpszLibName [I] Path to library.
3032 * bAutoFree [I] Whether the library should automatically be freed.
3034 * RETURNS
3035 * Success: Handle to loaded library.
3036 * Failure: NULL.
3038 * SEE ALSO
3039 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3041 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3043 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3045 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3048 /***********************************************************************
3049 * CoFreeLibrary [OLE32.@]
3051 * Unloads a library from memory.
3053 * PARAMS
3054 * hLibrary [I] Handle to library to unload.
3056 * RETURNS
3057 * Nothing
3059 * SEE ALSO
3060 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3062 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3064 FreeLibrary(hLibrary);
3068 /***********************************************************************
3069 * CoFreeAllLibraries [OLE32.@]
3071 * Function for backwards compatibility only. Does nothing.
3073 * RETURNS
3074 * Nothing.
3076 * SEE ALSO
3077 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3079 void WINAPI CoFreeAllLibraries(void)
3081 /* NOP */
3084 /***********************************************************************
3085 * CoFreeUnusedLibrariesEx [OLE32.@]
3087 * Frees any previously unused libraries whose delay has expired and marks
3088 * currently unused libraries for unloading. Unused are identified as those that
3089 * return S_OK from their DllCanUnloadNow function.
3091 * PARAMS
3092 * dwUnloadDelay [I] Unload delay in milliseconds.
3093 * dwReserved [I] Reserved. Set to 0.
3095 * RETURNS
3096 * Nothing.
3098 * SEE ALSO
3099 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3101 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3103 struct apartment *apt = COM_CurrentApt();
3104 if (!apt)
3106 ERR("apartment not initialised\n");
3107 return;
3110 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3113 /***********************************************************************
3114 * CoFreeUnusedLibraries [OLE32.@]
3116 * Frees any unused libraries. Unused are identified as those that return
3117 * S_OK from their DllCanUnloadNow function.
3119 * RETURNS
3120 * Nothing.
3122 * SEE ALSO
3123 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3125 void WINAPI CoFreeUnusedLibraries(void)
3127 CoFreeUnusedLibrariesEx(INFINITE, 0);
3130 /***********************************************************************
3131 * CoFileTimeNow [OLE32.@]
3133 * Retrieves the current time in FILETIME format.
3135 * PARAMS
3136 * lpFileTime [O] The current time.
3138 * RETURNS
3139 * S_OK.
3141 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3143 GetSystemTimeAsFileTime( lpFileTime );
3144 return S_OK;
3147 /******************************************************************************
3148 * CoLockObjectExternal [OLE32.@]
3150 * Increments or decrements the external reference count of a stub object.
3152 * PARAMS
3153 * pUnk [I] Stub object.
3154 * fLock [I] If TRUE then increments the external ref-count,
3155 * otherwise decrements.
3156 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3157 * calling CoDisconnectObject.
3159 * RETURNS
3160 * Success: S_OK.
3161 * Failure: HRESULT code.
3163 * NOTES
3164 * If fLock is TRUE and an object is passed in that doesn't have a stub
3165 * manager then a new stub manager is created for the object.
3167 HRESULT WINAPI CoLockObjectExternal(
3168 LPUNKNOWN pUnk,
3169 BOOL fLock,
3170 BOOL fLastUnlockReleases)
3172 struct stub_manager *stubmgr;
3173 struct apartment *apt;
3175 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3176 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3178 apt = COM_CurrentApt();
3179 if (!apt) return CO_E_NOTINITIALIZED;
3181 stubmgr = get_stub_manager_from_object(apt, pUnk);
3183 if (stubmgr)
3185 if (fLock)
3186 stub_manager_ext_addref(stubmgr, 1, FALSE);
3187 else
3188 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3190 stub_manager_int_release(stubmgr);
3192 return S_OK;
3194 else if (fLock)
3196 stubmgr = new_stub_manager(apt, pUnk);
3198 if (stubmgr)
3200 stub_manager_ext_addref(stubmgr, 1, FALSE);
3201 stub_manager_int_release(stubmgr);
3204 return S_OK;
3206 else
3208 WARN("stub object not found %p\n", pUnk);
3209 /* Note: native is pretty broken here because it just silently
3210 * fails, without returning an appropriate error code, making apps
3211 * think that the object was disconnected, when it actually wasn't */
3212 return S_OK;
3216 /***********************************************************************
3217 * CoInitializeWOW (OLE32.@)
3219 * WOW equivalent of CoInitialize?
3221 * PARAMS
3222 * x [I] Unknown.
3223 * y [I] Unknown.
3225 * RETURNS
3226 * Unknown.
3228 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3230 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3231 return 0;
3234 /***********************************************************************
3235 * CoGetState [OLE32.@]
3237 * Retrieves the thread state object previously stored by CoSetState().
3239 * PARAMS
3240 * ppv [I] Address where pointer to object will be stored.
3242 * RETURNS
3243 * Success: S_OK.
3244 * Failure: E_OUTOFMEMORY.
3246 * NOTES
3247 * Crashes on all invalid ppv addresses, including NULL.
3248 * If the function returns a non-NULL object then the caller must release its
3249 * reference on the object when the object is no longer required.
3251 * SEE ALSO
3252 * CoSetState().
3254 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3256 struct oletls *info = COM_CurrentInfo();
3257 if (!info) return E_OUTOFMEMORY;
3259 *ppv = NULL;
3261 if (info->state)
3263 IUnknown_AddRef(info->state);
3264 *ppv = info->state;
3265 TRACE("apt->state=%p\n", info->state);
3268 return S_OK;
3271 /***********************************************************************
3272 * CoSetState [OLE32.@]
3274 * Sets the thread state object.
3276 * PARAMS
3277 * pv [I] Pointer to state object to be stored.
3279 * NOTES
3280 * The system keeps a reference on the object while the object stored.
3282 * RETURNS
3283 * Success: S_OK.
3284 * Failure: E_OUTOFMEMORY.
3286 HRESULT WINAPI CoSetState(IUnknown * pv)
3288 struct oletls *info = COM_CurrentInfo();
3289 if (!info) return E_OUTOFMEMORY;
3291 if (pv) IUnknown_AddRef(pv);
3293 if (info->state)
3295 TRACE("-- release %p now\n", info->state);
3296 IUnknown_Release(info->state);
3299 info->state = pv;
3301 return S_OK;
3305 /******************************************************************************
3306 * CoTreatAsClass [OLE32.@]
3308 * Sets the TreatAs value of a class.
3310 * PARAMS
3311 * clsidOld [I] Class to set TreatAs value on.
3312 * clsidNew [I] The class the clsidOld should be treated as.
3314 * RETURNS
3315 * Success: S_OK.
3316 * Failure: HRESULT code.
3318 * SEE ALSO
3319 * CoGetTreatAsClass
3321 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3323 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3324 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3325 HKEY hkey = NULL;
3326 WCHAR szClsidNew[CHARS_IN_GUID];
3327 HRESULT res = S_OK;
3328 WCHAR auto_treat_as[CHARS_IN_GUID];
3329 LONG auto_treat_as_size = sizeof(auto_treat_as);
3330 CLSID id;
3332 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3333 if (FAILED(res))
3334 goto done;
3335 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3337 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3338 CLSIDFromString(auto_treat_as, &id) == S_OK)
3340 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3342 res = REGDB_E_WRITEREGDB;
3343 goto done;
3346 else
3348 RegDeleteKeyW(hkey, wszTreatAs);
3349 goto done;
3352 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3353 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3355 res = REGDB_E_WRITEREGDB;
3356 goto done;
3359 done:
3360 if (hkey) RegCloseKey(hkey);
3361 return res;
3364 /******************************************************************************
3365 * CoGetTreatAsClass [OLE32.@]
3367 * Gets the TreatAs value of a class.
3369 * PARAMS
3370 * clsidOld [I] Class to get the TreatAs value of.
3371 * clsidNew [I] The class the clsidOld should be treated as.
3373 * RETURNS
3374 * Success: S_OK.
3375 * Failure: HRESULT code.
3377 * SEE ALSO
3378 * CoSetTreatAsClass
3380 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3382 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3383 HKEY hkey = NULL;
3384 WCHAR szClsidNew[CHARS_IN_GUID];
3385 HRESULT res = S_OK;
3386 LONG len = sizeof(szClsidNew);
3388 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3389 *clsidNew = *clsidOld; /* copy over old value */
3391 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3392 if (FAILED(res))
3394 res = S_FALSE;
3395 goto done;
3397 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3399 res = S_FALSE;
3400 goto done;
3402 res = CLSIDFromString(szClsidNew,clsidNew);
3403 if (FAILED(res))
3404 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3405 done:
3406 if (hkey) RegCloseKey(hkey);
3407 return res;
3410 /******************************************************************************
3411 * CoGetCurrentProcess [OLE32.@]
3413 * Gets the current process ID.
3415 * RETURNS
3416 * The current process ID.
3418 * NOTES
3419 * Is DWORD really the correct return type for this function?
3421 DWORD WINAPI CoGetCurrentProcess(void)
3423 return GetCurrentProcessId();
3426 /******************************************************************************
3427 * CoRegisterMessageFilter [OLE32.@]
3429 * Registers a message filter.
3431 * PARAMS
3432 * lpMessageFilter [I] Pointer to interface.
3433 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3435 * RETURNS
3436 * Success: S_OK.
3437 * Failure: HRESULT code.
3439 * NOTES
3440 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3441 * lpMessageFilter removes the message filter.
3443 * If lplpMessageFilter is not NULL the previous message filter will be
3444 * returned in the memory pointer to this parameter and the caller is
3445 * responsible for releasing the object.
3447 * The current thread be in an apartment otherwise the function will crash.
3449 HRESULT WINAPI CoRegisterMessageFilter(
3450 LPMESSAGEFILTER lpMessageFilter,
3451 LPMESSAGEFILTER *lplpMessageFilter)
3453 struct apartment *apt;
3454 IMessageFilter *lpOldMessageFilter;
3456 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3458 apt = COM_CurrentApt();
3460 /* can't set a message filter in a multi-threaded apartment */
3461 if (!apt || apt->multi_threaded)
3463 WARN("can't set message filter in MTA or uninitialized apt\n");
3464 return CO_E_NOT_SUPPORTED;
3467 if (lpMessageFilter)
3468 IMessageFilter_AddRef(lpMessageFilter);
3470 EnterCriticalSection(&apt->cs);
3472 lpOldMessageFilter = apt->filter;
3473 apt->filter = lpMessageFilter;
3475 LeaveCriticalSection(&apt->cs);
3477 if (lplpMessageFilter)
3478 *lplpMessageFilter = lpOldMessageFilter;
3479 else if (lpOldMessageFilter)
3480 IMessageFilter_Release(lpOldMessageFilter);
3482 return S_OK;
3485 /***********************************************************************
3486 * CoIsOle1Class [OLE32.@]
3488 * Determines whether the specified class an OLE v1 class.
3490 * PARAMS
3491 * clsid [I] Class to test.
3493 * RETURNS
3494 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3496 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3498 FIXME("%s\n", debugstr_guid(clsid));
3499 return FALSE;
3502 /***********************************************************************
3503 * IsEqualGUID [OLE32.@]
3505 * Compares two Unique Identifiers.
3507 * PARAMS
3508 * rguid1 [I] The first GUID to compare.
3509 * rguid2 [I] The other GUID to compare.
3511 * RETURNS
3512 * TRUE if equal
3514 #undef IsEqualGUID
3515 BOOL WINAPI IsEqualGUID(
3516 REFGUID rguid1,
3517 REFGUID rguid2)
3519 return !memcmp(rguid1,rguid2,sizeof(GUID));
3522 /***********************************************************************
3523 * CoInitializeSecurity [OLE32.@]
3525 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3526 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3527 void* pReserved1, DWORD dwAuthnLevel,
3528 DWORD dwImpLevel, void* pReserved2,
3529 DWORD dwCapabilities, void* pReserved3)
3531 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3532 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3533 dwCapabilities, pReserved3);
3534 return S_OK;
3537 /***********************************************************************
3538 * CoSuspendClassObjects [OLE32.@]
3540 * Suspends all registered class objects to prevent further requests coming in
3541 * for those objects.
3543 * RETURNS
3544 * Success: S_OK.
3545 * Failure: HRESULT code.
3547 HRESULT WINAPI CoSuspendClassObjects(void)
3549 FIXME("\n");
3550 return S_OK;
3553 /***********************************************************************
3554 * CoAddRefServerProcess [OLE32.@]
3556 * Helper function for incrementing the reference count of a local-server
3557 * process.
3559 * RETURNS
3560 * New reference count.
3562 * SEE ALSO
3563 * CoReleaseServerProcess().
3565 ULONG WINAPI CoAddRefServerProcess(void)
3567 ULONG refs;
3569 TRACE("\n");
3571 EnterCriticalSection(&csRegisteredClassList);
3572 refs = ++s_COMServerProcessReferences;
3573 LeaveCriticalSection(&csRegisteredClassList);
3575 TRACE("refs before: %d\n", refs - 1);
3577 return refs;
3580 /***********************************************************************
3581 * CoReleaseServerProcess [OLE32.@]
3583 * Helper function for decrementing the reference count of a local-server
3584 * process.
3586 * RETURNS
3587 * New reference count.
3589 * NOTES
3590 * When reference count reaches 0, this function suspends all registered
3591 * classes so no new connections are accepted.
3593 * SEE ALSO
3594 * CoAddRefServerProcess(), CoSuspendClassObjects().
3596 ULONG WINAPI CoReleaseServerProcess(void)
3598 ULONG refs;
3600 TRACE("\n");
3602 EnterCriticalSection(&csRegisteredClassList);
3604 refs = --s_COMServerProcessReferences;
3605 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3607 LeaveCriticalSection(&csRegisteredClassList);
3609 TRACE("refs after: %d\n", refs);
3611 return refs;
3614 /***********************************************************************
3615 * CoIsHandlerConnected [OLE32.@]
3617 * Determines whether a proxy is connected to a remote stub.
3619 * PARAMS
3620 * pUnk [I] Pointer to object that may or may not be connected.
3622 * RETURNS
3623 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3624 * FALSE otherwise.
3626 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3628 FIXME("%p\n", pUnk);
3630 return TRUE;
3633 /***********************************************************************
3634 * CoAllowSetForegroundWindow [OLE32.@]
3637 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3639 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3640 return S_OK;
3643 /***********************************************************************
3644 * CoQueryProxyBlanket [OLE32.@]
3646 * Retrieves the security settings being used by a proxy.
3648 * PARAMS
3649 * pProxy [I] Pointer to the proxy object.
3650 * pAuthnSvc [O] The type of authentication service.
3651 * pAuthzSvc [O] The type of authorization service.
3652 * ppServerPrincName [O] Optional. The server prinicple name.
3653 * pAuthnLevel [O] The authentication level.
3654 * pImpLevel [O] The impersonation level.
3655 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3656 * pCapabilities [O] Flags affecting the security behaviour.
3658 * RETURNS
3659 * Success: S_OK.
3660 * Failure: HRESULT code.
3662 * SEE ALSO
3663 * CoCopyProxy, CoSetProxyBlanket.
3665 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3666 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3667 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3669 IClientSecurity *pCliSec;
3670 HRESULT hr;
3672 TRACE("%p\n", pProxy);
3674 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3675 if (SUCCEEDED(hr))
3677 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3678 pAuthzSvc, ppServerPrincName,
3679 pAuthnLevel, pImpLevel, ppAuthInfo,
3680 pCapabilities);
3681 IClientSecurity_Release(pCliSec);
3684 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3685 return hr;
3688 /***********************************************************************
3689 * CoSetProxyBlanket [OLE32.@]
3691 * Sets the security settings for a proxy.
3693 * PARAMS
3694 * pProxy [I] Pointer to the proxy object.
3695 * AuthnSvc [I] The type of authentication service.
3696 * AuthzSvc [I] The type of authorization service.
3697 * pServerPrincName [I] The server prinicple name.
3698 * AuthnLevel [I] The authentication level.
3699 * ImpLevel [I] The impersonation level.
3700 * pAuthInfo [I] Information specific to the authorization/authentication service.
3701 * Capabilities [I] Flags affecting the security behaviour.
3703 * RETURNS
3704 * Success: S_OK.
3705 * Failure: HRESULT code.
3707 * SEE ALSO
3708 * CoQueryProxyBlanket, CoCopyProxy.
3710 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3711 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3712 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3714 IClientSecurity *pCliSec;
3715 HRESULT hr;
3717 TRACE("%p\n", pProxy);
3719 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3720 if (SUCCEEDED(hr))
3722 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3723 AuthzSvc, pServerPrincName,
3724 AuthnLevel, ImpLevel, pAuthInfo,
3725 Capabilities);
3726 IClientSecurity_Release(pCliSec);
3729 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3730 return hr;
3733 /***********************************************************************
3734 * CoCopyProxy [OLE32.@]
3736 * Copies a proxy.
3738 * PARAMS
3739 * pProxy [I] Pointer to the proxy object.
3740 * ppCopy [O] Copy of the proxy.
3742 * RETURNS
3743 * Success: S_OK.
3744 * Failure: HRESULT code.
3746 * SEE ALSO
3747 * CoQueryProxyBlanket, CoSetProxyBlanket.
3749 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3751 IClientSecurity *pCliSec;
3752 HRESULT hr;
3754 TRACE("%p\n", pProxy);
3756 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3757 if (SUCCEEDED(hr))
3759 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3760 IClientSecurity_Release(pCliSec);
3763 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3764 return hr;
3768 /***********************************************************************
3769 * CoGetCallContext [OLE32.@]
3771 * Gets the context of the currently executing server call in the current
3772 * thread.
3774 * PARAMS
3775 * riid [I] Context interface to return.
3776 * ppv [O] Pointer to memory that will receive the context on return.
3778 * RETURNS
3779 * Success: S_OK.
3780 * Failure: HRESULT code.
3782 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3784 struct oletls *info = COM_CurrentInfo();
3786 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3788 if (!info)
3789 return E_OUTOFMEMORY;
3791 if (!info->call_state)
3792 return RPC_E_CALL_COMPLETE;
3794 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3797 /***********************************************************************
3798 * CoSwitchCallContext [OLE32.@]
3800 * Switches the context of the currently executing server call in the current
3801 * thread.
3803 * PARAMS
3804 * pObject [I] Pointer to new context object
3805 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3807 * RETURNS
3808 * Success: S_OK.
3809 * Failure: HRESULT code.
3811 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3813 struct oletls *info = COM_CurrentInfo();
3815 TRACE("(%p, %p)\n", pObject, ppOldObject);
3817 if (!info)
3818 return E_OUTOFMEMORY;
3820 *ppOldObject = info->call_state;
3821 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3823 return S_OK;
3826 /***********************************************************************
3827 * CoQueryClientBlanket [OLE32.@]
3829 * Retrieves the authentication information about the client of the currently
3830 * executing server call in the current thread.
3832 * PARAMS
3833 * pAuthnSvc [O] Optional. The type of authentication service.
3834 * pAuthzSvc [O] Optional. The type of authorization service.
3835 * pServerPrincName [O] Optional. The server prinicple name.
3836 * pAuthnLevel [O] Optional. The authentication level.
3837 * pImpLevel [O] Optional. The impersonation level.
3838 * pPrivs [O] Optional. Information about the privileges of the client.
3839 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3841 * RETURNS
3842 * Success: S_OK.
3843 * Failure: HRESULT code.
3845 * SEE ALSO
3846 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3848 HRESULT WINAPI CoQueryClientBlanket(
3849 DWORD *pAuthnSvc,
3850 DWORD *pAuthzSvc,
3851 OLECHAR **pServerPrincName,
3852 DWORD *pAuthnLevel,
3853 DWORD *pImpLevel,
3854 RPC_AUTHZ_HANDLE *pPrivs,
3855 DWORD *pCapabilities)
3857 IServerSecurity *pSrvSec;
3858 HRESULT hr;
3860 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3861 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3862 pPrivs, pCapabilities);
3864 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3865 if (SUCCEEDED(hr))
3867 hr = IServerSecurity_QueryBlanket(
3868 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3869 pImpLevel, pPrivs, pCapabilities);
3870 IServerSecurity_Release(pSrvSec);
3873 return hr;
3876 /***********************************************************************
3877 * CoImpersonateClient [OLE32.@]
3879 * Impersonates the client of the currently executing server call in the
3880 * current thread.
3882 * PARAMS
3883 * None.
3885 * RETURNS
3886 * Success: S_OK.
3887 * Failure: HRESULT code.
3889 * NOTES
3890 * If this function fails then the current thread will not be impersonating
3891 * the client and all actions will take place on behalf of the server.
3892 * Therefore, it is important to check the return value from this function.
3894 * SEE ALSO
3895 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3897 HRESULT WINAPI CoImpersonateClient(void)
3899 IServerSecurity *pSrvSec;
3900 HRESULT hr;
3902 TRACE("\n");
3904 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3905 if (SUCCEEDED(hr))
3907 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3908 IServerSecurity_Release(pSrvSec);
3911 return hr;
3914 /***********************************************************************
3915 * CoRevertToSelf [OLE32.@]
3917 * Ends the impersonation of the client of the currently executing server
3918 * call in the current thread.
3920 * PARAMS
3921 * None.
3923 * RETURNS
3924 * Success: S_OK.
3925 * Failure: HRESULT code.
3927 * SEE ALSO
3928 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3930 HRESULT WINAPI CoRevertToSelf(void)
3932 IServerSecurity *pSrvSec;
3933 HRESULT hr;
3935 TRACE("\n");
3937 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3938 if (SUCCEEDED(hr))
3940 hr = IServerSecurity_RevertToSelf(pSrvSec);
3941 IServerSecurity_Release(pSrvSec);
3944 return hr;
3947 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3949 /* first try to retrieve messages for incoming COM calls to the apartment window */
3950 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3951 /* next retrieve other messages necessary for the app to remain responsive */
3952 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3953 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3956 /***********************************************************************
3957 * CoWaitForMultipleHandles [OLE32.@]
3959 * Waits for one or more handles to become signaled.
3961 * PARAMS
3962 * dwFlags [I] Flags. See notes.
3963 * dwTimeout [I] Timeout in milliseconds.
3964 * cHandles [I] Number of handles pointed to by pHandles.
3965 * pHandles [I] Handles to wait for.
3966 * lpdwindex [O] Index of handle that was signaled.
3968 * RETURNS
3969 * Success: S_OK.
3970 * Failure: RPC_S_CALLPENDING on timeout.
3972 * NOTES
3974 * The dwFlags parameter can be zero or more of the following:
3975 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3976 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3978 * SEE ALSO
3979 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3981 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3982 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3984 HRESULT hr = S_OK;
3985 DWORD start_time = GetTickCount();
3986 APARTMENT *apt = COM_CurrentApt();
3987 BOOL message_loop = apt && !apt->multi_threaded;
3989 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3990 pHandles, lpdwindex);
3992 while (TRUE)
3994 DWORD now = GetTickCount();
3995 DWORD res;
3997 if (now - start_time > dwTimeout)
3999 hr = RPC_S_CALLPENDING;
4000 break;
4003 if (message_loop)
4005 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4006 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4008 TRACE("waiting for rpc completion or window message\n");
4010 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4011 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4012 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4014 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4016 MSG msg;
4017 int count = 0;
4019 /* call message filter */
4021 if (COM_CurrentApt()->filter)
4023 PENDINGTYPE pendingtype =
4024 COM_CurrentInfo()->pending_call_count_server ?
4025 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4026 DWORD be_handled = IMessageFilter_MessagePending(
4027 COM_CurrentApt()->filter, 0 /* FIXME */,
4028 now - start_time, pendingtype);
4029 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4030 switch (be_handled)
4032 case PENDINGMSG_CANCELCALL:
4033 WARN("call canceled\n");
4034 hr = RPC_E_CALL_CANCELED;
4035 break;
4036 case PENDINGMSG_WAITNOPROCESS:
4037 case PENDINGMSG_WAITDEFPROCESS:
4038 default:
4039 /* FIXME: MSDN is very vague about the difference
4040 * between WAITNOPROCESS and WAITDEFPROCESS - there
4041 * appears to be none, so it is possibly a left-over
4042 * from the 16-bit world. */
4043 break;
4047 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4048 * so after processing 100 messages we go back to checking the wait handles */
4049 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4051 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4052 TranslateMessage(&msg);
4053 DispatchMessageW(&msg);
4054 if (msg.message == WM_QUIT)
4056 TRACE("resending WM_QUIT to outer message loop\n");
4057 PostQuitMessage(msg.wParam);
4058 /* no longer need to process messages */
4059 message_loop = FALSE;
4060 break;
4063 continue;
4066 else
4068 TRACE("waiting for rpc completion\n");
4070 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4071 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4072 (dwFlags & COWAIT_ALERTABLE) != 0);
4075 switch (res)
4077 case WAIT_TIMEOUT:
4078 hr = RPC_S_CALLPENDING;
4079 break;
4080 case WAIT_FAILED:
4081 hr = HRESULT_FROM_WIN32( GetLastError() );
4082 break;
4083 default:
4084 *lpdwindex = res;
4085 break;
4087 break;
4089 TRACE("-- 0x%08x\n", hr);
4090 return hr;
4094 /***********************************************************************
4095 * CoGetObject [OLE32.@]
4097 * Gets the object named by converting the name to a moniker and binding to it.
4099 * PARAMS
4100 * pszName [I] String representing the object.
4101 * pBindOptions [I] Parameters affecting the binding to the named object.
4102 * riid [I] Interface to bind to on the objecct.
4103 * ppv [O] On output, the interface riid of the object represented
4104 * by pszName.
4106 * RETURNS
4107 * Success: S_OK.
4108 * Failure: HRESULT code.
4110 * SEE ALSO
4111 * MkParseDisplayName.
4113 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4114 REFIID riid, void **ppv)
4116 IBindCtx *pbc;
4117 HRESULT hr;
4119 *ppv = NULL;
4121 hr = CreateBindCtx(0, &pbc);
4122 if (SUCCEEDED(hr))
4124 if (pBindOptions)
4125 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4127 if (SUCCEEDED(hr))
4129 ULONG chEaten;
4130 IMoniker *pmk;
4132 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4133 if (SUCCEEDED(hr))
4135 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4136 IMoniker_Release(pmk);
4140 IBindCtx_Release(pbc);
4142 return hr;
4145 /***********************************************************************
4146 * CoRegisterChannelHook [OLE32.@]
4148 * Registers a process-wide hook that is called during ORPC calls.
4150 * PARAMS
4151 * guidExtension [I] GUID of the channel hook to register.
4152 * pChannelHook [I] Channel hook object to register.
4154 * RETURNS
4155 * Success: S_OK.
4156 * Failure: HRESULT code.
4158 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4160 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4162 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4165 typedef struct Context
4167 IComThreadingInfo IComThreadingInfo_iface;
4168 IContextCallback IContextCallback_iface;
4169 IObjContext IObjContext_iface;
4170 LONG refs;
4171 APTTYPE apttype;
4172 } Context;
4174 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4176 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4179 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4181 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4184 static inline Context *impl_from_IObjContext( IObjContext *iface )
4186 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4189 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4191 *ppv = NULL;
4193 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4194 IsEqualIID(riid, &IID_IUnknown))
4196 *ppv = &iface->IComThreadingInfo_iface;
4198 else if (IsEqualIID(riid, &IID_IContextCallback))
4200 *ppv = &iface->IContextCallback_iface;
4202 else if (IsEqualIID(riid, &IID_IObjContext))
4204 *ppv = &iface->IObjContext_iface;
4207 if (*ppv)
4209 IUnknown_AddRef((IUnknown*)*ppv);
4210 return S_OK;
4213 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4214 return E_NOINTERFACE;
4217 static ULONG Context_AddRef(Context *This)
4219 return InterlockedIncrement(&This->refs);
4222 static ULONG Context_Release(Context *This)
4224 ULONG refs = InterlockedDecrement(&This->refs);
4225 if (!refs)
4226 HeapFree(GetProcessHeap(), 0, This);
4227 return refs;
4230 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4232 Context *This = impl_from_IComThreadingInfo(iface);
4233 return Context_QueryInterface(This, riid, ppv);
4236 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4238 Context *This = impl_from_IComThreadingInfo(iface);
4239 return Context_AddRef(This);
4242 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4244 Context *This = impl_from_IComThreadingInfo(iface);
4245 return Context_Release(This);
4248 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4250 Context *This = impl_from_IComThreadingInfo(iface);
4252 TRACE("(%p)\n", apttype);
4254 *apttype = This->apttype;
4255 return S_OK;
4258 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4260 Context *This = impl_from_IComThreadingInfo(iface);
4262 TRACE("(%p)\n", thdtype);
4264 switch (This->apttype)
4266 case APTTYPE_STA:
4267 case APTTYPE_MAINSTA:
4268 *thdtype = THDTYPE_PROCESSMESSAGES;
4269 break;
4270 default:
4271 *thdtype = THDTYPE_BLOCKMESSAGES;
4272 break;
4274 return S_OK;
4277 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4279 FIXME("(%p): stub\n", logical_thread_id);
4280 return E_NOTIMPL;
4283 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4285 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4286 return E_NOTIMPL;
4289 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4291 Context_CTI_QueryInterface,
4292 Context_CTI_AddRef,
4293 Context_CTI_Release,
4294 Context_CTI_GetCurrentApartmentType,
4295 Context_CTI_GetCurrentThreadType,
4296 Context_CTI_GetCurrentLogicalThreadId,
4297 Context_CTI_SetCurrentLogicalThreadId
4300 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4302 Context *This = impl_from_IContextCallback(iface);
4303 return Context_QueryInterface(This, riid, ppv);
4306 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4308 Context *This = impl_from_IContextCallback(iface);
4309 return Context_AddRef(This);
4312 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4314 Context *This = impl_from_IContextCallback(iface);
4315 return Context_Release(This);
4318 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4319 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4321 Context *This = impl_from_IContextCallback(iface);
4323 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4324 return E_NOTIMPL;
4327 static const IContextCallbackVtbl Context_Callback_Vtbl =
4329 Context_CC_QueryInterface,
4330 Context_CC_AddRef,
4331 Context_CC_Release,
4332 Context_CC_ContextCallback
4335 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4337 Context *This = impl_from_IObjContext(iface);
4338 return Context_QueryInterface(This, riid, ppv);
4341 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4343 Context *This = impl_from_IObjContext(iface);
4344 return Context_AddRef(This);
4347 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4349 Context *This = impl_from_IObjContext(iface);
4350 return Context_Release(This);
4353 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4355 Context *This = impl_from_IObjContext(iface);
4357 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4358 return E_NOTIMPL;
4361 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4363 Context *This = impl_from_IObjContext(iface);
4365 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4366 return E_NOTIMPL;
4369 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4371 Context *This = impl_from_IObjContext(iface);
4373 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4374 return E_NOTIMPL;
4377 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4379 Context *This = impl_from_IObjContext(iface);
4381 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4382 return E_NOTIMPL;
4385 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4387 Context *This = impl_from_IObjContext(iface);
4388 FIXME("(%p/%p)\n", This, iface);
4391 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4393 Context *This = impl_from_IObjContext(iface);
4394 FIXME("(%p/%p)\n", This, iface);
4397 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4399 Context *This = impl_from_IObjContext(iface);
4400 FIXME("(%p/%p)\n", This, iface);
4403 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4405 Context *This = impl_from_IObjContext(iface);
4406 FIXME("(%p/%p)\n", This, iface);
4409 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4411 Context *This = impl_from_IObjContext(iface);
4412 FIXME("(%p/%p)\n", This, iface);
4415 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4417 Context *This = impl_from_IObjContext(iface);
4418 FIXME("(%p/%p)\n", This, iface);
4421 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4423 Context *This = impl_from_IObjContext(iface);
4424 FIXME("(%p/%p)\n", This, iface);
4427 static const IObjContextVtbl Context_Object_Vtbl =
4429 Context_OC_QueryInterface,
4430 Context_OC_AddRef,
4431 Context_OC_Release,
4432 Context_OC_SetProperty,
4433 Context_OC_RemoveProperty,
4434 Context_OC_GetProperty,
4435 Context_OC_EnumContextProps,
4436 Context_OC_Reserved1,
4437 Context_OC_Reserved2,
4438 Context_OC_Reserved3,
4439 Context_OC_Reserved4,
4440 Context_OC_Reserved5,
4441 Context_OC_Reserved6,
4442 Context_OC_Reserved7
4445 /***********************************************************************
4446 * CoGetObjectContext [OLE32.@]
4448 * Retrieves an object associated with the current context (i.e. apartment).
4450 * PARAMS
4451 * riid [I] ID of the interface of the object to retrieve.
4452 * ppv [O] Address where object will be stored on return.
4454 * RETURNS
4455 * Success: S_OK.
4456 * Failure: HRESULT code.
4458 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4460 APARTMENT *apt = COM_CurrentApt();
4461 Context *context;
4462 HRESULT hr;
4464 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4466 *ppv = NULL;
4467 if (!apt)
4469 if (!(apt = apartment_find_multi_threaded()))
4471 ERR("apartment not initialised\n");
4472 return CO_E_NOTINITIALIZED;
4474 apartment_release(apt);
4477 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4478 if (!context)
4479 return E_OUTOFMEMORY;
4481 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4482 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4483 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4484 context->refs = 1;
4485 if (apt->multi_threaded)
4486 context->apttype = APTTYPE_MTA;
4487 else if (apt->main)
4488 context->apttype = APTTYPE_MAINSTA;
4489 else
4490 context->apttype = APTTYPE_STA;
4492 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4493 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4495 return hr;
4499 /***********************************************************************
4500 * CoGetContextToken [OLE32.@]
4502 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4504 struct oletls *info = COM_CurrentInfo();
4506 TRACE("(%p)\n", token);
4508 if (!info)
4509 return E_OUTOFMEMORY;
4511 if (!info->apt)
4513 APARTMENT *apt;
4514 if (!(apt = apartment_find_multi_threaded()))
4516 ERR("apartment not initialised\n");
4517 return CO_E_NOTINITIALIZED;
4519 apartment_release(apt);
4522 if (!token)
4523 return E_POINTER;
4525 if (!info->context_token)
4527 HRESULT hr;
4528 IObjContext *ctx;
4530 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4531 if (FAILED(hr)) return hr;
4532 info->context_token = ctx;
4535 *token = (ULONG_PTR)info->context_token;
4536 TRACE("apt->context_token=%p\n", info->context_token);
4538 return S_OK;
4541 /***********************************************************************
4542 * CoGetDefaultContext [OLE32.@]
4544 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4546 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4547 return E_NOINTERFACE;
4550 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4552 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4553 HKEY hkey;
4554 HRESULT hres;
4556 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4557 if (SUCCEEDED(hres))
4559 WCHAR dllpath[MAX_PATH+1];
4561 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4563 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4564 if (!strcmpiW(dllpath, wszOle32))
4566 RegCloseKey(hkey);
4567 return HandlerCF_Create(rclsid, riid, ppv);
4570 else
4571 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4572 RegCloseKey(hkey);
4575 return CLASS_E_CLASSNOTAVAILABLE;
4578 /***********************************************************************
4579 * DllMain (OLE32.@)
4581 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
4583 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
4585 switch(fdwReason) {
4586 case DLL_PROCESS_ATTACH:
4587 hProxyDll = hinstDLL;
4588 COMPOBJ_InitProcess();
4589 break;
4591 case DLL_PROCESS_DETACH:
4592 if (reserved) break;
4593 COMPOBJ_UninitProcess();
4594 RPC_UnregisterAllChannelHooks();
4595 COMPOBJ_DllList_Free();
4596 DeleteCriticalSection(&csRegisteredClassList);
4597 DeleteCriticalSection(&csApartment);
4598 break;
4600 case DLL_THREAD_DETACH:
4601 COM_TlsDestroy();
4602 break;
4604 return TRUE;
4607 /***********************************************************************
4608 * DllRegisterServer (OLE32.@)
4610 HRESULT WINAPI DllRegisterServer(void)
4612 return OLE32_DllRegisterServer();
4615 /***********************************************************************
4616 * DllUnregisterServer (OLE32.@)
4618 HRESULT WINAPI DllUnregisterServer(void)
4620 return OLE32_DllUnregisterServer();