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
57 #define USE_COM_CONTEXT_DEF
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 is a marshallable object exposing registered local servers.
102 * IServiceProvider is used only because it happens meet requirements
103 * and already has proxy/stub code. If more functionality is needed,
104 * a custom interface may be used instead.
108 IServiceProvider IServiceProvider_iface
;
111 IStream
*marshal_stream
;
115 * This lock count counts the number of times CoInitialize is called. It is
116 * decreased every time CoUninitialize is called. When it hits 0, the COM
117 * libraries are freed
119 static LONG s_COMLockCount
= 0;
120 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
121 static LONG s_COMServerProcessReferences
= 0;
124 * This linked list contains the list of registered class objects. These
125 * are mostly used to register the factories for out-of-proc servers of OLE
128 * TODO: Make this data structure aware of inter-process communication. This
129 * means that parts of this will be exported to rpcss.
131 typedef struct tagRegisteredClass
134 CLSID classIdentifier
;
136 LPUNKNOWN classObject
;
140 void *RpcRegistration
;
143 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
145 static CRITICAL_SECTION csRegisteredClassList
;
146 static CRITICAL_SECTION_DEBUG class_cs_debug
=
148 0, 0, &csRegisteredClassList
,
149 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
150 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
152 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
154 /* wrapper for NtCreateKey that creates the key recursively if necessary */
155 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
157 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
159 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
161 HANDLE subkey
, root
= attr
->RootDirectory
;
162 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
163 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
166 while (i
< len
&& buffer
[i
] != '\\') i
++;
167 if (i
== len
) return status
;
169 attrs
= attr
->Attributes
;
170 attr
->ObjectName
= &str
;
174 str
.Buffer
= buffer
+ pos
;
175 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
176 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
177 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
178 if (status
) return status
;
179 attr
->RootDirectory
= subkey
;
180 while (i
< len
&& buffer
[i
] == '\\') i
++;
182 while (i
< len
&& buffer
[i
] != '\\') i
++;
184 str
.Buffer
= buffer
+ pos
;
185 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
186 attr
->Attributes
= attrs
;
187 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
188 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
193 static const WCHAR classes_rootW
[] =
194 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
196 static HKEY classes_root_hkey
;
198 /* create the special HKEY_CLASSES_ROOT key */
199 static HKEY
create_classes_root_hkey(void)
202 OBJECT_ATTRIBUTES attr
;
205 attr
.Length
= sizeof(attr
);
206 attr
.RootDirectory
= 0;
207 attr
.ObjectName
= &name
;
209 attr
.SecurityDescriptor
= NULL
;
210 attr
.SecurityQualityOfService
= NULL
;
211 RtlInitUnicodeString( &name
, classes_rootW
);
212 if (create_key( &hkey
, MAXIMUM_ALLOWED
, &attr
)) return 0;
213 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
215 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
218 NtClose( hkey
); /* somebody beat us to it */
222 /* map the hkey from special root to normal key if necessary */
223 static inline HKEY
get_classes_root_hkey( HKEY hkey
)
227 if (hkey
== HKEY_CLASSES_ROOT
&& !(ret
= classes_root_hkey
))
228 ret
= create_classes_root_hkey();
233 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
235 OBJECT_ATTRIBUTES attr
;
236 UNICODE_STRING nameW
;
238 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
240 attr
.Length
= sizeof(attr
);
241 attr
.RootDirectory
= hkey
;
242 attr
.ObjectName
= &nameW
;
244 attr
.SecurityDescriptor
= NULL
;
245 attr
.SecurityQualityOfService
= NULL
;
246 RtlInitUnicodeString( &nameW
, name
);
248 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
251 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
253 OBJECT_ATTRIBUTES attr
;
254 UNICODE_STRING nameW
;
256 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
258 attr
.Length
= sizeof(attr
);
259 attr
.RootDirectory
= hkey
;
260 attr
.ObjectName
= &nameW
;
262 attr
.SecurityDescriptor
= NULL
;
263 attr
.SecurityQualityOfService
= NULL
;
264 RtlInitUnicodeString( &nameW
, name
);
266 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
269 /*****************************************************************************
270 * This section contains OpenDllList definitions
272 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
273 * other functions that do LoadLibrary _without_ giving back a HMODULE.
274 * Without this list these handles would never be freed.
276 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
277 * next unload-call but not before 600 sec.
280 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
281 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
283 typedef struct tagOpenDll
288 DllGetClassObjectFunc DllGetClassObject
;
289 DllCanUnloadNowFunc DllCanUnloadNow
;
293 static struct list openDllList
= LIST_INIT(openDllList
);
295 static CRITICAL_SECTION csOpenDllList
;
296 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
298 0, 0, &csOpenDllList
,
299 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
300 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
302 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
304 struct apartment_loaded_dll
312 static const WCHAR wszAptWinClass
[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
313 '0','x','#','#','#','#','#','#','#','#',' ',0};
315 /*****************************************************************************
316 * This section contains OpenDllList implementation
319 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
323 EnterCriticalSection(&csOpenDllList
);
324 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
326 if (!strcmpiW(library_name
, ptr
->library_name
) &&
327 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
333 LeaveCriticalSection(&csOpenDllList
);
337 /* caller must ensure that library_name is not already in the open dll list */
338 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
344 DllCanUnloadNowFunc DllCanUnloadNow
;
345 DllGetClassObjectFunc DllGetClassObject
;
349 *ret
= COMPOBJ_DllList_Get(library_name
);
350 if (*ret
) return S_OK
;
352 /* do this outside the csOpenDllList to avoid creating a lock dependency on
354 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
357 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
358 /* failure: DLL could not be loaded */
359 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
362 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
363 /* Note: failing to find DllCanUnloadNow is not a failure */
364 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
365 if (!DllGetClassObject
)
367 /* failure: the dll did not export DllGetClassObject */
368 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
369 FreeLibrary(hLibrary
);
370 return CO_E_DLLNOTFOUND
;
373 EnterCriticalSection( &csOpenDllList
);
375 *ret
= COMPOBJ_DllList_Get(library_name
);
378 /* another caller to this function already added the dll while we
379 * weren't in the critical section */
380 FreeLibrary(hLibrary
);
384 len
= strlenW(library_name
);
385 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
387 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
388 if (entry
&& entry
->library_name
)
390 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
391 entry
->library
= hLibrary
;
393 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
394 entry
->DllGetClassObject
= DllGetClassObject
;
395 list_add_tail(&openDllList
, &entry
->entry
);
400 HeapFree(GetProcessHeap(), 0, entry
);
402 FreeLibrary(hLibrary
);
406 LeaveCriticalSection( &csOpenDllList
);
411 /* pass FALSE for free_entry to release a reference without destroying the
412 * entry if it reaches zero or TRUE otherwise */
413 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
415 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
417 EnterCriticalSection(&csOpenDllList
);
418 list_remove(&entry
->entry
);
419 LeaveCriticalSection(&csOpenDllList
);
421 TRACE("freeing %p\n", entry
->library
);
422 FreeLibrary(entry
->library
);
424 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
425 HeapFree(GetProcessHeap(), 0, entry
);
429 /* frees memory associated with active dll list */
430 static void COMPOBJ_DllList_Free(void)
432 OpenDll
*entry
, *cursor2
;
433 EnterCriticalSection(&csOpenDllList
);
434 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
436 list_remove(&entry
->entry
);
438 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
439 HeapFree(GetProcessHeap(), 0, entry
);
441 LeaveCriticalSection(&csOpenDllList
);
442 DeleteCriticalSection(&csOpenDllList
);
445 /******************************************************************************
449 static DWORD
apartment_addref(struct apartment
*apt
)
451 DWORD refs
= InterlockedIncrement(&apt
->refs
);
452 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
456 /* allocates memory and fills in the necessary fields for a new apartment
457 * object. must be called inside apartment cs */
458 static APARTMENT
*apartment_construct(DWORD model
)
462 TRACE("creating new apartment, model=%d\n", model
);
464 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
465 apt
->tid
= GetCurrentThreadId();
467 list_init(&apt
->proxies
);
468 list_init(&apt
->stubmgrs
);
469 list_init(&apt
->psclsids
);
470 list_init(&apt
->loaded_dlls
);
473 apt
->remunk_exported
= FALSE
;
475 InitializeCriticalSection(&apt
->cs
);
476 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
478 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
480 if (apt
->multi_threaded
)
482 /* FIXME: should be randomly generated by in an RPC call to rpcss */
483 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
487 /* FIXME: should be randomly generated by in an RPC call to rpcss */
488 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
491 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
493 list_add_head(&apts
, &apt
->entry
);
498 /* gets and existing apartment if one exists or otherwise creates an apartment
499 * structure which stores OLE apartment-local information and stores a pointer
500 * to it in the thread-local storage */
501 static APARTMENT
*apartment_get_or_create(DWORD model
)
503 APARTMENT
*apt
= COM_CurrentApt();
507 if (model
& COINIT_APARTMENTTHREADED
)
509 EnterCriticalSection(&csApartment
);
511 apt
= apartment_construct(model
);
516 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
519 LeaveCriticalSection(&csApartment
);
522 apartment_createwindowifneeded(apt
);
526 EnterCriticalSection(&csApartment
);
528 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
529 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
533 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
534 apartment_addref(MTA
);
537 MTA
= apartment_construct(model
);
541 LeaveCriticalSection(&csApartment
);
543 COM_CurrentInfo()->apt
= apt
;
549 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
551 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
554 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
556 list_remove(&curClass
->entry
);
558 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
559 RPC_StopLocalServer(curClass
->RpcRegistration
);
561 IUnknown_Release(curClass
->classObject
);
562 HeapFree(GetProcessHeap(), 0, curClass
);
565 static void COM_RevokeAllClasses(const struct apartment
*apt
)
567 RegisteredClass
*curClass
, *cursor
;
569 EnterCriticalSection( &csRegisteredClassList
);
571 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
573 if (curClass
->apartment_id
== apt
->oxid
)
574 COM_RevokeRegisteredClassObject(curClass
);
577 LeaveCriticalSection( &csRegisteredClassList
);
580 /******************************************************************************
581 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
584 typedef struct ManualResetEvent
{
585 ISynchronize ISynchronize_iface
;
586 ISynchronizeHandle ISynchronizeHandle_iface
;
591 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
593 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
596 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
598 MREImpl
*This
= impl_from_ISynchronize(iface
);
600 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
602 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
603 *ppv
= &This
->ISynchronize_iface
;
604 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
605 *ppv
= &This
->ISynchronizeHandle_iface
;
607 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
609 return E_NOINTERFACE
;
612 IUnknown_AddRef((IUnknown
*)*ppv
);
616 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
618 MREImpl
*This
= impl_from_ISynchronize(iface
);
619 LONG ref
= InterlockedIncrement(&This
->ref
);
620 TRACE("%p - ref %d\n", This
, ref
);
625 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
627 MREImpl
*This
= impl_from_ISynchronize(iface
);
628 LONG ref
= InterlockedDecrement(&This
->ref
);
629 TRACE("%p - ref %d\n", This
, ref
);
633 CloseHandle(This
->event
);
634 HeapFree(GetProcessHeap(), 0, This
);
640 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
642 MREImpl
*This
= impl_from_ISynchronize(iface
);
644 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
645 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
648 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
650 MREImpl
*This
= impl_from_ISynchronize(iface
);
652 SetEvent(This
->event
);
656 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
658 MREImpl
*This
= impl_from_ISynchronize(iface
);
660 ResetEvent(This
->event
);
664 static ISynchronizeVtbl vt_ISynchronize
= {
665 ISynchronize_fnQueryInterface
,
666 ISynchronize_fnAddRef
,
667 ISynchronize_fnRelease
,
669 ISynchronize_fnSignal
,
673 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
675 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
678 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
680 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
681 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
684 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
686 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
687 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
690 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
692 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
693 return ISynchronize_Release(&This
->ISynchronize_iface
);
696 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
698 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
704 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
705 SynchronizeHandle_QueryInterface
,
706 SynchronizeHandle_AddRef
,
707 SynchronizeHandle_Release
,
708 SynchronizeHandle_GetHandle
711 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
713 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
717 FIXME("Aggregation not implemented.\n");
720 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
721 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
722 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
724 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
725 ISynchronize_Release(&This
->ISynchronize_iface
);
729 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
731 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
734 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
736 LocalServer
*This
= impl_from_IServiceProvider(iface
);
738 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
740 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
741 *ppv
= &This
->IServiceProvider_iface
;
744 return E_NOINTERFACE
;
747 IUnknown_AddRef((IUnknown
*)*ppv
);
751 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
753 LocalServer
*This
= impl_from_IServiceProvider(iface
);
754 LONG ref
= InterlockedIncrement(&This
->ref
);
756 TRACE("(%p) ref=%d\n", This
, ref
);
761 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
763 LocalServer
*This
= impl_from_IServiceProvider(iface
);
764 LONG ref
= InterlockedDecrement(&This
->ref
);
766 TRACE("(%p) ref=%d\n", This
, ref
);
770 HeapFree(GetProcessHeap(), 0, This
);
776 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
778 LocalServer
*This
= impl_from_IServiceProvider(iface
);
779 APARTMENT
*apt
= COM_CurrentApt();
780 RegisteredClass
*iter
;
781 HRESULT hres
= E_FAIL
;
783 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
788 EnterCriticalSection(&csRegisteredClassList
);
790 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
791 if(iter
->apartment_id
== apt
->oxid
792 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
793 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
794 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
799 LeaveCriticalSection( &csRegisteredClassList
);
804 static const IServiceProviderVtbl LocalServerVtbl
= {
805 LocalServer_QueryInterface
,
808 LocalServer_QueryService
811 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
815 EnterCriticalSection(&apt
->cs
);
817 if(!apt
->local_server
) {
820 obj
= heap_alloc(sizeof(*obj
));
822 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
826 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
827 if(SUCCEEDED(hres
)) {
828 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
829 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
831 IStream_Release(obj
->marshal_stream
);
835 apt
->local_server
= obj
;
839 hres
= E_OUTOFMEMORY
;
844 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
846 LeaveCriticalSection(&apt
->cs
);
849 ERR("Failed: %08x\n", hres
);
853 /***********************************************************************
854 * CoRevokeClassObject [OLE32.@]
856 * Removes a class object from the class registry.
859 * dwRegister [I] Cookie returned from CoRegisterClassObject().
863 * Failure: HRESULT code.
866 * Must be called from the same apartment that called CoRegisterClassObject(),
867 * otherwise it will fail with RPC_E_WRONG_THREAD.
870 * CoRegisterClassObject
872 HRESULT WINAPI
CoRevokeClassObject(
875 HRESULT hr
= E_INVALIDARG
;
876 RegisteredClass
*curClass
;
879 TRACE("(%08x)\n",dwRegister
);
881 apt
= COM_CurrentApt();
884 ERR("COM was not initialized\n");
885 return CO_E_NOTINITIALIZED
;
888 EnterCriticalSection( &csRegisteredClassList
);
890 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
893 * Check if we have a match on the cookie.
895 if (curClass
->dwCookie
== dwRegister
)
897 if (curClass
->apartment_id
== apt
->oxid
)
899 COM_RevokeRegisteredClassObject(curClass
);
904 ERR("called from wrong apartment, should be called from %s\n",
905 wine_dbgstr_longlong(curClass
->apartment_id
));
906 hr
= RPC_E_WRONG_THREAD
;
912 LeaveCriticalSection( &csRegisteredClassList
);
917 /* frees unused libraries loaded by apartment_getclassobject by calling the
918 * DLL's DllCanUnloadNow entry point */
919 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
921 struct apartment_loaded_dll
*entry
, *next
;
922 EnterCriticalSection(&apt
->cs
);
923 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
925 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
927 DWORD real_delay
= delay
;
929 if (real_delay
== INFINITE
)
931 /* DLLs that return multi-threaded objects aren't unloaded
932 * straight away to cope for programs that have races between
933 * last object destruction and threads in the DLLs that haven't
934 * finished, despite DllCanUnloadNow returning S_OK */
935 if (entry
->multi_threaded
)
936 real_delay
= 10 * 60 * 1000; /* 10 minutes */
941 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
943 list_remove(&entry
->entry
);
944 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
945 HeapFree(GetProcessHeap(), 0, entry
);
949 entry
->unload_time
= GetTickCount() + real_delay
;
950 if (!entry
->unload_time
) entry
->unload_time
= 1;
953 else if (entry
->unload_time
)
954 entry
->unload_time
= 0;
956 LeaveCriticalSection(&apt
->cs
);
959 DWORD
apartment_release(struct apartment
*apt
)
963 EnterCriticalSection(&csApartment
);
965 ret
= InterlockedDecrement(&apt
->refs
);
966 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
967 /* destruction stuff that needs to happen under csApartment CS */
970 if (apt
== MTA
) MTA
= NULL
;
971 else if (apt
== MainApartment
) MainApartment
= NULL
;
972 list_remove(&apt
->entry
);
975 LeaveCriticalSection(&csApartment
);
979 struct list
*cursor
, *cursor2
;
981 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
983 if(apt
->local_server
) {
984 LocalServer
*local_server
= apt
->local_server
;
987 memset(&zero
, 0, sizeof(zero
));
988 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
989 CoReleaseMarshalData(local_server
->marshal_stream
);
990 IStream_Release(local_server
->marshal_stream
);
991 local_server
->marshal_stream
= NULL
;
993 apt
->local_server
= NULL
;
994 local_server
->apt
= NULL
;
995 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
998 /* Release the references to the registered class objects */
999 COM_RevokeAllClasses(apt
);
1001 /* no locking is needed for this apartment, because no other thread
1002 * can access it at this point */
1004 apartment_disconnectproxies(apt
);
1006 if (apt
->win
) DestroyWindow(apt
->win
);
1007 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1009 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1011 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1012 /* release the implicit reference given by the fact that the
1013 * stub has external references (it must do since it is in the
1014 * stub manager list in the apartment and all non-apartment users
1015 * must have a ref on the apartment and so it cannot be destroyed).
1017 stub_manager_int_release(stubmgr
);
1020 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1022 struct registered_psclsid
*registered_psclsid
=
1023 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1025 list_remove(®istered_psclsid
->entry
);
1026 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1029 /* if this assert fires, then another thread took a reference to a
1030 * stub manager without taking a reference to the containing
1031 * apartment, which it must do. */
1032 assert(list_empty(&apt
->stubmgrs
));
1034 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1036 /* free as many unused libraries as possible... */
1037 apartment_freeunusedlibraries(apt
, 0);
1039 /* ... and free the memory for the apartment loaded dll entry and
1040 * release the dll list reference without freeing the library for the
1042 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1044 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1045 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1046 list_remove(cursor
);
1047 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1050 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1051 DeleteCriticalSection(&apt
->cs
);
1053 HeapFree(GetProcessHeap(), 0, apt
);
1059 /* The given OXID must be local to this process:
1061 * The ref parameter is here mostly to ensure people remember that
1062 * they get one, you should normally take a ref for thread safety.
1064 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1066 APARTMENT
*result
= NULL
;
1067 struct list
*cursor
;
1069 EnterCriticalSection(&csApartment
);
1070 LIST_FOR_EACH( cursor
, &apts
)
1072 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1073 if (apt
->oxid
== oxid
)
1076 if (ref
) apartment_addref(result
);
1080 LeaveCriticalSection(&csApartment
);
1085 /* gets the apartment which has a given creator thread ID. The caller must
1086 * release the reference from the apartment as soon as the apartment pointer
1087 * is no longer required. */
1088 APARTMENT
*apartment_findfromtid(DWORD tid
)
1090 APARTMENT
*result
= NULL
;
1091 struct list
*cursor
;
1093 EnterCriticalSection(&csApartment
);
1094 LIST_FOR_EACH( cursor
, &apts
)
1096 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1097 if (apt
->tid
== tid
)
1100 apartment_addref(result
);
1104 LeaveCriticalSection(&csApartment
);
1109 /* gets the main apartment if it exists. The caller must
1110 * release the reference from the apartment as soon as the apartment pointer
1111 * is no longer required. */
1112 static APARTMENT
*apartment_findmain(void)
1116 EnterCriticalSection(&csApartment
);
1118 result
= MainApartment
;
1119 if (result
) apartment_addref(result
);
1121 LeaveCriticalSection(&csApartment
);
1126 /* gets the multi-threaded apartment if it exists. The caller must
1127 * release the reference from the apartment as soon as the apartment pointer
1128 * is no longer required. */
1129 static APARTMENT
*apartment_find_multi_threaded(void)
1131 APARTMENT
*result
= NULL
;
1132 struct list
*cursor
;
1134 EnterCriticalSection(&csApartment
);
1136 LIST_FOR_EACH( cursor
, &apts
)
1138 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1139 if (apt
->multi_threaded
)
1142 apartment_addref(result
);
1147 LeaveCriticalSection(&csApartment
);
1151 /* gets the specified class object by loading the appropriate DLL, if
1152 * necessary and calls the DllGetClassObject function for the DLL */
1153 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1154 BOOL apartment_threaded
,
1155 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1157 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1160 struct apartment_loaded_dll
*apartment_loaded_dll
;
1162 if (!strcmpiW(dllpath
, wszOle32
))
1164 /* we don't need to control the lifetime of this dll, so use the local
1165 * implementation of DllGetClassObject directly */
1166 TRACE("calling ole32!DllGetClassObject\n");
1167 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1170 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1175 EnterCriticalSection(&apt
->cs
);
1177 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1178 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1180 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1187 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1188 if (!apartment_loaded_dll
)
1192 apartment_loaded_dll
->unload_time
= 0;
1193 apartment_loaded_dll
->multi_threaded
= FALSE
;
1194 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1196 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1200 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1201 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1205 LeaveCriticalSection(&apt
->cs
);
1209 /* one component being multi-threaded overrides any number of
1210 * apartment-threaded components */
1211 if (!apartment_threaded
)
1212 apartment_loaded_dll
->multi_threaded
= TRUE
;
1214 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1215 /* OK: get the ClassObject */
1216 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1219 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1225 /***********************************************************************
1226 * COM_RegReadPath [internal]
1228 * Reads a registry value and expands it when necessary
1230 static DWORD
COM_RegReadPath(HKEY hkeyroot
, WCHAR
* dst
, DWORD dstlen
)
1234 WCHAR src
[MAX_PATH
];
1235 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1237 if( (ret
= RegQueryValueExW(hkeyroot
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1238 if (keytype
== REG_EXPAND_SZ
) {
1239 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1241 const WCHAR
*quote_start
;
1242 quote_start
= strchrW(src
, '\"');
1244 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1246 memmove(src
, quote_start
+ 1,
1247 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1248 src
[quote_end
- quote_start
- 1] = '\0';
1251 lstrcpynW(dst
, src
, dstlen
);
1257 struct host_object_params
1260 CLSID clsid
; /* clsid of object to marshal */
1261 IID iid
; /* interface to marshal */
1262 HANDLE event
; /* event signalling when ready for multi-threaded case */
1263 HRESULT hr
; /* result for multi-threaded case */
1264 IStream
*stream
; /* stream that the object will be marshaled into */
1265 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1268 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1269 const struct host_object_params
*params
)
1273 static const LARGE_INTEGER llZero
;
1274 WCHAR dllpath
[MAX_PATH
+1];
1276 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1278 if (COM_RegReadPath(params
->hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1280 /* failure: CLSID is not found in registry */
1281 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1282 return REGDB_E_CLASSNOTREG
;
1285 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1286 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1290 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1292 IUnknown_Release(object
);
1293 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1298 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1303 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1306 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1308 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1312 struct host_thread_params
1314 COINIT threading_model
;
1316 HWND apartment_hwnd
;
1319 /* thread for hosting an object to allow an object to appear to be created in
1320 * an apartment with an incompatible threading model */
1321 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1323 struct host_thread_params
*params
= p
;
1326 struct apartment
*apt
;
1330 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1331 if (FAILED(hr
)) return hr
;
1333 apt
= COM_CurrentApt();
1334 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1336 apartment_createwindowifneeded(apt
);
1337 params
->apartment_hwnd
= apartment_getwindow(apt
);
1340 params
->apartment_hwnd
= NULL
;
1342 /* force the message queue to be created before signaling parent thread */
1343 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1345 SetEvent(params
->ready_event
);
1346 params
= NULL
; /* can't touch params after here as it may be invalid */
1348 while (GetMessageW(&msg
, NULL
, 0, 0))
1350 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1352 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1353 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1354 SetEvent(obj_params
->event
);
1358 TranslateMessage(&msg
);
1359 DispatchMessageW(&msg
);
1370 /* finds or creates a host apartment, creates the object inside it and returns
1371 * a proxy to it so that the object can be used in the apartment of the
1372 * caller of this function */
1373 static HRESULT
apartment_hostobject_in_hostapt(
1374 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1375 HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1377 struct host_object_params params
;
1378 HWND apartment_hwnd
= NULL
;
1379 DWORD apartment_tid
= 0;
1382 if (!multi_threaded
&& main_apartment
)
1384 APARTMENT
*host_apt
= apartment_findmain();
1387 apartment_hwnd
= apartment_getwindow(host_apt
);
1388 apartment_release(host_apt
);
1392 if (!apartment_hwnd
)
1394 EnterCriticalSection(&apt
->cs
);
1396 if (!apt
->host_apt_tid
)
1398 struct host_thread_params thread_params
;
1402 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1403 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1404 thread_params
.apartment_hwnd
= NULL
;
1405 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1408 CloseHandle(handles
[0]);
1409 LeaveCriticalSection(&apt
->cs
);
1410 return E_OUTOFMEMORY
;
1412 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1413 CloseHandle(handles
[0]);
1414 CloseHandle(handles
[1]);
1415 if (wait_value
== WAIT_OBJECT_0
)
1416 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1419 LeaveCriticalSection(&apt
->cs
);
1420 return E_OUTOFMEMORY
;
1424 if (multi_threaded
|| !main_apartment
)
1426 apartment_hwnd
= apt
->host_apt_hwnd
;
1427 apartment_tid
= apt
->host_apt_tid
;
1430 LeaveCriticalSection(&apt
->cs
);
1433 /* another thread may have become the main apartment in the time it took
1434 * us to create the thread for the host apartment */
1435 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1437 APARTMENT
*host_apt
= apartment_findmain();
1440 apartment_hwnd
= apartment_getwindow(host_apt
);
1441 apartment_release(host_apt
);
1445 params
.hkeydll
= hkeydll
;
1446 params
.clsid
= *rclsid
;
1448 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1451 params
.apartment_threaded
= !multi_threaded
;
1455 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1456 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1460 WaitForSingleObject(params
.event
, INFINITE
);
1463 CloseHandle(params
.event
);
1467 if (!apartment_hwnd
)
1469 ERR("host apartment didn't create window\n");
1473 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1476 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1477 IStream_Release(params
.stream
);
1481 /* create a window for the apartment or return the current one if one has
1482 * already been created */
1483 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1485 if (apt
->multi_threaded
)
1490 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
1492 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1495 ERR("CreateWindow failed with error %d\n", GetLastError());
1496 return HRESULT_FROM_WIN32(GetLastError());
1498 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1499 /* someone beat us to it */
1500 DestroyWindow(hwnd
);
1506 /* retrieves the window for the main- or apartment-threaded apartment */
1507 HWND
apartment_getwindow(const struct apartment
*apt
)
1509 assert(!apt
->multi_threaded
);
1513 void apartment_joinmta(void)
1515 apartment_addref(MTA
);
1516 COM_CurrentInfo()->apt
= MTA
;
1519 static void COMPOBJ_InitProcess( void )
1523 /* Dispatching to the correct thread in an apartment is done through
1524 * window messages rather than RPC transports. When an interface is
1525 * marshalled into another apartment in the same process, a window of the
1526 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1527 * application) is responsible for pumping the message loop in that thread.
1528 * The WM_USER messages which point to the RPCs are then dispatched to
1529 * apartment_wndproc by the user's code from the apartment in which the
1530 * interface was unmarshalled.
1532 memset(&wclass
, 0, sizeof(wclass
));
1533 wclass
.lpfnWndProc
= apartment_wndproc
;
1534 wclass
.hInstance
= hProxyDll
;
1535 wclass
.lpszClassName
= wszAptWinClass
;
1536 RegisterClassW(&wclass
);
1539 static void COMPOBJ_UninitProcess( void )
1541 UnregisterClassW(wszAptWinClass
, hProxyDll
);
1544 static void COM_TlsDestroy(void)
1546 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1549 if (info
->apt
) apartment_release(info
->apt
);
1550 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1551 if (info
->state
) IUnknown_Release(info
->state
);
1552 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1553 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1554 HeapFree(GetProcessHeap(), 0, info
);
1555 NtCurrentTeb()->ReservedForOle
= NULL
;
1559 /******************************************************************************
1560 * CoBuildVersion [OLE32.@]
1562 * Gets the build version of the DLL.
1567 * Current build version, hiword is majornumber, loword is minornumber
1569 DWORD WINAPI
CoBuildVersion(void)
1571 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1572 return (rmm
<<16)+rup
;
1575 /******************************************************************************
1576 * CoRegisterInitializeSpy [OLE32.@]
1578 * Add a Spy that watches CoInitializeEx calls
1581 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1582 * cookie [II] cookie receiver
1585 * Success: S_OK if not already initialized, S_FALSE otherwise.
1586 * Failure: HRESULT code.
1591 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1593 struct oletls
*info
= COM_CurrentInfo();
1596 TRACE("(%p, %p)\n", spy
, cookie
);
1598 if (!spy
|| !cookie
|| !info
)
1601 WARN("Could not allocate tls\n");
1602 return E_INVALIDARG
;
1607 FIXME("Already registered?\n");
1608 return E_UNEXPECTED
;
1611 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1614 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1620 /******************************************************************************
1621 * CoRevokeInitializeSpy [OLE32.@]
1623 * Remove a spy that previously watched CoInitializeEx calls
1626 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1629 * Success: S_OK if a spy is removed
1630 * Failure: E_INVALIDARG
1635 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1637 struct oletls
*info
= COM_CurrentInfo();
1638 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1640 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1641 return E_INVALIDARG
;
1643 IInitializeSpy_Release(info
->spy
);
1649 /******************************************************************************
1650 * CoInitialize [OLE32.@]
1652 * Initializes the COM libraries by calling CoInitializeEx with
1653 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1656 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1659 * Success: S_OK if not already initialized, S_FALSE otherwise.
1660 * Failure: HRESULT code.
1665 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1668 * Just delegate to the newer method.
1670 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1673 /******************************************************************************
1674 * CoInitializeEx [OLE32.@]
1676 * Initializes the COM libraries.
1679 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1680 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1683 * S_OK if successful,
1684 * S_FALSE if this function was called already.
1685 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1690 * The behavior used to set the IMalloc used for memory management is
1692 * The dwCoInit parameter must specify one of the following apartment
1694 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1695 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1696 * The parameter may also specify zero or more of the following flags:
1697 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1698 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1703 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1705 struct oletls
*info
= COM_CurrentInfo();
1709 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1711 if (lpReserved
!=NULL
)
1713 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1717 * Check the lock count. If this is the first time going through the initialize
1718 * process, we have to initialize the libraries.
1720 * And crank-up that lock count.
1722 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1725 * Initialize the various COM libraries and data structures.
1727 TRACE("() - Initializing the COM libraries\n");
1729 /* we may need to defer this until after apartment initialisation */
1730 RunningObjectTableImpl_Initialize();
1734 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1736 if (!(apt
= info
->apt
))
1738 apt
= apartment_get_or_create(dwCoInit
);
1739 if (!apt
) return E_OUTOFMEMORY
;
1741 else if (!apartment_is_model(apt
, dwCoInit
))
1743 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1744 code then we are probably using the wrong threading model to implement that API. */
1745 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1746 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1747 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1748 return RPC_E_CHANGED_MODE
;
1756 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1761 /***********************************************************************
1762 * CoUninitialize [OLE32.@]
1764 * This method will decrement the refcount on the current apartment, freeing
1765 * the resources associated with it if it is the last thread in the apartment.
1766 * If the last apartment is freed, the function will additionally release
1767 * any COM resources associated with the process.
1777 void WINAPI
CoUninitialize(void)
1779 struct oletls
* info
= COM_CurrentInfo();
1784 /* will only happen on OOM */
1788 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1793 ERR("Mismatched CoUninitialize\n");
1796 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1802 apartment_release(info
->apt
);
1807 * Decrease the reference count.
1808 * If we are back to 0 locks on the COM library, make sure we free
1809 * all the associated data structures.
1811 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1814 TRACE("() - Releasing the COM libraries\n");
1816 RunningObjectTableImpl_UnInitialize();
1818 else if (lCOMRefCnt
<1) {
1819 ERR( "CoUninitialize() - not CoInitialized.\n" );
1820 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1823 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1826 /******************************************************************************
1827 * CoDisconnectObject [OLE32.@]
1829 * Disconnects all connections to this object from remote processes. Dispatches
1830 * pending RPCs while blocking new RPCs from occurring, and then calls
1831 * IMarshal::DisconnectObject on the given object.
1833 * Typically called when the object server is forced to shut down, for instance by
1837 * lpUnk [I] The object whose stub should be disconnected.
1838 * reserved [I] Reserved. Should be set to 0.
1842 * Failure: HRESULT code.
1845 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1847 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
1853 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
1855 if (!lpUnk
) return E_INVALIDARG
;
1857 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
1860 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
1861 IMarshal_Release(marshal
);
1865 apt
= COM_CurrentApt();
1867 return CO_E_NOTINITIALIZED
;
1869 apartment_disconnectobject(apt
, lpUnk
);
1871 /* Note: native is pretty broken here because it just silently
1872 * fails, without returning an appropriate error code if the object was
1873 * not found, making apps think that the object was disconnected, when
1874 * it actually wasn't */
1879 /******************************************************************************
1880 * CoCreateGuid [OLE32.@]
1882 * Simply forwards to UuidCreate in RPCRT4.
1885 * pguid [O] Points to the GUID to initialize.
1889 * Failure: HRESULT code.
1894 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
1896 DWORD status
= UuidCreate(pguid
);
1897 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
1898 return HRESULT_FROM_WIN32( status
);
1901 static inline BOOL
is_valid_hex(WCHAR c
)
1903 if (!(((c
>= '0') && (c
<= '9')) ||
1904 ((c
>= 'a') && (c
<= 'f')) ||
1905 ((c
>= 'A') && (c
<= 'F'))))
1910 /******************************************************************************
1911 * CLSIDFromString [OLE32.@]
1912 * IIDFromString [OLE32.@]
1914 * Converts a unique identifier from its string representation into
1918 * idstr [I] The string representation of the GUID.
1919 * id [O] GUID converted from the string.
1923 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1928 static HRESULT
__CLSIDFromString(LPCWSTR s
, LPCLSID id
)
1933 if (!s
|| s
[0]!='{') {
1934 memset( id
, 0, sizeof (CLSID
) );
1936 return CO_E_CLASSSTRING
;
1939 TRACE("%s -> %p\n", debugstr_w(s
), id
);
1941 /* quick lookup table */
1942 memset(table
, 0, 256);
1944 for (i
= 0; i
< 10; i
++) {
1947 for (i
= 0; i
< 6; i
++) {
1948 table
['A' + i
] = i
+10;
1949 table
['a' + i
] = i
+10;
1952 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1955 for (i
= 1; i
< 9; i
++) {
1956 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1957 id
->Data1
= (id
->Data1
<< 4) | table
[s
[i
]];
1959 if (s
[9]!='-') return CO_E_CLASSSTRING
;
1962 for (i
= 10; i
< 14; i
++) {
1963 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1964 id
->Data2
= (id
->Data2
<< 4) | table
[s
[i
]];
1966 if (s
[14]!='-') return CO_E_CLASSSTRING
;
1969 for (i
= 15; i
< 19; i
++) {
1970 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1971 id
->Data3
= (id
->Data3
<< 4) | table
[s
[i
]];
1973 if (s
[19]!='-') return CO_E_CLASSSTRING
;
1975 for (i
= 20; i
< 37; i
+=2) {
1977 if (s
[i
]!='-') return CO_E_CLASSSTRING
;
1980 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return CO_E_CLASSSTRING
;
1981 id
->Data4
[(i
-20)/2] = table
[s
[i
]] << 4 | table
[s
[i
+1]];
1984 if (s
[37] == '}' && s
[38] == '\0')
1987 return CO_E_CLASSSTRING
;
1990 /*****************************************************************************/
1992 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
1997 return E_INVALIDARG
;
1999 ret
= __CLSIDFromString(idstr
, id
);
2000 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
2002 ret
= CLSIDFromProgID(idstr
, &tmp_id
);
2010 /******************************************************************************
2011 * StringFromCLSID [OLE32.@]
2012 * StringFromIID [OLE32.@]
2014 * Converts a GUID into the respective string representation.
2015 * The target string is allocated using the OLE IMalloc.
2018 * id [I] the GUID to be converted.
2019 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2026 * StringFromGUID2, CLSIDFromString
2028 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2033 if ((ret
= CoGetMalloc(0,&mllc
))) return ret
;
2034 if (!(*idstr
= IMalloc_Alloc( mllc
, CHARS_IN_GUID
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
2035 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2039 /******************************************************************************
2040 * StringFromGUID2 [OLE32.@]
2042 * Modified version of StringFromCLSID that allows you to specify max
2046 * id [I] GUID to convert to string.
2047 * str [O] Buffer where the result will be stored.
2048 * cmax [I] Size of the buffer in characters.
2051 * Success: The length of the resulting string in characters.
2054 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2056 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2057 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2058 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2059 '%','0','2','X','%','0','2','X','}',0 };
2060 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2061 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2062 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2063 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2064 return CHARS_IN_GUID
;
2067 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2068 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2070 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2071 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2075 strcpyW(path
, wszCLSIDSlash
);
2076 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2077 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2078 if (res
== ERROR_FILE_NOT_FOUND
)
2079 return REGDB_E_CLASSNOTREG
;
2080 else if (res
!= ERROR_SUCCESS
)
2081 return REGDB_E_READREGDB
;
2089 res
= open_classes_key(key
, keyname
, access
, subkey
);
2091 if (res
== ERROR_FILE_NOT_FOUND
)
2092 return REGDB_E_KEYMISSING
;
2093 else if (res
!= ERROR_SUCCESS
)
2094 return REGDB_E_READREGDB
;
2099 /* open HKCR\\AppId\\{string form of appid clsid} key */
2100 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2102 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2103 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2105 WCHAR buf
[CHARS_IN_GUID
];
2106 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2112 /* read the AppID value under the class's key */
2113 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2118 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2120 if (res
== ERROR_FILE_NOT_FOUND
)
2121 return REGDB_E_KEYMISSING
;
2122 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2123 return REGDB_E_READREGDB
;
2125 strcpyW(keyname
, szAppIdKey
);
2126 strcatW(keyname
, buf
);
2127 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2128 if (res
== ERROR_FILE_NOT_FOUND
)
2129 return REGDB_E_KEYMISSING
;
2130 else if (res
!= ERROR_SUCCESS
)
2131 return REGDB_E_READREGDB
;
2136 /******************************************************************************
2137 * ProgIDFromCLSID [OLE32.@]
2139 * Converts a class id into the respective program ID.
2142 * clsid [I] Class ID, as found in registry.
2143 * ppszProgID [O] Associated ProgID.
2148 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2150 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2152 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2159 ERR("ppszProgId isn't optional\n");
2160 return E_INVALIDARG
;
2164 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2168 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2169 ret
= REGDB_E_CLASSNOTREG
;
2173 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2176 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2177 ret
= REGDB_E_CLASSNOTREG
;
2178 CoTaskMemFree(*ppszProgID
);
2183 ret
= E_OUTOFMEMORY
;
2190 /******************************************************************************
2191 * CLSIDFromProgID [OLE32.@]
2193 * Converts a program id into the respective GUID.
2196 * progid [I] Unicode program ID, as found in registry.
2197 * clsid [O] Associated CLSID.
2201 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2203 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2205 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2206 WCHAR buf2
[CHARS_IN_GUID
];
2207 LONG buf2len
= sizeof(buf2
);
2211 if (!progid
|| !clsid
)
2213 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
2214 return E_INVALIDARG
;
2217 /* initialise clsid in case of failure */
2218 memset(clsid
, 0, sizeof(*clsid
));
2220 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2221 strcpyW( buf
, progid
);
2222 strcatW( buf
, clsidW
);
2223 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2225 HeapFree(GetProcessHeap(),0,buf
);
2226 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2227 return CO_E_CLASSSTRING
;
2229 HeapFree(GetProcessHeap(),0,buf
);
2231 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2234 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2235 return CO_E_CLASSSTRING
;
2238 return __CLSIDFromString(buf2
,clsid
);
2241 /******************************************************************************
2242 * CLSIDFromProgIDEx [OLE32.@]
2244 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2246 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2248 return CLSIDFromProgID(progid
, clsid
);
2251 /*****************************************************************************
2252 * CoGetPSClsid [OLE32.@]
2254 * Retrieves the CLSID of the proxy/stub factory that implements
2255 * IPSFactoryBuffer for the specified interface.
2258 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2259 * pclsid [O] Where to store returned proxy/stub CLSID.
2264 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2268 * The standard marshaller activates the object with the CLSID
2269 * returned and uses the CreateProxy and CreateStub methods on its
2270 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2273 * CoGetPSClsid determines this CLSID by searching the
2274 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2275 * in the registry and any interface id registered by
2276 * CoRegisterPSClsid within the current process.
2280 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2281 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2282 * considered a bug in native unless an application depends on this (unlikely).
2285 * CoRegisterPSClsid.
2287 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2289 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2290 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2291 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2292 WCHAR value
[CHARS_IN_GUID
];
2295 APARTMENT
*apt
= COM_CurrentApt();
2296 struct registered_psclsid
*registered_psclsid
;
2298 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2302 ERR("apartment not initialised\n");
2303 return CO_E_NOTINITIALIZED
;
2308 ERR("pclsid isn't optional\n");
2309 return E_INVALIDARG
;
2312 EnterCriticalSection(&apt
->cs
);
2314 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2315 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2317 *pclsid
= registered_psclsid
->clsid
;
2318 LeaveCriticalSection(&apt
->cs
);
2322 LeaveCriticalSection(&apt
->cs
);
2324 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2325 strcpyW(path
, wszInterface
);
2326 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2327 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2329 /* Open the key.. */
2330 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2332 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2333 return REGDB_E_IIDNOTREG
;
2336 /* ... Once we have the key, query the registry to get the
2337 value of CLSID as a string, and convert it into a
2338 proper CLSID structure to be passed back to the app */
2339 len
= sizeof(value
);
2340 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2343 return REGDB_E_IIDNOTREG
;
2347 /* We have the CLSID we want back from the registry as a string, so
2348 let's convert it into a CLSID structure */
2349 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2350 return REGDB_E_IIDNOTREG
;
2352 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2356 /*****************************************************************************
2357 * CoRegisterPSClsid [OLE32.@]
2359 * Register a proxy/stub CLSID for the given interface in the current process
2363 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2364 * rclsid [I] CLSID of the proxy/stub.
2368 * Failure: E_OUTOFMEMORY
2372 * This function does not add anything to the registry and the effects are
2373 * limited to the lifetime of the current process.
2378 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2380 APARTMENT
*apt
= COM_CurrentApt();
2381 struct registered_psclsid
*registered_psclsid
;
2383 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2387 ERR("apartment not initialised\n");
2388 return CO_E_NOTINITIALIZED
;
2391 EnterCriticalSection(&apt
->cs
);
2393 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2394 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2396 registered_psclsid
->clsid
= *rclsid
;
2397 LeaveCriticalSection(&apt
->cs
);
2401 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2402 if (!registered_psclsid
)
2404 LeaveCriticalSection(&apt
->cs
);
2405 return E_OUTOFMEMORY
;
2408 registered_psclsid
->iid
= *riid
;
2409 registered_psclsid
->clsid
= *rclsid
;
2410 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2412 LeaveCriticalSection(&apt
->cs
);
2419 * COM_GetRegisteredClassObject
2421 * This internal method is used to scan the registered class list to
2422 * find a class object.
2425 * rclsid Class ID of the class to find.
2426 * dwClsContext Class context to match.
2427 * ppv [out] returns a pointer to the class object. Complying
2428 * to normal COM usage, this method will increase the
2429 * reference count on this object.
2431 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2432 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2434 HRESULT hr
= S_FALSE
;
2435 RegisteredClass
*curClass
;
2437 EnterCriticalSection( &csRegisteredClassList
);
2439 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2442 * Check if we have a match on the class ID and context.
2444 if ((apt
->oxid
== curClass
->apartment_id
) &&
2445 (dwClsContext
& curClass
->runContext
) &&
2446 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2449 * We have a match, return the pointer to the class object.
2451 *ppUnk
= curClass
->classObject
;
2453 IUnknown_AddRef(curClass
->classObject
);
2460 LeaveCriticalSection( &csRegisteredClassList
);
2465 /******************************************************************************
2466 * CoRegisterClassObject [OLE32.@]
2468 * Registers the class object for a given class ID. Servers housed in EXE
2469 * files use this method instead of exporting DllGetClassObject to allow
2470 * other code to connect to their objects.
2473 * rclsid [I] CLSID of the object to register.
2474 * pUnk [I] IUnknown of the object.
2475 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2476 * flags [I] REGCLS flags indicating how connections are made.
2477 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2481 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2482 * CO_E_OBJISREG if the object is already registered. We should not return this.
2485 * CoRevokeClassObject, CoGetClassObject
2488 * In-process objects are only registered for the current apartment.
2489 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2490 * in other apartments.
2493 * MSDN claims that multiple interface registrations are legal, but we
2494 * can't do that with our current implementation.
2496 HRESULT WINAPI
CoRegisterClassObject(
2501 LPDWORD lpdwRegister
)
2503 static LONG next_cookie
;
2504 RegisteredClass
* newClass
;
2505 LPUNKNOWN foundObject
;
2509 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2510 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2512 if ( (lpdwRegister
==0) || (pUnk
==0) )
2513 return E_INVALIDARG
;
2515 apt
= COM_CurrentApt();
2518 ERR("COM was not initialized\n");
2519 return CO_E_NOTINITIALIZED
;
2524 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2525 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2526 if (flags
& REGCLS_MULTIPLEUSE
)
2527 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2530 * First, check if the class is already registered.
2531 * If it is, this should cause an error.
2533 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2535 if (flags
& REGCLS_MULTIPLEUSE
) {
2536 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2537 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2538 IUnknown_Release(foundObject
);
2541 IUnknown_Release(foundObject
);
2542 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2543 return CO_E_OBJISREG
;
2546 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2547 if ( newClass
== NULL
)
2548 return E_OUTOFMEMORY
;
2550 newClass
->classIdentifier
= *rclsid
;
2551 newClass
->apartment_id
= apt
->oxid
;
2552 newClass
->runContext
= dwClsContext
;
2553 newClass
->connectFlags
= flags
;
2554 newClass
->RpcRegistration
= NULL
;
2556 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2557 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2560 * Since we're making a copy of the object pointer, we have to increase its
2563 newClass
->classObject
= pUnk
;
2564 IUnknown_AddRef(newClass
->classObject
);
2566 EnterCriticalSection( &csRegisteredClassList
);
2567 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2568 LeaveCriticalSection( &csRegisteredClassList
);
2570 *lpdwRegister
= newClass
->dwCookie
;
2572 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2573 IStream
*marshal_stream
;
2575 hr
= get_local_server_stream(apt
, &marshal_stream
);
2579 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2581 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2582 &newClass
->RpcRegistration
);
2583 IStream_Release(marshal_stream
);
2588 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
2590 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2593 DWORD dwLength
= len
* sizeof(WCHAR
);
2595 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
2596 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2600 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
,
2601 REFCLSID rclsid
, REFIID riid
,
2602 BOOL hostifnecessary
, void **ppv
)
2604 WCHAR dllpath
[MAX_PATH
+1];
2605 BOOL apartment_threaded
;
2607 if (hostifnecessary
)
2609 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2610 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2611 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2612 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2614 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
2616 if (!strcmpiW(threading_model
, wszApartment
))
2618 apartment_threaded
= TRUE
;
2619 if (apt
->multi_threaded
)
2620 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2623 else if (!strcmpiW(threading_model
, wszFree
))
2625 apartment_threaded
= FALSE
;
2626 if (!apt
->multi_threaded
)
2627 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2629 /* everything except "Apartment", "Free" and "Both" */
2630 else if (strcmpiW(threading_model
, wszBoth
))
2632 apartment_threaded
= TRUE
;
2633 /* everything else is main-threaded */
2634 if (threading_model
[0])
2635 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2636 debugstr_w(threading_model
), debugstr_guid(rclsid
));
2638 if (apt
->multi_threaded
|| !apt
->main
)
2639 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, hkeydll
, rclsid
, riid
, ppv
);
2642 apartment_threaded
= FALSE
;
2645 apartment_threaded
= !apt
->multi_threaded
;
2647 if (COM_RegReadPath(hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2649 /* failure: CLSID is not found in registry */
2650 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2651 return REGDB_E_CLASSNOTREG
;
2654 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2658 /***********************************************************************
2659 * CoGetClassObject [OLE32.@]
2661 * Creates an object of the specified class.
2664 * rclsid [I] Class ID to create an instance of.
2665 * dwClsContext [I] Flags to restrict the location of the created instance.
2666 * pServerInfo [I] Optional. Details for connecting to a remote server.
2667 * iid [I] The ID of the interface of the instance to return.
2668 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2672 * Failure: HRESULT code.
2675 * The dwClsContext parameter can be one or more of the following:
2676 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2677 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2678 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2679 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2682 * CoCreateInstance()
2684 HRESULT WINAPI
CoGetClassObject(
2685 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2686 REFIID iid
, LPVOID
*ppv
)
2688 LPUNKNOWN regClassObject
;
2689 HRESULT hres
= E_UNEXPECTED
;
2691 BOOL release_apt
= FALSE
;
2693 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2696 return E_INVALIDARG
;
2700 if (!(apt
= COM_CurrentApt()))
2702 if (!(apt
= apartment_find_multi_threaded()))
2704 ERR("apartment not initialised\n");
2705 return CO_E_NOTINITIALIZED
;
2711 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2712 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2716 * First, try and see if we can't match the class ID with one of the
2717 * registered classes.
2719 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2722 /* Get the required interface from the retrieved pointer. */
2723 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2726 * Since QI got another reference on the pointer, we want to release the
2727 * one we already have. If QI was unsuccessful, this will release the object. This
2728 * is good since we are not returning it in the "out" parameter.
2730 IUnknown_Release(regClassObject
);
2731 if (release_apt
) apartment_release(apt
);
2735 /* First try in-process server */
2736 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2738 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2741 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2743 if (release_apt
) apartment_release(apt
);
2744 return FTMarshalCF_Create(iid
, ppv
);
2747 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2750 if (hres
== REGDB_E_CLASSNOTREG
)
2751 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2752 else if (hres
== REGDB_E_KEYMISSING
)
2754 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2755 hres
= REGDB_E_CLASSNOTREG
;
2759 if (SUCCEEDED(hres
))
2761 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2762 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2766 /* return if we got a class, otherwise fall through to one of the
2768 if (SUCCEEDED(hres
))
2770 if (release_apt
) apartment_release(apt
);
2775 /* Next try in-process handler */
2776 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2778 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2781 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2784 if (hres
== REGDB_E_CLASSNOTREG
)
2785 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2786 else if (hres
== REGDB_E_KEYMISSING
)
2788 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2789 hres
= REGDB_E_CLASSNOTREG
;
2793 if (SUCCEEDED(hres
))
2795 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2796 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2800 /* return if we got a class, otherwise fall through to one of the
2802 if (SUCCEEDED(hres
))
2804 if (release_apt
) apartment_release(apt
);
2808 if (release_apt
) apartment_release(apt
);
2810 /* Next try out of process */
2811 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2813 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2814 if (SUCCEEDED(hres
))
2818 /* Finally try remote: this requires networked DCOM (a lot of work) */
2819 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2821 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2822 hres
= REGDB_E_CLASSNOTREG
;
2826 ERR("no class object %s could be created for context 0x%x\n",
2827 debugstr_guid(rclsid
), dwClsContext
);
2831 /***********************************************************************
2832 * CoResumeClassObjects (OLE32.@)
2834 * Resumes all class objects registered with REGCLS_SUSPENDED.
2838 * Failure: HRESULT code.
2840 HRESULT WINAPI
CoResumeClassObjects(void)
2846 /***********************************************************************
2847 * CoCreateInstance [OLE32.@]
2849 * Creates an instance of the specified class.
2852 * rclsid [I] Class ID to create an instance of.
2853 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2854 * dwClsContext [I] Flags to restrict the location of the created instance.
2855 * iid [I] The ID of the interface of the instance to return.
2856 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2860 * Failure: HRESULT code.
2863 * The dwClsContext parameter can be one or more of the following:
2864 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2865 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2866 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2867 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2869 * Aggregation is the concept of deferring the IUnknown of an object to another
2870 * object. This allows a separate object to behave as though it was part of
2871 * the object and to allow this the pUnkOuter parameter can be set. Note that
2872 * not all objects support having an outer of unknown.
2875 * CoGetClassObject()
2877 HRESULT WINAPI
CoCreateInstance(
2879 LPUNKNOWN pUnkOuter
,
2885 LPCLASSFACTORY lpclf
= 0;
2888 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2889 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2896 if (!(apt
= COM_CurrentApt()))
2898 if (!(apt
= apartment_find_multi_threaded()))
2900 ERR("apartment not initialised\n");
2901 return CO_E_NOTINITIALIZED
;
2903 apartment_release(apt
);
2907 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2909 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
2911 IGlobalInterfaceTable
*git
= get_std_git();
2912 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
2913 if (hres
!= S_OK
) return hres
;
2915 TRACE("Retrieved GIT (%p)\n", *ppv
);
2919 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
2920 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
2923 * Get a class factory to construct the object we want.
2925 hres
= CoGetClassObject(rclsid
,
2935 * Create the object and don't forget to release the factory
2937 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2938 IClassFactory_Release(lpclf
);
2941 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
2942 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
2944 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2946 debugstr_guid(rclsid
),hres
);
2952 /***********************************************************************
2953 * CoCreateInstanceEx [OLE32.@]
2955 HRESULT WINAPI
CoCreateInstanceEx(
2957 LPUNKNOWN pUnkOuter
,
2959 COSERVERINFO
* pServerInfo
,
2963 IUnknown
* pUnk
= NULL
;
2966 ULONG successCount
= 0;
2971 if ( (cmq
==0) || (pResults
==NULL
))
2972 return E_INVALIDARG
;
2974 if (pServerInfo
!=NULL
)
2975 FIXME("() non-NULL pServerInfo not supported!\n");
2978 * Initialize all the "out" parameters.
2980 for (index
= 0; index
< cmq
; index
++)
2982 pResults
[index
].pItf
= NULL
;
2983 pResults
[index
].hr
= E_NOINTERFACE
;
2987 * Get the object and get its IUnknown pointer.
2989 hr
= CoCreateInstance(rclsid
,
2999 * Then, query for all the interfaces requested.
3001 for (index
= 0; index
< cmq
; index
++)
3003 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
3004 pResults
[index
].pIID
,
3005 (VOID
**)&(pResults
[index
].pItf
));
3007 if (pResults
[index
].hr
== S_OK
)
3012 * Release our temporary unknown pointer.
3014 IUnknown_Release(pUnk
);
3016 if (successCount
== 0)
3017 return E_NOINTERFACE
;
3019 if (successCount
!=cmq
)
3020 return CO_S_NOTALLINTERFACES
;
3025 /***********************************************************************
3026 * CoLoadLibrary (OLE32.@)
3031 * lpszLibName [I] Path to library.
3032 * bAutoFree [I] Whether the library should automatically be freed.
3035 * Success: Handle to loaded library.
3039 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3041 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3043 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3045 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3048 /***********************************************************************
3049 * CoFreeLibrary [OLE32.@]
3051 * Unloads a library from memory.
3054 * hLibrary [I] Handle to library to unload.
3060 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3062 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3064 FreeLibrary(hLibrary
);
3068 /***********************************************************************
3069 * CoFreeAllLibraries [OLE32.@]
3071 * Function for backwards compatibility only. Does nothing.
3077 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3079 void WINAPI
CoFreeAllLibraries(void)
3084 /***********************************************************************
3085 * CoFreeUnusedLibrariesEx [OLE32.@]
3087 * Frees any previously unused libraries whose delay has expired and marks
3088 * currently unused libraries for unloading. Unused are identified as those that
3089 * return S_OK from their DllCanUnloadNow function.
3092 * dwUnloadDelay [I] Unload delay in milliseconds.
3093 * dwReserved [I] Reserved. Set to 0.
3099 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3101 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3103 struct apartment
*apt
= COM_CurrentApt();
3106 ERR("apartment not initialised\n");
3110 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3113 /***********************************************************************
3114 * CoFreeUnusedLibraries [OLE32.@]
3116 * Frees any unused libraries. Unused are identified as those that return
3117 * S_OK from their DllCanUnloadNow function.
3123 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3125 void WINAPI
CoFreeUnusedLibraries(void)
3127 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3130 /***********************************************************************
3131 * CoFileTimeNow [OLE32.@]
3133 * Retrieves the current time in FILETIME format.
3136 * lpFileTime [O] The current time.
3141 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3143 GetSystemTimeAsFileTime( lpFileTime
);
3147 /******************************************************************************
3148 * CoLockObjectExternal [OLE32.@]
3150 * Increments or decrements the external reference count of a stub object.
3153 * pUnk [I] Stub object.
3154 * fLock [I] If TRUE then increments the external ref-count,
3155 * otherwise decrements.
3156 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3157 * calling CoDisconnectObject.
3161 * Failure: HRESULT code.
3164 * If fLock is TRUE and an object is passed in that doesn't have a stub
3165 * manager then a new stub manager is created for the object.
3167 HRESULT WINAPI
CoLockObjectExternal(
3170 BOOL fLastUnlockReleases
)
3172 struct stub_manager
*stubmgr
;
3173 struct apartment
*apt
;
3175 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3176 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3178 apt
= COM_CurrentApt();
3179 if (!apt
) return CO_E_NOTINITIALIZED
;
3181 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3186 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3188 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3190 stub_manager_int_release(stubmgr
);
3196 stubmgr
= new_stub_manager(apt
, pUnk
);
3200 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3201 stub_manager_int_release(stubmgr
);
3208 WARN("stub object not found %p\n", pUnk
);
3209 /* Note: native is pretty broken here because it just silently
3210 * fails, without returning an appropriate error code, making apps
3211 * think that the object was disconnected, when it actually wasn't */
3216 /***********************************************************************
3217 * CoInitializeWOW (OLE32.@)
3219 * WOW equivalent of CoInitialize?
3228 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3230 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3234 /***********************************************************************
3235 * CoGetState [OLE32.@]
3237 * Retrieves the thread state object previously stored by CoSetState().
3240 * ppv [I] Address where pointer to object will be stored.
3244 * Failure: E_OUTOFMEMORY.
3247 * Crashes on all invalid ppv addresses, including NULL.
3248 * If the function returns a non-NULL object then the caller must release its
3249 * reference on the object when the object is no longer required.
3254 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3256 struct oletls
*info
= COM_CurrentInfo();
3257 if (!info
) return E_OUTOFMEMORY
;
3263 IUnknown_AddRef(info
->state
);
3265 TRACE("apt->state=%p\n", info
->state
);
3271 /***********************************************************************
3272 * CoSetState [OLE32.@]
3274 * Sets the thread state object.
3277 * pv [I] Pointer to state object to be stored.
3280 * The system keeps a reference on the object while the object stored.
3284 * Failure: E_OUTOFMEMORY.
3286 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3288 struct oletls
*info
= COM_CurrentInfo();
3289 if (!info
) return E_OUTOFMEMORY
;
3291 if (pv
) IUnknown_AddRef(pv
);
3295 TRACE("-- release %p now\n", info
->state
);
3296 IUnknown_Release(info
->state
);
3305 /******************************************************************************
3306 * CoTreatAsClass [OLE32.@]
3308 * Sets the TreatAs value of a class.
3311 * clsidOld [I] Class to set TreatAs value on.
3312 * clsidNew [I] The class the clsidOld should be treated as.
3316 * Failure: HRESULT code.
3321 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3323 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3324 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3326 WCHAR szClsidNew
[CHARS_IN_GUID
];
3328 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3329 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3332 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3335 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3337 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3338 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3340 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3342 res
= REGDB_E_WRITEREGDB
;
3348 RegDeleteKeyW(hkey
, wszTreatAs
);
3352 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3353 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3355 res
= REGDB_E_WRITEREGDB
;
3360 if (hkey
) RegCloseKey(hkey
);
3364 /******************************************************************************
3365 * CoGetTreatAsClass [OLE32.@]
3367 * Gets the TreatAs value of a class.
3370 * clsidOld [I] Class to get the TreatAs value of.
3371 * clsidNew [I] The class the clsidOld should be treated as.
3375 * Failure: HRESULT code.
3380 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3382 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3384 WCHAR szClsidNew
[CHARS_IN_GUID
];
3386 LONG len
= sizeof(szClsidNew
);
3388 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3389 *clsidNew
= *clsidOld
; /* copy over old value */
3391 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3397 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3402 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3404 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3406 if (hkey
) RegCloseKey(hkey
);
3410 /******************************************************************************
3411 * CoGetCurrentProcess [OLE32.@]
3413 * Gets the current process ID.
3416 * The current process ID.
3419 * Is DWORD really the correct return type for this function?
3421 DWORD WINAPI
CoGetCurrentProcess(void)
3423 return GetCurrentProcessId();
3426 /******************************************************************************
3427 * CoRegisterMessageFilter [OLE32.@]
3429 * Registers a message filter.
3432 * lpMessageFilter [I] Pointer to interface.
3433 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3437 * Failure: HRESULT code.
3440 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3441 * lpMessageFilter removes the message filter.
3443 * If lplpMessageFilter is not NULL the previous message filter will be
3444 * returned in the memory pointer to this parameter and the caller is
3445 * responsible for releasing the object.
3447 * The current thread be in an apartment otherwise the function will crash.
3449 HRESULT WINAPI
CoRegisterMessageFilter(
3450 LPMESSAGEFILTER lpMessageFilter
,
3451 LPMESSAGEFILTER
*lplpMessageFilter
)
3453 struct apartment
*apt
;
3454 IMessageFilter
*lpOldMessageFilter
;
3456 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3458 apt
= COM_CurrentApt();
3460 /* can't set a message filter in a multi-threaded apartment */
3461 if (!apt
|| apt
->multi_threaded
)
3463 WARN("can't set message filter in MTA or uninitialized apt\n");
3464 return CO_E_NOT_SUPPORTED
;
3467 if (lpMessageFilter
)
3468 IMessageFilter_AddRef(lpMessageFilter
);
3470 EnterCriticalSection(&apt
->cs
);
3472 lpOldMessageFilter
= apt
->filter
;
3473 apt
->filter
= lpMessageFilter
;
3475 LeaveCriticalSection(&apt
->cs
);
3477 if (lplpMessageFilter
)
3478 *lplpMessageFilter
= lpOldMessageFilter
;
3479 else if (lpOldMessageFilter
)
3480 IMessageFilter_Release(lpOldMessageFilter
);
3485 /***********************************************************************
3486 * CoIsOle1Class [OLE32.@]
3488 * Determines whether the specified class an OLE v1 class.
3491 * clsid [I] Class to test.
3494 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3496 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3498 FIXME("%s\n", debugstr_guid(clsid
));
3502 /***********************************************************************
3503 * IsEqualGUID [OLE32.@]
3505 * Compares two Unique Identifiers.
3508 * rguid1 [I] The first GUID to compare.
3509 * rguid2 [I] The other GUID to compare.
3515 BOOL WINAPI
IsEqualGUID(
3519 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3522 /***********************************************************************
3523 * CoInitializeSecurity [OLE32.@]
3525 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3526 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3527 void* pReserved1
, DWORD dwAuthnLevel
,
3528 DWORD dwImpLevel
, void* pReserved2
,
3529 DWORD dwCapabilities
, void* pReserved3
)
3531 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3532 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3533 dwCapabilities
, pReserved3
);
3537 /***********************************************************************
3538 * CoSuspendClassObjects [OLE32.@]
3540 * Suspends all registered class objects to prevent further requests coming in
3541 * for those objects.
3545 * Failure: HRESULT code.
3547 HRESULT WINAPI
CoSuspendClassObjects(void)
3553 /***********************************************************************
3554 * CoAddRefServerProcess [OLE32.@]
3556 * Helper function for incrementing the reference count of a local-server
3560 * New reference count.
3563 * CoReleaseServerProcess().
3565 ULONG WINAPI
CoAddRefServerProcess(void)
3571 EnterCriticalSection(&csRegisteredClassList
);
3572 refs
= ++s_COMServerProcessReferences
;
3573 LeaveCriticalSection(&csRegisteredClassList
);
3575 TRACE("refs before: %d\n", refs
- 1);
3580 /***********************************************************************
3581 * CoReleaseServerProcess [OLE32.@]
3583 * Helper function for decrementing the reference count of a local-server
3587 * New reference count.
3590 * When reference count reaches 0, this function suspends all registered
3591 * classes so no new connections are accepted.
3594 * CoAddRefServerProcess(), CoSuspendClassObjects().
3596 ULONG WINAPI
CoReleaseServerProcess(void)
3602 EnterCriticalSection(&csRegisteredClassList
);
3604 refs
= --s_COMServerProcessReferences
;
3605 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3607 LeaveCriticalSection(&csRegisteredClassList
);
3609 TRACE("refs after: %d\n", refs
);
3614 /***********************************************************************
3615 * CoIsHandlerConnected [OLE32.@]
3617 * Determines whether a proxy is connected to a remote stub.
3620 * pUnk [I] Pointer to object that may or may not be connected.
3623 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3626 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3628 FIXME("%p\n", pUnk
);
3633 /***********************************************************************
3634 * CoAllowSetForegroundWindow [OLE32.@]
3637 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3639 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3643 /***********************************************************************
3644 * CoQueryProxyBlanket [OLE32.@]
3646 * Retrieves the security settings being used by a proxy.
3649 * pProxy [I] Pointer to the proxy object.
3650 * pAuthnSvc [O] The type of authentication service.
3651 * pAuthzSvc [O] The type of authorization service.
3652 * ppServerPrincName [O] Optional. The server prinicple name.
3653 * pAuthnLevel [O] The authentication level.
3654 * pImpLevel [O] The impersonation level.
3655 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3656 * pCapabilities [O] Flags affecting the security behaviour.
3660 * Failure: HRESULT code.
3663 * CoCopyProxy, CoSetProxyBlanket.
3665 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
3666 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
3667 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
3669 IClientSecurity
*pCliSec
;
3672 TRACE("%p\n", pProxy
);
3674 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3677 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
3678 pAuthzSvc
, ppServerPrincName
,
3679 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
3681 IClientSecurity_Release(pCliSec
);
3684 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3688 /***********************************************************************
3689 * CoSetProxyBlanket [OLE32.@]
3691 * Sets the security settings for a proxy.
3694 * pProxy [I] Pointer to the proxy object.
3695 * AuthnSvc [I] The type of authentication service.
3696 * AuthzSvc [I] The type of authorization service.
3697 * pServerPrincName [I] The server prinicple name.
3698 * AuthnLevel [I] The authentication level.
3699 * ImpLevel [I] The impersonation level.
3700 * pAuthInfo [I] Information specific to the authorization/authentication service.
3701 * Capabilities [I] Flags affecting the security behaviour.
3705 * Failure: HRESULT code.
3708 * CoQueryProxyBlanket, CoCopyProxy.
3710 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
3711 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
3712 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
3714 IClientSecurity
*pCliSec
;
3717 TRACE("%p\n", pProxy
);
3719 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3722 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
3723 AuthzSvc
, pServerPrincName
,
3724 AuthnLevel
, ImpLevel
, pAuthInfo
,
3726 IClientSecurity_Release(pCliSec
);
3729 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3733 /***********************************************************************
3734 * CoCopyProxy [OLE32.@]
3739 * pProxy [I] Pointer to the proxy object.
3740 * ppCopy [O] Copy of the proxy.
3744 * Failure: HRESULT code.
3747 * CoQueryProxyBlanket, CoSetProxyBlanket.
3749 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
3751 IClientSecurity
*pCliSec
;
3754 TRACE("%p\n", pProxy
);
3756 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3759 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
3760 IClientSecurity_Release(pCliSec
);
3763 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3768 /***********************************************************************
3769 * CoGetCallContext [OLE32.@]
3771 * Gets the context of the currently executing server call in the current
3775 * riid [I] Context interface to return.
3776 * ppv [O] Pointer to memory that will receive the context on return.
3780 * Failure: HRESULT code.
3782 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3784 struct oletls
*info
= COM_CurrentInfo();
3786 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3789 return E_OUTOFMEMORY
;
3791 if (!info
->call_state
)
3792 return RPC_E_CALL_COMPLETE
;
3794 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3797 /***********************************************************************
3798 * CoSwitchCallContext [OLE32.@]
3800 * Switches the context of the currently executing server call in the current
3804 * pObject [I] Pointer to new context object
3805 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3809 * Failure: HRESULT code.
3811 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3813 struct oletls
*info
= COM_CurrentInfo();
3815 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3818 return E_OUTOFMEMORY
;
3820 *ppOldObject
= info
->call_state
;
3821 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3826 /***********************************************************************
3827 * CoQueryClientBlanket [OLE32.@]
3829 * Retrieves the authentication information about the client of the currently
3830 * executing server call in the current thread.
3833 * pAuthnSvc [O] Optional. The type of authentication service.
3834 * pAuthzSvc [O] Optional. The type of authorization service.
3835 * pServerPrincName [O] Optional. The server prinicple name.
3836 * pAuthnLevel [O] Optional. The authentication level.
3837 * pImpLevel [O] Optional. The impersonation level.
3838 * pPrivs [O] Optional. Information about the privileges of the client.
3839 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3843 * Failure: HRESULT code.
3846 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3848 HRESULT WINAPI
CoQueryClientBlanket(
3851 OLECHAR
**pServerPrincName
,
3854 RPC_AUTHZ_HANDLE
*pPrivs
,
3855 DWORD
*pCapabilities
)
3857 IServerSecurity
*pSrvSec
;
3860 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3861 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3862 pPrivs
, pCapabilities
);
3864 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3867 hr
= IServerSecurity_QueryBlanket(
3868 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3869 pImpLevel
, pPrivs
, pCapabilities
);
3870 IServerSecurity_Release(pSrvSec
);
3876 /***********************************************************************
3877 * CoImpersonateClient [OLE32.@]
3879 * Impersonates the client of the currently executing server call in the
3887 * Failure: HRESULT code.
3890 * If this function fails then the current thread will not be impersonating
3891 * the client and all actions will take place on behalf of the server.
3892 * Therefore, it is important to check the return value from this function.
3895 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3897 HRESULT WINAPI
CoImpersonateClient(void)
3899 IServerSecurity
*pSrvSec
;
3904 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3907 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3908 IServerSecurity_Release(pSrvSec
);
3914 /***********************************************************************
3915 * CoRevertToSelf [OLE32.@]
3917 * Ends the impersonation of the client of the currently executing server
3918 * call in the current thread.
3925 * Failure: HRESULT code.
3928 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3930 HRESULT WINAPI
CoRevertToSelf(void)
3932 IServerSecurity
*pSrvSec
;
3937 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3940 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3941 IServerSecurity_Release(pSrvSec
);
3947 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3949 /* first try to retrieve messages for incoming COM calls to the apartment window */
3950 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
3951 /* next retrieve other messages necessary for the app to remain responsive */
3952 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3953 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3956 /***********************************************************************
3957 * CoWaitForMultipleHandles [OLE32.@]
3959 * Waits for one or more handles to become signaled.
3962 * dwFlags [I] Flags. See notes.
3963 * dwTimeout [I] Timeout in milliseconds.
3964 * cHandles [I] Number of handles pointed to by pHandles.
3965 * pHandles [I] Handles to wait for.
3966 * lpdwindex [O] Index of handle that was signaled.
3970 * Failure: RPC_S_CALLPENDING on timeout.
3974 * The dwFlags parameter can be zero or more of the following:
3975 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3976 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3979 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3981 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3982 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3985 DWORD start_time
= GetTickCount();
3986 APARTMENT
*apt
= COM_CurrentApt();
3987 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3989 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3990 pHandles
, lpdwindex
);
3994 DWORD now
= GetTickCount();
3997 if (now
- start_time
> dwTimeout
)
3999 hr
= RPC_S_CALLPENDING
;
4005 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4006 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4008 TRACE("waiting for rpc completion or window message\n");
4010 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4011 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4012 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4014 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4019 /* call message filter */
4021 if (COM_CurrentApt()->filter
)
4023 PENDINGTYPE pendingtype
=
4024 COM_CurrentInfo()->pending_call_count_server
?
4025 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4026 DWORD be_handled
= IMessageFilter_MessagePending(
4027 COM_CurrentApt()->filter
, 0 /* FIXME */,
4028 now
- start_time
, pendingtype
);
4029 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4032 case PENDINGMSG_CANCELCALL
:
4033 WARN("call canceled\n");
4034 hr
= RPC_E_CALL_CANCELED
;
4036 case PENDINGMSG_WAITNOPROCESS
:
4037 case PENDINGMSG_WAITDEFPROCESS
:
4039 /* FIXME: MSDN is very vague about the difference
4040 * between WAITNOPROCESS and WAITDEFPROCESS - there
4041 * appears to be none, so it is possibly a left-over
4042 * from the 16-bit world. */
4047 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4048 * so after processing 100 messages we go back to checking the wait handles */
4049 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4051 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4052 TranslateMessage(&msg
);
4053 DispatchMessageW(&msg
);
4054 if (msg
.message
== WM_QUIT
)
4056 TRACE("resending WM_QUIT to outer message loop\n");
4057 PostQuitMessage(msg
.wParam
);
4058 /* no longer need to process messages */
4059 message_loop
= FALSE
;
4068 TRACE("waiting for rpc completion\n");
4070 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4071 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4072 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4078 hr
= RPC_S_CALLPENDING
;
4081 hr
= HRESULT_FROM_WIN32( GetLastError() );
4089 TRACE("-- 0x%08x\n", hr
);
4094 /***********************************************************************
4095 * CoGetObject [OLE32.@]
4097 * Gets the object named by converting the name to a moniker and binding to it.
4100 * pszName [I] String representing the object.
4101 * pBindOptions [I] Parameters affecting the binding to the named object.
4102 * riid [I] Interface to bind to on the objecct.
4103 * ppv [O] On output, the interface riid of the object represented
4108 * Failure: HRESULT code.
4111 * MkParseDisplayName.
4113 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4114 REFIID riid
, void **ppv
)
4121 hr
= CreateBindCtx(0, &pbc
);
4125 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4132 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4135 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4136 IMoniker_Release(pmk
);
4140 IBindCtx_Release(pbc
);
4145 /***********************************************************************
4146 * CoRegisterChannelHook [OLE32.@]
4148 * Registers a process-wide hook that is called during ORPC calls.
4151 * guidExtension [I] GUID of the channel hook to register.
4152 * pChannelHook [I] Channel hook object to register.
4156 * Failure: HRESULT code.
4158 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4160 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4162 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4165 typedef struct Context
4167 IComThreadingInfo IComThreadingInfo_iface
;
4168 IContextCallback IContextCallback_iface
;
4169 IObjContext IObjContext_iface
;
4174 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4176 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4179 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4181 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4184 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4186 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4189 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4193 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4194 IsEqualIID(riid
, &IID_IUnknown
))
4196 *ppv
= &iface
->IComThreadingInfo_iface
;
4198 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4200 *ppv
= &iface
->IContextCallback_iface
;
4202 else if (IsEqualIID(riid
, &IID_IObjContext
))
4204 *ppv
= &iface
->IObjContext_iface
;
4209 IUnknown_AddRef((IUnknown
*)*ppv
);
4213 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4214 return E_NOINTERFACE
;
4217 static ULONG
Context_AddRef(Context
*This
)
4219 return InterlockedIncrement(&This
->refs
);
4222 static ULONG
Context_Release(Context
*This
)
4224 ULONG refs
= InterlockedDecrement(&This
->refs
);
4226 HeapFree(GetProcessHeap(), 0, This
);
4230 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4232 Context
*This
= impl_from_IComThreadingInfo(iface
);
4233 return Context_QueryInterface(This
, riid
, ppv
);
4236 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4238 Context
*This
= impl_from_IComThreadingInfo(iface
);
4239 return Context_AddRef(This
);
4242 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4244 Context
*This
= impl_from_IComThreadingInfo(iface
);
4245 return Context_Release(This
);
4248 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4250 Context
*This
= impl_from_IComThreadingInfo(iface
);
4252 TRACE("(%p)\n", apttype
);
4254 *apttype
= This
->apttype
;
4258 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4260 Context
*This
= impl_from_IComThreadingInfo(iface
);
4262 TRACE("(%p)\n", thdtype
);
4264 switch (This
->apttype
)
4267 case APTTYPE_MAINSTA
:
4268 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4271 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4277 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4279 FIXME("(%p): stub\n", logical_thread_id
);
4283 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4285 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4289 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4291 Context_CTI_QueryInterface
,
4293 Context_CTI_Release
,
4294 Context_CTI_GetCurrentApartmentType
,
4295 Context_CTI_GetCurrentThreadType
,
4296 Context_CTI_GetCurrentLogicalThreadId
,
4297 Context_CTI_SetCurrentLogicalThreadId
4300 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4302 Context
*This
= impl_from_IContextCallback(iface
);
4303 return Context_QueryInterface(This
, riid
, ppv
);
4306 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4308 Context
*This
= impl_from_IContextCallback(iface
);
4309 return Context_AddRef(This
);
4312 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4314 Context
*This
= impl_from_IContextCallback(iface
);
4315 return Context_Release(This
);
4318 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4319 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4321 Context
*This
= impl_from_IContextCallback(iface
);
4323 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4327 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4329 Context_CC_QueryInterface
,
4332 Context_CC_ContextCallback
4335 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4337 Context
*This
= impl_from_IObjContext(iface
);
4338 return Context_QueryInterface(This
, riid
, ppv
);
4341 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4343 Context
*This
= impl_from_IObjContext(iface
);
4344 return Context_AddRef(This
);
4347 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4349 Context
*This
= impl_from_IObjContext(iface
);
4350 return Context_Release(This
);
4353 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4355 Context
*This
= impl_from_IObjContext(iface
);
4357 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4361 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4363 Context
*This
= impl_from_IObjContext(iface
);
4365 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4369 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4371 Context
*This
= impl_from_IObjContext(iface
);
4373 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4377 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4379 Context
*This
= impl_from_IObjContext(iface
);
4381 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4385 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4387 Context
*This
= impl_from_IObjContext(iface
);
4388 FIXME("(%p/%p)\n", This
, iface
);
4391 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4393 Context
*This
= impl_from_IObjContext(iface
);
4394 FIXME("(%p/%p)\n", This
, iface
);
4397 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4399 Context
*This
= impl_from_IObjContext(iface
);
4400 FIXME("(%p/%p)\n", This
, iface
);
4403 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4405 Context
*This
= impl_from_IObjContext(iface
);
4406 FIXME("(%p/%p)\n", This
, iface
);
4409 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4411 Context
*This
= impl_from_IObjContext(iface
);
4412 FIXME("(%p/%p)\n", This
, iface
);
4415 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4417 Context
*This
= impl_from_IObjContext(iface
);
4418 FIXME("(%p/%p)\n", This
, iface
);
4421 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4423 Context
*This
= impl_from_IObjContext(iface
);
4424 FIXME("(%p/%p)\n", This
, iface
);
4427 static const IObjContextVtbl Context_Object_Vtbl
=
4429 Context_OC_QueryInterface
,
4432 Context_OC_SetProperty
,
4433 Context_OC_RemoveProperty
,
4434 Context_OC_GetProperty
,
4435 Context_OC_EnumContextProps
,
4436 Context_OC_Reserved1
,
4437 Context_OC_Reserved2
,
4438 Context_OC_Reserved3
,
4439 Context_OC_Reserved4
,
4440 Context_OC_Reserved5
,
4441 Context_OC_Reserved6
,
4442 Context_OC_Reserved7
4445 /***********************************************************************
4446 * CoGetObjectContext [OLE32.@]
4448 * Retrieves an object associated with the current context (i.e. apartment).
4451 * riid [I] ID of the interface of the object to retrieve.
4452 * ppv [O] Address where object will be stored on return.
4456 * Failure: HRESULT code.
4458 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4460 APARTMENT
*apt
= COM_CurrentApt();
4464 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4469 if (!(apt
= apartment_find_multi_threaded()))
4471 ERR("apartment not initialised\n");
4472 return CO_E_NOTINITIALIZED
;
4474 apartment_release(apt
);
4477 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4479 return E_OUTOFMEMORY
;
4481 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4482 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4483 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4485 if (apt
->multi_threaded
)
4486 context
->apttype
= APTTYPE_MTA
;
4488 context
->apttype
= APTTYPE_MAINSTA
;
4490 context
->apttype
= APTTYPE_STA
;
4492 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4493 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4499 /***********************************************************************
4500 * CoGetContextToken [OLE32.@]
4502 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4504 struct oletls
*info
= COM_CurrentInfo();
4506 TRACE("(%p)\n", token
);
4509 return E_OUTOFMEMORY
;
4514 if (!(apt
= apartment_find_multi_threaded()))
4516 ERR("apartment not initialised\n");
4517 return CO_E_NOTINITIALIZED
;
4519 apartment_release(apt
);
4525 if (!info
->context_token
)
4530 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4531 if (FAILED(hr
)) return hr
;
4532 info
->context_token
= ctx
;
4535 *token
= (ULONG_PTR
)info
->context_token
;
4536 TRACE("apt->context_token=%p\n", info
->context_token
);
4541 /***********************************************************************
4542 * CoGetDefaultContext [OLE32.@]
4544 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4546 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4547 return E_NOINTERFACE
;
4550 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4552 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4556 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4557 if (SUCCEEDED(hres
))
4559 WCHAR dllpath
[MAX_PATH
+1];
4561 if (COM_RegReadPath(hkey
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4563 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4564 if (!strcmpiW(dllpath
, wszOle32
))
4567 return HandlerCF_Create(rclsid
, riid
, ppv
);
4571 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4575 return CLASS_E_CLASSNOTAVAILABLE
;
4578 /***********************************************************************
4581 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4583 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4586 case DLL_PROCESS_ATTACH
:
4587 hProxyDll
= hinstDLL
;
4588 COMPOBJ_InitProcess();
4591 case DLL_PROCESS_DETACH
:
4592 if (reserved
) break;
4594 COMPOBJ_UninitProcess();
4595 RPC_UnregisterAllChannelHooks();
4596 COMPOBJ_DllList_Free();
4597 DeleteCriticalSection(&csRegisteredClassList
);
4598 DeleteCriticalSection(&csApartment
);
4601 case DLL_THREAD_DETACH
:
4608 /***********************************************************************
4609 * DllRegisterServer (OLE32.@)
4611 HRESULT WINAPI
DllRegisterServer(void)
4613 return OLE32_DllRegisterServer();
4616 /***********************************************************************
4617 * DllUnregisterServer (OLE32.@)
4619 HRESULT WINAPI
DllUnregisterServer(void)
4621 return OLE32_DllUnregisterServer();