oledb32: Support DBSTATUS_S_ISNULL when converting to VARIANT.
[wine.git] / dlls / ole32 / compobj.c
blobe007440563f4d68a2b99997a3b1bc95a2cd5a992
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winuser.h"
57 #define USE_COM_CONTEXT_DEF
58 #include "objbase.h"
59 #include "ole2.h"
60 #include "ole2ver.h"
61 #include "ctxtcall.h"
62 #include "dde.h"
64 #include "initguid.h"
65 #include "compobj_private.h"
66 #include "moniker.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
94 struct list entry;
95 IID iid;
96 CLSID clsid;
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
118 struct list entry;
119 CLSID classIdentifier;
120 OXID apartment_id;
121 LPUNKNOWN classObject;
122 DWORD runContext;
123 DWORD connectFlags;
124 DWORD dwCookie;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
127 } RegisteredClass;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /* wrapper for NtCreateKey that creates the key recursively if necessary */
141 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
143 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
145 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
147 HANDLE subkey, root = attr->RootDirectory;
148 WCHAR *buffer = attr->ObjectName->Buffer;
149 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
150 UNICODE_STRING str;
152 while (i < len && buffer[i] != '\\') i++;
153 if (i == len) return status;
155 attrs = attr->Attributes;
156 attr->ObjectName = &str;
158 while (i < len)
160 str.Buffer = buffer + pos;
161 str.Length = (i - pos) * sizeof(WCHAR);
162 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
163 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
164 if (status) return status;
165 attr->RootDirectory = subkey;
166 while (i < len && buffer[i] == '\\') i++;
167 pos = i;
168 while (i < len && buffer[i] != '\\') i++;
170 str.Buffer = buffer + pos;
171 str.Length = (i - pos) * sizeof(WCHAR);
172 attr->Attributes = attrs;
173 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
174 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
176 return status;
179 static const WCHAR classes_rootW[] =
180 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
182 static HKEY classes_root_hkey;
184 /* create the special HKEY_CLASSES_ROOT key */
185 static HKEY create_classes_root_hkey(void)
187 HKEY hkey, ret = 0;
188 OBJECT_ATTRIBUTES attr;
189 UNICODE_STRING name;
191 attr.Length = sizeof(attr);
192 attr.RootDirectory = 0;
193 attr.ObjectName = &name;
194 attr.Attributes = 0;
195 attr.SecurityDescriptor = NULL;
196 attr.SecurityQualityOfService = NULL;
197 RtlInitUnicodeString( &name, classes_rootW );
198 if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
199 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
201 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
202 ret = hkey;
203 else
204 NtClose( hkey ); /* somebody beat us to it */
205 return ret;
208 /* map the hkey from special root to normal key if necessary */
209 static inline HKEY get_classes_root_hkey( HKEY hkey )
211 HKEY ret = hkey;
213 if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
214 ret = create_classes_root_hkey();
216 return ret;
219 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
221 OBJECT_ATTRIBUTES attr;
222 UNICODE_STRING nameW;
224 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
226 attr.Length = sizeof(attr);
227 attr.RootDirectory = hkey;
228 attr.ObjectName = &nameW;
229 attr.Attributes = 0;
230 attr.SecurityDescriptor = NULL;
231 attr.SecurityQualityOfService = NULL;
232 RtlInitUnicodeString( &nameW, name );
234 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
237 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
239 OBJECT_ATTRIBUTES attr;
240 UNICODE_STRING nameW;
242 if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
244 attr.Length = sizeof(attr);
245 attr.RootDirectory = hkey;
246 attr.ObjectName = &nameW;
247 attr.Attributes = 0;
248 attr.SecurityDescriptor = NULL;
249 attr.SecurityQualityOfService = NULL;
250 RtlInitUnicodeString( &nameW, name );
252 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
255 /*****************************************************************************
256 * This section contains OpenDllList definitions
258 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
259 * other functions that do LoadLibrary _without_ giving back a HMODULE.
260 * Without this list these handles would never be freed.
262 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
263 * next unload-call but not before 600 sec.
266 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
267 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
269 typedef struct tagOpenDll
271 LONG refs;
272 LPWSTR library_name;
273 HANDLE library;
274 DllGetClassObjectFunc DllGetClassObject;
275 DllCanUnloadNowFunc DllCanUnloadNow;
276 struct list entry;
277 } OpenDll;
279 static struct list openDllList = LIST_INIT(openDllList);
281 static CRITICAL_SECTION csOpenDllList;
282 static CRITICAL_SECTION_DEBUG dll_cs_debug =
284 0, 0, &csOpenDllList,
285 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
286 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
288 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
290 struct apartment_loaded_dll
292 struct list entry;
293 OpenDll *dll;
294 DWORD unload_time;
295 BOOL multi_threaded;
298 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
299 '0','x','#','#','#','#','#','#','#','#',' ',0};
301 /*****************************************************************************
302 * This section contains OpenDllList implementation
305 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
307 OpenDll *ptr;
308 OpenDll *ret = NULL;
309 EnterCriticalSection(&csOpenDllList);
310 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
312 if (!strcmpiW(library_name, ptr->library_name) &&
313 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
315 ret = ptr;
316 break;
319 LeaveCriticalSection(&csOpenDllList);
320 return ret;
323 /* caller must ensure that library_name is not already in the open dll list */
324 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
326 OpenDll *entry;
327 int len;
328 HRESULT hr = S_OK;
329 HANDLE hLibrary;
330 DllCanUnloadNowFunc DllCanUnloadNow;
331 DllGetClassObjectFunc DllGetClassObject;
333 TRACE("\n");
335 *ret = COMPOBJ_DllList_Get(library_name);
336 if (*ret) return S_OK;
338 /* do this outside the csOpenDllList to avoid creating a lock dependency on
339 * the loader lock */
340 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
341 if (!hLibrary)
343 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
344 /* failure: DLL could not be loaded */
345 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
348 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
349 /* Note: failing to find DllCanUnloadNow is not a failure */
350 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
351 if (!DllGetClassObject)
353 /* failure: the dll did not export DllGetClassObject */
354 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
355 FreeLibrary(hLibrary);
356 return CO_E_DLLNOTFOUND;
359 EnterCriticalSection( &csOpenDllList );
361 *ret = COMPOBJ_DllList_Get(library_name);
362 if (*ret)
364 /* another caller to this function already added the dll while we
365 * weren't in the critical section */
366 FreeLibrary(hLibrary);
368 else
370 len = strlenW(library_name);
371 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
372 if (entry)
373 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
374 if (entry && entry->library_name)
376 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
377 entry->library = hLibrary;
378 entry->refs = 1;
379 entry->DllCanUnloadNow = DllCanUnloadNow;
380 entry->DllGetClassObject = DllGetClassObject;
381 list_add_tail(&openDllList, &entry->entry);
382 *ret = entry;
384 else
386 HeapFree(GetProcessHeap(), 0, entry);
387 hr = E_OUTOFMEMORY;
388 FreeLibrary(hLibrary);
392 LeaveCriticalSection( &csOpenDllList );
394 return hr;
397 /* pass FALSE for free_entry to release a reference without destroying the
398 * entry if it reaches zero or TRUE otherwise */
399 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
401 if (!InterlockedDecrement(&entry->refs) && free_entry)
403 EnterCriticalSection(&csOpenDllList);
404 list_remove(&entry->entry);
405 LeaveCriticalSection(&csOpenDllList);
407 TRACE("freeing %p\n", entry->library);
408 FreeLibrary(entry->library);
410 HeapFree(GetProcessHeap(), 0, entry->library_name);
411 HeapFree(GetProcessHeap(), 0, entry);
415 /* frees memory associated with active dll list */
416 static void COMPOBJ_DllList_Free(void)
418 OpenDll *entry, *cursor2;
419 EnterCriticalSection(&csOpenDllList);
420 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
422 list_remove(&entry->entry);
424 HeapFree(GetProcessHeap(), 0, entry->library_name);
425 HeapFree(GetProcessHeap(), 0, entry);
427 LeaveCriticalSection(&csOpenDllList);
428 DeleteCriticalSection(&csOpenDllList);
431 /******************************************************************************
432 * Manage apartments.
435 static DWORD apartment_addref(struct apartment *apt)
437 DWORD refs = InterlockedIncrement(&apt->refs);
438 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
439 return refs;
442 /* allocates memory and fills in the necessary fields for a new apartment
443 * object. must be called inside apartment cs */
444 static APARTMENT *apartment_construct(DWORD model)
446 APARTMENT *apt;
448 TRACE("creating new apartment, model=%d\n", model);
450 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
451 apt->tid = GetCurrentThreadId();
453 list_init(&apt->proxies);
454 list_init(&apt->stubmgrs);
455 list_init(&apt->psclsids);
456 list_init(&apt->loaded_dlls);
457 apt->ipidc = 0;
458 apt->refs = 1;
459 apt->remunk_exported = FALSE;
460 apt->oidc = 1;
461 InitializeCriticalSection(&apt->cs);
462 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
464 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
466 if (apt->multi_threaded)
468 /* FIXME: should be randomly generated by in an RPC call to rpcss */
469 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
471 else
473 /* FIXME: should be randomly generated by in an RPC call to rpcss */
474 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
477 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
479 list_add_head(&apts, &apt->entry);
481 return apt;
484 /* gets and existing apartment if one exists or otherwise creates an apartment
485 * structure which stores OLE apartment-local information and stores a pointer
486 * to it in the thread-local storage */
487 static APARTMENT *apartment_get_or_create(DWORD model)
489 APARTMENT *apt = COM_CurrentApt();
491 if (!apt)
493 if (model & COINIT_APARTMENTTHREADED)
495 EnterCriticalSection(&csApartment);
497 apt = apartment_construct(model);
498 if (!MainApartment)
500 MainApartment = apt;
501 apt->main = TRUE;
502 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
505 LeaveCriticalSection(&csApartment);
507 if (apt->main)
508 apartment_createwindowifneeded(apt);
510 else
512 EnterCriticalSection(&csApartment);
514 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
515 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
516 * in a process */
517 if (MTA)
519 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
520 apartment_addref(MTA);
522 else
523 MTA = apartment_construct(model);
525 apt = MTA;
527 LeaveCriticalSection(&csApartment);
529 COM_CurrentInfo()->apt = apt;
532 return apt;
535 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
537 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
540 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
542 list_remove(&curClass->entry);
544 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
545 RPC_StopLocalServer(curClass->RpcRegistration);
548 * Release the reference to the class object.
550 IUnknown_Release(curClass->classObject);
552 if (curClass->pMarshaledData)
554 LARGE_INTEGER zero;
555 memset(&zero, 0, sizeof(zero));
556 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
557 CoReleaseMarshalData(curClass->pMarshaledData);
558 IStream_Release(curClass->pMarshaledData);
561 HeapFree(GetProcessHeap(), 0, curClass);
564 static void COM_RevokeAllClasses(const struct apartment *apt)
566 RegisteredClass *curClass, *cursor;
568 EnterCriticalSection( &csRegisteredClassList );
570 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
572 if (curClass->apartment_id == apt->oxid)
573 COM_RevokeRegisteredClassObject(curClass);
576 LeaveCriticalSection( &csRegisteredClassList );
579 /******************************************************************************
580 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
583 typedef struct ManualResetEvent {
584 ISynchronize ISynchronize_iface;
585 ISynchronizeHandle ISynchronizeHandle_iface;
586 LONG ref;
587 HANDLE event;
588 } MREImpl;
590 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
592 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
595 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
597 MREImpl *This = impl_from_ISynchronize(iface);
599 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
601 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
602 *ppv = &This->ISynchronize_iface;
603 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
604 *ppv = &This->ISynchronizeHandle_iface;
605 }else {
606 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
607 *ppv = NULL;
608 return E_NOINTERFACE;
611 IUnknown_AddRef((IUnknown*)*ppv);
612 return S_OK;
615 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
617 MREImpl *This = impl_from_ISynchronize(iface);
618 LONG ref = InterlockedIncrement(&This->ref);
619 TRACE("%p - ref %d\n", This, ref);
621 return ref;
624 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
626 MREImpl *This = impl_from_ISynchronize(iface);
627 LONG ref = InterlockedDecrement(&This->ref);
628 TRACE("%p - ref %d\n", This, ref);
630 if(!ref)
632 CloseHandle(This->event);
633 HeapFree(GetProcessHeap(), 0, This);
636 return ref;
639 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
641 MREImpl *This = impl_from_ISynchronize(iface);
642 UINT index;
643 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
644 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
647 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
649 MREImpl *This = impl_from_ISynchronize(iface);
650 TRACE("%p\n", This);
651 SetEvent(This->event);
652 return S_OK;
655 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
657 MREImpl *This = impl_from_ISynchronize(iface);
658 TRACE("%p\n", This);
659 ResetEvent(This->event);
660 return S_OK;
663 static ISynchronizeVtbl vt_ISynchronize = {
664 ISynchronize_fnQueryInterface,
665 ISynchronize_fnAddRef,
666 ISynchronize_fnRelease,
667 ISynchronize_fnWait,
668 ISynchronize_fnSignal,
669 ISynchronize_fnReset
672 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
674 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
677 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
679 MREImpl *This = impl_from_ISynchronizeHandle(iface);
680 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
683 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
685 MREImpl *This = impl_from_ISynchronizeHandle(iface);
686 return ISynchronize_AddRef(&This->ISynchronize_iface);
689 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
691 MREImpl *This = impl_from_ISynchronizeHandle(iface);
692 return ISynchronize_Release(&This->ISynchronize_iface);
695 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
697 MREImpl *This = impl_from_ISynchronizeHandle(iface);
699 *ph = This->event;
700 return S_OK;
703 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
704 SynchronizeHandle_QueryInterface,
705 SynchronizeHandle_AddRef,
706 SynchronizeHandle_Release,
707 SynchronizeHandle_GetHandle
710 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
712 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
713 HRESULT hr;
715 if(punkouter)
716 FIXME("Aggregation not implemented.\n");
718 This->ref = 1;
719 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
720 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
721 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
723 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
724 ISynchronize_Release(&This->ISynchronize_iface);
725 return hr;
728 /***********************************************************************
729 * CoRevokeClassObject [OLE32.@]
731 * Removes a class object from the class registry.
733 * PARAMS
734 * dwRegister [I] Cookie returned from CoRegisterClassObject().
736 * RETURNS
737 * Success: S_OK.
738 * Failure: HRESULT code.
740 * NOTES
741 * Must be called from the same apartment that called CoRegisterClassObject(),
742 * otherwise it will fail with RPC_E_WRONG_THREAD.
744 * SEE ALSO
745 * CoRegisterClassObject
747 HRESULT WINAPI CoRevokeClassObject(
748 DWORD dwRegister)
750 HRESULT hr = E_INVALIDARG;
751 RegisteredClass *curClass;
752 APARTMENT *apt;
754 TRACE("(%08x)\n",dwRegister);
756 apt = COM_CurrentApt();
757 if (!apt)
759 ERR("COM was not initialized\n");
760 return CO_E_NOTINITIALIZED;
763 EnterCriticalSection( &csRegisteredClassList );
765 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
768 * Check if we have a match on the cookie.
770 if (curClass->dwCookie == dwRegister)
772 if (curClass->apartment_id == apt->oxid)
774 COM_RevokeRegisteredClassObject(curClass);
775 hr = S_OK;
777 else
779 ERR("called from wrong apartment, should be called from %s\n",
780 wine_dbgstr_longlong(curClass->apartment_id));
781 hr = RPC_E_WRONG_THREAD;
783 break;
787 LeaveCriticalSection( &csRegisteredClassList );
789 return hr;
792 /* frees unused libraries loaded by apartment_getclassobject by calling the
793 * DLL's DllCanUnloadNow entry point */
794 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
796 struct apartment_loaded_dll *entry, *next;
797 EnterCriticalSection(&apt->cs);
798 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
800 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
802 DWORD real_delay = delay;
804 if (real_delay == INFINITE)
806 /* DLLs that return multi-threaded objects aren't unloaded
807 * straight away to cope for programs that have races between
808 * last object destruction and threads in the DLLs that haven't
809 * finished, despite DllCanUnloadNow returning S_OK */
810 if (entry->multi_threaded)
811 real_delay = 10 * 60 * 1000; /* 10 minutes */
812 else
813 real_delay = 0;
816 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
818 list_remove(&entry->entry);
819 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
820 HeapFree(GetProcessHeap(), 0, entry);
822 else
824 entry->unload_time = GetTickCount() + real_delay;
825 if (!entry->unload_time) entry->unload_time = 1;
828 else if (entry->unload_time)
829 entry->unload_time = 0;
831 LeaveCriticalSection(&apt->cs);
834 DWORD apartment_release(struct apartment *apt)
836 DWORD ret;
838 EnterCriticalSection(&csApartment);
840 ret = InterlockedDecrement(&apt->refs);
841 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
842 /* destruction stuff that needs to happen under csApartment CS */
843 if (ret == 0)
845 if (apt == MTA) MTA = NULL;
846 else if (apt == MainApartment) MainApartment = NULL;
847 list_remove(&apt->entry);
850 LeaveCriticalSection(&csApartment);
852 if (ret == 0)
854 struct list *cursor, *cursor2;
856 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
858 /* Release the references to the registered class objects */
859 COM_RevokeAllClasses(apt);
861 /* no locking is needed for this apartment, because no other thread
862 * can access it at this point */
864 apartment_disconnectproxies(apt);
866 if (apt->win) DestroyWindow(apt->win);
867 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
869 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
871 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
872 /* release the implicit reference given by the fact that the
873 * stub has external references (it must do since it is in the
874 * stub manager list in the apartment and all non-apartment users
875 * must have a ref on the apartment and so it cannot be destroyed).
877 stub_manager_int_release(stubmgr);
880 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
882 struct registered_psclsid *registered_psclsid =
883 LIST_ENTRY(cursor, struct registered_psclsid, entry);
885 list_remove(&registered_psclsid->entry);
886 HeapFree(GetProcessHeap(), 0, registered_psclsid);
889 /* if this assert fires, then another thread took a reference to a
890 * stub manager without taking a reference to the containing
891 * apartment, which it must do. */
892 assert(list_empty(&apt->stubmgrs));
894 if (apt->filter) IMessageFilter_Release(apt->filter);
896 /* free as many unused libraries as possible... */
897 apartment_freeunusedlibraries(apt, 0);
899 /* ... and free the memory for the apartment loaded dll entry and
900 * release the dll list reference without freeing the library for the
901 * rest */
902 while ((cursor = list_head(&apt->loaded_dlls)))
904 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
905 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
906 list_remove(cursor);
907 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
910 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
911 DeleteCriticalSection(&apt->cs);
913 HeapFree(GetProcessHeap(), 0, apt);
916 return ret;
919 /* The given OXID must be local to this process:
921 * The ref parameter is here mostly to ensure people remember that
922 * they get one, you should normally take a ref for thread safety.
924 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
926 APARTMENT *result = NULL;
927 struct list *cursor;
929 EnterCriticalSection(&csApartment);
930 LIST_FOR_EACH( cursor, &apts )
932 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
933 if (apt->oxid == oxid)
935 result = apt;
936 if (ref) apartment_addref(result);
937 break;
940 LeaveCriticalSection(&csApartment);
942 return result;
945 /* gets the apartment which has a given creator thread ID. The caller must
946 * release the reference from the apartment as soon as the apartment pointer
947 * is no longer required. */
948 APARTMENT *apartment_findfromtid(DWORD tid)
950 APARTMENT *result = NULL;
951 struct list *cursor;
953 EnterCriticalSection(&csApartment);
954 LIST_FOR_EACH( cursor, &apts )
956 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
957 if (apt->tid == tid)
959 result = apt;
960 apartment_addref(result);
961 break;
964 LeaveCriticalSection(&csApartment);
966 return result;
969 /* gets the main apartment if it exists. The caller must
970 * release the reference from the apartment as soon as the apartment pointer
971 * is no longer required. */
972 static APARTMENT *apartment_findmain(void)
974 APARTMENT *result;
976 EnterCriticalSection(&csApartment);
978 result = MainApartment;
979 if (result) apartment_addref(result);
981 LeaveCriticalSection(&csApartment);
983 return result;
986 /* gets the multi-threaded apartment if it exists. The caller must
987 * release the reference from the apartment as soon as the apartment pointer
988 * is no longer required. */
989 static APARTMENT *apartment_find_multi_threaded(void)
991 APARTMENT *result = NULL;
992 struct list *cursor;
994 EnterCriticalSection(&csApartment);
996 LIST_FOR_EACH( cursor, &apts )
998 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
999 if (apt->multi_threaded)
1001 result = apt;
1002 apartment_addref(result);
1003 break;
1007 LeaveCriticalSection(&csApartment);
1008 return result;
1011 /* gets the specified class object by loading the appropriate DLL, if
1012 * necessary and calls the DllGetClassObject function for the DLL */
1013 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1014 BOOL apartment_threaded,
1015 REFCLSID rclsid, REFIID riid, void **ppv)
1017 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1018 HRESULT hr = S_OK;
1019 BOOL found = FALSE;
1020 struct apartment_loaded_dll *apartment_loaded_dll;
1022 if (!strcmpiW(dllpath, wszOle32))
1024 /* we don't need to control the lifetime of this dll, so use the local
1025 * implementation of DllGetClassObject directly */
1026 TRACE("calling ole32!DllGetClassObject\n");
1027 hr = DllGetClassObject(rclsid, riid, ppv);
1029 if (hr != S_OK)
1030 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1032 return hr;
1035 EnterCriticalSection(&apt->cs);
1037 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1038 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1040 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1041 found = TRUE;
1042 break;
1045 if (!found)
1047 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1048 if (!apartment_loaded_dll)
1049 hr = E_OUTOFMEMORY;
1050 if (SUCCEEDED(hr))
1052 apartment_loaded_dll->unload_time = 0;
1053 apartment_loaded_dll->multi_threaded = FALSE;
1054 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1055 if (FAILED(hr))
1056 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1058 if (SUCCEEDED(hr))
1060 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1061 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1065 LeaveCriticalSection(&apt->cs);
1067 if (SUCCEEDED(hr))
1069 /* one component being multi-threaded overrides any number of
1070 * apartment-threaded components */
1071 if (!apartment_threaded)
1072 apartment_loaded_dll->multi_threaded = TRUE;
1074 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1075 /* OK: get the ClassObject */
1076 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1078 if (hr != S_OK)
1079 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1082 return hr;
1085 /***********************************************************************
1086 * COM_RegReadPath [internal]
1088 * Reads a registry value and expands it when necessary
1090 static DWORD COM_RegReadPath(HKEY hkeyroot, WCHAR * dst, DWORD dstlen)
1092 DWORD ret;
1093 DWORD keytype;
1094 WCHAR src[MAX_PATH];
1095 DWORD dwLength = dstlen * sizeof(WCHAR);
1097 if( (ret = RegQueryValueExW(hkeyroot, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1098 if (keytype == REG_EXPAND_SZ) {
1099 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1100 } else {
1101 const WCHAR *quote_start;
1102 quote_start = strchrW(src, '\"');
1103 if (quote_start) {
1104 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1105 if (quote_end) {
1106 memmove(src, quote_start + 1,
1107 (quote_end - quote_start - 1) * sizeof(WCHAR));
1108 src[quote_end - quote_start - 1] = '\0';
1111 lstrcpynW(dst, src, dstlen);
1114 return ret;
1117 struct host_object_params
1119 HKEY hkeydll;
1120 CLSID clsid; /* clsid of object to marshal */
1121 IID iid; /* interface to marshal */
1122 HANDLE event; /* event signalling when ready for multi-threaded case */
1123 HRESULT hr; /* result for multi-threaded case */
1124 IStream *stream; /* stream that the object will be marshaled into */
1125 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1128 static HRESULT apartment_hostobject(struct apartment *apt,
1129 const struct host_object_params *params)
1131 IUnknown *object;
1132 HRESULT hr;
1133 static const LARGE_INTEGER llZero;
1134 WCHAR dllpath[MAX_PATH+1];
1136 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1138 if (COM_RegReadPath(params->hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1140 /* failure: CLSID is not found in registry */
1141 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1142 return REGDB_E_CLASSNOTREG;
1145 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1146 &params->clsid, &params->iid, (void **)&object);
1147 if (FAILED(hr))
1148 return hr;
1150 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1151 if (FAILED(hr))
1152 IUnknown_Release(object);
1153 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1155 return hr;
1158 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1160 switch (msg)
1162 case DM_EXECUTERPC:
1163 RPC_ExecuteCall((struct dispatch_params *)lParam);
1164 return 0;
1165 case DM_HOSTOBJECT:
1166 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1167 default:
1168 return DefWindowProcW(hWnd, msg, wParam, lParam);
1172 struct host_thread_params
1174 COINIT threading_model;
1175 HANDLE ready_event;
1176 HWND apartment_hwnd;
1179 /* thread for hosting an object to allow an object to appear to be created in
1180 * an apartment with an incompatible threading model */
1181 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1183 struct host_thread_params *params = p;
1184 MSG msg;
1185 HRESULT hr;
1186 struct apartment *apt;
1188 TRACE("\n");
1190 hr = CoInitializeEx(NULL, params->threading_model);
1191 if (FAILED(hr)) return hr;
1193 apt = COM_CurrentApt();
1194 if (params->threading_model == COINIT_APARTMENTTHREADED)
1196 apartment_createwindowifneeded(apt);
1197 params->apartment_hwnd = apartment_getwindow(apt);
1199 else
1200 params->apartment_hwnd = NULL;
1202 /* force the message queue to be created before signaling parent thread */
1203 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1205 SetEvent(params->ready_event);
1206 params = NULL; /* can't touch params after here as it may be invalid */
1208 while (GetMessageW(&msg, NULL, 0, 0))
1210 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1212 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1213 obj_params->hr = apartment_hostobject(apt, obj_params);
1214 SetEvent(obj_params->event);
1216 else
1218 TranslateMessage(&msg);
1219 DispatchMessageW(&msg);
1223 TRACE("exiting\n");
1225 CoUninitialize();
1227 return S_OK;
1230 /* finds or creates a host apartment, creates the object inside it and returns
1231 * a proxy to it so that the object can be used in the apartment of the
1232 * caller of this function */
1233 static HRESULT apartment_hostobject_in_hostapt(
1234 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1235 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1237 struct host_object_params params;
1238 HWND apartment_hwnd = NULL;
1239 DWORD apartment_tid = 0;
1240 HRESULT hr;
1242 if (!multi_threaded && main_apartment)
1244 APARTMENT *host_apt = apartment_findmain();
1245 if (host_apt)
1247 apartment_hwnd = apartment_getwindow(host_apt);
1248 apartment_release(host_apt);
1252 if (!apartment_hwnd)
1254 EnterCriticalSection(&apt->cs);
1256 if (!apt->host_apt_tid)
1258 struct host_thread_params thread_params;
1259 HANDLE handles[2];
1260 DWORD wait_value;
1262 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1263 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1264 thread_params.apartment_hwnd = NULL;
1265 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1266 if (!handles[1])
1268 CloseHandle(handles[0]);
1269 LeaveCriticalSection(&apt->cs);
1270 return E_OUTOFMEMORY;
1272 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1273 CloseHandle(handles[0]);
1274 CloseHandle(handles[1]);
1275 if (wait_value == WAIT_OBJECT_0)
1276 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1277 else
1279 LeaveCriticalSection(&apt->cs);
1280 return E_OUTOFMEMORY;
1284 if (multi_threaded || !main_apartment)
1286 apartment_hwnd = apt->host_apt_hwnd;
1287 apartment_tid = apt->host_apt_tid;
1290 LeaveCriticalSection(&apt->cs);
1293 /* another thread may have become the main apartment in the time it took
1294 * us to create the thread for the host apartment */
1295 if (!apartment_hwnd && !multi_threaded && main_apartment)
1297 APARTMENT *host_apt = apartment_findmain();
1298 if (host_apt)
1300 apartment_hwnd = apartment_getwindow(host_apt);
1301 apartment_release(host_apt);
1305 params.hkeydll = hkeydll;
1306 params.clsid = *rclsid;
1307 params.iid = *riid;
1308 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1309 if (FAILED(hr))
1310 return hr;
1311 params.apartment_threaded = !multi_threaded;
1312 if (multi_threaded)
1314 params.hr = S_OK;
1315 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1316 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1317 hr = E_OUTOFMEMORY;
1318 else
1320 WaitForSingleObject(params.event, INFINITE);
1321 hr = params.hr;
1323 CloseHandle(params.event);
1325 else
1327 if (!apartment_hwnd)
1329 ERR("host apartment didn't create window\n");
1330 hr = E_OUTOFMEMORY;
1332 else
1333 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1335 if (SUCCEEDED(hr))
1336 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1337 IStream_Release(params.stream);
1338 return hr;
1341 /* create a window for the apartment or return the current one if one has
1342 * already been created */
1343 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1345 if (apt->multi_threaded)
1346 return S_OK;
1348 if (!apt->win)
1350 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1351 0, 0, 0, 0,
1352 HWND_MESSAGE, 0, hProxyDll, NULL);
1353 if (!hwnd)
1355 ERR("CreateWindow failed with error %d\n", GetLastError());
1356 return HRESULT_FROM_WIN32(GetLastError());
1358 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1359 /* someone beat us to it */
1360 DestroyWindow(hwnd);
1363 return S_OK;
1366 /* retrieves the window for the main- or apartment-threaded apartment */
1367 HWND apartment_getwindow(const struct apartment *apt)
1369 assert(!apt->multi_threaded);
1370 return apt->win;
1373 void apartment_joinmta(void)
1375 apartment_addref(MTA);
1376 COM_CurrentInfo()->apt = MTA;
1379 static void COMPOBJ_InitProcess( void )
1381 WNDCLASSW wclass;
1383 /* Dispatching to the correct thread in an apartment is done through
1384 * window messages rather than RPC transports. When an interface is
1385 * marshalled into another apartment in the same process, a window of the
1386 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1387 * application) is responsible for pumping the message loop in that thread.
1388 * The WM_USER messages which point to the RPCs are then dispatched to
1389 * apartment_wndproc by the user's code from the apartment in which the
1390 * interface was unmarshalled.
1392 memset(&wclass, 0, sizeof(wclass));
1393 wclass.lpfnWndProc = apartment_wndproc;
1394 wclass.hInstance = hProxyDll;
1395 wclass.lpszClassName = wszAptWinClass;
1396 RegisterClassW(&wclass);
1399 static void COMPOBJ_UninitProcess( void )
1401 UnregisterClassW(wszAptWinClass, hProxyDll);
1404 static void COM_TlsDestroy(void)
1406 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1407 if (info)
1409 if (info->apt) apartment_release(info->apt);
1410 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1411 if (info->state) IUnknown_Release(info->state);
1412 if (info->spy) IInitializeSpy_Release(info->spy);
1413 if (info->context_token) IObjContext_Release(info->context_token);
1414 HeapFree(GetProcessHeap(), 0, info);
1415 NtCurrentTeb()->ReservedForOle = NULL;
1419 /******************************************************************************
1420 * CoBuildVersion [OLE32.@]
1422 * Gets the build version of the DLL.
1424 * PARAMS
1426 * RETURNS
1427 * Current build version, hiword is majornumber, loword is minornumber
1429 DWORD WINAPI CoBuildVersion(void)
1431 TRACE("Returning version %d, build %d.\n", rmm, rup);
1432 return (rmm<<16)+rup;
1435 /******************************************************************************
1436 * CoRegisterInitializeSpy [OLE32.@]
1438 * Add a Spy that watches CoInitializeEx calls
1440 * PARAMS
1441 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1442 * cookie [II] cookie receiver
1444 * RETURNS
1445 * Success: S_OK if not already initialized, S_FALSE otherwise.
1446 * Failure: HRESULT code.
1448 * SEE ALSO
1449 * CoInitializeEx
1451 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1453 struct oletls *info = COM_CurrentInfo();
1454 HRESULT hr;
1456 TRACE("(%p, %p)\n", spy, cookie);
1458 if (!spy || !cookie || !info)
1460 if (!info)
1461 WARN("Could not allocate tls\n");
1462 return E_INVALIDARG;
1465 if (info->spy)
1467 FIXME("Already registered?\n");
1468 return E_UNEXPECTED;
1471 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1472 if (SUCCEEDED(hr))
1474 cookie->QuadPart = (DWORD_PTR)spy;
1475 return S_OK;
1477 return hr;
1480 /******************************************************************************
1481 * CoRevokeInitializeSpy [OLE32.@]
1483 * Remove a spy that previously watched CoInitializeEx calls
1485 * PARAMS
1486 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1488 * RETURNS
1489 * Success: S_OK if a spy is removed
1490 * Failure: E_INVALIDARG
1492 * SEE ALSO
1493 * CoInitializeEx
1495 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1497 struct oletls *info = COM_CurrentInfo();
1498 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1500 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1501 return E_INVALIDARG;
1503 IInitializeSpy_Release(info->spy);
1504 info->spy = NULL;
1505 return S_OK;
1509 /******************************************************************************
1510 * CoInitialize [OLE32.@]
1512 * Initializes the COM libraries by calling CoInitializeEx with
1513 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1515 * PARAMS
1516 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1518 * RETURNS
1519 * Success: S_OK if not already initialized, S_FALSE otherwise.
1520 * Failure: HRESULT code.
1522 * SEE ALSO
1523 * CoInitializeEx
1525 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1528 * Just delegate to the newer method.
1530 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1533 /******************************************************************************
1534 * CoInitializeEx [OLE32.@]
1536 * Initializes the COM libraries.
1538 * PARAMS
1539 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1540 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1542 * RETURNS
1543 * S_OK if successful,
1544 * S_FALSE if this function was called already.
1545 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1546 * threading model.
1548 * NOTES
1550 * The behavior used to set the IMalloc used for memory management is
1551 * obsolete.
1552 * The dwCoInit parameter must specify one of the following apartment
1553 * threading models:
1554 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1555 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1556 * The parameter may also specify zero or more of the following flags:
1557 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1558 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1560 * SEE ALSO
1561 * CoUninitialize
1563 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1565 struct oletls *info = COM_CurrentInfo();
1566 HRESULT hr = S_OK;
1567 APARTMENT *apt;
1569 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1571 if (lpReserved!=NULL)
1573 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1577 * Check the lock count. If this is the first time going through the initialize
1578 * process, we have to initialize the libraries.
1580 * And crank-up that lock count.
1582 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1585 * Initialize the various COM libraries and data structures.
1587 TRACE("() - Initializing the COM libraries\n");
1589 /* we may need to defer this until after apartment initialisation */
1590 RunningObjectTableImpl_Initialize();
1593 if (info->spy)
1594 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1596 if (!(apt = info->apt))
1598 apt = apartment_get_or_create(dwCoInit);
1599 if (!apt) return E_OUTOFMEMORY;
1601 else if (!apartment_is_model(apt, dwCoInit))
1603 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1604 code then we are probably using the wrong threading model to implement that API. */
1605 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1606 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1607 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1608 return RPC_E_CHANGED_MODE;
1610 else
1611 hr = S_FALSE;
1613 info->inits++;
1615 if (info->spy)
1616 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1618 return hr;
1621 /***********************************************************************
1622 * CoUninitialize [OLE32.@]
1624 * This method will decrement the refcount on the current apartment, freeing
1625 * the resources associated with it if it is the last thread in the apartment.
1626 * If the last apartment is freed, the function will additionally release
1627 * any COM resources associated with the process.
1629 * PARAMS
1631 * RETURNS
1632 * Nothing.
1634 * SEE ALSO
1635 * CoInitializeEx
1637 void WINAPI CoUninitialize(void)
1639 struct oletls * info = COM_CurrentInfo();
1640 LONG lCOMRefCnt;
1642 TRACE("()\n");
1644 /* will only happen on OOM */
1645 if (!info) return;
1647 if (info->spy)
1648 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1650 /* sanity check */
1651 if (!info->inits)
1653 ERR("Mismatched CoUninitialize\n");
1655 if (info->spy)
1656 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1657 return;
1660 if (!--info->inits)
1662 apartment_release(info->apt);
1663 info->apt = NULL;
1667 * Decrease the reference count.
1668 * If we are back to 0 locks on the COM library, make sure we free
1669 * all the associated data structures.
1671 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1672 if (lCOMRefCnt==1)
1674 TRACE("() - Releasing the COM libraries\n");
1676 RunningObjectTableImpl_UnInitialize();
1678 else if (lCOMRefCnt<1) {
1679 ERR( "CoUninitialize() - not CoInitialized.\n" );
1680 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1682 if (info->spy)
1683 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1686 /******************************************************************************
1687 * CoDisconnectObject [OLE32.@]
1689 * Disconnects all connections to this object from remote processes. Dispatches
1690 * pending RPCs while blocking new RPCs from occurring, and then calls
1691 * IMarshal::DisconnectObject on the given object.
1693 * Typically called when the object server is forced to shut down, for instance by
1694 * the user.
1696 * PARAMS
1697 * lpUnk [I] The object whose stub should be disconnected.
1698 * reserved [I] Reserved. Should be set to 0.
1700 * RETURNS
1701 * Success: S_OK.
1702 * Failure: HRESULT code.
1704 * SEE ALSO
1705 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1707 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1709 HRESULT hr;
1710 IMarshal *marshal;
1711 APARTMENT *apt;
1713 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1715 if (!lpUnk) return E_INVALIDARG;
1717 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1718 if (hr == S_OK)
1720 hr = IMarshal_DisconnectObject(marshal, reserved);
1721 IMarshal_Release(marshal);
1722 return hr;
1725 apt = COM_CurrentApt();
1726 if (!apt)
1727 return CO_E_NOTINITIALIZED;
1729 apartment_disconnectobject(apt, lpUnk);
1731 /* Note: native is pretty broken here because it just silently
1732 * fails, without returning an appropriate error code if the object was
1733 * not found, making apps think that the object was disconnected, when
1734 * it actually wasn't */
1736 return S_OK;
1739 /******************************************************************************
1740 * CoCreateGuid [OLE32.@]
1742 * Simply forwards to UuidCreate in RPCRT4.
1744 * PARAMS
1745 * pguid [O] Points to the GUID to initialize.
1747 * RETURNS
1748 * Success: S_OK.
1749 * Failure: HRESULT code.
1751 * SEE ALSO
1752 * UuidCreate
1754 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1756 DWORD status = UuidCreate(pguid);
1757 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1758 return HRESULT_FROM_WIN32( status );
1761 static inline BOOL is_valid_hex(WCHAR c)
1763 if (!(((c >= '0') && (c <= '9')) ||
1764 ((c >= 'a') && (c <= 'f')) ||
1765 ((c >= 'A') && (c <= 'F'))))
1766 return FALSE;
1767 return TRUE;
1770 /******************************************************************************
1771 * CLSIDFromString [OLE32.@]
1772 * IIDFromString [OLE32.@]
1774 * Converts a unique identifier from its string representation into
1775 * the GUID struct.
1777 * PARAMS
1778 * idstr [I] The string representation of the GUID.
1779 * id [O] GUID converted from the string.
1781 * RETURNS
1782 * S_OK on success
1783 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1785 * SEE ALSO
1786 * StringFromCLSID
1788 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1790 int i;
1791 BYTE table[256];
1793 if (!s || s[0]!='{') {
1794 memset( id, 0, sizeof (CLSID) );
1795 if(!s) return S_OK;
1796 return CO_E_CLASSSTRING;
1799 TRACE("%s -> %p\n", debugstr_w(s), id);
1801 /* quick lookup table */
1802 memset(table, 0, 256);
1804 for (i = 0; i < 10; i++) {
1805 table['0' + i] = i;
1807 for (i = 0; i < 6; i++) {
1808 table['A' + i] = i+10;
1809 table['a' + i] = i+10;
1812 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1814 id->Data1 = 0;
1815 for (i = 1; i < 9; i++) {
1816 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1817 id->Data1 = (id->Data1 << 4) | table[s[i]];
1819 if (s[9]!='-') return CO_E_CLASSSTRING;
1821 id->Data2 = 0;
1822 for (i = 10; i < 14; i++) {
1823 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1824 id->Data2 = (id->Data2 << 4) | table[s[i]];
1826 if (s[14]!='-') return CO_E_CLASSSTRING;
1828 id->Data3 = 0;
1829 for (i = 15; i < 19; i++) {
1830 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1831 id->Data3 = (id->Data3 << 4) | table[s[i]];
1833 if (s[19]!='-') return CO_E_CLASSSTRING;
1835 for (i = 20; i < 37; i+=2) {
1836 if (i == 24) {
1837 if (s[i]!='-') return CO_E_CLASSSTRING;
1838 i++;
1840 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1841 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1844 if (s[37] == '}' && s[38] == '\0')
1845 return S_OK;
1847 return CO_E_CLASSSTRING;
1850 /*****************************************************************************/
1852 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1854 HRESULT ret;
1856 if (!id)
1857 return E_INVALIDARG;
1859 ret = __CLSIDFromString(idstr, id);
1860 if(ret != S_OK) { /* It appears a ProgID is also valid */
1861 CLSID tmp_id;
1862 ret = CLSIDFromProgID(idstr, &tmp_id);
1863 if(SUCCEEDED(ret))
1864 *id = tmp_id;
1866 return ret;
1870 /******************************************************************************
1871 * StringFromCLSID [OLE32.@]
1872 * StringFromIID [OLE32.@]
1874 * Converts a GUID into the respective string representation.
1875 * The target string is allocated using the OLE IMalloc.
1877 * PARAMS
1878 * id [I] the GUID to be converted.
1879 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1881 * RETURNS
1882 * S_OK
1883 * E_FAIL
1885 * SEE ALSO
1886 * StringFromGUID2, CLSIDFromString
1888 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1890 HRESULT ret;
1891 LPMALLOC mllc;
1893 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1894 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1895 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1896 return S_OK;
1899 /******************************************************************************
1900 * StringFromGUID2 [OLE32.@]
1902 * Modified version of StringFromCLSID that allows you to specify max
1903 * buffer size.
1905 * PARAMS
1906 * id [I] GUID to convert to string.
1907 * str [O] Buffer where the result will be stored.
1908 * cmax [I] Size of the buffer in characters.
1910 * RETURNS
1911 * Success: The length of the resulting string in characters.
1912 * Failure: 0.
1914 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1916 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1917 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1918 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1919 '%','0','2','X','%','0','2','X','}',0 };
1920 if (!id || cmax < CHARS_IN_GUID) return 0;
1921 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1922 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1923 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1924 return CHARS_IN_GUID;
1927 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1928 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1930 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1931 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1932 LONG res;
1933 HKEY key;
1935 strcpyW(path, wszCLSIDSlash);
1936 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1937 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
1938 if (res == ERROR_FILE_NOT_FOUND)
1939 return REGDB_E_CLASSNOTREG;
1940 else if (res != ERROR_SUCCESS)
1941 return REGDB_E_READREGDB;
1943 if (!keyname)
1945 *subkey = key;
1946 return S_OK;
1949 res = open_classes_key(key, keyname, access, subkey);
1950 RegCloseKey(key);
1951 if (res == ERROR_FILE_NOT_FOUND)
1952 return REGDB_E_KEYMISSING;
1953 else if (res != ERROR_SUCCESS)
1954 return REGDB_E_READREGDB;
1956 return S_OK;
1959 /* open HKCR\\AppId\\{string form of appid clsid} key */
1960 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1962 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1963 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1964 DWORD res;
1965 WCHAR buf[CHARS_IN_GUID];
1966 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1967 DWORD size;
1968 HKEY hkey;
1969 DWORD type;
1970 HRESULT hr;
1972 /* read the AppID value under the class's key */
1973 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1974 if (FAILED(hr))
1975 return hr;
1977 size = sizeof(buf);
1978 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1979 RegCloseKey(hkey);
1980 if (res == ERROR_FILE_NOT_FOUND)
1981 return REGDB_E_KEYMISSING;
1982 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1983 return REGDB_E_READREGDB;
1985 strcpyW(keyname, szAppIdKey);
1986 strcatW(keyname, buf);
1987 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
1988 if (res == ERROR_FILE_NOT_FOUND)
1989 return REGDB_E_KEYMISSING;
1990 else if (res != ERROR_SUCCESS)
1991 return REGDB_E_READREGDB;
1993 return S_OK;
1996 /******************************************************************************
1997 * ProgIDFromCLSID [OLE32.@]
1999 * Converts a class id into the respective program ID.
2001 * PARAMS
2002 * clsid [I] Class ID, as found in registry.
2003 * ppszProgID [O] Associated ProgID.
2005 * RETURNS
2006 * S_OK
2007 * E_OUTOFMEMORY
2008 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2010 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2012 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2013 HKEY hkey;
2014 HRESULT ret;
2015 LONG progidlen = 0;
2017 if (!ppszProgID)
2019 ERR("ppszProgId isn't optional\n");
2020 return E_INVALIDARG;
2023 *ppszProgID = NULL;
2024 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2025 if (FAILED(ret))
2026 return ret;
2028 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2029 ret = REGDB_E_CLASSNOTREG;
2031 if (ret == S_OK)
2033 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2034 if (*ppszProgID)
2036 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2037 ret = REGDB_E_CLASSNOTREG;
2038 CoTaskMemFree(*ppszProgID);
2039 *ppszProgID = NULL;
2042 else
2043 ret = E_OUTOFMEMORY;
2046 RegCloseKey(hkey);
2047 return ret;
2050 /******************************************************************************
2051 * CLSIDFromProgID [OLE32.@]
2053 * Converts a program id into the respective GUID.
2055 * PARAMS
2056 * progid [I] Unicode program ID, as found in registry.
2057 * clsid [O] Associated CLSID.
2059 * RETURNS
2060 * Success: S_OK
2061 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2063 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2065 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2066 WCHAR buf2[CHARS_IN_GUID];
2067 LONG buf2len = sizeof(buf2);
2068 HKEY xhkey;
2069 WCHAR *buf;
2071 if (!progid || !clsid)
2073 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
2074 return E_INVALIDARG;
2077 /* initialise clsid in case of failure */
2078 memset(clsid, 0, sizeof(*clsid));
2080 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2081 strcpyW( buf, progid );
2082 strcatW( buf, clsidW );
2083 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2085 HeapFree(GetProcessHeap(),0,buf);
2086 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2087 return CO_E_CLASSSTRING;
2089 HeapFree(GetProcessHeap(),0,buf);
2091 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2093 RegCloseKey(xhkey);
2094 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2095 return CO_E_CLASSSTRING;
2097 RegCloseKey(xhkey);
2098 return __CLSIDFromString(buf2,clsid);
2101 /******************************************************************************
2102 * CLSIDFromProgIDEx [OLE32.@]
2104 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2106 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2108 return CLSIDFromProgID(progid, clsid);
2111 /*****************************************************************************
2112 * CoGetPSClsid [OLE32.@]
2114 * Retrieves the CLSID of the proxy/stub factory that implements
2115 * IPSFactoryBuffer for the specified interface.
2117 * PARAMS
2118 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2119 * pclsid [O] Where to store returned proxy/stub CLSID.
2121 * RETURNS
2122 * S_OK
2123 * E_OUTOFMEMORY
2124 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2126 * NOTES
2128 * The standard marshaller activates the object with the CLSID
2129 * returned and uses the CreateProxy and CreateStub methods on its
2130 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2131 * given object.
2133 * CoGetPSClsid determines this CLSID by searching the
2134 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2135 * in the registry and any interface id registered by
2136 * CoRegisterPSClsid within the current process.
2138 * BUGS
2140 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2141 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2142 * considered a bug in native unless an application depends on this (unlikely).
2144 * SEE ALSO
2145 * CoRegisterPSClsid.
2147 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2149 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2150 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2151 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2152 WCHAR value[CHARS_IN_GUID];
2153 LONG len;
2154 HKEY hkey;
2155 APARTMENT *apt = COM_CurrentApt();
2156 struct registered_psclsid *registered_psclsid;
2158 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2160 if (!apt)
2162 ERR("apartment not initialised\n");
2163 return CO_E_NOTINITIALIZED;
2166 if (!pclsid)
2168 ERR("pclsid isn't optional\n");
2169 return E_INVALIDARG;
2172 EnterCriticalSection(&apt->cs);
2174 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2175 if (IsEqualIID(&registered_psclsid->iid, riid))
2177 *pclsid = registered_psclsid->clsid;
2178 LeaveCriticalSection(&apt->cs);
2179 return S_OK;
2182 LeaveCriticalSection(&apt->cs);
2184 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2185 strcpyW(path, wszInterface);
2186 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2187 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2189 /* Open the key.. */
2190 if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
2192 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2193 return REGDB_E_IIDNOTREG;
2196 /* ... Once we have the key, query the registry to get the
2197 value of CLSID as a string, and convert it into a
2198 proper CLSID structure to be passed back to the app */
2199 len = sizeof(value);
2200 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2202 RegCloseKey(hkey);
2203 return REGDB_E_IIDNOTREG;
2205 RegCloseKey(hkey);
2207 /* We have the CLSID we want back from the registry as a string, so
2208 let's convert it into a CLSID structure */
2209 if (CLSIDFromString(value, pclsid) != NOERROR)
2210 return REGDB_E_IIDNOTREG;
2212 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2213 return S_OK;
2216 /*****************************************************************************
2217 * CoRegisterPSClsid [OLE32.@]
2219 * Register a proxy/stub CLSID for the given interface in the current process
2220 * only.
2222 * PARAMS
2223 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2224 * rclsid [I] CLSID of the proxy/stub.
2226 * RETURNS
2227 * Success: S_OK
2228 * Failure: E_OUTOFMEMORY
2230 * NOTES
2232 * This function does not add anything to the registry and the effects are
2233 * limited to the lifetime of the current process.
2235 * SEE ALSO
2236 * CoGetPSClsid.
2238 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2240 APARTMENT *apt = COM_CurrentApt();
2241 struct registered_psclsid *registered_psclsid;
2243 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2245 if (!apt)
2247 ERR("apartment not initialised\n");
2248 return CO_E_NOTINITIALIZED;
2251 EnterCriticalSection(&apt->cs);
2253 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2254 if (IsEqualIID(&registered_psclsid->iid, riid))
2256 registered_psclsid->clsid = *rclsid;
2257 LeaveCriticalSection(&apt->cs);
2258 return S_OK;
2261 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2262 if (!registered_psclsid)
2264 LeaveCriticalSection(&apt->cs);
2265 return E_OUTOFMEMORY;
2268 registered_psclsid->iid = *riid;
2269 registered_psclsid->clsid = *rclsid;
2270 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2272 LeaveCriticalSection(&apt->cs);
2274 return S_OK;
2278 /***
2279 * COM_GetRegisteredClassObject
2281 * This internal method is used to scan the registered class list to
2282 * find a class object.
2284 * Params:
2285 * rclsid Class ID of the class to find.
2286 * dwClsContext Class context to match.
2287 * ppv [out] returns a pointer to the class object. Complying
2288 * to normal COM usage, this method will increase the
2289 * reference count on this object.
2291 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2292 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2294 HRESULT hr = S_FALSE;
2295 RegisteredClass *curClass;
2297 EnterCriticalSection( &csRegisteredClassList );
2299 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2302 * Check if we have a match on the class ID and context.
2304 if ((apt->oxid == curClass->apartment_id) &&
2305 (dwClsContext & curClass->runContext) &&
2306 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2309 * We have a match, return the pointer to the class object.
2311 *ppUnk = curClass->classObject;
2313 IUnknown_AddRef(curClass->classObject);
2315 hr = S_OK;
2316 break;
2320 LeaveCriticalSection( &csRegisteredClassList );
2322 return hr;
2325 /******************************************************************************
2326 * CoRegisterClassObject [OLE32.@]
2328 * Registers the class object for a given class ID. Servers housed in EXE
2329 * files use this method instead of exporting DllGetClassObject to allow
2330 * other code to connect to their objects.
2332 * PARAMS
2333 * rclsid [I] CLSID of the object to register.
2334 * pUnk [I] IUnknown of the object.
2335 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2336 * flags [I] REGCLS flags indicating how connections are made.
2337 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2339 * RETURNS
2340 * S_OK on success,
2341 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2342 * CO_E_OBJISREG if the object is already registered. We should not return this.
2344 * SEE ALSO
2345 * CoRevokeClassObject, CoGetClassObject
2347 * NOTES
2348 * In-process objects are only registered for the current apartment.
2349 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2350 * in other apartments.
2352 * BUGS
2353 * MSDN claims that multiple interface registrations are legal, but we
2354 * can't do that with our current implementation.
2356 HRESULT WINAPI CoRegisterClassObject(
2357 REFCLSID rclsid,
2358 LPUNKNOWN pUnk,
2359 DWORD dwClsContext,
2360 DWORD flags,
2361 LPDWORD lpdwRegister)
2363 static LONG next_cookie;
2364 RegisteredClass* newClass;
2365 LPUNKNOWN foundObject;
2366 HRESULT hr;
2367 APARTMENT *apt;
2369 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2370 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2372 if ( (lpdwRegister==0) || (pUnk==0) )
2373 return E_INVALIDARG;
2375 apt = COM_CurrentApt();
2376 if (!apt)
2378 ERR("COM was not initialized\n");
2379 return CO_E_NOTINITIALIZED;
2382 *lpdwRegister = 0;
2384 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2385 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2386 if (flags & REGCLS_MULTIPLEUSE)
2387 dwClsContext |= CLSCTX_INPROC_SERVER;
2390 * First, check if the class is already registered.
2391 * If it is, this should cause an error.
2393 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2394 if (hr == S_OK) {
2395 if (flags & REGCLS_MULTIPLEUSE) {
2396 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2397 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2398 IUnknown_Release(foundObject);
2399 return hr;
2401 IUnknown_Release(foundObject);
2402 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2403 return CO_E_OBJISREG;
2406 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2407 if ( newClass == NULL )
2408 return E_OUTOFMEMORY;
2410 newClass->classIdentifier = *rclsid;
2411 newClass->apartment_id = apt->oxid;
2412 newClass->runContext = dwClsContext;
2413 newClass->connectFlags = flags;
2414 newClass->pMarshaledData = NULL;
2415 newClass->RpcRegistration = NULL;
2417 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2418 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2421 * Since we're making a copy of the object pointer, we have to increase its
2422 * reference count.
2424 newClass->classObject = pUnk;
2425 IUnknown_AddRef(newClass->classObject);
2427 EnterCriticalSection( &csRegisteredClassList );
2428 list_add_tail(&RegisteredClassList, &newClass->entry);
2429 LeaveCriticalSection( &csRegisteredClassList );
2431 *lpdwRegister = newClass->dwCookie;
2433 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2434 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2435 if (hr) {
2436 FIXME("Failed to create stream on hglobal, %x\n", hr);
2437 return hr;
2439 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2440 newClass->classObject, MSHCTX_LOCAL, NULL,
2441 MSHLFLAGS_TABLESTRONG);
2442 if (hr) {
2443 FIXME("CoMarshalInterface failed, %x!\n",hr);
2444 return hr;
2447 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2448 newClass->pMarshaledData,
2449 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2450 &newClass->RpcRegistration);
2452 return S_OK;
2455 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2457 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2458 DWORD keytype;
2459 DWORD ret;
2460 DWORD dwLength = len * sizeof(WCHAR);
2462 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2463 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2464 value[0] = '\0';
2467 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2468 REFCLSID rclsid, REFIID riid,
2469 BOOL hostifnecessary, void **ppv)
2471 WCHAR dllpath[MAX_PATH+1];
2472 BOOL apartment_threaded;
2474 if (hostifnecessary)
2476 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2477 static const WCHAR wszFree[] = {'F','r','e','e',0};
2478 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2479 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2481 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2482 /* "Apartment" */
2483 if (!strcmpiW(threading_model, wszApartment))
2485 apartment_threaded = TRUE;
2486 if (apt->multi_threaded)
2487 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2489 /* "Free" */
2490 else if (!strcmpiW(threading_model, wszFree))
2492 apartment_threaded = FALSE;
2493 if (!apt->multi_threaded)
2494 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2496 /* everything except "Apartment", "Free" and "Both" */
2497 else if (strcmpiW(threading_model, wszBoth))
2499 apartment_threaded = TRUE;
2500 /* everything else is main-threaded */
2501 if (threading_model[0])
2502 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2503 debugstr_w(threading_model), debugstr_guid(rclsid));
2505 if (apt->multi_threaded || !apt->main)
2506 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2508 else
2509 apartment_threaded = FALSE;
2511 else
2512 apartment_threaded = !apt->multi_threaded;
2514 if (COM_RegReadPath(hkeydll, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2516 /* failure: CLSID is not found in registry */
2517 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2518 return REGDB_E_CLASSNOTREG;
2521 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2522 rclsid, riid, ppv);
2525 /***********************************************************************
2526 * CoGetClassObject [OLE32.@]
2528 * Creates an object of the specified class.
2530 * PARAMS
2531 * rclsid [I] Class ID to create an instance of.
2532 * dwClsContext [I] Flags to restrict the location of the created instance.
2533 * pServerInfo [I] Optional. Details for connecting to a remote server.
2534 * iid [I] The ID of the interface of the instance to return.
2535 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2537 * RETURNS
2538 * Success: S_OK
2539 * Failure: HRESULT code.
2541 * NOTES
2542 * The dwClsContext parameter can be one or more of the following:
2543 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2544 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2545 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2546 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2548 * SEE ALSO
2549 * CoCreateInstance()
2551 HRESULT WINAPI CoGetClassObject(
2552 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2553 REFIID iid, LPVOID *ppv)
2555 LPUNKNOWN regClassObject;
2556 HRESULT hres = E_UNEXPECTED;
2557 APARTMENT *apt;
2558 BOOL release_apt = FALSE;
2560 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2562 if (!ppv)
2563 return E_INVALIDARG;
2565 *ppv = NULL;
2567 if (!(apt = COM_CurrentApt()))
2569 if (!(apt = apartment_find_multi_threaded()))
2571 ERR("apartment not initialised\n");
2572 return CO_E_NOTINITIALIZED;
2574 release_apt = TRUE;
2577 if (pServerInfo) {
2578 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2579 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2583 * First, try and see if we can't match the class ID with one of the
2584 * registered classes.
2586 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2587 &regClassObject))
2589 /* Get the required interface from the retrieved pointer. */
2590 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2593 * Since QI got another reference on the pointer, we want to release the
2594 * one we already have. If QI was unsuccessful, this will release the object. This
2595 * is good since we are not returning it in the "out" parameter.
2597 IUnknown_Release(regClassObject);
2598 if (release_apt) apartment_release(apt);
2599 return hres;
2602 /* First try in-process server */
2603 if (CLSCTX_INPROC_SERVER & dwClsContext)
2605 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2606 HKEY hkey;
2608 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2610 if (release_apt) apartment_release(apt);
2611 return FTMarshalCF_Create(iid, ppv);
2614 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2615 if (FAILED(hres))
2617 if (hres == REGDB_E_CLASSNOTREG)
2618 ERR("class %s not registered\n", debugstr_guid(rclsid));
2619 else if (hres == REGDB_E_KEYMISSING)
2621 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2622 hres = REGDB_E_CLASSNOTREG;
2626 if (SUCCEEDED(hres))
2628 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2629 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2630 RegCloseKey(hkey);
2633 /* return if we got a class, otherwise fall through to one of the
2634 * other types */
2635 if (SUCCEEDED(hres))
2637 if (release_apt) apartment_release(apt);
2638 return hres;
2642 /* Next try in-process handler */
2643 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2645 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2646 HKEY hkey;
2648 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2649 if (FAILED(hres))
2651 if (hres == REGDB_E_CLASSNOTREG)
2652 ERR("class %s not registered\n", debugstr_guid(rclsid));
2653 else if (hres == REGDB_E_KEYMISSING)
2655 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2656 hres = REGDB_E_CLASSNOTREG;
2660 if (SUCCEEDED(hres))
2662 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2663 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2664 RegCloseKey(hkey);
2667 /* return if we got a class, otherwise fall through to one of the
2668 * other types */
2669 if (SUCCEEDED(hres))
2671 if (release_apt) apartment_release(apt);
2672 return hres;
2675 if (release_apt) apartment_release(apt);
2677 /* Next try out of process */
2678 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2680 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2681 if (SUCCEEDED(hres))
2682 return hres;
2685 /* Finally try remote: this requires networked DCOM (a lot of work) */
2686 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2688 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2689 hres = REGDB_E_CLASSNOTREG;
2692 if (FAILED(hres))
2693 ERR("no class object %s could be created for context 0x%x\n",
2694 debugstr_guid(rclsid), dwClsContext);
2695 return hres;
2698 /***********************************************************************
2699 * CoResumeClassObjects (OLE32.@)
2701 * Resumes all class objects registered with REGCLS_SUSPENDED.
2703 * RETURNS
2704 * Success: S_OK.
2705 * Failure: HRESULT code.
2707 HRESULT WINAPI CoResumeClassObjects(void)
2709 FIXME("stub\n");
2710 return S_OK;
2713 /***********************************************************************
2714 * CoCreateInstance [OLE32.@]
2716 * Creates an instance of the specified class.
2718 * PARAMS
2719 * rclsid [I] Class ID to create an instance of.
2720 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2721 * dwClsContext [I] Flags to restrict the location of the created instance.
2722 * iid [I] The ID of the interface of the instance to return.
2723 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2725 * RETURNS
2726 * Success: S_OK
2727 * Failure: HRESULT code.
2729 * NOTES
2730 * The dwClsContext parameter can be one or more of the following:
2731 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2732 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2733 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2734 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2736 * Aggregation is the concept of deferring the IUnknown of an object to another
2737 * object. This allows a separate object to behave as though it was part of
2738 * the object and to allow this the pUnkOuter parameter can be set. Note that
2739 * not all objects support having an outer of unknown.
2741 * SEE ALSO
2742 * CoGetClassObject()
2744 HRESULT WINAPI CoCreateInstance(
2745 REFCLSID rclsid,
2746 LPUNKNOWN pUnkOuter,
2747 DWORD dwClsContext,
2748 REFIID iid,
2749 LPVOID *ppv)
2751 HRESULT hres;
2752 LPCLASSFACTORY lpclf = 0;
2753 APARTMENT *apt;
2755 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2756 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2758 if (ppv==0)
2759 return E_POINTER;
2761 *ppv = 0;
2763 if (!(apt = COM_CurrentApt()))
2765 if (!(apt = apartment_find_multi_threaded()))
2767 ERR("apartment not initialised\n");
2768 return CO_E_NOTINITIALIZED;
2770 apartment_release(apt);
2774 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2775 * Rather than create a class factory, we can just check for it here
2777 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable))
2779 if (StdGlobalInterfaceTableInstance == NULL)
2780 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2781 hres = IGlobalInterfaceTable_QueryInterface((IGlobalInterfaceTable*)StdGlobalInterfaceTableInstance,
2782 iid,
2783 ppv);
2784 if (hres) return hres;
2786 TRACE("Retrieved GIT (%p)\n", *ppv);
2787 return S_OK;
2790 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2791 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2794 * Get a class factory to construct the object we want.
2796 hres = CoGetClassObject(rclsid,
2797 dwClsContext,
2798 NULL,
2799 &IID_IClassFactory,
2800 (LPVOID)&lpclf);
2802 if (FAILED(hres))
2803 return hres;
2806 * Create the object and don't forget to release the factory
2808 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2809 IClassFactory_Release(lpclf);
2810 if (FAILED(hres))
2812 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2813 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2814 else
2815 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2816 debugstr_guid(iid),
2817 debugstr_guid(rclsid),hres);
2820 return hres;
2823 /***********************************************************************
2824 * CoCreateInstanceEx [OLE32.@]
2826 HRESULT WINAPI CoCreateInstanceEx(
2827 REFCLSID rclsid,
2828 LPUNKNOWN pUnkOuter,
2829 DWORD dwClsContext,
2830 COSERVERINFO* pServerInfo,
2831 ULONG cmq,
2832 MULTI_QI* pResults)
2834 IUnknown* pUnk = NULL;
2835 HRESULT hr;
2836 ULONG index;
2837 ULONG successCount = 0;
2840 * Sanity check
2842 if ( (cmq==0) || (pResults==NULL))
2843 return E_INVALIDARG;
2845 if (pServerInfo!=NULL)
2846 FIXME("() non-NULL pServerInfo not supported!\n");
2849 * Initialize all the "out" parameters.
2851 for (index = 0; index < cmq; index++)
2853 pResults[index].pItf = NULL;
2854 pResults[index].hr = E_NOINTERFACE;
2858 * Get the object and get its IUnknown pointer.
2860 hr = CoCreateInstance(rclsid,
2861 pUnkOuter,
2862 dwClsContext,
2863 &IID_IUnknown,
2864 (VOID**)&pUnk);
2866 if (hr)
2867 return hr;
2870 * Then, query for all the interfaces requested.
2872 for (index = 0; index < cmq; index++)
2874 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2875 pResults[index].pIID,
2876 (VOID**)&(pResults[index].pItf));
2878 if (pResults[index].hr == S_OK)
2879 successCount++;
2883 * Release our temporary unknown pointer.
2885 IUnknown_Release(pUnk);
2887 if (successCount == 0)
2888 return E_NOINTERFACE;
2890 if (successCount!=cmq)
2891 return CO_S_NOTALLINTERFACES;
2893 return S_OK;
2896 /***********************************************************************
2897 * CoLoadLibrary (OLE32.@)
2899 * Loads a library.
2901 * PARAMS
2902 * lpszLibName [I] Path to library.
2903 * bAutoFree [I] Whether the library should automatically be freed.
2905 * RETURNS
2906 * Success: Handle to loaded library.
2907 * Failure: NULL.
2909 * SEE ALSO
2910 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2912 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2914 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2916 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2919 /***********************************************************************
2920 * CoFreeLibrary [OLE32.@]
2922 * Unloads a library from memory.
2924 * PARAMS
2925 * hLibrary [I] Handle to library to unload.
2927 * RETURNS
2928 * Nothing
2930 * SEE ALSO
2931 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2933 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2935 FreeLibrary(hLibrary);
2939 /***********************************************************************
2940 * CoFreeAllLibraries [OLE32.@]
2942 * Function for backwards compatibility only. Does nothing.
2944 * RETURNS
2945 * Nothing.
2947 * SEE ALSO
2948 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2950 void WINAPI CoFreeAllLibraries(void)
2952 /* NOP */
2955 /***********************************************************************
2956 * CoFreeUnusedLibrariesEx [OLE32.@]
2958 * Frees any previously unused libraries whose delay has expired and marks
2959 * currently unused libraries for unloading. Unused are identified as those that
2960 * return S_OK from their DllCanUnloadNow function.
2962 * PARAMS
2963 * dwUnloadDelay [I] Unload delay in milliseconds.
2964 * dwReserved [I] Reserved. Set to 0.
2966 * RETURNS
2967 * Nothing.
2969 * SEE ALSO
2970 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2972 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2974 struct apartment *apt = COM_CurrentApt();
2975 if (!apt)
2977 ERR("apartment not initialised\n");
2978 return;
2981 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2984 /***********************************************************************
2985 * CoFreeUnusedLibraries [OLE32.@]
2987 * Frees any unused libraries. Unused are identified as those that return
2988 * S_OK from their DllCanUnloadNow function.
2990 * RETURNS
2991 * Nothing.
2993 * SEE ALSO
2994 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2996 void WINAPI CoFreeUnusedLibraries(void)
2998 CoFreeUnusedLibrariesEx(INFINITE, 0);
3001 /***********************************************************************
3002 * CoFileTimeNow [OLE32.@]
3004 * Retrieves the current time in FILETIME format.
3006 * PARAMS
3007 * lpFileTime [O] The current time.
3009 * RETURNS
3010 * S_OK.
3012 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3014 GetSystemTimeAsFileTime( lpFileTime );
3015 return S_OK;
3018 /******************************************************************************
3019 * CoLockObjectExternal [OLE32.@]
3021 * Increments or decrements the external reference count of a stub object.
3023 * PARAMS
3024 * pUnk [I] Stub object.
3025 * fLock [I] If TRUE then increments the external ref-count,
3026 * otherwise decrements.
3027 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3028 * calling CoDisconnectObject.
3030 * RETURNS
3031 * Success: S_OK.
3032 * Failure: HRESULT code.
3034 * NOTES
3035 * If fLock is TRUE and an object is passed in that doesn't have a stub
3036 * manager then a new stub manager is created for the object.
3038 HRESULT WINAPI CoLockObjectExternal(
3039 LPUNKNOWN pUnk,
3040 BOOL fLock,
3041 BOOL fLastUnlockReleases)
3043 struct stub_manager *stubmgr;
3044 struct apartment *apt;
3046 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3047 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3049 apt = COM_CurrentApt();
3050 if (!apt) return CO_E_NOTINITIALIZED;
3052 stubmgr = get_stub_manager_from_object(apt, pUnk);
3054 if (stubmgr)
3056 if (fLock)
3057 stub_manager_ext_addref(stubmgr, 1, FALSE);
3058 else
3059 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3061 stub_manager_int_release(stubmgr);
3063 return S_OK;
3065 else if (fLock)
3067 stubmgr = new_stub_manager(apt, pUnk);
3069 if (stubmgr)
3071 stub_manager_ext_addref(stubmgr, 1, FALSE);
3072 stub_manager_int_release(stubmgr);
3075 return S_OK;
3077 else
3079 WARN("stub object not found %p\n", pUnk);
3080 /* Note: native is pretty broken here because it just silently
3081 * fails, without returning an appropriate error code, making apps
3082 * think that the object was disconnected, when it actually wasn't */
3083 return S_OK;
3087 /***********************************************************************
3088 * CoInitializeWOW (OLE32.@)
3090 * WOW equivalent of CoInitialize?
3092 * PARAMS
3093 * x [I] Unknown.
3094 * y [I] Unknown.
3096 * RETURNS
3097 * Unknown.
3099 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3101 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3102 return 0;
3105 /***********************************************************************
3106 * CoGetState [OLE32.@]
3108 * Retrieves the thread state object previously stored by CoSetState().
3110 * PARAMS
3111 * ppv [I] Address where pointer to object will be stored.
3113 * RETURNS
3114 * Success: S_OK.
3115 * Failure: E_OUTOFMEMORY.
3117 * NOTES
3118 * Crashes on all invalid ppv addresses, including NULL.
3119 * If the function returns a non-NULL object then the caller must release its
3120 * reference on the object when the object is no longer required.
3122 * SEE ALSO
3123 * CoSetState().
3125 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3127 struct oletls *info = COM_CurrentInfo();
3128 if (!info) return E_OUTOFMEMORY;
3130 *ppv = NULL;
3132 if (info->state)
3134 IUnknown_AddRef(info->state);
3135 *ppv = info->state;
3136 TRACE("apt->state=%p\n", info->state);
3139 return S_OK;
3142 /***********************************************************************
3143 * CoSetState [OLE32.@]
3145 * Sets the thread state object.
3147 * PARAMS
3148 * pv [I] Pointer to state object to be stored.
3150 * NOTES
3151 * The system keeps a reference on the object while the object stored.
3153 * RETURNS
3154 * Success: S_OK.
3155 * Failure: E_OUTOFMEMORY.
3157 HRESULT WINAPI CoSetState(IUnknown * pv)
3159 struct oletls *info = COM_CurrentInfo();
3160 if (!info) return E_OUTOFMEMORY;
3162 if (pv) IUnknown_AddRef(pv);
3164 if (info->state)
3166 TRACE("-- release %p now\n", info->state);
3167 IUnknown_Release(info->state);
3170 info->state = pv;
3172 return S_OK;
3176 /******************************************************************************
3177 * CoTreatAsClass [OLE32.@]
3179 * Sets the TreatAs value of a class.
3181 * PARAMS
3182 * clsidOld [I] Class to set TreatAs value on.
3183 * clsidNew [I] The class the clsidOld should be treated as.
3185 * RETURNS
3186 * Success: S_OK.
3187 * Failure: HRESULT code.
3189 * SEE ALSO
3190 * CoGetTreatAsClass
3192 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3194 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3195 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3196 HKEY hkey = NULL;
3197 WCHAR szClsidNew[CHARS_IN_GUID];
3198 HRESULT res = S_OK;
3199 WCHAR auto_treat_as[CHARS_IN_GUID];
3200 LONG auto_treat_as_size = sizeof(auto_treat_as);
3201 CLSID id;
3203 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3204 if (FAILED(res))
3205 goto done;
3206 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3208 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3209 CLSIDFromString(auto_treat_as, &id) == S_OK)
3211 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3213 res = REGDB_E_WRITEREGDB;
3214 goto done;
3217 else
3219 RegDeleteKeyW(hkey, wszTreatAs);
3220 goto done;
3223 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3224 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3226 res = REGDB_E_WRITEREGDB;
3227 goto done;
3230 done:
3231 if (hkey) RegCloseKey(hkey);
3232 return res;
3235 /******************************************************************************
3236 * CoGetTreatAsClass [OLE32.@]
3238 * Gets the TreatAs value of a class.
3240 * PARAMS
3241 * clsidOld [I] Class to get the TreatAs value of.
3242 * clsidNew [I] The class the clsidOld should be treated as.
3244 * RETURNS
3245 * Success: S_OK.
3246 * Failure: HRESULT code.
3248 * SEE ALSO
3249 * CoSetTreatAsClass
3251 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3253 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3254 HKEY hkey = NULL;
3255 WCHAR szClsidNew[CHARS_IN_GUID];
3256 HRESULT res = S_OK;
3257 LONG len = sizeof(szClsidNew);
3259 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3260 *clsidNew = *clsidOld; /* copy over old value */
3262 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3263 if (FAILED(res))
3265 res = S_FALSE;
3266 goto done;
3268 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3270 res = S_FALSE;
3271 goto done;
3273 res = CLSIDFromString(szClsidNew,clsidNew);
3274 if (FAILED(res))
3275 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3276 done:
3277 if (hkey) RegCloseKey(hkey);
3278 return res;
3281 /******************************************************************************
3282 * CoGetCurrentProcess [OLE32.@]
3284 * Gets the current process ID.
3286 * RETURNS
3287 * The current process ID.
3289 * NOTES
3290 * Is DWORD really the correct return type for this function?
3292 DWORD WINAPI CoGetCurrentProcess(void)
3294 return GetCurrentProcessId();
3297 /******************************************************************************
3298 * CoRegisterMessageFilter [OLE32.@]
3300 * Registers a message filter.
3302 * PARAMS
3303 * lpMessageFilter [I] Pointer to interface.
3304 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3306 * RETURNS
3307 * Success: S_OK.
3308 * Failure: HRESULT code.
3310 * NOTES
3311 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3312 * lpMessageFilter removes the message filter.
3314 * If lplpMessageFilter is not NULL the previous message filter will be
3315 * returned in the memory pointer to this parameter and the caller is
3316 * responsible for releasing the object.
3318 * The current thread be in an apartment otherwise the function will crash.
3320 HRESULT WINAPI CoRegisterMessageFilter(
3321 LPMESSAGEFILTER lpMessageFilter,
3322 LPMESSAGEFILTER *lplpMessageFilter)
3324 struct apartment *apt;
3325 IMessageFilter *lpOldMessageFilter;
3327 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3329 apt = COM_CurrentApt();
3331 /* can't set a message filter in a multi-threaded apartment */
3332 if (!apt || apt->multi_threaded)
3334 WARN("can't set message filter in MTA or uninitialized apt\n");
3335 return CO_E_NOT_SUPPORTED;
3338 if (lpMessageFilter)
3339 IMessageFilter_AddRef(lpMessageFilter);
3341 EnterCriticalSection(&apt->cs);
3343 lpOldMessageFilter = apt->filter;
3344 apt->filter = lpMessageFilter;
3346 LeaveCriticalSection(&apt->cs);
3348 if (lplpMessageFilter)
3349 *lplpMessageFilter = lpOldMessageFilter;
3350 else if (lpOldMessageFilter)
3351 IMessageFilter_Release(lpOldMessageFilter);
3353 return S_OK;
3356 /***********************************************************************
3357 * CoIsOle1Class [OLE32.@]
3359 * Determines whether the specified class an OLE v1 class.
3361 * PARAMS
3362 * clsid [I] Class to test.
3364 * RETURNS
3365 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3367 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3369 FIXME("%s\n", debugstr_guid(clsid));
3370 return FALSE;
3373 /***********************************************************************
3374 * IsEqualGUID [OLE32.@]
3376 * Compares two Unique Identifiers.
3378 * PARAMS
3379 * rguid1 [I] The first GUID to compare.
3380 * rguid2 [I] The other GUID to compare.
3382 * RETURNS
3383 * TRUE if equal
3385 #undef IsEqualGUID
3386 BOOL WINAPI IsEqualGUID(
3387 REFGUID rguid1,
3388 REFGUID rguid2)
3390 return !memcmp(rguid1,rguid2,sizeof(GUID));
3393 /***********************************************************************
3394 * CoInitializeSecurity [OLE32.@]
3396 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3397 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3398 void* pReserved1, DWORD dwAuthnLevel,
3399 DWORD dwImpLevel, void* pReserved2,
3400 DWORD dwCapabilities, void* pReserved3)
3402 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3403 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3404 dwCapabilities, pReserved3);
3405 return S_OK;
3408 /***********************************************************************
3409 * CoSuspendClassObjects [OLE32.@]
3411 * Suspends all registered class objects to prevent further requests coming in
3412 * for those objects.
3414 * RETURNS
3415 * Success: S_OK.
3416 * Failure: HRESULT code.
3418 HRESULT WINAPI CoSuspendClassObjects(void)
3420 FIXME("\n");
3421 return S_OK;
3424 /***********************************************************************
3425 * CoAddRefServerProcess [OLE32.@]
3427 * Helper function for incrementing the reference count of a local-server
3428 * process.
3430 * RETURNS
3431 * New reference count.
3433 * SEE ALSO
3434 * CoReleaseServerProcess().
3436 ULONG WINAPI CoAddRefServerProcess(void)
3438 ULONG refs;
3440 TRACE("\n");
3442 EnterCriticalSection(&csRegisteredClassList);
3443 refs = ++s_COMServerProcessReferences;
3444 LeaveCriticalSection(&csRegisteredClassList);
3446 TRACE("refs before: %d\n", refs - 1);
3448 return refs;
3451 /***********************************************************************
3452 * CoReleaseServerProcess [OLE32.@]
3454 * Helper function for decrementing the reference count of a local-server
3455 * process.
3457 * RETURNS
3458 * New reference count.
3460 * NOTES
3461 * When reference count reaches 0, this function suspends all registered
3462 * classes so no new connections are accepted.
3464 * SEE ALSO
3465 * CoAddRefServerProcess(), CoSuspendClassObjects().
3467 ULONG WINAPI CoReleaseServerProcess(void)
3469 ULONG refs;
3471 TRACE("\n");
3473 EnterCriticalSection(&csRegisteredClassList);
3475 refs = --s_COMServerProcessReferences;
3476 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3478 LeaveCriticalSection(&csRegisteredClassList);
3480 TRACE("refs after: %d\n", refs);
3482 return refs;
3485 /***********************************************************************
3486 * CoIsHandlerConnected [OLE32.@]
3488 * Determines whether a proxy is connected to a remote stub.
3490 * PARAMS
3491 * pUnk [I] Pointer to object that may or may not be connected.
3493 * RETURNS
3494 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3495 * FALSE otherwise.
3497 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3499 FIXME("%p\n", pUnk);
3501 return TRUE;
3504 /***********************************************************************
3505 * CoAllowSetForegroundWindow [OLE32.@]
3508 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3510 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3511 return S_OK;
3514 /***********************************************************************
3515 * CoQueryProxyBlanket [OLE32.@]
3517 * Retrieves the security settings being used by a proxy.
3519 * PARAMS
3520 * pProxy [I] Pointer to the proxy object.
3521 * pAuthnSvc [O] The type of authentication service.
3522 * pAuthzSvc [O] The type of authorization service.
3523 * ppServerPrincName [O] Optional. The server prinicple name.
3524 * pAuthnLevel [O] The authentication level.
3525 * pImpLevel [O] The impersonation level.
3526 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3527 * pCapabilities [O] Flags affecting the security behaviour.
3529 * RETURNS
3530 * Success: S_OK.
3531 * Failure: HRESULT code.
3533 * SEE ALSO
3534 * CoCopyProxy, CoSetProxyBlanket.
3536 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3537 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3538 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3540 IClientSecurity *pCliSec;
3541 HRESULT hr;
3543 TRACE("%p\n", pProxy);
3545 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3546 if (SUCCEEDED(hr))
3548 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3549 pAuthzSvc, ppServerPrincName,
3550 pAuthnLevel, pImpLevel, ppAuthInfo,
3551 pCapabilities);
3552 IClientSecurity_Release(pCliSec);
3555 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3556 return hr;
3559 /***********************************************************************
3560 * CoSetProxyBlanket [OLE32.@]
3562 * Sets the security settings for a proxy.
3564 * PARAMS
3565 * pProxy [I] Pointer to the proxy object.
3566 * AuthnSvc [I] The type of authentication service.
3567 * AuthzSvc [I] The type of authorization service.
3568 * pServerPrincName [I] The server prinicple name.
3569 * AuthnLevel [I] The authentication level.
3570 * ImpLevel [I] The impersonation level.
3571 * pAuthInfo [I] Information specific to the authorization/authentication service.
3572 * Capabilities [I] Flags affecting the security behaviour.
3574 * RETURNS
3575 * Success: S_OK.
3576 * Failure: HRESULT code.
3578 * SEE ALSO
3579 * CoQueryProxyBlanket, CoCopyProxy.
3581 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3582 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3583 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3585 IClientSecurity *pCliSec;
3586 HRESULT hr;
3588 TRACE("%p\n", pProxy);
3590 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3591 if (SUCCEEDED(hr))
3593 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3594 AuthzSvc, pServerPrincName,
3595 AuthnLevel, ImpLevel, pAuthInfo,
3596 Capabilities);
3597 IClientSecurity_Release(pCliSec);
3600 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3601 return hr;
3604 /***********************************************************************
3605 * CoCopyProxy [OLE32.@]
3607 * Copies a proxy.
3609 * PARAMS
3610 * pProxy [I] Pointer to the proxy object.
3611 * ppCopy [O] Copy of the proxy.
3613 * RETURNS
3614 * Success: S_OK.
3615 * Failure: HRESULT code.
3617 * SEE ALSO
3618 * CoQueryProxyBlanket, CoSetProxyBlanket.
3620 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3622 IClientSecurity *pCliSec;
3623 HRESULT hr;
3625 TRACE("%p\n", pProxy);
3627 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3628 if (SUCCEEDED(hr))
3630 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3631 IClientSecurity_Release(pCliSec);
3634 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3635 return hr;
3639 /***********************************************************************
3640 * CoGetCallContext [OLE32.@]
3642 * Gets the context of the currently executing server call in the current
3643 * thread.
3645 * PARAMS
3646 * riid [I] Context interface to return.
3647 * ppv [O] Pointer to memory that will receive the context on return.
3649 * RETURNS
3650 * Success: S_OK.
3651 * Failure: HRESULT code.
3653 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3655 struct oletls *info = COM_CurrentInfo();
3657 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3659 if (!info)
3660 return E_OUTOFMEMORY;
3662 if (!info->call_state)
3663 return RPC_E_CALL_COMPLETE;
3665 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3668 /***********************************************************************
3669 * CoSwitchCallContext [OLE32.@]
3671 * Switches the context of the currently executing server call in the current
3672 * thread.
3674 * PARAMS
3675 * pObject [I] Pointer to new context object
3676 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3678 * RETURNS
3679 * Success: S_OK.
3680 * Failure: HRESULT code.
3682 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3684 struct oletls *info = COM_CurrentInfo();
3686 TRACE("(%p, %p)\n", pObject, ppOldObject);
3688 if (!info)
3689 return E_OUTOFMEMORY;
3691 *ppOldObject = info->call_state;
3692 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3694 return S_OK;
3697 /***********************************************************************
3698 * CoQueryClientBlanket [OLE32.@]
3700 * Retrieves the authentication information about the client of the currently
3701 * executing server call in the current thread.
3703 * PARAMS
3704 * pAuthnSvc [O] Optional. The type of authentication service.
3705 * pAuthzSvc [O] Optional. The type of authorization service.
3706 * pServerPrincName [O] Optional. The server prinicple name.
3707 * pAuthnLevel [O] Optional. The authentication level.
3708 * pImpLevel [O] Optional. The impersonation level.
3709 * pPrivs [O] Optional. Information about the privileges of the client.
3710 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3712 * RETURNS
3713 * Success: S_OK.
3714 * Failure: HRESULT code.
3716 * SEE ALSO
3717 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3719 HRESULT WINAPI CoQueryClientBlanket(
3720 DWORD *pAuthnSvc,
3721 DWORD *pAuthzSvc,
3722 OLECHAR **pServerPrincName,
3723 DWORD *pAuthnLevel,
3724 DWORD *pImpLevel,
3725 RPC_AUTHZ_HANDLE *pPrivs,
3726 DWORD *pCapabilities)
3728 IServerSecurity *pSrvSec;
3729 HRESULT hr;
3731 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3732 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3733 pPrivs, pCapabilities);
3735 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3736 if (SUCCEEDED(hr))
3738 hr = IServerSecurity_QueryBlanket(
3739 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3740 pImpLevel, pPrivs, pCapabilities);
3741 IServerSecurity_Release(pSrvSec);
3744 return hr;
3747 /***********************************************************************
3748 * CoImpersonateClient [OLE32.@]
3750 * Impersonates the client of the currently executing server call in the
3751 * current thread.
3753 * PARAMS
3754 * None.
3756 * RETURNS
3757 * Success: S_OK.
3758 * Failure: HRESULT code.
3760 * NOTES
3761 * If this function fails then the current thread will not be impersonating
3762 * the client and all actions will take place on behalf of the server.
3763 * Therefore, it is important to check the return value from this function.
3765 * SEE ALSO
3766 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3768 HRESULT WINAPI CoImpersonateClient(void)
3770 IServerSecurity *pSrvSec;
3771 HRESULT hr;
3773 TRACE("\n");
3775 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3776 if (SUCCEEDED(hr))
3778 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3779 IServerSecurity_Release(pSrvSec);
3782 return hr;
3785 /***********************************************************************
3786 * CoRevertToSelf [OLE32.@]
3788 * Ends the impersonation of the client of the currently executing server
3789 * call in the current thread.
3791 * PARAMS
3792 * None.
3794 * RETURNS
3795 * Success: S_OK.
3796 * Failure: HRESULT code.
3798 * SEE ALSO
3799 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3801 HRESULT WINAPI CoRevertToSelf(void)
3803 IServerSecurity *pSrvSec;
3804 HRESULT hr;
3806 TRACE("\n");
3808 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3809 if (SUCCEEDED(hr))
3811 hr = IServerSecurity_RevertToSelf(pSrvSec);
3812 IServerSecurity_Release(pSrvSec);
3815 return hr;
3818 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3820 /* first try to retrieve messages for incoming COM calls to the apartment window */
3821 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
3822 /* next retrieve other messages necessary for the app to remain responsive */
3823 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3824 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3827 /***********************************************************************
3828 * CoWaitForMultipleHandles [OLE32.@]
3830 * Waits for one or more handles to become signaled.
3832 * PARAMS
3833 * dwFlags [I] Flags. See notes.
3834 * dwTimeout [I] Timeout in milliseconds.
3835 * cHandles [I] Number of handles pointed to by pHandles.
3836 * pHandles [I] Handles to wait for.
3837 * lpdwindex [O] Index of handle that was signaled.
3839 * RETURNS
3840 * Success: S_OK.
3841 * Failure: RPC_S_CALLPENDING on timeout.
3843 * NOTES
3845 * The dwFlags parameter can be zero or more of the following:
3846 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3847 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3849 * SEE ALSO
3850 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3852 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3853 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3855 HRESULT hr = S_OK;
3856 DWORD start_time = GetTickCount();
3857 APARTMENT *apt = COM_CurrentApt();
3858 BOOL message_loop = apt && !apt->multi_threaded;
3860 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3861 pHandles, lpdwindex);
3863 while (TRUE)
3865 DWORD now = GetTickCount();
3866 DWORD res;
3868 if (now - start_time > dwTimeout)
3870 hr = RPC_S_CALLPENDING;
3871 break;
3874 if (message_loop)
3876 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3877 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3879 TRACE("waiting for rpc completion or window message\n");
3881 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3882 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3883 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
3885 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3887 MSG msg;
3888 int count = 0;
3890 /* call message filter */
3892 if (COM_CurrentApt()->filter)
3894 PENDINGTYPE pendingtype =
3895 COM_CurrentInfo()->pending_call_count_server ?
3896 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3897 DWORD be_handled = IMessageFilter_MessagePending(
3898 COM_CurrentApt()->filter, 0 /* FIXME */,
3899 now - start_time, pendingtype);
3900 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3901 switch (be_handled)
3903 case PENDINGMSG_CANCELCALL:
3904 WARN("call canceled\n");
3905 hr = RPC_E_CALL_CANCELED;
3906 break;
3907 case PENDINGMSG_WAITNOPROCESS:
3908 case PENDINGMSG_WAITDEFPROCESS:
3909 default:
3910 /* FIXME: MSDN is very vague about the difference
3911 * between WAITNOPROCESS and WAITDEFPROCESS - there
3912 * appears to be none, so it is possibly a left-over
3913 * from the 16-bit world. */
3914 break;
3918 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3919 * so after processing 100 messages we go back to checking the wait handles */
3920 while (count++ < 100 && COM_PeekMessage(apt, &msg))
3922 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3923 TranslateMessage(&msg);
3924 DispatchMessageW(&msg);
3925 if (msg.message == WM_QUIT)
3927 TRACE("resending WM_QUIT to outer message loop\n");
3928 PostQuitMessage(msg.wParam);
3929 /* no longer need to process messages */
3930 message_loop = FALSE;
3931 break;
3934 continue;
3937 else
3939 TRACE("waiting for rpc completion\n");
3941 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
3942 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3943 (dwFlags & COWAIT_ALERTABLE) != 0);
3946 switch (res)
3948 case WAIT_TIMEOUT:
3949 hr = RPC_S_CALLPENDING;
3950 break;
3951 case WAIT_FAILED:
3952 hr = HRESULT_FROM_WIN32( GetLastError() );
3953 break;
3954 default:
3955 *lpdwindex = res;
3956 break;
3958 break;
3960 TRACE("-- 0x%08x\n", hr);
3961 return hr;
3965 /***********************************************************************
3966 * CoGetObject [OLE32.@]
3968 * Gets the object named by converting the name to a moniker and binding to it.
3970 * PARAMS
3971 * pszName [I] String representing the object.
3972 * pBindOptions [I] Parameters affecting the binding to the named object.
3973 * riid [I] Interface to bind to on the objecct.
3974 * ppv [O] On output, the interface riid of the object represented
3975 * by pszName.
3977 * RETURNS
3978 * Success: S_OK.
3979 * Failure: HRESULT code.
3981 * SEE ALSO
3982 * MkParseDisplayName.
3984 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3985 REFIID riid, void **ppv)
3987 IBindCtx *pbc;
3988 HRESULT hr;
3990 *ppv = NULL;
3992 hr = CreateBindCtx(0, &pbc);
3993 if (SUCCEEDED(hr))
3995 if (pBindOptions)
3996 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3998 if (SUCCEEDED(hr))
4000 ULONG chEaten;
4001 IMoniker *pmk;
4003 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4004 if (SUCCEEDED(hr))
4006 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4007 IMoniker_Release(pmk);
4011 IBindCtx_Release(pbc);
4013 return hr;
4016 /***********************************************************************
4017 * CoRegisterChannelHook [OLE32.@]
4019 * Registers a process-wide hook that is called during ORPC calls.
4021 * PARAMS
4022 * guidExtension [I] GUID of the channel hook to register.
4023 * pChannelHook [I] Channel hook object to register.
4025 * RETURNS
4026 * Success: S_OK.
4027 * Failure: HRESULT code.
4029 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4031 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4033 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4036 typedef struct Context
4038 IComThreadingInfo IComThreadingInfo_iface;
4039 IContextCallback IContextCallback_iface;
4040 IObjContext IObjContext_iface;
4041 LONG refs;
4042 APTTYPE apttype;
4043 } Context;
4045 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4047 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4050 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4052 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4055 static inline Context *impl_from_IObjContext( IObjContext *iface )
4057 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4060 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4062 *ppv = NULL;
4064 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4065 IsEqualIID(riid, &IID_IUnknown))
4067 *ppv = &iface->IComThreadingInfo_iface;
4069 else if (IsEqualIID(riid, &IID_IContextCallback))
4071 *ppv = &iface->IContextCallback_iface;
4073 else if (IsEqualIID(riid, &IID_IObjContext))
4075 *ppv = &iface->IObjContext_iface;
4078 if (*ppv)
4080 IUnknown_AddRef((IUnknown*)*ppv);
4081 return S_OK;
4084 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4085 return E_NOINTERFACE;
4088 static ULONG Context_AddRef(Context *This)
4090 return InterlockedIncrement(&This->refs);
4093 static ULONG Context_Release(Context *This)
4095 ULONG refs = InterlockedDecrement(&This->refs);
4096 if (!refs)
4097 HeapFree(GetProcessHeap(), 0, This);
4098 return refs;
4101 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4103 Context *This = impl_from_IComThreadingInfo(iface);
4104 return Context_QueryInterface(This, riid, ppv);
4107 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4109 Context *This = impl_from_IComThreadingInfo(iface);
4110 return Context_AddRef(This);
4113 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4115 Context *This = impl_from_IComThreadingInfo(iface);
4116 return Context_Release(This);
4119 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4121 Context *This = impl_from_IComThreadingInfo(iface);
4123 TRACE("(%p)\n", apttype);
4125 *apttype = This->apttype;
4126 return S_OK;
4129 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4131 Context *This = impl_from_IComThreadingInfo(iface);
4133 TRACE("(%p)\n", thdtype);
4135 switch (This->apttype)
4137 case APTTYPE_STA:
4138 case APTTYPE_MAINSTA:
4139 *thdtype = THDTYPE_PROCESSMESSAGES;
4140 break;
4141 default:
4142 *thdtype = THDTYPE_BLOCKMESSAGES;
4143 break;
4145 return S_OK;
4148 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4150 FIXME("(%p): stub\n", logical_thread_id);
4151 return E_NOTIMPL;
4154 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4156 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4157 return E_NOTIMPL;
4160 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4162 Context_CTI_QueryInterface,
4163 Context_CTI_AddRef,
4164 Context_CTI_Release,
4165 Context_CTI_GetCurrentApartmentType,
4166 Context_CTI_GetCurrentThreadType,
4167 Context_CTI_GetCurrentLogicalThreadId,
4168 Context_CTI_SetCurrentLogicalThreadId
4171 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4173 Context *This = impl_from_IContextCallback(iface);
4174 return Context_QueryInterface(This, riid, ppv);
4177 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4179 Context *This = impl_from_IContextCallback(iface);
4180 return Context_AddRef(This);
4183 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4185 Context *This = impl_from_IContextCallback(iface);
4186 return Context_Release(This);
4189 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4190 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4192 Context *This = impl_from_IContextCallback(iface);
4194 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4195 return E_NOTIMPL;
4198 static const IContextCallbackVtbl Context_Callback_Vtbl =
4200 Context_CC_QueryInterface,
4201 Context_CC_AddRef,
4202 Context_CC_Release,
4203 Context_CC_ContextCallback
4206 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4208 Context *This = impl_from_IObjContext(iface);
4209 return Context_QueryInterface(This, riid, ppv);
4212 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4214 Context *This = impl_from_IObjContext(iface);
4215 return Context_AddRef(This);
4218 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4220 Context *This = impl_from_IObjContext(iface);
4221 return Context_Release(This);
4224 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4226 Context *This = impl_from_IObjContext(iface);
4228 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4229 return E_NOTIMPL;
4232 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4234 Context *This = impl_from_IObjContext(iface);
4236 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4237 return E_NOTIMPL;
4240 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4242 Context *This = impl_from_IObjContext(iface);
4244 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4245 return E_NOTIMPL;
4248 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4250 Context *This = impl_from_IObjContext(iface);
4252 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4253 return E_NOTIMPL;
4256 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4258 Context *This = impl_from_IObjContext(iface);
4259 FIXME("(%p/%p)\n", This, iface);
4262 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4264 Context *This = impl_from_IObjContext(iface);
4265 FIXME("(%p/%p)\n", This, iface);
4268 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4270 Context *This = impl_from_IObjContext(iface);
4271 FIXME("(%p/%p)\n", This, iface);
4274 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4276 Context *This = impl_from_IObjContext(iface);
4277 FIXME("(%p/%p)\n", This, iface);
4280 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4282 Context *This = impl_from_IObjContext(iface);
4283 FIXME("(%p/%p)\n", This, iface);
4286 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4288 Context *This = impl_from_IObjContext(iface);
4289 FIXME("(%p/%p)\n", This, iface);
4292 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4294 Context *This = impl_from_IObjContext(iface);
4295 FIXME("(%p/%p)\n", This, iface);
4298 static const IObjContextVtbl Context_Object_Vtbl =
4300 Context_OC_QueryInterface,
4301 Context_OC_AddRef,
4302 Context_OC_Release,
4303 Context_OC_SetProperty,
4304 Context_OC_RemoveProperty,
4305 Context_OC_GetProperty,
4306 Context_OC_EnumContextProps,
4307 Context_OC_Reserved1,
4308 Context_OC_Reserved2,
4309 Context_OC_Reserved3,
4310 Context_OC_Reserved4,
4311 Context_OC_Reserved5,
4312 Context_OC_Reserved6,
4313 Context_OC_Reserved7
4316 /***********************************************************************
4317 * CoGetObjectContext [OLE32.@]
4319 * Retrieves an object associated with the current context (i.e. apartment).
4321 * PARAMS
4322 * riid [I] ID of the interface of the object to retrieve.
4323 * ppv [O] Address where object will be stored on return.
4325 * RETURNS
4326 * Success: S_OK.
4327 * Failure: HRESULT code.
4329 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4331 APARTMENT *apt = COM_CurrentApt();
4332 Context *context;
4333 HRESULT hr;
4335 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4337 *ppv = NULL;
4338 if (!apt)
4340 if (!(apt = apartment_find_multi_threaded()))
4342 ERR("apartment not initialised\n");
4343 return CO_E_NOTINITIALIZED;
4345 apartment_release(apt);
4348 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4349 if (!context)
4350 return E_OUTOFMEMORY;
4352 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4353 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4354 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4355 context->refs = 1;
4356 if (apt->multi_threaded)
4357 context->apttype = APTTYPE_MTA;
4358 else if (apt->main)
4359 context->apttype = APTTYPE_MAINSTA;
4360 else
4361 context->apttype = APTTYPE_STA;
4363 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4364 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4366 return hr;
4370 /***********************************************************************
4371 * CoGetContextToken [OLE32.@]
4373 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4375 struct oletls *info = COM_CurrentInfo();
4377 TRACE("(%p)\n", token);
4379 if (!info)
4380 return E_OUTOFMEMORY;
4382 if (!info->apt)
4384 APARTMENT *apt;
4385 if (!(apt = apartment_find_multi_threaded()))
4387 ERR("apartment not initialised\n");
4388 return CO_E_NOTINITIALIZED;
4390 apartment_release(apt);
4393 if (!token)
4394 return E_POINTER;
4396 if (!info->context_token)
4398 HRESULT hr;
4399 IObjContext *ctx;
4401 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4402 if (FAILED(hr)) return hr;
4403 info->context_token = ctx;
4406 *token = (ULONG_PTR)info->context_token;
4407 TRACE("apt->context_token=%p\n", info->context_token);
4409 return S_OK;
4412 /***********************************************************************
4413 * CoGetDefaultContext [OLE32.@]
4415 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4417 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4418 return E_NOINTERFACE;
4421 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4423 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4424 HKEY hkey;
4425 HRESULT hres;
4427 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4428 if (SUCCEEDED(hres))
4430 WCHAR dllpath[MAX_PATH+1];
4432 if (COM_RegReadPath(hkey, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4434 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4435 if (!strcmpiW(dllpath, wszOle32))
4437 RegCloseKey(hkey);
4438 return HandlerCF_Create(rclsid, riid, ppv);
4441 else
4442 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4443 RegCloseKey(hkey);
4446 return CLASS_E_CLASSNOTAVAILABLE;
4449 /***********************************************************************
4450 * DllMain (OLE32.@)
4452 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
4454 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
4456 switch(fdwReason) {
4457 case DLL_PROCESS_ATTACH:
4458 hProxyDll = hinstDLL;
4459 COMPOBJ_InitProcess();
4460 break;
4462 case DLL_PROCESS_DETACH:
4463 if (reserved) break;
4464 COMPOBJ_UninitProcess();
4465 RPC_UnregisterAllChannelHooks();
4466 COMPOBJ_DllList_Free();
4467 DeleteCriticalSection(&csRegisteredClassList);
4468 DeleteCriticalSection(&csApartment);
4469 break;
4471 case DLL_THREAD_DETACH:
4472 COM_TlsDestroy();
4473 break;
4475 return TRUE;
4478 /***********************************************************************
4479 * DllRegisterServer (OLE32.@)
4481 HRESULT WINAPI DllRegisterServer(void)
4483 return OLE32_DllRegisterServer();
4486 /***********************************************************************
4487 * DllUnregisterServer (OLE32.@)
4489 HRESULT WINAPI DllUnregisterServer(void)
4491 return OLE32_DllUnregisterServer();