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
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
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
51 #define WIN32_NO_STATUS
55 //#include "winerror.h"
57 //#include "winuser.h"
58 #define USE_COM_CONTEXT_DEF
59 //#include "objbase.h"
66 #include "compobj_private.h"
69 #include <wine/unicode.h>
70 #include <wine/debug.h>
72 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
80 static APARTMENT
*MTA
; /* protected by csApartment */
81 static APARTMENT
*MainApartment
; /* the first STA apartment */
82 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment
;
85 static CRITICAL_SECTION_DEBUG critsect_debug
=
88 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
89 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
91 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
93 struct registered_psclsid
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount
= 0;
106 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
107 static LONG s_COMServerProcessReferences
= 0;
110 * This linked list contains the list of registered class objects. These
111 * are mostly used to register the factories for out-of-proc servers of OLE
114 * TODO: Make this data structure aware of inter-process communication. This
115 * means that parts of this will be exported to rpcss.
117 typedef struct tagRegisteredClass
120 CLSID classIdentifier
;
122 LPUNKNOWN classObject
;
126 LPSTREAM pMarshaledData
; /* FIXME: only really need to store OXID and IPID */
127 void *RpcRegistration
;
130 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
132 static CRITICAL_SECTION csRegisteredClassList
;
133 static CRITICAL_SECTION_DEBUG class_cs_debug
=
135 0, 0, &csRegisteredClassList
,
136 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
137 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
139 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
141 /* wrapper for NtCreateKey that creates the key recursively if necessary */
142 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
144 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
146 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
148 HANDLE subkey
, root
= attr
->RootDirectory
;
149 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
150 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
153 while (i
< len
&& buffer
[i
] != '\\') i
++;
154 if (i
== len
) return status
;
156 attrs
= attr
->Attributes
;
157 attr
->ObjectName
= &str
;
161 str
.Buffer
= buffer
+ pos
;
162 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
163 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
164 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
165 if (status
) return status
;
166 attr
->RootDirectory
= subkey
;
167 while (i
< len
&& buffer
[i
] == '\\') i
++;
169 while (i
< len
&& buffer
[i
] != '\\') i
++;
171 str
.Buffer
= buffer
+ pos
;
172 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
173 attr
->Attributes
= attrs
;
174 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
175 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
181 static const WCHAR classes_rootW
[] = L
"\\REGISTRY\\Machine\\Software\\Classes";
183 static const WCHAR classes_rootW
[] =
184 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
187 static HKEY classes_root_hkey
;
189 /* create the special HKEY_CLASSES_ROOT key */
190 static HKEY
create_classes_root_hkey(void)
193 OBJECT_ATTRIBUTES attr
;
196 attr
.Length
= sizeof(attr
);
197 attr
.RootDirectory
= 0;
198 attr
.ObjectName
= &name
;
200 attr
.SecurityDescriptor
= NULL
;
201 attr
.SecurityQualityOfService
= NULL
;
202 RtlInitUnicodeString( &name
, classes_rootW
);
203 if (create_key( &hkey
, MAXIMUM_ALLOWED
, &attr
)) return 0;
204 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
206 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
209 NtClose( hkey
); /* somebody beat us to it */
213 /* map the hkey from special root to normal key if necessary */
214 static inline HKEY
get_classes_root_hkey( HKEY hkey
)
218 if (hkey
== HKEY_CLASSES_ROOT
&& !(ret
= classes_root_hkey
))
219 ret
= create_classes_root_hkey();
224 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
226 OBJECT_ATTRIBUTES attr
;
227 UNICODE_STRING nameW
;
229 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
231 attr
.Length
= sizeof(attr
);
232 attr
.RootDirectory
= hkey
;
233 attr
.ObjectName
= &nameW
;
235 attr
.SecurityDescriptor
= NULL
;
236 attr
.SecurityQualityOfService
= NULL
;
237 RtlInitUnicodeString( &nameW
, name
);
239 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
242 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
244 OBJECT_ATTRIBUTES attr
;
245 UNICODE_STRING nameW
;
247 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
249 attr
.Length
= sizeof(attr
);
250 attr
.RootDirectory
= hkey
;
251 attr
.ObjectName
= &nameW
;
253 attr
.SecurityDescriptor
= NULL
;
254 attr
.SecurityQualityOfService
= NULL
;
255 RtlInitUnicodeString( &nameW
, name
);
257 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
260 /*****************************************************************************
261 * This section contains OpenDllList definitions
263 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
264 * other functions that do LoadLibrary _without_ giving back a HMODULE.
265 * Without this list these handles would never be freed.
267 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
268 * next unload-call but not before 600 sec.
271 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
272 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
274 typedef struct tagOpenDll
279 DllGetClassObjectFunc DllGetClassObject
;
280 DllCanUnloadNowFunc DllCanUnloadNow
;
284 static struct list openDllList
= LIST_INIT(openDllList
);
286 static CRITICAL_SECTION csOpenDllList
;
287 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
289 0, 0, &csOpenDllList
,
290 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
291 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
293 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
295 struct apartment_loaded_dll
303 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',' ',
304 '0','x','#','#','#','#','#','#','#','#',' ',0};
306 /*****************************************************************************
307 * This section contains OpenDllList implementation
310 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
314 EnterCriticalSection(&csOpenDllList
);
315 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
317 if (!strcmpiW(library_name
, ptr
->library_name
) &&
318 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
324 LeaveCriticalSection(&csOpenDllList
);
328 /* caller must ensure that library_name is not already in the open dll list */
329 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
335 DllCanUnloadNowFunc DllCanUnloadNow
;
336 DllGetClassObjectFunc DllGetClassObject
;
340 *ret
= COMPOBJ_DllList_Get(library_name
);
341 if (*ret
) return S_OK
;
343 /* do this outside the csOpenDllList to avoid creating a lock dependency on
345 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
348 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
349 /* failure: DLL could not be loaded */
350 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
353 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
354 /* Note: failing to find DllCanUnloadNow is not a failure */
355 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
356 if (!DllGetClassObject
)
358 /* failure: the dll did not export DllGetClassObject */
359 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
360 FreeLibrary(hLibrary
);
361 return CO_E_DLLNOTFOUND
;
364 EnterCriticalSection( &csOpenDllList
);
366 *ret
= COMPOBJ_DllList_Get(library_name
);
369 /* another caller to this function already added the dll while we
370 * weren't in the critical section */
371 FreeLibrary(hLibrary
);
375 len
= strlenW(library_name
);
376 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
378 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
379 if (entry
&& entry
->library_name
)
381 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
382 entry
->library
= hLibrary
;
384 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
385 entry
->DllGetClassObject
= DllGetClassObject
;
386 list_add_tail(&openDllList
, &entry
->entry
);
390 HeapFree(GetProcessHeap(), 0, entry
);
392 FreeLibrary(hLibrary
);
397 LeaveCriticalSection( &csOpenDllList
);
402 /* pass FALSE for free_entry to release a reference without destroying the
403 * entry if it reaches zero or TRUE otherwise */
404 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
406 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
408 EnterCriticalSection(&csOpenDllList
);
409 list_remove(&entry
->entry
);
410 LeaveCriticalSection(&csOpenDllList
);
412 TRACE("freeing %p\n", entry
->library
);
413 FreeLibrary(entry
->library
);
415 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
416 HeapFree(GetProcessHeap(), 0, entry
);
420 /* frees memory associated with active dll list */
421 static void COMPOBJ_DllList_Free(void)
423 OpenDll
*entry
, *cursor2
;
424 EnterCriticalSection(&csOpenDllList
);
425 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
427 list_remove(&entry
->entry
);
429 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
430 HeapFree(GetProcessHeap(), 0, entry
);
432 LeaveCriticalSection(&csOpenDllList
);
433 DeleteCriticalSection(&csOpenDllList
);
436 /******************************************************************************
440 static DWORD
apartment_addref(struct apartment
*apt
)
442 DWORD refs
= InterlockedIncrement(&apt
->refs
);
443 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
447 /* allocates memory and fills in the necessary fields for a new apartment
448 * object. must be called inside apartment cs */
449 static APARTMENT
*apartment_construct(DWORD model
)
453 TRACE("creating new apartment, model=%d\n", model
);
455 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
456 apt
->tid
= GetCurrentThreadId();
458 list_init(&apt
->proxies
);
459 list_init(&apt
->stubmgrs
);
460 list_init(&apt
->psclsids
);
461 list_init(&apt
->loaded_dlls
);
464 apt
->remunk_exported
= FALSE
;
466 InitializeCriticalSection(&apt
->cs
);
467 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
469 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
471 if (apt
->multi_threaded
)
473 /* FIXME: should be randomly generated by in an RPC call to rpcss */
474 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
478 /* FIXME: should be randomly generated by in an RPC call to rpcss */
479 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
482 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
484 list_add_head(&apts
, &apt
->entry
);
489 /* gets and existing apartment if one exists or otherwise creates an apartment
490 * structure which stores OLE apartment-local information and stores a pointer
491 * to it in the thread-local storage */
492 static APARTMENT
*apartment_get_or_create(DWORD model
)
494 APARTMENT
*apt
= COM_CurrentApt();
498 if (model
& COINIT_APARTMENTTHREADED
)
500 EnterCriticalSection(&csApartment
);
502 apt
= apartment_construct(model
);
507 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
510 LeaveCriticalSection(&csApartment
);
513 apartment_createwindowifneeded(apt
);
517 EnterCriticalSection(&csApartment
);
519 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
520 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
524 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
525 apartment_addref(MTA
);
528 MTA
= apartment_construct(model
);
532 LeaveCriticalSection(&csApartment
);
534 COM_CurrentInfo()->apt
= apt
;
540 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
542 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
545 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
547 list_remove(&curClass
->entry
);
549 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
550 RPC_StopLocalServer(curClass
->RpcRegistration
);
553 * Release the reference to the class object.
555 IUnknown_Release(curClass
->classObject
);
557 if (curClass
->pMarshaledData
)
560 memset(&zero
, 0, sizeof(zero
));
561 IStream_Seek(curClass
->pMarshaledData
, zero
, STREAM_SEEK_SET
, NULL
);
562 CoReleaseMarshalData(curClass
->pMarshaledData
);
563 IStream_Release(curClass
->pMarshaledData
);
566 HeapFree(GetProcessHeap(), 0, curClass
);
569 static void COM_RevokeAllClasses(const struct apartment
*apt
)
571 RegisteredClass
*curClass
, *cursor
;
573 EnterCriticalSection( &csRegisteredClassList
);
575 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
577 if (curClass
->apartment_id
== apt
->oxid
)
578 COM_RevokeRegisteredClassObject(curClass
);
581 LeaveCriticalSection( &csRegisteredClassList
);
584 /******************************************************************************
585 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
588 typedef struct ManualResetEvent
{
589 ISynchronize ISynchronize_iface
;
590 ISynchronizeHandle ISynchronizeHandle_iface
;
595 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
597 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
600 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
602 MREImpl
*This
= impl_from_ISynchronize(iface
);
604 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
606 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
607 *ppv
= &This
->ISynchronize_iface
;
608 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
609 *ppv
= &This
->ISynchronizeHandle_iface
;
611 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
613 return E_NOINTERFACE
;
616 IUnknown_AddRef((IUnknown
*)*ppv
);
620 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
622 MREImpl
*This
= impl_from_ISynchronize(iface
);
623 LONG ref
= InterlockedIncrement(&This
->ref
);
624 TRACE("%p - ref %d\n", This
, ref
);
629 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
631 MREImpl
*This
= impl_from_ISynchronize(iface
);
632 LONG ref
= InterlockedDecrement(&This
->ref
);
633 TRACE("%p - ref %d\n", This
, ref
);
637 CloseHandle(This
->event
);
638 HeapFree(GetProcessHeap(), 0, This
);
644 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
646 MREImpl
*This
= impl_from_ISynchronize(iface
);
648 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
649 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
652 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
654 MREImpl
*This
= impl_from_ISynchronize(iface
);
656 SetEvent(This
->event
);
660 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
662 MREImpl
*This
= impl_from_ISynchronize(iface
);
664 ResetEvent(This
->event
);
668 static ISynchronizeVtbl vt_ISynchronize
= {
669 ISynchronize_fnQueryInterface
,
670 ISynchronize_fnAddRef
,
671 ISynchronize_fnRelease
,
673 ISynchronize_fnSignal
,
677 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
679 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
682 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
684 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
685 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
688 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
690 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
691 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
694 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
696 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
697 return ISynchronize_Release(&This
->ISynchronize_iface
);
700 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
702 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
708 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
709 SynchronizeHandle_QueryInterface
,
710 SynchronizeHandle_AddRef
,
711 SynchronizeHandle_Release
,
712 SynchronizeHandle_GetHandle
715 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
717 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
721 FIXME("Aggregation not implemented.\n");
724 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
725 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
726 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
728 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
729 ISynchronize_Release(&This
->ISynchronize_iface
);
733 /***********************************************************************
734 * CoRevokeClassObject [OLE32.@]
736 * Removes a class object from the class registry.
739 * dwRegister [I] Cookie returned from CoRegisterClassObject().
743 * Failure: HRESULT code.
746 * Must be called from the same apartment that called CoRegisterClassObject(),
747 * otherwise it will fail with RPC_E_WRONG_THREAD.
750 * CoRegisterClassObject
752 HRESULT WINAPI
CoRevokeClassObject(
755 HRESULT hr
= E_INVALIDARG
;
756 RegisteredClass
*curClass
;
759 TRACE("(%08x)\n",dwRegister
);
761 apt
= COM_CurrentApt();
764 ERR("COM was not initialized\n");
765 return CO_E_NOTINITIALIZED
;
768 EnterCriticalSection( &csRegisteredClassList
);
770 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
773 * Check if we have a match on the cookie.
775 if (curClass
->dwCookie
== dwRegister
)
777 if (curClass
->apartment_id
== apt
->oxid
)
779 COM_RevokeRegisteredClassObject(curClass
);
784 ERR("called from wrong apartment, should be called from %s\n",
785 wine_dbgstr_longlong(curClass
->apartment_id
));
786 hr
= RPC_E_WRONG_THREAD
;
792 LeaveCriticalSection( &csRegisteredClassList
);
797 /* frees unused libraries loaded by apartment_getclassobject by calling the
798 * DLL's DllCanUnloadNow entry point */
799 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
801 struct apartment_loaded_dll
*entry
, *next
;
802 EnterCriticalSection(&apt
->cs
);
803 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
805 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
807 DWORD real_delay
= delay
;
809 if (real_delay
== INFINITE
)
811 /* DLLs that return multi-threaded objects aren't unloaded
812 * straight away to cope for programs that have races between
813 * last object destruction and threads in the DLLs that haven't
814 * finished, despite DllCanUnloadNow returning S_OK */
815 if (entry
->multi_threaded
)
816 real_delay
= 10 * 60 * 1000; /* 10 minutes */
821 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
823 list_remove(&entry
->entry
);
824 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
825 HeapFree(GetProcessHeap(), 0, entry
);
829 entry
->unload_time
= GetTickCount() + real_delay
;
830 if (!entry
->unload_time
) entry
->unload_time
= 1;
833 else if (entry
->unload_time
)
834 entry
->unload_time
= 0;
836 LeaveCriticalSection(&apt
->cs
);
839 DWORD
apartment_release(struct apartment
*apt
)
843 EnterCriticalSection(&csApartment
);
845 ret
= InterlockedDecrement(&apt
->refs
);
846 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
847 /* destruction stuff that needs to happen under csApartment CS */
850 if (apt
== MTA
) MTA
= NULL
;
851 else if (apt
== MainApartment
) MainApartment
= NULL
;
852 list_remove(&apt
->entry
);
855 LeaveCriticalSection(&csApartment
);
859 struct list
*cursor
, *cursor2
;
861 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
863 /* Release the references to the registered class objects */
864 COM_RevokeAllClasses(apt
);
866 /* no locking is needed for this apartment, because no other thread
867 * can access it at this point */
869 apartment_disconnectproxies(apt
);
871 if (apt
->win
) DestroyWindow(apt
->win
);
872 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
874 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
876 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
877 /* release the implicit reference given by the fact that the
878 * stub has external references (it must do since it is in the
879 * stub manager list in the apartment and all non-apartment users
880 * must have a ref on the apartment and so it cannot be destroyed).
882 stub_manager_int_release(stubmgr
);
885 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
887 struct registered_psclsid
*registered_psclsid
=
888 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
890 list_remove(®istered_psclsid
->entry
);
891 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
894 /* if this assert fires, then another thread took a reference to a
895 * stub manager without taking a reference to the containing
896 * apartment, which it must do. */
897 assert(list_empty(&apt
->stubmgrs
));
899 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
901 /* free as many unused libraries as possible... */
902 apartment_freeunusedlibraries(apt
, 0);
904 /* ... and free the memory for the apartment loaded dll entry and
905 * release the dll list reference without freeing the library for the
907 while ((cursor
= list_head(&apt
->loaded_dlls
)))
909 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
910 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
912 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
915 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
916 DeleteCriticalSection(&apt
->cs
);
918 HeapFree(GetProcessHeap(), 0, apt
);
924 /* The given OXID must be local to this process:
926 * The ref parameter is here mostly to ensure people remember that
927 * they get one, you should normally take a ref for thread safety.
929 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
931 APARTMENT
*result
= NULL
;
934 EnterCriticalSection(&csApartment
);
935 LIST_FOR_EACH( cursor
, &apts
)
937 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
938 if (apt
->oxid
== oxid
)
941 if (ref
) apartment_addref(result
);
945 LeaveCriticalSection(&csApartment
);
950 /* gets the apartment which has a given creator thread ID. The caller must
951 * release the reference from the apartment as soon as the apartment pointer
952 * is no longer required. */
953 APARTMENT
*apartment_findfromtid(DWORD tid
)
955 APARTMENT
*result
= NULL
;
958 EnterCriticalSection(&csApartment
);
959 LIST_FOR_EACH( cursor
, &apts
)
961 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
965 apartment_addref(result
);
969 LeaveCriticalSection(&csApartment
);
974 /* gets the main apartment if it exists. The caller must
975 * release the reference from the apartment as soon as the apartment pointer
976 * is no longer required. */
977 static APARTMENT
*apartment_findmain(void)
981 EnterCriticalSection(&csApartment
);
983 result
= MainApartment
;
984 if (result
) apartment_addref(result
);
986 LeaveCriticalSection(&csApartment
);
991 /* gets the multi-threaded apartment if it exists. The caller must
992 * release the reference from the apartment as soon as the apartment pointer
993 * is no longer required. */
994 static APARTMENT
*apartment_find_multi_threaded(void)
996 APARTMENT
*result
= NULL
;
999 EnterCriticalSection(&csApartment
);
1001 LIST_FOR_EACH( cursor
, &apts
)
1003 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1004 if (apt
->multi_threaded
)
1007 apartment_addref(result
);
1012 LeaveCriticalSection(&csApartment
);
1016 /* gets the specified class object by loading the appropriate DLL, if
1017 * necessary and calls the DllGetClassObject function for the DLL */
1018 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1019 BOOL apartment_threaded
,
1020 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1022 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1025 struct apartment_loaded_dll
*apartment_loaded_dll
;
1027 if (!strcmpiW(dllpath
, wszOle32
))
1029 /* we don't need to control the lifetime of this dll, so use the local
1030 * implementation of DllGetClassObject directly */
1031 TRACE("calling ole32!DllGetClassObject\n");
1032 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1035 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1040 EnterCriticalSection(&apt
->cs
);
1042 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1043 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1045 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1052 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1053 if (!apartment_loaded_dll
)
1057 apartment_loaded_dll
->unload_time
= 0;
1058 apartment_loaded_dll
->multi_threaded
= FALSE
;
1059 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1061 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1065 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1066 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1070 LeaveCriticalSection(&apt
->cs
);
1074 /* one component being multi-threaded overrides any number of
1075 * apartment-threaded components */
1076 if (!apartment_threaded
)
1077 apartment_loaded_dll
->multi_threaded
= TRUE
;
1079 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1080 /* OK: get the ClassObject */
1081 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1084 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1090 /***********************************************************************
1091 * COM_RegReadPath [internal]
1093 * Reads a registry value and expands it when necessary
1095 static DWORD
COM_RegReadPath(HKEY hkeyroot
, WCHAR
* dst
, DWORD dstlen
)
1099 WCHAR src
[MAX_PATH
];
1100 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1102 if( (ret
= RegQueryValueExW(hkeyroot
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1103 if (keytype
== REG_EXPAND_SZ
) {
1104 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1106 const WCHAR
*quote_start
;
1107 quote_start
= strchrW(src
, '\"');
1109 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1111 memmove(src
, quote_start
+ 1,
1112 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1113 src
[quote_end
- quote_start
- 1] = '\0';
1116 lstrcpynW(dst
, src
, dstlen
);
1122 struct host_object_params
1125 CLSID clsid
; /* clsid of object to marshal */
1126 IID iid
; /* interface to marshal */
1127 HANDLE event
; /* event signalling when ready for multi-threaded case */
1128 HRESULT hr
; /* result for multi-threaded case */
1129 IStream
*stream
; /* stream that the object will be marshaled into */
1130 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1133 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1134 const struct host_object_params
*params
)
1138 static const LARGE_INTEGER llZero
;
1139 WCHAR dllpath
[MAX_PATH
+1];
1141 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1143 if (COM_RegReadPath(params
->hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1145 /* failure: CLSID is not found in registry */
1146 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1147 return REGDB_E_CLASSNOTREG
;
1150 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1151 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1155 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1157 IUnknown_Release(object
);
1158 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1163 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1168 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1171 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1173 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1177 struct host_thread_params
1179 COINIT threading_model
;
1181 HWND apartment_hwnd
;
1184 /* thread for hosting an object to allow an object to appear to be created in
1185 * an apartment with an incompatible threading model */
1186 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1188 struct host_thread_params
*params
= p
;
1191 struct apartment
*apt
;
1195 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1196 if (FAILED(hr
)) return hr
;
1198 apt
= COM_CurrentApt();
1199 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1201 apartment_createwindowifneeded(apt
);
1202 params
->apartment_hwnd
= apartment_getwindow(apt
);
1205 params
->apartment_hwnd
= NULL
;
1207 /* force the message queue to be created before signaling parent thread */
1208 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1210 SetEvent(params
->ready_event
);
1211 params
= NULL
; /* can't touch params after here as it may be invalid */
1213 while (GetMessageW(&msg
, NULL
, 0, 0))
1215 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1217 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1218 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1219 SetEvent(obj_params
->event
);
1223 TranslateMessage(&msg
);
1224 DispatchMessageW(&msg
);
1235 /* finds or creates a host apartment, creates the object inside it and returns
1236 * a proxy to it so that the object can be used in the apartment of the
1237 * caller of this function */
1238 static HRESULT
apartment_hostobject_in_hostapt(
1239 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1240 HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1242 struct host_object_params params
;
1243 HWND apartment_hwnd
= NULL
;
1244 DWORD apartment_tid
= 0;
1247 if (!multi_threaded
&& main_apartment
)
1249 APARTMENT
*host_apt
= apartment_findmain();
1252 apartment_hwnd
= apartment_getwindow(host_apt
);
1253 apartment_release(host_apt
);
1257 if (!apartment_hwnd
)
1259 EnterCriticalSection(&apt
->cs
);
1261 if (!apt
->host_apt_tid
)
1263 struct host_thread_params thread_params
;
1267 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1268 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1269 thread_params
.apartment_hwnd
= NULL
;
1270 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1273 CloseHandle(handles
[0]);
1274 LeaveCriticalSection(&apt
->cs
);
1275 return E_OUTOFMEMORY
;
1277 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1278 CloseHandle(handles
[0]);
1279 CloseHandle(handles
[1]);
1280 if (wait_value
== WAIT_OBJECT_0
)
1281 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1284 LeaveCriticalSection(&apt
->cs
);
1285 return E_OUTOFMEMORY
;
1289 if (multi_threaded
|| !main_apartment
)
1291 apartment_hwnd
= apt
->host_apt_hwnd
;
1292 apartment_tid
= apt
->host_apt_tid
;
1295 LeaveCriticalSection(&apt
->cs
);
1298 /* another thread may have become the main apartment in the time it took
1299 * us to create the thread for the host apartment */
1300 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1302 APARTMENT
*host_apt
= apartment_findmain();
1305 apartment_hwnd
= apartment_getwindow(host_apt
);
1306 apartment_release(host_apt
);
1310 params
.hkeydll
= hkeydll
;
1311 params
.clsid
= *rclsid
;
1313 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1316 params
.apartment_threaded
= !multi_threaded
;
1320 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1321 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1325 WaitForSingleObject(params
.event
, INFINITE
);
1328 CloseHandle(params
.event
);
1332 if (!apartment_hwnd
)
1334 ERR("host apartment didn't create window\n");
1338 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1341 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1342 IStream_Release(params
.stream
);
1346 /* create a window for the apartment or return the current one if one has
1347 * already been created */
1348 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1350 if (apt
->multi_threaded
)
1355 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
1357 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1360 ERR("CreateWindow failed with error %d\n", GetLastError());
1361 return HRESULT_FROM_WIN32(GetLastError());
1363 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1364 /* someone beat us to it */
1365 DestroyWindow(hwnd
);
1371 /* retrieves the window for the main- or apartment-threaded apartment */
1372 HWND
apartment_getwindow(const struct apartment
*apt
)
1374 assert(!apt
->multi_threaded
);
1378 void apartment_joinmta(void)
1380 apartment_addref(MTA
);
1381 COM_CurrentInfo()->apt
= MTA
;
1384 static void COMPOBJ_InitProcess( void )
1388 /* Dispatching to the correct thread in an apartment is done through
1389 * window messages rather than RPC transports. When an interface is
1390 * marshalled into another apartment in the same process, a window of the
1391 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1392 * application) is responsible for pumping the message loop in that thread.
1393 * The WM_USER messages which point to the RPCs are then dispatched to
1394 * apartment_wndproc by the user's code from the apartment in which the
1395 * interface was unmarshalled.
1397 memset(&wclass
, 0, sizeof(wclass
));
1398 wclass
.lpfnWndProc
= apartment_wndproc
;
1399 wclass
.hInstance
= hProxyDll
;
1400 wclass
.lpszClassName
= wszAptWinClass
;
1401 RegisterClassW(&wclass
);
1404 static void COMPOBJ_UninitProcess( void )
1406 UnregisterClassW(wszAptWinClass
, hProxyDll
);
1409 static void COM_TlsDestroy(void)
1411 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1414 if (info
->apt
) apartment_release(info
->apt
);
1415 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1416 if (info
->state
) IUnknown_Release(info
->state
);
1417 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1418 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1419 HeapFree(GetProcessHeap(), 0, info
);
1420 NtCurrentTeb()->ReservedForOle
= NULL
;
1424 /******************************************************************************
1425 * CoBuildVersion [OLE32.@]
1427 * Gets the build version of the DLL.
1432 * Current build version, hiword is majornumber, loword is minornumber
1434 DWORD WINAPI
CoBuildVersion(void)
1436 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1437 return (rmm
<<16)+rup
;
1440 /******************************************************************************
1441 * CoRegisterInitializeSpy [OLE32.@]
1443 * Add a Spy that watches CoInitializeEx calls
1446 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1447 * cookie [II] cookie receiver
1450 * Success: S_OK if not already initialized, S_FALSE otherwise.
1451 * Failure: HRESULT code.
1456 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1458 struct oletls
*info
= COM_CurrentInfo();
1461 TRACE("(%p, %p)\n", spy
, cookie
);
1463 if (!spy
|| !cookie
|| !info
)
1466 WARN("Could not allocate tls\n");
1467 return E_INVALIDARG
;
1472 FIXME("Already registered?\n");
1473 return E_UNEXPECTED
;
1476 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1479 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1485 /******************************************************************************
1486 * CoRevokeInitializeSpy [OLE32.@]
1488 * Remove a spy that previously watched CoInitializeEx calls
1491 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1494 * Success: S_OK if a spy is removed
1495 * Failure: E_INVALIDARG
1500 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1502 struct oletls
*info
= COM_CurrentInfo();
1503 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1505 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1506 return E_INVALIDARG
;
1508 IInitializeSpy_Release(info
->spy
);
1514 /******************************************************************************
1515 * CoInitialize [OLE32.@]
1517 * Initializes the COM libraries by calling CoInitializeEx with
1518 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1521 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1524 * Success: S_OK if not already initialized, S_FALSE otherwise.
1525 * Failure: HRESULT code.
1530 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1533 * Just delegate to the newer method.
1535 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1538 /******************************************************************************
1539 * CoInitializeEx [OLE32.@]
1541 * Initializes the COM libraries.
1544 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1545 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1548 * S_OK if successful,
1549 * S_FALSE if this function was called already.
1550 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1555 * The behavior used to set the IMalloc used for memory management is
1557 * The dwCoInit parameter must specify one of the following apartment
1559 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1560 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1561 * The parameter may also specify zero or more of the following flags:
1562 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1563 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1568 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1570 struct oletls
*info
= COM_CurrentInfo();
1574 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1576 if (lpReserved
!=NULL
)
1578 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1582 * Check the lock count. If this is the first time going through the initialize
1583 * process, we have to initialize the libraries.
1585 * And crank-up that lock count.
1587 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1590 * Initialize the various COM libraries and data structures.
1592 TRACE("() - Initializing the COM libraries\n");
1594 /* we may need to defer this until after apartment initialisation */
1595 RunningObjectTableImpl_Initialize();
1599 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1601 if (!(apt
= info
->apt
))
1603 apt
= apartment_get_or_create(dwCoInit
);
1604 if (!apt
) return E_OUTOFMEMORY
;
1606 else if (!apartment_is_model(apt
, dwCoInit
))
1608 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1609 code then we are probably using the wrong threading model to implement that API. */
1610 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1611 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1612 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1613 return RPC_E_CHANGED_MODE
;
1621 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1626 /***********************************************************************
1627 * CoUninitialize [OLE32.@]
1629 * This method will decrement the refcount on the current apartment, freeing
1630 * the resources associated with it if it is the last thread in the apartment.
1631 * If the last apartment is freed, the function will additionally release
1632 * any COM resources associated with the process.
1642 void WINAPI
CoUninitialize(void)
1644 struct oletls
* info
= COM_CurrentInfo();
1649 /* will only happen on OOM */
1653 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1658 ERR("Mismatched CoUninitialize\n");
1661 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1667 apartment_release(info
->apt
);
1672 * Decrease the reference count.
1673 * If we are back to 0 locks on the COM library, make sure we free
1674 * all the associated data structures.
1676 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1679 TRACE("() - Releasing the COM libraries\n");
1681 RunningObjectTableImpl_UnInitialize();
1683 else if (lCOMRefCnt
<1) {
1684 ERR( "CoUninitialize() - not CoInitialized.\n" );
1685 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1688 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1691 /******************************************************************************
1692 * CoDisconnectObject [OLE32.@]
1694 * Disconnects all connections to this object from remote processes. Dispatches
1695 * pending RPCs while blocking new RPCs from occurring, and then calls
1696 * IMarshal::DisconnectObject on the given object.
1698 * Typically called when the object server is forced to shut down, for instance by
1702 * lpUnk [I] The object whose stub should be disconnected.
1703 * reserved [I] Reserved. Should be set to 0.
1707 * Failure: HRESULT code.
1710 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1712 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
1718 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
1720 if (!lpUnk
) return E_INVALIDARG
;
1722 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
1725 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
1726 IMarshal_Release(marshal
);
1730 apt
= COM_CurrentApt();
1732 return CO_E_NOTINITIALIZED
;
1734 apartment_disconnectobject(apt
, lpUnk
);
1736 /* Note: native is pretty broken here because it just silently
1737 * fails, without returning an appropriate error code if the object was
1738 * not found, making apps think that the object was disconnected, when
1739 * it actually wasn't */
1744 /******************************************************************************
1745 * CoCreateGuid [OLE32.@]
1747 * Simply forwards to UuidCreate in RPCRT4.
1750 * pguid [O] Points to the GUID to initialize.
1754 * Failure: HRESULT code.
1759 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
1761 DWORD status
= UuidCreate(pguid
);
1762 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
1763 return HRESULT_FROM_WIN32( status
);
1766 static inline BOOL
is_valid_hex(WCHAR c
)
1768 if (!(((c
>= '0') && (c
<= '9')) ||
1769 ((c
>= 'a') && (c
<= 'f')) ||
1770 ((c
>= 'A') && (c
<= 'F'))))
1775 /******************************************************************************
1776 * CLSIDFromString [OLE32.@]
1777 * IIDFromString [OLE32.@]
1779 * Converts a unique identifier from its string representation into
1783 * idstr [I] The string representation of the GUID.
1784 * id [O] GUID converted from the string.
1788 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1793 static HRESULT
__CLSIDFromString(LPCWSTR s
, LPCLSID id
)
1798 if (!s
|| s
[0]!='{') {
1799 memset( id
, 0, sizeof (CLSID
) );
1801 return CO_E_CLASSSTRING
;
1804 TRACE("%s -> %p\n", debugstr_w(s
), id
);
1806 /* quick lookup table */
1807 memset(table
, 0, 256);
1809 for (i
= 0; i
< 10; i
++) {
1812 for (i
= 0; i
< 6; i
++) {
1813 table
['A' + i
] = i
+10;
1814 table
['a' + i
] = i
+10;
1817 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1820 for (i
= 1; i
< 9; i
++) {
1821 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1822 id
->Data1
= (id
->Data1
<< 4) | table
[s
[i
]];
1824 if (s
[9]!='-') return CO_E_CLASSSTRING
;
1827 for (i
= 10; i
< 14; i
++) {
1828 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1829 id
->Data2
= (id
->Data2
<< 4) | table
[s
[i
]];
1831 if (s
[14]!='-') return CO_E_CLASSSTRING
;
1834 for (i
= 15; i
< 19; i
++) {
1835 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1836 id
->Data3
= (id
->Data3
<< 4) | table
[s
[i
]];
1838 if (s
[19]!='-') return CO_E_CLASSSTRING
;
1840 for (i
= 20; i
< 37; i
+=2) {
1842 if (s
[i
]!='-') return CO_E_CLASSSTRING
;
1845 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return CO_E_CLASSSTRING
;
1846 id
->Data4
[(i
-20)/2] = table
[s
[i
]] << 4 | table
[s
[i
+1]];
1849 if (s
[37] == '}' && s
[38] == '\0')
1852 return CO_E_CLASSSTRING
;
1855 /*****************************************************************************/
1857 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
1862 return E_INVALIDARG
;
1864 ret
= __CLSIDFromString(idstr
, id
);
1865 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
1867 ret
= CLSIDFromProgID(idstr
, &tmp_id
);
1875 /******************************************************************************
1876 * StringFromCLSID [OLE32.@]
1877 * StringFromIID [OLE32.@]
1879 * Converts a GUID into the respective string representation.
1880 * The target string is allocated using the OLE IMalloc.
1883 * id [I] the GUID to be converted.
1884 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1891 * StringFromGUID2, CLSIDFromString
1893 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
1898 if ((ret
= CoGetMalloc(0,&mllc
))) return ret
;
1899 if (!(*idstr
= IMalloc_Alloc( mllc
, CHARS_IN_GUID
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
1900 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
1904 /******************************************************************************
1905 * StringFromGUID2 [OLE32.@]
1907 * Modified version of StringFromCLSID that allows you to specify max
1911 * id [I] GUID to convert to string.
1912 * str [O] Buffer where the result will be stored.
1913 * cmax [I] Size of the buffer in characters.
1916 * Success: The length of the resulting string in characters.
1919 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
1921 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
1922 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1923 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1924 '%','0','2','X','%','0','2','X','}',0 };
1925 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
1926 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
1927 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
1928 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
1929 return CHARS_IN_GUID
;
1932 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1933 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
1935 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
1936 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
1940 strcpyW(path
, wszCLSIDSlash
);
1941 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
1942 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
1943 if (res
== ERROR_FILE_NOT_FOUND
)
1944 return REGDB_E_CLASSNOTREG
;
1945 else if (res
!= ERROR_SUCCESS
)
1946 return REGDB_E_READREGDB
;
1954 res
= open_classes_key(key
, keyname
, access
, subkey
);
1956 if (res
== ERROR_FILE_NOT_FOUND
)
1957 return REGDB_E_KEYMISSING
;
1958 else if (res
!= ERROR_SUCCESS
)
1959 return REGDB_E_READREGDB
;
1964 /* open HKCR\\AppId\\{string form of appid clsid} key */
1965 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
1967 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
1968 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
1970 WCHAR buf
[CHARS_IN_GUID
];
1971 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
1977 /* read the AppID value under the class's key */
1978 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
1983 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
1985 if (res
== ERROR_FILE_NOT_FOUND
)
1986 return REGDB_E_KEYMISSING
;
1987 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
1988 return REGDB_E_READREGDB
;
1990 strcpyW(keyname
, szAppIdKey
);
1991 strcatW(keyname
, buf
);
1992 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
1993 if (res
== ERROR_FILE_NOT_FOUND
)
1994 return REGDB_E_KEYMISSING
;
1995 else if (res
!= ERROR_SUCCESS
)
1996 return REGDB_E_READREGDB
;
2001 /******************************************************************************
2002 * ProgIDFromCLSID [OLE32.@]
2004 * Converts a class id into the respective program ID.
2007 * clsid [I] Class ID, as found in registry.
2008 * ppszProgID [O] Associated ProgID.
2013 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2015 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2017 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2024 ERR("ppszProgId isn't optional\n");
2025 return E_INVALIDARG
;
2029 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2033 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2034 ret
= REGDB_E_CLASSNOTREG
;
2038 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2041 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2042 ret
= REGDB_E_CLASSNOTREG
;
2043 CoTaskMemFree(*ppszProgID
);
2048 ret
= E_OUTOFMEMORY
;
2055 /******************************************************************************
2056 * CLSIDFromProgID [OLE32.@]
2058 * Converts a program id into the respective GUID.
2061 * progid [I] Unicode program ID, as found in registry.
2062 * clsid [O] Associated CLSID.
2066 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2068 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2070 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2071 WCHAR buf2
[CHARS_IN_GUID
];
2072 LONG buf2len
= sizeof(buf2
);
2076 if (!progid
|| !clsid
)
2078 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
2079 return E_INVALIDARG
;
2082 /* initialise clsid in case of failure */
2083 memset(clsid
, 0, sizeof(*clsid
));
2085 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2086 strcpyW( buf
, progid
);
2087 strcatW( buf
, clsidW
);
2088 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2090 HeapFree(GetProcessHeap(),0,buf
);
2091 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2092 return CO_E_CLASSSTRING
;
2094 HeapFree(GetProcessHeap(),0,buf
);
2096 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2099 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2100 return CO_E_CLASSSTRING
;
2103 return __CLSIDFromString(buf2
,clsid
);
2107 /*****************************************************************************
2108 * CoGetPSClsid [OLE32.@]
2110 * Retrieves the CLSID of the proxy/stub factory that implements
2111 * IPSFactoryBuffer for the specified interface.
2114 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2115 * pclsid [O] Where to store returned proxy/stub CLSID.
2120 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2124 * The standard marshaller activates the object with the CLSID
2125 * returned and uses the CreateProxy and CreateStub methods on its
2126 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2129 * CoGetPSClsid determines this CLSID by searching the
2130 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2131 * in the registry and any interface id registered by
2132 * CoRegisterPSClsid within the current process.
2136 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2137 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2138 * considered a bug in native unless an application depends on this (unlikely).
2141 * CoRegisterPSClsid.
2143 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2145 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2146 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2147 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2148 WCHAR value
[CHARS_IN_GUID
];
2151 APARTMENT
*apt
= COM_CurrentApt();
2152 struct registered_psclsid
*registered_psclsid
;
2154 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2158 ERR("apartment not initialised\n");
2159 return CO_E_NOTINITIALIZED
;
2164 ERR("pclsid isn't optional\n");
2165 return E_INVALIDARG
;
2168 EnterCriticalSection(&apt
->cs
);
2170 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2171 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2173 *pclsid
= registered_psclsid
->clsid
;
2174 LeaveCriticalSection(&apt
->cs
);
2178 LeaveCriticalSection(&apt
->cs
);
2180 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2181 strcpyW(path
, wszInterface
);
2182 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2183 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2185 /* Open the key.. */
2186 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2188 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2189 return REGDB_E_IIDNOTREG
;
2192 /* ... Once we have the key, query the registry to get the
2193 value of CLSID as a string, and convert it into a
2194 proper CLSID structure to be passed back to the app */
2195 len
= sizeof(value
);
2196 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2199 return REGDB_E_IIDNOTREG
;
2203 /* We have the CLSID we want back from the registry as a string, so
2204 let's convert it into a CLSID structure */
2205 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2206 return REGDB_E_IIDNOTREG
;
2208 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2212 /*****************************************************************************
2213 * CoRegisterPSClsid [OLE32.@]
2215 * Register a proxy/stub CLSID for the given interface in the current process
2219 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2220 * rclsid [I] CLSID of the proxy/stub.
2224 * Failure: E_OUTOFMEMORY
2228 * This function does not add anything to the registry and the effects are
2229 * limited to the lifetime of the current process.
2234 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2236 APARTMENT
*apt
= COM_CurrentApt();
2237 struct registered_psclsid
*registered_psclsid
;
2239 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2243 ERR("apartment not initialised\n");
2244 return CO_E_NOTINITIALIZED
;
2247 EnterCriticalSection(&apt
->cs
);
2249 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2250 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2252 registered_psclsid
->clsid
= *rclsid
;
2253 LeaveCriticalSection(&apt
->cs
);
2257 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2258 if (!registered_psclsid
)
2260 LeaveCriticalSection(&apt
->cs
);
2261 return E_OUTOFMEMORY
;
2264 registered_psclsid
->iid
= *riid
;
2265 registered_psclsid
->clsid
= *rclsid
;
2266 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2268 LeaveCriticalSection(&apt
->cs
);
2275 * COM_GetRegisteredClassObject
2277 * This internal method is used to scan the registered class list to
2278 * find a class object.
2281 * rclsid Class ID of the class to find.
2282 * dwClsContext Class context to match.
2283 * ppv [out] returns a pointer to the class object. Complying
2284 * to normal COM usage, this method will increase the
2285 * reference count on this object.
2287 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2288 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2290 HRESULT hr
= S_FALSE
;
2291 RegisteredClass
*curClass
;
2293 EnterCriticalSection( &csRegisteredClassList
);
2295 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2298 * Check if we have a match on the class ID and context.
2300 if ((apt
->oxid
== curClass
->apartment_id
) &&
2301 (dwClsContext
& curClass
->runContext
) &&
2302 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2305 * We have a match, return the pointer to the class object.
2307 *ppUnk
= curClass
->classObject
;
2309 IUnknown_AddRef(curClass
->classObject
);
2316 LeaveCriticalSection( &csRegisteredClassList
);
2321 /******************************************************************************
2322 * CoRegisterClassObject [OLE32.@]
2324 * Registers the class object for a given class ID. Servers housed in EXE
2325 * files use this method instead of exporting DllGetClassObject to allow
2326 * other code to connect to their objects.
2329 * rclsid [I] CLSID of the object to register.
2330 * pUnk [I] IUnknown of the object.
2331 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2332 * flags [I] REGCLS flags indicating how connections are made.
2333 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2337 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2338 * CO_E_OBJISREG if the object is already registered. We should not return this.
2341 * CoRevokeClassObject, CoGetClassObject
2344 * In-process objects are only registered for the current apartment.
2345 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2346 * in other apartments.
2349 * MSDN claims that multiple interface registrations are legal, but we
2350 * can't do that with our current implementation.
2352 HRESULT WINAPI
CoRegisterClassObject(
2357 LPDWORD lpdwRegister
)
2359 static LONG next_cookie
;
2360 RegisteredClass
* newClass
;
2361 LPUNKNOWN foundObject
;
2365 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2366 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2368 if ( (lpdwRegister
==0) || (pUnk
==0) )
2369 return E_INVALIDARG
;
2371 apt
= COM_CurrentApt();
2374 ERR("COM was not initialized\n");
2375 return CO_E_NOTINITIALIZED
;
2380 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2381 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2382 if (flags
& REGCLS_MULTIPLEUSE
)
2383 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2386 * First, check if the class is already registered.
2387 * If it is, this should cause an error.
2389 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2391 if (flags
& REGCLS_MULTIPLEUSE
) {
2392 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2393 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2394 IUnknown_Release(foundObject
);
2397 IUnknown_Release(foundObject
);
2398 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2399 return CO_E_OBJISREG
;
2402 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2403 if ( newClass
== NULL
)
2404 return E_OUTOFMEMORY
;
2406 newClass
->classIdentifier
= *rclsid
;
2407 newClass
->apartment_id
= apt
->oxid
;
2408 newClass
->runContext
= dwClsContext
;
2409 newClass
->connectFlags
= flags
;
2410 newClass
->pMarshaledData
= NULL
;
2411 newClass
->RpcRegistration
= NULL
;
2413 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2414 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2417 * Since we're making a copy of the object pointer, we have to increase its
2420 newClass
->classObject
= pUnk
;
2421 IUnknown_AddRef(newClass
->classObject
);
2423 EnterCriticalSection( &csRegisteredClassList
);
2424 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2425 LeaveCriticalSection( &csRegisteredClassList
);
2427 *lpdwRegister
= newClass
->dwCookie
;
2429 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2430 hr
= CreateStreamOnHGlobal(0, TRUE
, &newClass
->pMarshaledData
);
2432 FIXME("Failed to create stream on hglobal, %x\n", hr
);
2435 hr
= CoMarshalInterface(newClass
->pMarshaledData
, &IID_IUnknown
,
2436 newClass
->classObject
, MSHCTX_LOCAL
, NULL
,
2437 MSHLFLAGS_TABLESTRONG
);
2439 FIXME("CoMarshalInterface failed, %x!\n",hr
);
2443 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2444 newClass
->pMarshaledData
,
2445 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2446 &newClass
->RpcRegistration
);
2451 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
2453 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2456 DWORD dwLength
= len
* sizeof(WCHAR
);
2458 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
2459 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2463 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
,
2464 REFCLSID rclsid
, REFIID riid
,
2465 BOOL hostifnecessary
, void **ppv
)
2467 WCHAR dllpath
[MAX_PATH
+1];
2468 BOOL apartment_threaded
;
2470 if (hostifnecessary
)
2472 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2473 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2474 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2475 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2477 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
2479 if (!strcmpiW(threading_model
, wszApartment
))
2481 apartment_threaded
= TRUE
;
2482 if (apt
->multi_threaded
)
2483 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2486 else if (!strcmpiW(threading_model
, wszFree
))
2488 apartment_threaded
= FALSE
;
2489 if (!apt
->multi_threaded
)
2490 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2492 /* everything except "Apartment", "Free" and "Both" */
2493 else if (strcmpiW(threading_model
, wszBoth
))
2495 apartment_threaded
= TRUE
;
2496 /* everything else is main-threaded */
2497 if (threading_model
[0])
2498 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2499 debugstr_w(threading_model
), debugstr_guid(rclsid
));
2501 if (apt
->multi_threaded
|| !apt
->main
)
2502 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, hkeydll
, rclsid
, riid
, ppv
);
2505 apartment_threaded
= FALSE
;
2508 apartment_threaded
= !apt
->multi_threaded
;
2510 if (COM_RegReadPath(hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2512 /* failure: CLSID is not found in registry */
2513 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2514 return REGDB_E_CLASSNOTREG
;
2517 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2521 /***********************************************************************
2522 * CoGetClassObject [OLE32.@]
2524 * Creates an object of the specified class.
2527 * rclsid [I] Class ID to create an instance of.
2528 * dwClsContext [I] Flags to restrict the location of the created instance.
2529 * pServerInfo [I] Optional. Details for connecting to a remote server.
2530 * iid [I] The ID of the interface of the instance to return.
2531 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2535 * Failure: HRESULT code.
2538 * The dwClsContext parameter can be one or more of the following:
2539 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2540 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2541 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2542 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2545 * CoCreateInstance()
2547 HRESULT WINAPI
CoGetClassObject(
2548 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2549 REFIID iid
, LPVOID
*ppv
)
2551 LPUNKNOWN regClassObject
;
2552 HRESULT hres
= E_UNEXPECTED
;
2554 BOOL release_apt
= FALSE
;
2556 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2559 return E_INVALIDARG
;
2563 if (!(apt
= COM_CurrentApt()))
2565 if (!(apt
= apartment_find_multi_threaded()))
2567 ERR("apartment not initialised\n");
2568 return CO_E_NOTINITIALIZED
;
2574 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2575 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2579 * First, try and see if we can't match the class ID with one of the
2580 * registered classes.
2582 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2585 /* Get the required interface from the retrieved pointer. */
2586 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2589 * Since QI got another reference on the pointer, we want to release the
2590 * one we already have. If QI was unsuccessful, this will release the object. This
2591 * is good since we are not returning it in the "out" parameter.
2593 IUnknown_Release(regClassObject
);
2594 if (release_apt
) apartment_release(apt
);
2598 /* First try in-process server */
2599 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2601 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2604 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2606 if (release_apt
) apartment_release(apt
);
2607 return FTMarshalCF_Create(iid
, ppv
);
2610 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2613 if (hres
== REGDB_E_CLASSNOTREG
)
2614 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2615 else if (hres
== REGDB_E_KEYMISSING
)
2617 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2618 hres
= REGDB_E_CLASSNOTREG
;
2622 if (SUCCEEDED(hres
))
2624 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2625 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2629 /* return if we got a class, otherwise fall through to one of the
2631 if (SUCCEEDED(hres
))
2633 if (release_apt
) apartment_release(apt
);
2638 /* Next try in-process handler */
2639 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2641 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2644 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2647 if (hres
== REGDB_E_CLASSNOTREG
)
2648 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2649 else if (hres
== REGDB_E_KEYMISSING
)
2651 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2652 hres
= REGDB_E_CLASSNOTREG
;
2656 if (SUCCEEDED(hres
))
2658 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2659 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2663 /* return if we got a class, otherwise fall through to one of the
2665 if (SUCCEEDED(hres
))
2667 if (release_apt
) apartment_release(apt
);
2671 if (release_apt
) apartment_release(apt
);
2673 /* Next try out of process */
2674 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2676 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2677 if (SUCCEEDED(hres
))
2681 /* Finally try remote: this requires networked DCOM (a lot of work) */
2682 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2684 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2685 hres
= REGDB_E_CLASSNOTREG
;
2689 ERR("no class object %s could be created for context 0x%x\n",
2690 debugstr_guid(rclsid
), dwClsContext
);
2694 /***********************************************************************
2695 * CoResumeClassObjects (OLE32.@)
2697 * Resumes all class objects registered with REGCLS_SUSPENDED.
2701 * Failure: HRESULT code.
2703 HRESULT WINAPI
CoResumeClassObjects(void)
2709 /***********************************************************************
2710 * CoCreateInstance [OLE32.@]
2712 * Creates an instance of the specified class.
2715 * rclsid [I] Class ID to create an instance of.
2716 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2717 * dwClsContext [I] Flags to restrict the location of the created instance.
2718 * iid [I] The ID of the interface of the instance to return.
2719 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2723 * Failure: HRESULT code.
2726 * The dwClsContext parameter can be one or more of the following:
2727 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2728 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2729 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2730 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2732 * Aggregation is the concept of deferring the IUnknown of an object to another
2733 * object. This allows a separate object to behave as though it was part of
2734 * the object and to allow this the pUnkOuter parameter can be set. Note that
2735 * not all objects support having an outer of unknown.
2738 * CoGetClassObject()
2740 HRESULT WINAPI
CoCreateInstance(
2742 LPUNKNOWN pUnkOuter
,
2748 LPCLASSFACTORY lpclf
= 0;
2751 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2752 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2759 if (!(apt
= COM_CurrentApt()))
2761 if (!(apt
= apartment_find_multi_threaded()))
2763 ERR("apartment not initialised\n");
2764 return CO_E_NOTINITIALIZED
;
2766 apartment_release(apt
);
2770 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2771 * Rather than create a class factory, we can just check for it here
2773 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
2775 if (StdGlobalInterfaceTableInstance
== NULL
)
2776 StdGlobalInterfaceTableInstance
= StdGlobalInterfaceTable_Construct();
2777 hres
= IGlobalInterfaceTable_QueryInterface((IGlobalInterfaceTable
*)StdGlobalInterfaceTableInstance
,
2780 if (hres
) return hres
;
2782 TRACE("Retrieved GIT (%p)\n", *ppv
);
2786 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
2787 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
2790 * Get a class factory to construct the object we want.
2792 hres
= CoGetClassObject(rclsid
,
2802 * Create the object and don't forget to release the factory
2804 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2805 IClassFactory_Release(lpclf
);
2808 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
2809 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
2811 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2813 debugstr_guid(rclsid
),hres
);
2819 /***********************************************************************
2820 * CoCreateInstanceEx [OLE32.@]
2822 HRESULT WINAPI
CoCreateInstanceEx(
2824 LPUNKNOWN pUnkOuter
,
2826 COSERVERINFO
* pServerInfo
,
2830 IUnknown
* pUnk
= NULL
;
2833 ULONG successCount
= 0;
2838 if ( (cmq
==0) || (pResults
==NULL
))
2839 return E_INVALIDARG
;
2841 if (pServerInfo
!=NULL
)
2842 FIXME("() non-NULL pServerInfo not supported!\n");
2845 * Initialize all the "out" parameters.
2847 for (index
= 0; index
< cmq
; index
++)
2849 pResults
[index
].pItf
= NULL
;
2850 pResults
[index
].hr
= E_NOINTERFACE
;
2854 * Get the object and get its IUnknown pointer.
2856 hr
= CoCreateInstance(rclsid
,
2866 * Then, query for all the interfaces requested.
2868 for (index
= 0; index
< cmq
; index
++)
2870 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
2871 pResults
[index
].pIID
,
2872 (VOID
**)&(pResults
[index
].pItf
));
2874 if (pResults
[index
].hr
== S_OK
)
2879 * Release our temporary unknown pointer.
2881 IUnknown_Release(pUnk
);
2883 if (successCount
== 0)
2884 return E_NOINTERFACE
;
2886 if (successCount
!=cmq
)
2887 return CO_S_NOTALLINTERFACES
;
2892 /***********************************************************************
2893 * CoLoadLibrary (OLE32.@)
2898 * lpszLibName [I] Path to library.
2899 * bAutoFree [I] Whether the library should automatically be freed.
2902 * Success: Handle to loaded library.
2906 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2908 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
2910 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
2912 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
2915 /***********************************************************************
2916 * CoFreeLibrary [OLE32.@]
2918 * Unloads a library from memory.
2921 * hLibrary [I] Handle to library to unload.
2927 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2929 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
2931 FreeLibrary(hLibrary
);
2935 /***********************************************************************
2936 * CoFreeAllLibraries [OLE32.@]
2938 * Function for backwards compatibility only. Does nothing.
2944 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2946 void WINAPI
CoFreeAllLibraries(void)
2951 /***********************************************************************
2952 * CoFreeUnusedLibrariesEx [OLE32.@]
2954 * Frees any previously unused libraries whose delay has expired and marks
2955 * currently unused libraries for unloading. Unused are identified as those that
2956 * return S_OK from their DllCanUnloadNow function.
2959 * dwUnloadDelay [I] Unload delay in milliseconds.
2960 * dwReserved [I] Reserved. Set to 0.
2966 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2968 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
2970 struct apartment
*apt
= COM_CurrentApt();
2973 ERR("apartment not initialised\n");
2977 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
2980 /***********************************************************************
2981 * CoFreeUnusedLibraries [OLE32.@]
2983 * Frees any unused libraries. Unused are identified as those that return
2984 * S_OK from their DllCanUnloadNow function.
2990 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2992 void WINAPI
CoFreeUnusedLibraries(void)
2994 CoFreeUnusedLibrariesEx(INFINITE
, 0);
2997 /***********************************************************************
2998 * CoFileTimeNow [OLE32.@]
3000 * Retrieves the current time in FILETIME format.
3003 * lpFileTime [O] The current time.
3008 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3010 GetSystemTimeAsFileTime( lpFileTime
);
3014 /******************************************************************************
3015 * CoLockObjectExternal [OLE32.@]
3017 * Increments or decrements the external reference count of a stub object.
3020 * pUnk [I] Stub object.
3021 * fLock [I] If TRUE then increments the external ref-count,
3022 * otherwise decrements.
3023 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3024 * calling CoDisconnectObject.
3028 * Failure: HRESULT code.
3031 * If fLock is TRUE and an object is passed in that doesn't have a stub
3032 * manager then a new stub manager is created for the object.
3034 HRESULT WINAPI
CoLockObjectExternal(
3037 BOOL fLastUnlockReleases
)
3039 struct stub_manager
*stubmgr
;
3040 struct apartment
*apt
;
3042 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3043 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3045 apt
= COM_CurrentApt();
3046 if (!apt
) return CO_E_NOTINITIALIZED
;
3048 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3053 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3055 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3057 stub_manager_int_release(stubmgr
);
3063 stubmgr
= new_stub_manager(apt
, pUnk
);
3067 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3068 stub_manager_int_release(stubmgr
);
3075 WARN("stub object not found %p\n", pUnk
);
3076 /* Note: native is pretty broken here because it just silently
3077 * fails, without returning an appropriate error code, making apps
3078 * think that the object was disconnected, when it actually wasn't */
3083 /***********************************************************************
3084 * CoInitializeWOW (OLE32.@)
3086 * WOW equivalent of CoInitialize?
3095 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3097 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3101 /***********************************************************************
3102 * CoGetState [OLE32.@]
3104 * Retrieves the thread state object previously stored by CoSetState().
3107 * ppv [I] Address where pointer to object will be stored.
3111 * Failure: E_OUTOFMEMORY.
3114 * Crashes on all invalid ppv addresses, including NULL.
3115 * If the function returns a non-NULL object then the caller must release its
3116 * reference on the object when the object is no longer required.
3121 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3123 struct oletls
*info
= COM_CurrentInfo();
3124 if (!info
) return E_OUTOFMEMORY
;
3130 IUnknown_AddRef(info
->state
);
3132 TRACE("apt->state=%p\n", info
->state
);
3138 /***********************************************************************
3139 * CoSetState [OLE32.@]
3141 * Sets the thread state object.
3144 * pv [I] Pointer to state object to be stored.
3147 * The system keeps a reference on the object while the object stored.
3151 * Failure: E_OUTOFMEMORY.
3153 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3155 struct oletls
*info
= COM_CurrentInfo();
3156 if (!info
) return E_OUTOFMEMORY
;
3158 if (pv
) IUnknown_AddRef(pv
);
3162 TRACE("-- release %p now\n", info
->state
);
3163 IUnknown_Release(info
->state
);
3172 /******************************************************************************
3173 * CoTreatAsClass [OLE32.@]
3175 * Sets the TreatAs value of a class.
3178 * clsidOld [I] Class to set TreatAs value on.
3179 * clsidNew [I] The class the clsidOld should be treated as.
3183 * Failure: HRESULT code.
3188 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3190 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3191 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3193 WCHAR szClsidNew
[CHARS_IN_GUID
];
3195 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3196 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3199 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3202 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3204 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3205 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3207 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3209 res
= REGDB_E_WRITEREGDB
;
3215 RegDeleteKeyW(hkey
, wszTreatAs
);
3219 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3220 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3222 res
= REGDB_E_WRITEREGDB
;
3227 if (hkey
) RegCloseKey(hkey
);
3231 /******************************************************************************
3232 * CoGetTreatAsClass [OLE32.@]
3234 * Gets the TreatAs value of a class.
3237 * clsidOld [I] Class to get the TreatAs value of.
3238 * clsidNew [I] The class the clsidOld should be treated as.
3242 * Failure: HRESULT code.
3247 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3249 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3251 WCHAR szClsidNew
[CHARS_IN_GUID
];
3253 LONG len
= sizeof(szClsidNew
);
3255 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3256 *clsidNew
= *clsidOld
; /* copy over old value */
3258 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3264 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3269 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3271 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3273 if (hkey
) RegCloseKey(hkey
);
3277 /******************************************************************************
3278 * CoGetCurrentProcess [OLE32.@]
3280 * Gets the current process ID.
3283 * The current process ID.
3286 * Is DWORD really the correct return type for this function?
3288 DWORD WINAPI
CoGetCurrentProcess(void)
3290 return GetCurrentProcessId();
3293 /******************************************************************************
3294 * CoRegisterMessageFilter [OLE32.@]
3296 * Registers a message filter.
3299 * lpMessageFilter [I] Pointer to interface.
3300 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3304 * Failure: HRESULT code.
3307 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3308 * lpMessageFilter removes the message filter.
3310 * If lplpMessageFilter is not NULL the previous message filter will be
3311 * returned in the memory pointer to this parameter and the caller is
3312 * responsible for releasing the object.
3314 * The current thread be in an apartment otherwise the function will crash.
3316 HRESULT WINAPI
CoRegisterMessageFilter(
3317 LPMESSAGEFILTER lpMessageFilter
,
3318 LPMESSAGEFILTER
*lplpMessageFilter
)
3320 struct apartment
*apt
;
3321 IMessageFilter
*lpOldMessageFilter
;
3323 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3325 apt
= COM_CurrentApt();
3327 /* can't set a message filter in a multi-threaded apartment */
3328 if (!apt
|| apt
->multi_threaded
)
3330 WARN("can't set message filter in MTA or uninitialized apt\n");
3331 return CO_E_NOT_SUPPORTED
;
3334 if (lpMessageFilter
)
3335 IMessageFilter_AddRef(lpMessageFilter
);
3337 EnterCriticalSection(&apt
->cs
);
3339 lpOldMessageFilter
= apt
->filter
;
3340 apt
->filter
= lpMessageFilter
;
3342 LeaveCriticalSection(&apt
->cs
);
3344 if (lplpMessageFilter
)
3345 *lplpMessageFilter
= lpOldMessageFilter
;
3346 else if (lpOldMessageFilter
)
3347 IMessageFilter_Release(lpOldMessageFilter
);
3352 /***********************************************************************
3353 * CoIsOle1Class [OLE32.@]
3355 * Determines whether the specified class an OLE v1 class.
3358 * clsid [I] Class to test.
3361 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3363 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3365 FIXME("%s\n", debugstr_guid(clsid
));
3369 /***********************************************************************
3370 * IsEqualGUID [OLE32.@]
3372 * Compares two Unique Identifiers.
3375 * rguid1 [I] The first GUID to compare.
3376 * rguid2 [I] The other GUID to compare.
3382 BOOL WINAPI
IsEqualGUID(
3386 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3389 /***********************************************************************
3390 * CoInitializeSecurity [OLE32.@]
3392 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3393 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3394 void* pReserved1
, DWORD dwAuthnLevel
,
3395 DWORD dwImpLevel
, void* pReserved2
,
3396 DWORD dwCapabilities
, void* pReserved3
)
3398 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3399 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3400 dwCapabilities
, pReserved3
);
3404 /***********************************************************************
3405 * CoSuspendClassObjects [OLE32.@]
3407 * Suspends all registered class objects to prevent further requests coming in
3408 * for those objects.
3412 * Failure: HRESULT code.
3414 HRESULT WINAPI
CoSuspendClassObjects(void)
3420 /***********************************************************************
3421 * CoAddRefServerProcess [OLE32.@]
3423 * Helper function for incrementing the reference count of a local-server
3427 * New reference count.
3430 * CoReleaseServerProcess().
3432 ULONG WINAPI
CoAddRefServerProcess(void)
3438 EnterCriticalSection(&csRegisteredClassList
);
3439 refs
= ++s_COMServerProcessReferences
;
3440 LeaveCriticalSection(&csRegisteredClassList
);
3442 TRACE("refs before: %d\n", refs
- 1);
3447 /***********************************************************************
3448 * CoReleaseServerProcess [OLE32.@]
3450 * Helper function for decrementing the reference count of a local-server
3454 * New reference count.
3457 * When reference count reaches 0, this function suspends all registered
3458 * classes so no new connections are accepted.
3461 * CoAddRefServerProcess(), CoSuspendClassObjects().
3463 ULONG WINAPI
CoReleaseServerProcess(void)
3469 EnterCriticalSection(&csRegisteredClassList
);
3471 refs
= --s_COMServerProcessReferences
;
3472 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3474 LeaveCriticalSection(&csRegisteredClassList
);
3476 TRACE("refs after: %d\n", refs
);
3481 /***********************************************************************
3482 * CoIsHandlerConnected [OLE32.@]
3484 * Determines whether a proxy is connected to a remote stub.
3487 * pUnk [I] Pointer to object that may or may not be connected.
3490 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3493 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3495 FIXME("%p\n", pUnk
);
3500 /***********************************************************************
3501 * CoAllowSetForegroundWindow [OLE32.@]
3504 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3506 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3510 /***********************************************************************
3511 * CoQueryProxyBlanket [OLE32.@]
3513 * Retrieves the security settings being used by a proxy.
3516 * pProxy [I] Pointer to the proxy object.
3517 * pAuthnSvc [O] The type of authentication service.
3518 * pAuthzSvc [O] The type of authorization service.
3519 * ppServerPrincName [O] Optional. The server prinicple name.
3520 * pAuthnLevel [O] The authentication level.
3521 * pImpLevel [O] The impersonation level.
3522 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3523 * pCapabilities [O] Flags affecting the security behaviour.
3527 * Failure: HRESULT code.
3530 * CoCopyProxy, CoSetProxyBlanket.
3532 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
3533 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
3534 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
3536 IClientSecurity
*pCliSec
;
3539 TRACE("%p\n", pProxy
);
3541 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3544 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
3545 pAuthzSvc
, ppServerPrincName
,
3546 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
3548 IClientSecurity_Release(pCliSec
);
3551 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3555 /***********************************************************************
3556 * CoSetProxyBlanket [OLE32.@]
3558 * Sets the security settings for a proxy.
3561 * pProxy [I] Pointer to the proxy object.
3562 * AuthnSvc [I] The type of authentication service.
3563 * AuthzSvc [I] The type of authorization service.
3564 * pServerPrincName [I] The server prinicple name.
3565 * AuthnLevel [I] The authentication level.
3566 * ImpLevel [I] The impersonation level.
3567 * pAuthInfo [I] Information specific to the authorization/authentication service.
3568 * Capabilities [I] Flags affecting the security behaviour.
3572 * Failure: HRESULT code.
3575 * CoQueryProxyBlanket, CoCopyProxy.
3577 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
3578 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
3579 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
3581 IClientSecurity
*pCliSec
;
3584 TRACE("%p\n", pProxy
);
3586 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3589 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
3590 AuthzSvc
, pServerPrincName
,
3591 AuthnLevel
, ImpLevel
, pAuthInfo
,
3593 IClientSecurity_Release(pCliSec
);
3596 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3600 /***********************************************************************
3601 * CoCopyProxy [OLE32.@]
3606 * pProxy [I] Pointer to the proxy object.
3607 * ppCopy [O] Copy of the proxy.
3611 * Failure: HRESULT code.
3614 * CoQueryProxyBlanket, CoSetProxyBlanket.
3616 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
3618 IClientSecurity
*pCliSec
;
3621 TRACE("%p\n", pProxy
);
3623 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3626 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
3627 IClientSecurity_Release(pCliSec
);
3630 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3635 /***********************************************************************
3636 * CoGetCallContext [OLE32.@]
3638 * Gets the context of the currently executing server call in the current
3642 * riid [I] Context interface to return.
3643 * ppv [O] Pointer to memory that will receive the context on return.
3647 * Failure: HRESULT code.
3649 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3651 struct oletls
*info
= COM_CurrentInfo();
3653 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3656 return E_OUTOFMEMORY
;
3658 if (!info
->call_state
)
3659 return RPC_E_CALL_COMPLETE
;
3661 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3664 /***********************************************************************
3665 * CoSwitchCallContext [OLE32.@]
3667 * Switches the context of the currently executing server call in the current
3671 * pObject [I] Pointer to new context object
3672 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3676 * Failure: HRESULT code.
3678 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3680 struct oletls
*info
= COM_CurrentInfo();
3682 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3685 return E_OUTOFMEMORY
;
3687 *ppOldObject
= info
->call_state
;
3688 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3693 /***********************************************************************
3694 * CoQueryClientBlanket [OLE32.@]
3696 * Retrieves the authentication information about the client of the currently
3697 * executing server call in the current thread.
3700 * pAuthnSvc [O] Optional. The type of authentication service.
3701 * pAuthzSvc [O] Optional. The type of authorization service.
3702 * pServerPrincName [O] Optional. The server prinicple name.
3703 * pAuthnLevel [O] Optional. The authentication level.
3704 * pImpLevel [O] Optional. The impersonation level.
3705 * pPrivs [O] Optional. Information about the privileges of the client.
3706 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3710 * Failure: HRESULT code.
3713 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3715 HRESULT WINAPI
CoQueryClientBlanket(
3718 OLECHAR
**pServerPrincName
,
3721 RPC_AUTHZ_HANDLE
*pPrivs
,
3722 DWORD
*pCapabilities
)
3724 IServerSecurity
*pSrvSec
;
3727 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3728 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3729 pPrivs
, pCapabilities
);
3731 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3734 hr
= IServerSecurity_QueryBlanket(
3735 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3736 pImpLevel
, pPrivs
, pCapabilities
);
3737 IServerSecurity_Release(pSrvSec
);
3743 /***********************************************************************
3744 * CoImpersonateClient [OLE32.@]
3746 * Impersonates the client of the currently executing server call in the
3754 * Failure: HRESULT code.
3757 * If this function fails then the current thread will not be impersonating
3758 * the client and all actions will take place on behalf of the server.
3759 * Therefore, it is important to check the return value from this function.
3762 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3764 HRESULT WINAPI
CoImpersonateClient(void)
3766 IServerSecurity
*pSrvSec
;
3771 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3774 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3775 IServerSecurity_Release(pSrvSec
);
3781 /***********************************************************************
3782 * CoRevertToSelf [OLE32.@]
3784 * Ends the impersonation of the client of the currently executing server
3785 * call in the current thread.
3792 * Failure: HRESULT code.
3795 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3797 HRESULT WINAPI
CoRevertToSelf(void)
3799 IServerSecurity
*pSrvSec
;
3804 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3807 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3808 IServerSecurity_Release(pSrvSec
);
3814 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3816 /* first try to retrieve messages for incoming COM calls to the apartment window */
3817 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
3818 /* next retrieve other messages necessary for the app to remain responsive */
3819 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3820 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3823 /***********************************************************************
3824 * CoWaitForMultipleHandles [OLE32.@]
3826 * Waits for one or more handles to become signaled.
3829 * dwFlags [I] Flags. See notes.
3830 * dwTimeout [I] Timeout in milliseconds.
3831 * cHandles [I] Number of handles pointed to by pHandles.
3832 * pHandles [I] Handles to wait for.
3833 * lpdwindex [O] Index of handle that was signaled.
3837 * Failure: RPC_S_CALLPENDING on timeout.
3841 * The dwFlags parameter can be zero or more of the following:
3842 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3843 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3846 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3848 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3849 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3852 DWORD start_time
= GetTickCount();
3853 APARTMENT
*apt
= COM_CurrentApt();
3854 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3856 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3857 pHandles
, lpdwindex
);
3861 DWORD now
= GetTickCount();
3864 if (now
- start_time
> dwTimeout
)
3866 hr
= RPC_S_CALLPENDING
;
3872 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
3873 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
3875 TRACE("waiting for rpc completion or window message\n");
3877 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
3878 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3879 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
3881 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
3886 /* call message filter */
3888 if (COM_CurrentApt()->filter
)
3890 PENDINGTYPE pendingtype
=
3891 COM_CurrentInfo()->pending_call_count_server
?
3892 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
3893 DWORD be_handled
= IMessageFilter_MessagePending(
3894 COM_CurrentApt()->filter
, 0 /* FIXME */,
3895 now
- start_time
, pendingtype
);
3896 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
3899 case PENDINGMSG_CANCELCALL
:
3900 WARN("call canceled\n");
3901 hr
= RPC_E_CALL_CANCELED
;
3903 case PENDINGMSG_WAITNOPROCESS
:
3904 case PENDINGMSG_WAITDEFPROCESS
:
3906 /* FIXME: MSDN is very vague about the difference
3907 * between WAITNOPROCESS and WAITDEFPROCESS - there
3908 * appears to be none, so it is possibly a left-over
3909 * from the 16-bit world. */
3914 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
3915 * so after processing 100 messages we go back to checking the wait handles */
3916 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
3918 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
3919 TranslateMessage(&msg
);
3920 DispatchMessageW(&msg
);
3921 if (msg
.message
== WM_QUIT
)
3923 TRACE("resending WM_QUIT to outer message loop\n");
3924 PostQuitMessage(msg
.wParam
);
3925 /* no longer need to process messages */
3926 message_loop
= FALSE
;
3935 TRACE("waiting for rpc completion\n");
3937 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
3938 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3939 (dwFlags
& COWAIT_ALERTABLE
) != 0);
3945 hr
= RPC_S_CALLPENDING
;
3948 hr
= HRESULT_FROM_WIN32( GetLastError() );
3956 TRACE("-- 0x%08x\n", hr
);
3961 /***********************************************************************
3962 * CoGetObject [OLE32.@]
3964 * Gets the object named by converting the name to a moniker and binding to it.
3967 * pszName [I] String representing the object.
3968 * pBindOptions [I] Parameters affecting the binding to the named object.
3969 * riid [I] Interface to bind to on the objecct.
3970 * ppv [O] On output, the interface riid of the object represented
3975 * Failure: HRESULT code.
3978 * MkParseDisplayName.
3980 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
3981 REFIID riid
, void **ppv
)
3988 hr
= CreateBindCtx(0, &pbc
);
3992 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
3999 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4002 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4003 IMoniker_Release(pmk
);
4007 IBindCtx_Release(pbc
);
4012 /***********************************************************************
4013 * CoRegisterChannelHook [OLE32.@]
4015 * Registers a process-wide hook that is called during ORPC calls.
4018 * guidExtension [I] GUID of the channel hook to register.
4019 * pChannelHook [I] Channel hook object to register.
4023 * Failure: HRESULT code.
4025 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4027 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4029 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4032 typedef struct Context
4034 IComThreadingInfo IComThreadingInfo_iface
;
4035 IContextCallback IContextCallback_iface
;
4036 IObjContext IObjContext_iface
;
4041 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4043 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4046 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4048 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4051 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4053 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4056 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4060 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4061 IsEqualIID(riid
, &IID_IUnknown
))
4063 *ppv
= &iface
->IComThreadingInfo_iface
;
4065 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4067 *ppv
= &iface
->IContextCallback_iface
;
4069 else if (IsEqualIID(riid
, &IID_IObjContext
))
4071 *ppv
= &iface
->IObjContext_iface
;
4076 IUnknown_AddRef((IUnknown
*)*ppv
);
4080 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4081 return E_NOINTERFACE
;
4084 static ULONG
Context_AddRef(Context
*This
)
4086 return InterlockedIncrement(&This
->refs
);
4089 static ULONG
Context_Release(Context
*This
)
4091 ULONG refs
= InterlockedDecrement(&This
->refs
);
4093 HeapFree(GetProcessHeap(), 0, This
);
4097 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4099 Context
*This
= impl_from_IComThreadingInfo(iface
);
4100 return Context_QueryInterface(This
, riid
, ppv
);
4103 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4105 Context
*This
= impl_from_IComThreadingInfo(iface
);
4106 return Context_AddRef(This
);
4109 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4111 Context
*This
= impl_from_IComThreadingInfo(iface
);
4112 return Context_Release(This
);
4115 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4117 Context
*This
= impl_from_IComThreadingInfo(iface
);
4119 TRACE("(%p)\n", apttype
);
4121 *apttype
= This
->apttype
;
4125 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4127 Context
*This
= impl_from_IComThreadingInfo(iface
);
4129 TRACE("(%p)\n", thdtype
);
4131 switch (This
->apttype
)
4134 case APTTYPE_MAINSTA
:
4135 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4138 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4144 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4146 FIXME("(%p): stub\n", logical_thread_id
);
4150 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4152 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4156 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4158 Context_CTI_QueryInterface
,
4160 Context_CTI_Release
,
4161 Context_CTI_GetCurrentApartmentType
,
4162 Context_CTI_GetCurrentThreadType
,
4163 Context_CTI_GetCurrentLogicalThreadId
,
4164 Context_CTI_SetCurrentLogicalThreadId
4167 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4169 Context
*This
= impl_from_IContextCallback(iface
);
4170 return Context_QueryInterface(This
, riid
, ppv
);
4173 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4175 Context
*This
= impl_from_IContextCallback(iface
);
4176 return Context_AddRef(This
);
4179 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4181 Context
*This
= impl_from_IContextCallback(iface
);
4182 return Context_Release(This
);
4185 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4186 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4188 Context
*This
= impl_from_IContextCallback(iface
);
4190 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4194 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4196 Context_CC_QueryInterface
,
4199 Context_CC_ContextCallback
4202 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4204 Context
*This
= impl_from_IObjContext(iface
);
4205 return Context_QueryInterface(This
, riid
, ppv
);
4208 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4210 Context
*This
= impl_from_IObjContext(iface
);
4211 return Context_AddRef(This
);
4214 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4216 Context
*This
= impl_from_IObjContext(iface
);
4217 return Context_Release(This
);
4220 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4222 Context
*This
= impl_from_IObjContext(iface
);
4224 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4228 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4230 Context
*This
= impl_from_IObjContext(iface
);
4232 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4236 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4238 Context
*This
= impl_from_IObjContext(iface
);
4240 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4244 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4246 Context
*This
= impl_from_IObjContext(iface
);
4248 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4252 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4254 Context
*This
= impl_from_IObjContext(iface
);
4255 FIXME("(%p/%p)\n", This
, iface
);
4258 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4260 Context
*This
= impl_from_IObjContext(iface
);
4261 FIXME("(%p/%p)\n", This
, iface
);
4264 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4266 Context
*This
= impl_from_IObjContext(iface
);
4267 FIXME("(%p/%p)\n", This
, iface
);
4270 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4272 Context
*This
= impl_from_IObjContext(iface
);
4273 FIXME("(%p/%p)\n", This
, iface
);
4276 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4278 Context
*This
= impl_from_IObjContext(iface
);
4279 FIXME("(%p/%p)\n", This
, iface
);
4282 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4284 Context
*This
= impl_from_IObjContext(iface
);
4285 FIXME("(%p/%p)\n", This
, iface
);
4288 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4290 Context
*This
= impl_from_IObjContext(iface
);
4291 FIXME("(%p/%p)\n", This
, iface
);
4294 static const IObjContextVtbl Context_Object_Vtbl
=
4296 Context_OC_QueryInterface
,
4299 Context_OC_SetProperty
,
4300 Context_OC_RemoveProperty
,
4301 Context_OC_GetProperty
,
4302 Context_OC_EnumContextProps
,
4303 Context_OC_Reserved1
,
4304 Context_OC_Reserved2
,
4305 Context_OC_Reserved3
,
4306 Context_OC_Reserved4
,
4307 Context_OC_Reserved5
,
4308 Context_OC_Reserved6
,
4309 Context_OC_Reserved7
4312 /***********************************************************************
4313 * CoGetObjectContext [OLE32.@]
4315 * Retrieves an object associated with the current context (i.e. apartment).
4318 * riid [I] ID of the interface of the object to retrieve.
4319 * ppv [O] Address where object will be stored on return.
4323 * Failure: HRESULT code.
4325 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4327 APARTMENT
*apt
= COM_CurrentApt();
4331 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4336 if (!(apt
= apartment_find_multi_threaded()))
4338 ERR("apartment not initialised\n");
4339 return CO_E_NOTINITIALIZED
;
4341 apartment_release(apt
);
4344 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4346 return E_OUTOFMEMORY
;
4348 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4349 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4350 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4352 if (apt
->multi_threaded
)
4353 context
->apttype
= APTTYPE_MTA
;
4355 context
->apttype
= APTTYPE_MAINSTA
;
4357 context
->apttype
= APTTYPE_STA
;
4359 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4360 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4366 /***********************************************************************
4367 * CoGetContextToken [OLE32.@]
4369 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4371 struct oletls
*info
= COM_CurrentInfo();
4373 TRACE("(%p)\n", token
);
4376 return E_OUTOFMEMORY
;
4381 if (!(apt
= apartment_find_multi_threaded()))
4383 ERR("apartment not initialised\n");
4384 return CO_E_NOTINITIALIZED
;
4386 apartment_release(apt
);
4392 if (!info
->context_token
)
4397 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4398 if (FAILED(hr
)) return hr
;
4399 info
->context_token
= ctx
;
4402 *token
= (ULONG_PTR
)info
->context_token
;
4403 TRACE("apt->context_token=%p\n", info
->context_token
);
4408 /***********************************************************************
4409 * CoGetDefaultContext [OLE32.@]
4411 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4413 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4414 return E_NOINTERFACE
;
4417 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4419 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4423 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4424 if (SUCCEEDED(hres
))
4426 WCHAR dllpath
[MAX_PATH
+1];
4428 if (COM_RegReadPath(hkey
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4430 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4431 if (!strcmpiW(dllpath
, wszOle32
))
4434 return HandlerCF_Create(rclsid
, riid
, ppv
);
4438 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4442 return CLASS_E_CLASSNOTAVAILABLE
;
4445 /***********************************************************************
4448 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID fImpLoad
)
4450 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, fImpLoad
);
4453 case DLL_PROCESS_ATTACH
:
4454 hProxyDll
= hinstDLL
;
4455 COMPOBJ_InitProcess();
4458 case DLL_PROCESS_DETACH
:
4459 COMPOBJ_UninitProcess();
4460 RPC_UnregisterAllChannelHooks();
4461 COMPOBJ_DllList_Free();
4462 DeleteCriticalSection(&csRegisteredClassList
);
4463 DeleteCriticalSection(&csApartment
);
4466 case DLL_THREAD_DETACH
:
4473 /***********************************************************************
4474 * DllRegisterServer (OLE32.@)
4476 HRESULT WINAPI
DllRegisterServer(void)
4478 return OLE32_DllRegisterServer();
4481 /***********************************************************************
4482 * DllUnregisterServer (OLE32.@)
4484 HRESULT WINAPI
DllUnregisterServer(void)
4486 return OLE32_DllUnregisterServer();