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 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1485 /* Dispatching to the correct thread in an apartment is done through
1486 * window messages rather than RPC transports. When an interface is
1487 * marshalled into another apartment in the same process, a window of the
1488 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1489 * application) is responsible for pumping the message loop in that thread.
1490 * The WM_USER messages which point to the RPCs are then dispatched to
1491 * apartment_wndproc by the user's code from the apartment in which the
1492 * interface was unmarshalled.
1494 memset(&wclass
, 0, sizeof(wclass
));
1495 wclass
.lpfnWndProc
= apartment_wndproc
;
1496 wclass
.hInstance
= hProxyDll
;
1497 wclass
.lpszClassName
= wszAptWinClass
;
1498 RegisterClassW(&wclass
);
1502 /* create a window for the apartment or return the current one if one has
1503 * already been created */
1504 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1506 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1508 if (apt
->multi_threaded
)
1515 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1517 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1518 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1521 ERR("CreateWindow failed with error %d\n", GetLastError());
1522 return HRESULT_FROM_WIN32(GetLastError());
1524 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1525 /* someone beat us to it */
1526 DestroyWindow(hwnd
);
1532 /* retrieves the window for the main- or apartment-threaded apartment */
1533 HWND
apartment_getwindow(const struct apartment
*apt
)
1535 assert(!apt
->multi_threaded
);
1539 void apartment_joinmta(void)
1541 apartment_addref(MTA
);
1542 COM_CurrentInfo()->apt
= MTA
;
1545 static void COM_TlsDestroy(void)
1547 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1550 if (info
->apt
) apartment_release(info
->apt
);
1551 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1552 if (info
->state
) IUnknown_Release(info
->state
);
1553 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1554 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1555 HeapFree(GetProcessHeap(), 0, info
);
1556 NtCurrentTeb()->ReservedForOle
= NULL
;
1560 /******************************************************************************
1561 * CoBuildVersion [OLE32.@]
1563 * Gets the build version of the DLL.
1568 * Current build version, hiword is majornumber, loword is minornumber
1570 DWORD WINAPI
CoBuildVersion(void)
1572 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1573 return (rmm
<<16)+rup
;
1576 /******************************************************************************
1577 * CoRegisterInitializeSpy [OLE32.@]
1579 * Add a Spy that watches CoInitializeEx calls
1582 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1583 * cookie [II] cookie receiver
1586 * Success: S_OK if not already initialized, S_FALSE otherwise.
1587 * Failure: HRESULT code.
1592 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1594 struct oletls
*info
= COM_CurrentInfo();
1597 TRACE("(%p, %p)\n", spy
, cookie
);
1599 if (!spy
|| !cookie
|| !info
)
1602 WARN("Could not allocate tls\n");
1603 return E_INVALIDARG
;
1608 FIXME("Already registered?\n");
1609 return E_UNEXPECTED
;
1612 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1615 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1621 /******************************************************************************
1622 * CoRevokeInitializeSpy [OLE32.@]
1624 * Remove a spy that previously watched CoInitializeEx calls
1627 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1630 * Success: S_OK if a spy is removed
1631 * Failure: E_INVALIDARG
1636 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1638 struct oletls
*info
= COM_CurrentInfo();
1639 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1641 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1642 return E_INVALIDARG
;
1644 IInitializeSpy_Release(info
->spy
);
1650 /******************************************************************************
1651 * CoInitialize [OLE32.@]
1653 * Initializes the COM libraries by calling CoInitializeEx with
1654 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1657 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1660 * Success: S_OK if not already initialized, S_FALSE otherwise.
1661 * Failure: HRESULT code.
1666 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1669 * Just delegate to the newer method.
1671 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1674 /******************************************************************************
1675 * CoInitializeEx [OLE32.@]
1677 * Initializes the COM libraries.
1680 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1681 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1684 * S_OK if successful,
1685 * S_FALSE if this function was called already.
1686 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1691 * The behavior used to set the IMalloc used for memory management is
1693 * The dwCoInit parameter must specify one of the following apartment
1695 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1696 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1697 * The parameter may also specify zero or more of the following flags:
1698 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1699 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1704 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1706 struct oletls
*info
= COM_CurrentInfo();
1710 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1712 if (lpReserved
!=NULL
)
1714 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1718 * Check the lock count. If this is the first time going through the initialize
1719 * process, we have to initialize the libraries.
1721 * And crank-up that lock count.
1723 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1726 * Initialize the various COM libraries and data structures.
1728 TRACE("() - Initializing the COM libraries\n");
1730 /* we may need to defer this until after apartment initialisation */
1731 RunningObjectTableImpl_Initialize();
1735 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1737 if (!(apt
= info
->apt
))
1739 apt
= apartment_get_or_create(dwCoInit
);
1740 if (!apt
) return E_OUTOFMEMORY
;
1742 else if (!apartment_is_model(apt
, dwCoInit
))
1744 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1745 code then we are probably using the wrong threading model to implement that API. */
1746 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1747 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1748 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1749 return RPC_E_CHANGED_MODE
;
1757 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1762 /***********************************************************************
1763 * CoUninitialize [OLE32.@]
1765 * This method will decrement the refcount on the current apartment, freeing
1766 * the resources associated with it if it is the last thread in the apartment.
1767 * If the last apartment is freed, the function will additionally release
1768 * any COM resources associated with the process.
1778 void WINAPI
CoUninitialize(void)
1780 struct oletls
* info
= COM_CurrentInfo();
1785 /* will only happen on OOM */
1789 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1794 ERR("Mismatched CoUninitialize\n");
1797 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1803 apartment_release(info
->apt
);
1808 * Decrease the reference count.
1809 * If we are back to 0 locks on the COM library, make sure we free
1810 * all the associated data structures.
1812 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1815 TRACE("() - Releasing the COM libraries\n");
1817 RunningObjectTableImpl_UnInitialize();
1819 else if (lCOMRefCnt
<1) {
1820 ERR( "CoUninitialize() - not CoInitialized.\n" );
1821 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1824 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1827 /******************************************************************************
1828 * CoDisconnectObject [OLE32.@]
1830 * Disconnects all connections to this object from remote processes. Dispatches
1831 * pending RPCs while blocking new RPCs from occurring, and then calls
1832 * IMarshal::DisconnectObject on the given object.
1834 * Typically called when the object server is forced to shut down, for instance by
1838 * lpUnk [I] The object whose stub should be disconnected.
1839 * reserved [I] Reserved. Should be set to 0.
1843 * Failure: HRESULT code.
1846 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1848 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
1854 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
1856 if (!lpUnk
) return E_INVALIDARG
;
1858 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
1861 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
1862 IMarshal_Release(marshal
);
1866 apt
= COM_CurrentApt();
1868 return CO_E_NOTINITIALIZED
;
1870 apartment_disconnectobject(apt
, lpUnk
);
1872 /* Note: native is pretty broken here because it just silently
1873 * fails, without returning an appropriate error code if the object was
1874 * not found, making apps think that the object was disconnected, when
1875 * it actually wasn't */
1880 /******************************************************************************
1881 * CoCreateGuid [OLE32.@]
1883 * Simply forwards to UuidCreate in RPCRT4.
1886 * pguid [O] Points to the GUID to initialize.
1890 * Failure: HRESULT code.
1895 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
1897 DWORD status
= UuidCreate(pguid
);
1898 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
1899 return HRESULT_FROM_WIN32( status
);
1902 static inline BOOL
is_valid_hex(WCHAR c
)
1904 if (!(((c
>= '0') && (c
<= '9')) ||
1905 ((c
>= 'a') && (c
<= 'f')) ||
1906 ((c
>= 'A') && (c
<= 'F'))))
1911 /******************************************************************************
1912 * CLSIDFromString [OLE32.@]
1913 * IIDFromString [OLE32.@]
1915 * Converts a unique identifier from its string representation into
1919 * idstr [I] The string representation of the GUID.
1920 * id [O] GUID converted from the string.
1924 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1929 static HRESULT
__CLSIDFromString(LPCWSTR s
, LPCLSID id
)
1934 if (!s
|| s
[0]!='{') {
1935 memset( id
, 0, sizeof (CLSID
) );
1937 return CO_E_CLASSSTRING
;
1940 TRACE("%s -> %p\n", debugstr_w(s
), id
);
1942 /* quick lookup table */
1943 memset(table
, 0, 256);
1945 for (i
= 0; i
< 10; i
++) {
1948 for (i
= 0; i
< 6; i
++) {
1949 table
['A' + i
] = i
+10;
1950 table
['a' + i
] = i
+10;
1953 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1956 for (i
= 1; i
< 9; i
++) {
1957 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1958 id
->Data1
= (id
->Data1
<< 4) | table
[s
[i
]];
1960 if (s
[9]!='-') return CO_E_CLASSSTRING
;
1963 for (i
= 10; i
< 14; i
++) {
1964 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1965 id
->Data2
= (id
->Data2
<< 4) | table
[s
[i
]];
1967 if (s
[14]!='-') return CO_E_CLASSSTRING
;
1970 for (i
= 15; i
< 19; i
++) {
1971 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1972 id
->Data3
= (id
->Data3
<< 4) | table
[s
[i
]];
1974 if (s
[19]!='-') return CO_E_CLASSSTRING
;
1976 for (i
= 20; i
< 37; i
+=2) {
1978 if (s
[i
]!='-') return CO_E_CLASSSTRING
;
1981 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return CO_E_CLASSSTRING
;
1982 id
->Data4
[(i
-20)/2] = table
[s
[i
]] << 4 | table
[s
[i
+1]];
1985 if (s
[37] == '}' && s
[38] == '\0')
1988 return CO_E_CLASSSTRING
;
1991 /*****************************************************************************/
1993 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
1998 return E_INVALIDARG
;
2000 ret
= __CLSIDFromString(idstr
, id
);
2001 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
2003 ret
= CLSIDFromProgID(idstr
, &tmp_id
);
2011 /******************************************************************************
2012 * StringFromCLSID [OLE32.@]
2013 * StringFromIID [OLE32.@]
2015 * Converts a GUID into the respective string representation.
2016 * The target string is allocated using the OLE IMalloc.
2019 * id [I] the GUID to be converted.
2020 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2027 * StringFromGUID2, CLSIDFromString
2029 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2034 if ((ret
= CoGetMalloc(0,&mllc
))) return ret
;
2035 if (!(*idstr
= IMalloc_Alloc( mllc
, CHARS_IN_GUID
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
2036 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2040 /******************************************************************************
2041 * StringFromGUID2 [OLE32.@]
2043 * Modified version of StringFromCLSID that allows you to specify max
2047 * id [I] GUID to convert to string.
2048 * str [O] Buffer where the result will be stored.
2049 * cmax [I] Size of the buffer in characters.
2052 * Success: The length of the resulting string in characters.
2055 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2057 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2058 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2059 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2060 '%','0','2','X','%','0','2','X','}',0 };
2061 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2062 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2063 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2064 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2065 return CHARS_IN_GUID
;
2068 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2069 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2071 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2072 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2076 strcpyW(path
, wszCLSIDSlash
);
2077 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2078 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2079 if (res
== ERROR_FILE_NOT_FOUND
)
2080 return REGDB_E_CLASSNOTREG
;
2081 else if (res
!= ERROR_SUCCESS
)
2082 return REGDB_E_READREGDB
;
2090 res
= open_classes_key(key
, keyname
, access
, subkey
);
2092 if (res
== ERROR_FILE_NOT_FOUND
)
2093 return REGDB_E_KEYMISSING
;
2094 else if (res
!= ERROR_SUCCESS
)
2095 return REGDB_E_READREGDB
;
2100 /* open HKCR\\AppId\\{string form of appid clsid} key */
2101 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2103 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2104 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2106 WCHAR buf
[CHARS_IN_GUID
];
2107 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2113 /* read the AppID value under the class's key */
2114 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2119 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2121 if (res
== ERROR_FILE_NOT_FOUND
)
2122 return REGDB_E_KEYMISSING
;
2123 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2124 return REGDB_E_READREGDB
;
2126 strcpyW(keyname
, szAppIdKey
);
2127 strcatW(keyname
, buf
);
2128 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2129 if (res
== ERROR_FILE_NOT_FOUND
)
2130 return REGDB_E_KEYMISSING
;
2131 else if (res
!= ERROR_SUCCESS
)
2132 return REGDB_E_READREGDB
;
2137 /******************************************************************************
2138 * ProgIDFromCLSID [OLE32.@]
2140 * Converts a class id into the respective program ID.
2143 * clsid [I] Class ID, as found in registry.
2144 * ppszProgID [O] Associated ProgID.
2149 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2151 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2153 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2160 ERR("ppszProgId isn't optional\n");
2161 return E_INVALIDARG
;
2165 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2169 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2170 ret
= REGDB_E_CLASSNOTREG
;
2174 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2177 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2178 ret
= REGDB_E_CLASSNOTREG
;
2179 CoTaskMemFree(*ppszProgID
);
2184 ret
= E_OUTOFMEMORY
;
2191 /******************************************************************************
2192 * CLSIDFromProgID [OLE32.@]
2194 * Converts a program id into the respective GUID.
2197 * progid [I] Unicode program ID, as found in registry.
2198 * clsid [O] Associated CLSID.
2202 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2204 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2206 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2207 WCHAR buf2
[CHARS_IN_GUID
];
2208 LONG buf2len
= sizeof(buf2
);
2212 if (!progid
|| !clsid
)
2214 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
2215 return E_INVALIDARG
;
2218 /* initialise clsid in case of failure */
2219 memset(clsid
, 0, sizeof(*clsid
));
2221 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2222 strcpyW( buf
, progid
);
2223 strcatW( buf
, clsidW
);
2224 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2226 HeapFree(GetProcessHeap(),0,buf
);
2227 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2228 return CO_E_CLASSSTRING
;
2230 HeapFree(GetProcessHeap(),0,buf
);
2232 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2235 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2236 return CO_E_CLASSSTRING
;
2239 return __CLSIDFromString(buf2
,clsid
);
2242 /******************************************************************************
2243 * CLSIDFromProgIDEx [OLE32.@]
2245 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2247 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2249 return CLSIDFromProgID(progid
, clsid
);
2252 /*****************************************************************************
2253 * CoGetPSClsid [OLE32.@]
2255 * Retrieves the CLSID of the proxy/stub factory that implements
2256 * IPSFactoryBuffer for the specified interface.
2259 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2260 * pclsid [O] Where to store returned proxy/stub CLSID.
2265 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2269 * The standard marshaller activates the object with the CLSID
2270 * returned and uses the CreateProxy and CreateStub methods on its
2271 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2274 * CoGetPSClsid determines this CLSID by searching the
2275 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2276 * in the registry and any interface id registered by
2277 * CoRegisterPSClsid within the current process.
2281 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2282 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2283 * considered a bug in native unless an application depends on this (unlikely).
2286 * CoRegisterPSClsid.
2288 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2290 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2291 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2292 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2293 WCHAR value
[CHARS_IN_GUID
];
2296 APARTMENT
*apt
= COM_CurrentApt();
2297 struct registered_psclsid
*registered_psclsid
;
2299 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2303 ERR("apartment not initialised\n");
2304 return CO_E_NOTINITIALIZED
;
2309 ERR("pclsid isn't optional\n");
2310 return E_INVALIDARG
;
2313 EnterCriticalSection(&apt
->cs
);
2315 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2316 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2318 *pclsid
= registered_psclsid
->clsid
;
2319 LeaveCriticalSection(&apt
->cs
);
2323 LeaveCriticalSection(&apt
->cs
);
2325 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2326 strcpyW(path
, wszInterface
);
2327 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2328 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2330 /* Open the key.. */
2331 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2333 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2334 return REGDB_E_IIDNOTREG
;
2337 /* ... Once we have the key, query the registry to get the
2338 value of CLSID as a string, and convert it into a
2339 proper CLSID structure to be passed back to the app */
2340 len
= sizeof(value
);
2341 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2344 return REGDB_E_IIDNOTREG
;
2348 /* We have the CLSID we want back from the registry as a string, so
2349 let's convert it into a CLSID structure */
2350 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2351 return REGDB_E_IIDNOTREG
;
2353 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2357 /*****************************************************************************
2358 * CoRegisterPSClsid [OLE32.@]
2360 * Register a proxy/stub CLSID for the given interface in the current process
2364 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2365 * rclsid [I] CLSID of the proxy/stub.
2369 * Failure: E_OUTOFMEMORY
2373 * This function does not add anything to the registry and the effects are
2374 * limited to the lifetime of the current process.
2379 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2381 APARTMENT
*apt
= COM_CurrentApt();
2382 struct registered_psclsid
*registered_psclsid
;
2384 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2388 ERR("apartment not initialised\n");
2389 return CO_E_NOTINITIALIZED
;
2392 EnterCriticalSection(&apt
->cs
);
2394 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2395 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2397 registered_psclsid
->clsid
= *rclsid
;
2398 LeaveCriticalSection(&apt
->cs
);
2402 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2403 if (!registered_psclsid
)
2405 LeaveCriticalSection(&apt
->cs
);
2406 return E_OUTOFMEMORY
;
2409 registered_psclsid
->iid
= *riid
;
2410 registered_psclsid
->clsid
= *rclsid
;
2411 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2413 LeaveCriticalSection(&apt
->cs
);
2420 * COM_GetRegisteredClassObject
2422 * This internal method is used to scan the registered class list to
2423 * find a class object.
2426 * rclsid Class ID of the class to find.
2427 * dwClsContext Class context to match.
2428 * ppv [out] returns a pointer to the class object. Complying
2429 * to normal COM usage, this method will increase the
2430 * reference count on this object.
2432 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2433 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2435 HRESULT hr
= S_FALSE
;
2436 RegisteredClass
*curClass
;
2438 EnterCriticalSection( &csRegisteredClassList
);
2440 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2443 * Check if we have a match on the class ID and context.
2445 if ((apt
->oxid
== curClass
->apartment_id
) &&
2446 (dwClsContext
& curClass
->runContext
) &&
2447 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2450 * We have a match, return the pointer to the class object.
2452 *ppUnk
= curClass
->classObject
;
2454 IUnknown_AddRef(curClass
->classObject
);
2461 LeaveCriticalSection( &csRegisteredClassList
);
2466 /******************************************************************************
2467 * CoRegisterClassObject [OLE32.@]
2469 * Registers the class object for a given class ID. Servers housed in EXE
2470 * files use this method instead of exporting DllGetClassObject to allow
2471 * other code to connect to their objects.
2474 * rclsid [I] CLSID of the object to register.
2475 * pUnk [I] IUnknown of the object.
2476 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2477 * flags [I] REGCLS flags indicating how connections are made.
2478 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2482 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2483 * CO_E_OBJISREG if the object is already registered. We should not return this.
2486 * CoRevokeClassObject, CoGetClassObject
2489 * In-process objects are only registered for the current apartment.
2490 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2491 * in other apartments.
2494 * MSDN claims that multiple interface registrations are legal, but we
2495 * can't do that with our current implementation.
2497 HRESULT WINAPI
CoRegisterClassObject(
2502 LPDWORD lpdwRegister
)
2504 static LONG next_cookie
;
2505 RegisteredClass
* newClass
;
2506 LPUNKNOWN foundObject
;
2510 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2511 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2513 if ( (lpdwRegister
==0) || (pUnk
==0) )
2514 return E_INVALIDARG
;
2516 apt
= COM_CurrentApt();
2519 ERR("COM was not initialized\n");
2520 return CO_E_NOTINITIALIZED
;
2525 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2526 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2527 if (flags
& REGCLS_MULTIPLEUSE
)
2528 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2531 * First, check if the class is already registered.
2532 * If it is, this should cause an error.
2534 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2536 if (flags
& REGCLS_MULTIPLEUSE
) {
2537 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2538 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2539 IUnknown_Release(foundObject
);
2542 IUnknown_Release(foundObject
);
2543 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2544 return CO_E_OBJISREG
;
2547 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2548 if ( newClass
== NULL
)
2549 return E_OUTOFMEMORY
;
2551 newClass
->classIdentifier
= *rclsid
;
2552 newClass
->apartment_id
= apt
->oxid
;
2553 newClass
->runContext
= dwClsContext
;
2554 newClass
->connectFlags
= flags
;
2555 newClass
->RpcRegistration
= NULL
;
2557 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2558 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2561 * Since we're making a copy of the object pointer, we have to increase its
2564 newClass
->classObject
= pUnk
;
2565 IUnknown_AddRef(newClass
->classObject
);
2567 EnterCriticalSection( &csRegisteredClassList
);
2568 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2569 LeaveCriticalSection( &csRegisteredClassList
);
2571 *lpdwRegister
= newClass
->dwCookie
;
2573 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2574 IStream
*marshal_stream
;
2576 hr
= get_local_server_stream(apt
, &marshal_stream
);
2580 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2582 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2583 &newClass
->RpcRegistration
);
2584 IStream_Release(marshal_stream
);
2589 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
2591 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2594 DWORD dwLength
= len
* sizeof(WCHAR
);
2596 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
2597 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2601 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
,
2602 REFCLSID rclsid
, REFIID riid
,
2603 BOOL hostifnecessary
, void **ppv
)
2605 WCHAR dllpath
[MAX_PATH
+1];
2606 BOOL apartment_threaded
;
2608 if (hostifnecessary
)
2610 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2611 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2612 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2613 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2615 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
2617 if (!strcmpiW(threading_model
, wszApartment
))
2619 apartment_threaded
= TRUE
;
2620 if (apt
->multi_threaded
)
2621 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2624 else if (!strcmpiW(threading_model
, wszFree
))
2626 apartment_threaded
= FALSE
;
2627 if (!apt
->multi_threaded
)
2628 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2630 /* everything except "Apartment", "Free" and "Both" */
2631 else if (strcmpiW(threading_model
, wszBoth
))
2633 apartment_threaded
= TRUE
;
2634 /* everything else is main-threaded */
2635 if (threading_model
[0])
2636 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2637 debugstr_w(threading_model
), debugstr_guid(rclsid
));
2639 if (apt
->multi_threaded
|| !apt
->main
)
2640 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, hkeydll
, rclsid
, riid
, ppv
);
2643 apartment_threaded
= FALSE
;
2646 apartment_threaded
= !apt
->multi_threaded
;
2648 if (COM_RegReadPath(hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2650 /* failure: CLSID is not found in registry */
2651 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2652 return REGDB_E_CLASSNOTREG
;
2655 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2659 /***********************************************************************
2660 * CoGetClassObject [OLE32.@]
2662 * Creates an object of the specified class.
2665 * rclsid [I] Class ID to create an instance of.
2666 * dwClsContext [I] Flags to restrict the location of the created instance.
2667 * pServerInfo [I] Optional. Details for connecting to a remote server.
2668 * iid [I] The ID of the interface of the instance to return.
2669 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2673 * Failure: HRESULT code.
2676 * The dwClsContext parameter can be one or more of the following:
2677 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2678 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2679 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2680 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2683 * CoCreateInstance()
2685 HRESULT WINAPI
CoGetClassObject(
2686 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2687 REFIID iid
, LPVOID
*ppv
)
2689 LPUNKNOWN regClassObject
;
2690 HRESULT hres
= E_UNEXPECTED
;
2692 BOOL release_apt
= FALSE
;
2694 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2697 return E_INVALIDARG
;
2701 if (!(apt
= COM_CurrentApt()))
2703 if (!(apt
= apartment_find_multi_threaded()))
2705 ERR("apartment not initialised\n");
2706 return CO_E_NOTINITIALIZED
;
2712 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2713 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2717 * First, try and see if we can't match the class ID with one of the
2718 * registered classes.
2720 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2723 /* Get the required interface from the retrieved pointer. */
2724 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2727 * Since QI got another reference on the pointer, we want to release the
2728 * one we already have. If QI was unsuccessful, this will release the object. This
2729 * is good since we are not returning it in the "out" parameter.
2731 IUnknown_Release(regClassObject
);
2732 if (release_apt
) apartment_release(apt
);
2736 /* First try in-process server */
2737 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2739 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2742 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2744 if (release_apt
) apartment_release(apt
);
2745 return FTMarshalCF_Create(iid
, ppv
);
2748 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2751 if (hres
== REGDB_E_CLASSNOTREG
)
2752 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2753 else if (hres
== REGDB_E_KEYMISSING
)
2755 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2756 hres
= REGDB_E_CLASSNOTREG
;
2760 if (SUCCEEDED(hres
))
2762 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2763 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2767 /* return if we got a class, otherwise fall through to one of the
2769 if (SUCCEEDED(hres
))
2771 if (release_apt
) apartment_release(apt
);
2776 /* Next try in-process handler */
2777 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2779 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2782 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2785 if (hres
== REGDB_E_CLASSNOTREG
)
2786 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2787 else if (hres
== REGDB_E_KEYMISSING
)
2789 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2790 hres
= REGDB_E_CLASSNOTREG
;
2794 if (SUCCEEDED(hres
))
2796 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2797 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2801 /* return if we got a class, otherwise fall through to one of the
2803 if (SUCCEEDED(hres
))
2805 if (release_apt
) apartment_release(apt
);
2809 if (release_apt
) apartment_release(apt
);
2811 /* Next try out of process */
2812 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2814 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2815 if (SUCCEEDED(hres
))
2819 /* Finally try remote: this requires networked DCOM (a lot of work) */
2820 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2822 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2823 hres
= REGDB_E_CLASSNOTREG
;
2827 ERR("no class object %s could be created for context 0x%x\n",
2828 debugstr_guid(rclsid
), dwClsContext
);
2832 /***********************************************************************
2833 * CoResumeClassObjects (OLE32.@)
2835 * Resumes all class objects registered with REGCLS_SUSPENDED.
2839 * Failure: HRESULT code.
2841 HRESULT WINAPI
CoResumeClassObjects(void)
2847 /***********************************************************************
2848 * CoCreateInstance [OLE32.@]
2850 * Creates an instance of the specified class.
2853 * rclsid [I] Class ID to create an instance of.
2854 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2855 * dwClsContext [I] Flags to restrict the location of the created instance.
2856 * iid [I] The ID of the interface of the instance to return.
2857 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2861 * Failure: HRESULT code.
2864 * The dwClsContext parameter can be one or more of the following:
2865 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2866 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2867 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2868 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2870 * Aggregation is the concept of deferring the IUnknown of an object to another
2871 * object. This allows a separate object to behave as though it was part of
2872 * the object and to allow this the pUnkOuter parameter can be set. Note that
2873 * not all objects support having an outer of unknown.
2876 * CoGetClassObject()
2878 HRESULT WINAPI
CoCreateInstance(
2880 LPUNKNOWN pUnkOuter
,
2886 LPCLASSFACTORY lpclf
= 0;
2889 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2890 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2897 if (!(apt
= COM_CurrentApt()))
2899 if (!(apt
= apartment_find_multi_threaded()))
2901 ERR("apartment not initialised\n");
2902 return CO_E_NOTINITIALIZED
;
2904 apartment_release(apt
);
2908 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2910 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
2912 IGlobalInterfaceTable
*git
= get_std_git();
2913 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
2914 if (hres
!= S_OK
) return hres
;
2916 TRACE("Retrieved GIT (%p)\n", *ppv
);
2920 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
2921 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
2924 * Get a class factory to construct the object we want.
2926 hres
= CoGetClassObject(rclsid
,
2936 * Create the object and don't forget to release the factory
2938 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2939 IClassFactory_Release(lpclf
);
2942 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
2943 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
2945 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2947 debugstr_guid(rclsid
),hres
);
2953 /***********************************************************************
2954 * CoCreateInstanceEx [OLE32.@]
2956 HRESULT WINAPI
CoCreateInstanceEx(
2958 LPUNKNOWN pUnkOuter
,
2960 COSERVERINFO
* pServerInfo
,
2964 IUnknown
* pUnk
= NULL
;
2967 ULONG successCount
= 0;
2972 if ( (cmq
==0) || (pResults
==NULL
))
2973 return E_INVALIDARG
;
2975 if (pServerInfo
!=NULL
)
2976 FIXME("() non-NULL pServerInfo not supported!\n");
2979 * Initialize all the "out" parameters.
2981 for (index
= 0; index
< cmq
; index
++)
2983 pResults
[index
].pItf
= NULL
;
2984 pResults
[index
].hr
= E_NOINTERFACE
;
2988 * Get the object and get its IUnknown pointer.
2990 hr
= CoCreateInstance(rclsid
,
3000 * Then, query for all the interfaces requested.
3002 for (index
= 0; index
< cmq
; index
++)
3004 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
3005 pResults
[index
].pIID
,
3006 (VOID
**)&(pResults
[index
].pItf
));
3008 if (pResults
[index
].hr
== S_OK
)
3013 * Release our temporary unknown pointer.
3015 IUnknown_Release(pUnk
);
3017 if (successCount
== 0)
3018 return E_NOINTERFACE
;
3020 if (successCount
!=cmq
)
3021 return CO_S_NOTALLINTERFACES
;
3026 /***********************************************************************
3027 * CoLoadLibrary (OLE32.@)
3032 * lpszLibName [I] Path to library.
3033 * bAutoFree [I] Whether the library should automatically be freed.
3036 * Success: Handle to loaded library.
3040 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3042 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3044 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3046 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3049 /***********************************************************************
3050 * CoFreeLibrary [OLE32.@]
3052 * Unloads a library from memory.
3055 * hLibrary [I] Handle to library to unload.
3061 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3063 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3065 FreeLibrary(hLibrary
);
3069 /***********************************************************************
3070 * CoFreeAllLibraries [OLE32.@]
3072 * Function for backwards compatibility only. Does nothing.
3078 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3080 void WINAPI
CoFreeAllLibraries(void)
3085 /***********************************************************************
3086 * CoFreeUnusedLibrariesEx [OLE32.@]
3088 * Frees any previously unused libraries whose delay has expired and marks
3089 * currently unused libraries for unloading. Unused are identified as those that
3090 * return S_OK from their DllCanUnloadNow function.
3093 * dwUnloadDelay [I] Unload delay in milliseconds.
3094 * dwReserved [I] Reserved. Set to 0.
3100 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3102 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3104 struct apartment
*apt
= COM_CurrentApt();
3107 ERR("apartment not initialised\n");
3111 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3114 /***********************************************************************
3115 * CoFreeUnusedLibraries [OLE32.@]
3117 * Frees any unused libraries. Unused are identified as those that return
3118 * S_OK from their DllCanUnloadNow function.
3124 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3126 void WINAPI
CoFreeUnusedLibraries(void)
3128 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3131 /***********************************************************************
3132 * CoFileTimeNow [OLE32.@]
3134 * Retrieves the current time in FILETIME format.
3137 * lpFileTime [O] The current time.
3142 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3144 GetSystemTimeAsFileTime( lpFileTime
);
3148 /******************************************************************************
3149 * CoLockObjectExternal [OLE32.@]
3151 * Increments or decrements the external reference count of a stub object.
3154 * pUnk [I] Stub object.
3155 * fLock [I] If TRUE then increments the external ref-count,
3156 * otherwise decrements.
3157 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3158 * calling CoDisconnectObject.
3162 * Failure: HRESULT code.
3165 * If fLock is TRUE and an object is passed in that doesn't have a stub
3166 * manager then a new stub manager is created for the object.
3168 HRESULT WINAPI
CoLockObjectExternal(
3171 BOOL fLastUnlockReleases
)
3173 struct stub_manager
*stubmgr
;
3174 struct apartment
*apt
;
3176 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3177 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3179 apt
= COM_CurrentApt();
3180 if (!apt
) return CO_E_NOTINITIALIZED
;
3182 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3187 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3189 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3191 stub_manager_int_release(stubmgr
);
3197 stubmgr
= new_stub_manager(apt
, pUnk
);
3201 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3202 stub_manager_int_release(stubmgr
);
3209 WARN("stub object not found %p\n", pUnk
);
3210 /* Note: native is pretty broken here because it just silently
3211 * fails, without returning an appropriate error code, making apps
3212 * think that the object was disconnected, when it actually wasn't */
3217 /***********************************************************************
3218 * CoInitializeWOW (OLE32.@)
3220 * WOW equivalent of CoInitialize?
3229 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3231 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3235 /***********************************************************************
3236 * CoGetState [OLE32.@]
3238 * Retrieves the thread state object previously stored by CoSetState().
3241 * ppv [I] Address where pointer to object will be stored.
3245 * Failure: E_OUTOFMEMORY.
3248 * Crashes on all invalid ppv addresses, including NULL.
3249 * If the function returns a non-NULL object then the caller must release its
3250 * reference on the object when the object is no longer required.
3255 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3257 struct oletls
*info
= COM_CurrentInfo();
3258 if (!info
) return E_OUTOFMEMORY
;
3264 IUnknown_AddRef(info
->state
);
3266 TRACE("apt->state=%p\n", info
->state
);
3272 /***********************************************************************
3273 * CoSetState [OLE32.@]
3275 * Sets the thread state object.
3278 * pv [I] Pointer to state object to be stored.
3281 * The system keeps a reference on the object while the object stored.
3285 * Failure: E_OUTOFMEMORY.
3287 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3289 struct oletls
*info
= COM_CurrentInfo();
3290 if (!info
) return E_OUTOFMEMORY
;
3292 if (pv
) IUnknown_AddRef(pv
);
3296 TRACE("-- release %p now\n", info
->state
);
3297 IUnknown_Release(info
->state
);
3306 /******************************************************************************
3307 * CoTreatAsClass [OLE32.@]
3309 * Sets the TreatAs value of a class.
3312 * clsidOld [I] Class to set TreatAs value on.
3313 * clsidNew [I] The class the clsidOld should be treated as.
3317 * Failure: HRESULT code.
3322 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3324 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3325 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3327 WCHAR szClsidNew
[CHARS_IN_GUID
];
3329 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3330 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3333 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3336 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3338 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3339 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3341 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3343 res
= REGDB_E_WRITEREGDB
;
3349 RegDeleteKeyW(hkey
, wszTreatAs
);
3353 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3354 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3356 res
= REGDB_E_WRITEREGDB
;
3361 if (hkey
) RegCloseKey(hkey
);
3365 /******************************************************************************
3366 * CoGetTreatAsClass [OLE32.@]
3368 * Gets the TreatAs value of a class.
3371 * clsidOld [I] Class to get the TreatAs value of.
3372 * clsidNew [I] The class the clsidOld should be treated as.
3376 * Failure: HRESULT code.
3381 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3383 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3385 WCHAR szClsidNew
[CHARS_IN_GUID
];
3387 LONG len
= sizeof(szClsidNew
);
3389 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3390 *clsidNew
= *clsidOld
; /* copy over old value */
3392 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3398 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3403 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3405 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3407 if (hkey
) RegCloseKey(hkey
);
3411 /******************************************************************************
3412 * CoGetCurrentProcess [OLE32.@]
3414 * Gets the current process ID.
3417 * The current process ID.
3420 * Is DWORD really the correct return type for this function?
3422 DWORD WINAPI
CoGetCurrentProcess(void)
3424 return GetCurrentProcessId();
3427 /******************************************************************************
3428 * CoRegisterMessageFilter [OLE32.@]
3430 * Registers a message filter.
3433 * lpMessageFilter [I] Pointer to interface.
3434 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3438 * Failure: HRESULT code.
3441 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3442 * lpMessageFilter removes the message filter.
3444 * If lplpMessageFilter is not NULL the previous message filter will be
3445 * returned in the memory pointer to this parameter and the caller is
3446 * responsible for releasing the object.
3448 * The current thread be in an apartment otherwise the function will crash.
3450 HRESULT WINAPI
CoRegisterMessageFilter(
3451 LPMESSAGEFILTER lpMessageFilter
,
3452 LPMESSAGEFILTER
*lplpMessageFilter
)
3454 struct apartment
*apt
;
3455 IMessageFilter
*lpOldMessageFilter
;
3457 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3459 apt
= COM_CurrentApt();
3461 /* can't set a message filter in a multi-threaded apartment */
3462 if (!apt
|| apt
->multi_threaded
)
3464 WARN("can't set message filter in MTA or uninitialized apt\n");
3465 return CO_E_NOT_SUPPORTED
;
3468 if (lpMessageFilter
)
3469 IMessageFilter_AddRef(lpMessageFilter
);
3471 EnterCriticalSection(&apt
->cs
);
3473 lpOldMessageFilter
= apt
->filter
;
3474 apt
->filter
= lpMessageFilter
;
3476 LeaveCriticalSection(&apt
->cs
);
3478 if (lplpMessageFilter
)
3479 *lplpMessageFilter
= lpOldMessageFilter
;
3480 else if (lpOldMessageFilter
)
3481 IMessageFilter_Release(lpOldMessageFilter
);
3486 /***********************************************************************
3487 * CoIsOle1Class [OLE32.@]
3489 * Determines whether the specified class an OLE v1 class.
3492 * clsid [I] Class to test.
3495 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3497 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3499 FIXME("%s\n", debugstr_guid(clsid
));
3503 /***********************************************************************
3504 * IsEqualGUID [OLE32.@]
3506 * Compares two Unique Identifiers.
3509 * rguid1 [I] The first GUID to compare.
3510 * rguid2 [I] The other GUID to compare.
3516 BOOL WINAPI
IsEqualGUID(
3520 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3523 /***********************************************************************
3524 * CoInitializeSecurity [OLE32.@]
3526 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3527 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3528 void* pReserved1
, DWORD dwAuthnLevel
,
3529 DWORD dwImpLevel
, void* pReserved2
,
3530 DWORD dwCapabilities
, void* pReserved3
)
3532 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3533 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3534 dwCapabilities
, pReserved3
);
3538 /***********************************************************************
3539 * CoSuspendClassObjects [OLE32.@]
3541 * Suspends all registered class objects to prevent further requests coming in
3542 * for those objects.
3546 * Failure: HRESULT code.
3548 HRESULT WINAPI
CoSuspendClassObjects(void)
3554 /***********************************************************************
3555 * CoAddRefServerProcess [OLE32.@]
3557 * Helper function for incrementing the reference count of a local-server
3561 * New reference count.
3564 * CoReleaseServerProcess().
3566 ULONG WINAPI
CoAddRefServerProcess(void)
3572 EnterCriticalSection(&csRegisteredClassList
);
3573 refs
= ++s_COMServerProcessReferences
;
3574 LeaveCriticalSection(&csRegisteredClassList
);
3576 TRACE("refs before: %d\n", refs
- 1);
3581 /***********************************************************************
3582 * CoReleaseServerProcess [OLE32.@]
3584 * Helper function for decrementing the reference count of a local-server
3588 * New reference count.
3591 * When reference count reaches 0, this function suspends all registered
3592 * classes so no new connections are accepted.
3595 * CoAddRefServerProcess(), CoSuspendClassObjects().
3597 ULONG WINAPI
CoReleaseServerProcess(void)
3603 EnterCriticalSection(&csRegisteredClassList
);
3605 refs
= --s_COMServerProcessReferences
;
3606 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3608 LeaveCriticalSection(&csRegisteredClassList
);
3610 TRACE("refs after: %d\n", refs
);
3615 /***********************************************************************
3616 * CoIsHandlerConnected [OLE32.@]
3618 * Determines whether a proxy is connected to a remote stub.
3621 * pUnk [I] Pointer to object that may or may not be connected.
3624 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3627 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3629 FIXME("%p\n", pUnk
);
3634 /***********************************************************************
3635 * CoAllowSetForegroundWindow [OLE32.@]
3638 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3640 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3644 /***********************************************************************
3645 * CoQueryProxyBlanket [OLE32.@]
3647 * Retrieves the security settings being used by a proxy.
3650 * pProxy [I] Pointer to the proxy object.
3651 * pAuthnSvc [O] The type of authentication service.
3652 * pAuthzSvc [O] The type of authorization service.
3653 * ppServerPrincName [O] Optional. The server prinicple name.
3654 * pAuthnLevel [O] The authentication level.
3655 * pImpLevel [O] The impersonation level.
3656 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3657 * pCapabilities [O] Flags affecting the security behaviour.
3661 * Failure: HRESULT code.
3664 * CoCopyProxy, CoSetProxyBlanket.
3666 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
3667 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
3668 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
3670 IClientSecurity
*pCliSec
;
3673 TRACE("%p\n", pProxy
);
3675 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3678 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
3679 pAuthzSvc
, ppServerPrincName
,
3680 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
3682 IClientSecurity_Release(pCliSec
);
3685 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3689 /***********************************************************************
3690 * CoSetProxyBlanket [OLE32.@]
3692 * Sets the security settings for a proxy.
3695 * pProxy [I] Pointer to the proxy object.
3696 * AuthnSvc [I] The type of authentication service.
3697 * AuthzSvc [I] The type of authorization service.
3698 * pServerPrincName [I] The server prinicple name.
3699 * AuthnLevel [I] The authentication level.
3700 * ImpLevel [I] The impersonation level.
3701 * pAuthInfo [I] Information specific to the authorization/authentication service.
3702 * Capabilities [I] Flags affecting the security behaviour.
3706 * Failure: HRESULT code.
3709 * CoQueryProxyBlanket, CoCopyProxy.
3711 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
3712 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
3713 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
3715 IClientSecurity
*pCliSec
;
3718 TRACE("%p\n", pProxy
);
3720 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3723 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
3724 AuthzSvc
, pServerPrincName
,
3725 AuthnLevel
, ImpLevel
, pAuthInfo
,
3727 IClientSecurity_Release(pCliSec
);
3730 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3734 /***********************************************************************
3735 * CoCopyProxy [OLE32.@]
3740 * pProxy [I] Pointer to the proxy object.
3741 * ppCopy [O] Copy of the proxy.
3745 * Failure: HRESULT code.
3748 * CoQueryProxyBlanket, CoSetProxyBlanket.
3750 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
3752 IClientSecurity
*pCliSec
;
3755 TRACE("%p\n", pProxy
);
3757 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3760 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
3761 IClientSecurity_Release(pCliSec
);
3764 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3769 /***********************************************************************
3770 * CoGetCallContext [OLE32.@]
3772 * Gets the context of the currently executing server call in the current
3776 * riid [I] Context interface to return.
3777 * ppv [O] Pointer to memory that will receive the context on return.
3781 * Failure: HRESULT code.
3783 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3785 struct oletls
*info
= COM_CurrentInfo();
3787 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3790 return E_OUTOFMEMORY
;
3792 if (!info
->call_state
)
3793 return RPC_E_CALL_COMPLETE
;
3795 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3798 /***********************************************************************
3799 * CoSwitchCallContext [OLE32.@]
3801 * Switches the context of the currently executing server call in the current
3805 * pObject [I] Pointer to new context object
3806 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3810 * Failure: HRESULT code.
3812 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3814 struct oletls
*info
= COM_CurrentInfo();
3816 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3819 return E_OUTOFMEMORY
;
3821 *ppOldObject
= info
->call_state
;
3822 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3827 /***********************************************************************
3828 * CoQueryClientBlanket [OLE32.@]
3830 * Retrieves the authentication information about the client of the currently
3831 * executing server call in the current thread.
3834 * pAuthnSvc [O] Optional. The type of authentication service.
3835 * pAuthzSvc [O] Optional. The type of authorization service.
3836 * pServerPrincName [O] Optional. The server prinicple name.
3837 * pAuthnLevel [O] Optional. The authentication level.
3838 * pImpLevel [O] Optional. The impersonation level.
3839 * pPrivs [O] Optional. Information about the privileges of the client.
3840 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3844 * Failure: HRESULT code.
3847 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3849 HRESULT WINAPI
CoQueryClientBlanket(
3852 OLECHAR
**pServerPrincName
,
3855 RPC_AUTHZ_HANDLE
*pPrivs
,
3856 DWORD
*pCapabilities
)
3858 IServerSecurity
*pSrvSec
;
3861 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3862 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3863 pPrivs
, pCapabilities
);
3865 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3868 hr
= IServerSecurity_QueryBlanket(
3869 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3870 pImpLevel
, pPrivs
, pCapabilities
);
3871 IServerSecurity_Release(pSrvSec
);
3877 /***********************************************************************
3878 * CoImpersonateClient [OLE32.@]
3880 * Impersonates the client of the currently executing server call in the
3888 * Failure: HRESULT code.
3891 * If this function fails then the current thread will not be impersonating
3892 * the client and all actions will take place on behalf of the server.
3893 * Therefore, it is important to check the return value from this function.
3896 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3898 HRESULT WINAPI
CoImpersonateClient(void)
3900 IServerSecurity
*pSrvSec
;
3905 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3908 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3909 IServerSecurity_Release(pSrvSec
);
3915 /***********************************************************************
3916 * CoRevertToSelf [OLE32.@]
3918 * Ends the impersonation of the client of the currently executing server
3919 * call in the current thread.
3926 * Failure: HRESULT code.
3929 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3931 HRESULT WINAPI
CoRevertToSelf(void)
3933 IServerSecurity
*pSrvSec
;
3938 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3941 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3942 IServerSecurity_Release(pSrvSec
);
3948 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3950 /* first try to retrieve messages for incoming COM calls to the apartment window */
3951 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
3952 /* next retrieve other messages necessary for the app to remain responsive */
3953 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3954 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3957 /***********************************************************************
3958 * CoWaitForMultipleHandles [OLE32.@]
3960 * Waits for one or more handles to become signaled.
3963 * dwFlags [I] Flags. See notes.
3964 * dwTimeout [I] Timeout in milliseconds.
3965 * cHandles [I] Number of handles pointed to by pHandles.
3966 * pHandles [I] Handles to wait for.
3967 * lpdwindex [O] Index of handle that was signaled.
3971 * Failure: RPC_S_CALLPENDING on timeout.
3975 * The dwFlags parameter can be zero or more of the following:
3976 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3977 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3980 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3982 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3983 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3986 DWORD start_time
= GetTickCount();
3987 APARTMENT
*apt
= COM_CurrentApt();
3988 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3990 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3991 pHandles
, lpdwindex
);
3995 DWORD now
= GetTickCount();
3998 if (now
- start_time
> dwTimeout
)
4000 hr
= RPC_S_CALLPENDING
;
4006 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4007 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4009 TRACE("waiting for rpc completion or window message\n");
4011 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4012 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4013 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4015 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4020 /* call message filter */
4022 if (COM_CurrentApt()->filter
)
4024 PENDINGTYPE pendingtype
=
4025 COM_CurrentInfo()->pending_call_count_server
?
4026 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4027 DWORD be_handled
= IMessageFilter_MessagePending(
4028 COM_CurrentApt()->filter
, 0 /* FIXME */,
4029 now
- start_time
, pendingtype
);
4030 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4033 case PENDINGMSG_CANCELCALL
:
4034 WARN("call canceled\n");
4035 hr
= RPC_E_CALL_CANCELED
;
4037 case PENDINGMSG_WAITNOPROCESS
:
4038 case PENDINGMSG_WAITDEFPROCESS
:
4040 /* FIXME: MSDN is very vague about the difference
4041 * between WAITNOPROCESS and WAITDEFPROCESS - there
4042 * appears to be none, so it is possibly a left-over
4043 * from the 16-bit world. */
4048 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4049 * so after processing 100 messages we go back to checking the wait handles */
4050 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4052 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4053 TranslateMessage(&msg
);
4054 DispatchMessageW(&msg
);
4055 if (msg
.message
== WM_QUIT
)
4057 TRACE("resending WM_QUIT to outer message loop\n");
4058 PostQuitMessage(msg
.wParam
);
4059 /* no longer need to process messages */
4060 message_loop
= FALSE
;
4069 TRACE("waiting for rpc completion\n");
4071 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4072 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4073 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4079 hr
= RPC_S_CALLPENDING
;
4082 hr
= HRESULT_FROM_WIN32( GetLastError() );
4090 TRACE("-- 0x%08x\n", hr
);
4095 /***********************************************************************
4096 * CoGetObject [OLE32.@]
4098 * Gets the object named by converting the name to a moniker and binding to it.
4101 * pszName [I] String representing the object.
4102 * pBindOptions [I] Parameters affecting the binding to the named object.
4103 * riid [I] Interface to bind to on the objecct.
4104 * ppv [O] On output, the interface riid of the object represented
4109 * Failure: HRESULT code.
4112 * MkParseDisplayName.
4114 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4115 REFIID riid
, void **ppv
)
4122 hr
= CreateBindCtx(0, &pbc
);
4126 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4133 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4136 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4137 IMoniker_Release(pmk
);
4141 IBindCtx_Release(pbc
);
4146 /***********************************************************************
4147 * CoRegisterChannelHook [OLE32.@]
4149 * Registers a process-wide hook that is called during ORPC calls.
4152 * guidExtension [I] GUID of the channel hook to register.
4153 * pChannelHook [I] Channel hook object to register.
4157 * Failure: HRESULT code.
4159 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4161 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4163 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4166 typedef struct Context
4168 IComThreadingInfo IComThreadingInfo_iface
;
4169 IContextCallback IContextCallback_iface
;
4170 IObjContext IObjContext_iface
;
4175 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4177 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4180 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4182 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4185 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4187 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4190 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4194 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4195 IsEqualIID(riid
, &IID_IUnknown
))
4197 *ppv
= &iface
->IComThreadingInfo_iface
;
4199 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4201 *ppv
= &iface
->IContextCallback_iface
;
4203 else if (IsEqualIID(riid
, &IID_IObjContext
))
4205 *ppv
= &iface
->IObjContext_iface
;
4210 IUnknown_AddRef((IUnknown
*)*ppv
);
4214 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4215 return E_NOINTERFACE
;
4218 static ULONG
Context_AddRef(Context
*This
)
4220 return InterlockedIncrement(&This
->refs
);
4223 static ULONG
Context_Release(Context
*This
)
4225 ULONG refs
= InterlockedDecrement(&This
->refs
);
4227 HeapFree(GetProcessHeap(), 0, This
);
4231 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4233 Context
*This
= impl_from_IComThreadingInfo(iface
);
4234 return Context_QueryInterface(This
, riid
, ppv
);
4237 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4239 Context
*This
= impl_from_IComThreadingInfo(iface
);
4240 return Context_AddRef(This
);
4243 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4245 Context
*This
= impl_from_IComThreadingInfo(iface
);
4246 return Context_Release(This
);
4249 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4251 Context
*This
= impl_from_IComThreadingInfo(iface
);
4253 TRACE("(%p)\n", apttype
);
4255 *apttype
= This
->apttype
;
4259 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4261 Context
*This
= impl_from_IComThreadingInfo(iface
);
4263 TRACE("(%p)\n", thdtype
);
4265 switch (This
->apttype
)
4268 case APTTYPE_MAINSTA
:
4269 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4272 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4278 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4280 FIXME("(%p): stub\n", logical_thread_id
);
4284 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4286 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4290 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4292 Context_CTI_QueryInterface
,
4294 Context_CTI_Release
,
4295 Context_CTI_GetCurrentApartmentType
,
4296 Context_CTI_GetCurrentThreadType
,
4297 Context_CTI_GetCurrentLogicalThreadId
,
4298 Context_CTI_SetCurrentLogicalThreadId
4301 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4303 Context
*This
= impl_from_IContextCallback(iface
);
4304 return Context_QueryInterface(This
, riid
, ppv
);
4307 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4309 Context
*This
= impl_from_IContextCallback(iface
);
4310 return Context_AddRef(This
);
4313 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4315 Context
*This
= impl_from_IContextCallback(iface
);
4316 return Context_Release(This
);
4319 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4320 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4322 Context
*This
= impl_from_IContextCallback(iface
);
4324 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4328 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4330 Context_CC_QueryInterface
,
4333 Context_CC_ContextCallback
4336 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4338 Context
*This
= impl_from_IObjContext(iface
);
4339 return Context_QueryInterface(This
, riid
, ppv
);
4342 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4344 Context
*This
= impl_from_IObjContext(iface
);
4345 return Context_AddRef(This
);
4348 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4350 Context
*This
= impl_from_IObjContext(iface
);
4351 return Context_Release(This
);
4354 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4356 Context
*This
= impl_from_IObjContext(iface
);
4358 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4362 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4364 Context
*This
= impl_from_IObjContext(iface
);
4366 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4370 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4372 Context
*This
= impl_from_IObjContext(iface
);
4374 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4378 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4380 Context
*This
= impl_from_IObjContext(iface
);
4382 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4386 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4388 Context
*This
= impl_from_IObjContext(iface
);
4389 FIXME("(%p/%p)\n", This
, iface
);
4392 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4394 Context
*This
= impl_from_IObjContext(iface
);
4395 FIXME("(%p/%p)\n", This
, iface
);
4398 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4400 Context
*This
= impl_from_IObjContext(iface
);
4401 FIXME("(%p/%p)\n", This
, iface
);
4404 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4406 Context
*This
= impl_from_IObjContext(iface
);
4407 FIXME("(%p/%p)\n", This
, iface
);
4410 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4412 Context
*This
= impl_from_IObjContext(iface
);
4413 FIXME("(%p/%p)\n", This
, iface
);
4416 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4418 Context
*This
= impl_from_IObjContext(iface
);
4419 FIXME("(%p/%p)\n", This
, iface
);
4422 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4424 Context
*This
= impl_from_IObjContext(iface
);
4425 FIXME("(%p/%p)\n", This
, iface
);
4428 static const IObjContextVtbl Context_Object_Vtbl
=
4430 Context_OC_QueryInterface
,
4433 Context_OC_SetProperty
,
4434 Context_OC_RemoveProperty
,
4435 Context_OC_GetProperty
,
4436 Context_OC_EnumContextProps
,
4437 Context_OC_Reserved1
,
4438 Context_OC_Reserved2
,
4439 Context_OC_Reserved3
,
4440 Context_OC_Reserved4
,
4441 Context_OC_Reserved5
,
4442 Context_OC_Reserved6
,
4443 Context_OC_Reserved7
4446 /***********************************************************************
4447 * CoGetObjectContext [OLE32.@]
4449 * Retrieves an object associated with the current context (i.e. apartment).
4452 * riid [I] ID of the interface of the object to retrieve.
4453 * ppv [O] Address where object will be stored on return.
4457 * Failure: HRESULT code.
4459 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4461 APARTMENT
*apt
= COM_CurrentApt();
4465 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4470 if (!(apt
= apartment_find_multi_threaded()))
4472 ERR("apartment not initialised\n");
4473 return CO_E_NOTINITIALIZED
;
4475 apartment_release(apt
);
4478 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4480 return E_OUTOFMEMORY
;
4482 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4483 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4484 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4486 if (apt
->multi_threaded
)
4487 context
->apttype
= APTTYPE_MTA
;
4489 context
->apttype
= APTTYPE_MAINSTA
;
4491 context
->apttype
= APTTYPE_STA
;
4493 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4494 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4500 /***********************************************************************
4501 * CoGetContextToken [OLE32.@]
4503 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4505 struct oletls
*info
= COM_CurrentInfo();
4507 TRACE("(%p)\n", token
);
4510 return E_OUTOFMEMORY
;
4515 if (!(apt
= apartment_find_multi_threaded()))
4517 ERR("apartment not initialised\n");
4518 return CO_E_NOTINITIALIZED
;
4520 apartment_release(apt
);
4526 if (!info
->context_token
)
4531 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4532 if (FAILED(hr
)) return hr
;
4533 info
->context_token
= ctx
;
4536 *token
= (ULONG_PTR
)info
->context_token
;
4537 TRACE("apt->context_token=%p\n", info
->context_token
);
4542 /***********************************************************************
4543 * CoGetDefaultContext [OLE32.@]
4545 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4547 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4548 return E_NOINTERFACE
;
4551 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4553 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4557 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4558 if (SUCCEEDED(hres
))
4560 WCHAR dllpath
[MAX_PATH
+1];
4562 if (COM_RegReadPath(hkey
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4564 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4565 if (!strcmpiW(dllpath
, wszOle32
))
4568 return HandlerCF_Create(rclsid
, riid
, ppv
);
4572 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4576 return CLASS_E_CLASSNOTAVAILABLE
;
4579 /***********************************************************************
4582 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4584 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4587 case DLL_PROCESS_ATTACH
:
4588 hProxyDll
= hinstDLL
;
4591 case DLL_PROCESS_DETACH
:
4592 if (reserved
) break;
4594 UnregisterClassW( wszAptWinClass
, hProxyDll
);
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();