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
44 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
46 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
48 /****************************************************************************
49 * This section defines variables internal to the COM module.
52 static APARTMENT
*MTA
; /* protected by csApartment */
53 static APARTMENT
*MainApartment
; /* the first STA apartment */
54 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
56 static CRITICAL_SECTION csApartment
;
57 static CRITICAL_SECTION_DEBUG critsect_debug
=
60 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
61 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
63 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
65 struct registered_psclsid
73 * This is a marshallable object exposing registered local servers.
74 * IServiceProvider is used only because it happens meet requirements
75 * and already has proxy/stub code. If more functionality is needed,
76 * a custom interface may be used instead.
80 IServiceProvider IServiceProvider_iface
;
83 IStream
*marshal_stream
;
87 * This lock count counts the number of times CoInitialize is called. It is
88 * decreased every time CoUninitialize is called. When it hits 0, the COM
91 static LONG s_COMLockCount
= 0;
92 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
93 static LONG s_COMServerProcessReferences
= 0;
96 * This linked list contains the list of registered class objects. These
97 * are mostly used to register the factories for out-of-proc servers of OLE
100 * TODO: Make this data structure aware of inter-process communication. This
101 * means that parts of this will be exported to rpcss.
103 typedef struct tagRegisteredClass
106 CLSID classIdentifier
;
108 LPUNKNOWN classObject
;
112 void *RpcRegistration
;
115 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
117 static CRITICAL_SECTION csRegisteredClassList
;
118 static CRITICAL_SECTION_DEBUG class_cs_debug
=
120 0, 0, &csRegisteredClassList
,
121 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
122 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
124 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
126 /* wrapper for NtCreateKey that creates the key recursively if necessary */
127 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
129 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
131 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
133 HANDLE subkey
, root
= attr
->RootDirectory
;
134 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
135 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
138 while (i
< len
&& buffer
[i
] != '\\') i
++;
139 if (i
== len
) return status
;
141 attrs
= attr
->Attributes
;
142 attr
->ObjectName
= &str
;
146 str
.Buffer
= buffer
+ pos
;
147 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
148 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
149 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
150 if (status
) return status
;
151 attr
->RootDirectory
= subkey
;
152 while (i
< len
&& buffer
[i
] == '\\') i
++;
154 while (i
< len
&& buffer
[i
] != '\\') i
++;
156 str
.Buffer
= buffer
+ pos
;
157 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
158 attr
->Attributes
= attrs
;
159 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
160 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
166 static const WCHAR classes_rootW
[] = L
"\\REGISTRY\\Machine\\Software\\Classes";
168 static const WCHAR classes_rootW
[] =
169 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
172 static HKEY classes_root_hkey
;
174 /* create the special HKEY_CLASSES_ROOT key */
175 static HKEY
create_classes_root_hkey(void)
178 OBJECT_ATTRIBUTES attr
;
181 attr
.Length
= sizeof(attr
);
182 attr
.RootDirectory
= 0;
183 attr
.ObjectName
= &name
;
185 attr
.SecurityDescriptor
= NULL
;
186 attr
.SecurityQualityOfService
= NULL
;
187 RtlInitUnicodeString( &name
, classes_rootW
);
188 if (create_key( &hkey
, MAXIMUM_ALLOWED
, &attr
)) return 0;
189 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
191 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
194 NtClose( hkey
); /* somebody beat us to it */
198 /* map the hkey from special root to normal key if necessary */
199 static inline HKEY
get_classes_root_hkey( HKEY hkey
)
203 if (hkey
== HKEY_CLASSES_ROOT
&& !(ret
= classes_root_hkey
))
204 ret
= create_classes_root_hkey();
209 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
211 OBJECT_ATTRIBUTES attr
;
212 UNICODE_STRING nameW
;
214 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
216 attr
.Length
= sizeof(attr
);
217 attr
.RootDirectory
= hkey
;
218 attr
.ObjectName
= &nameW
;
220 attr
.SecurityDescriptor
= NULL
;
221 attr
.SecurityQualityOfService
= NULL
;
222 RtlInitUnicodeString( &nameW
, name
);
224 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
227 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
229 OBJECT_ATTRIBUTES attr
;
230 UNICODE_STRING nameW
;
232 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
234 attr
.Length
= sizeof(attr
);
235 attr
.RootDirectory
= hkey
;
236 attr
.ObjectName
= &nameW
;
238 attr
.SecurityDescriptor
= NULL
;
239 attr
.SecurityQualityOfService
= NULL
;
240 RtlInitUnicodeString( &nameW
, name
);
242 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
245 /*****************************************************************************
246 * This section contains OpenDllList definitions
248 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
249 * other functions that do LoadLibrary _without_ giving back a HMODULE.
250 * Without this list these handles would never be freed.
252 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
253 * next unload-call but not before 600 sec.
256 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
257 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
259 typedef struct tagOpenDll
264 DllGetClassObjectFunc DllGetClassObject
;
265 DllCanUnloadNowFunc DllCanUnloadNow
;
269 static struct list openDllList
= LIST_INIT(openDllList
);
271 static CRITICAL_SECTION csOpenDllList
;
272 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
274 0, 0, &csOpenDllList
,
275 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
276 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
278 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
280 struct apartment_loaded_dll
288 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',' ',
289 '0','x','#','#','#','#','#','#','#','#',' ',0};
291 /*****************************************************************************
292 * This section contains OpenDllList implementation
295 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
299 EnterCriticalSection(&csOpenDllList
);
300 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
302 if (!strcmpiW(library_name
, ptr
->library_name
) &&
303 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
309 LeaveCriticalSection(&csOpenDllList
);
313 /* caller must ensure that library_name is not already in the open dll list */
314 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
320 DllCanUnloadNowFunc DllCanUnloadNow
;
321 DllGetClassObjectFunc DllGetClassObject
;
325 *ret
= COMPOBJ_DllList_Get(library_name
);
326 if (*ret
) return S_OK
;
328 /* do this outside the csOpenDllList to avoid creating a lock dependency on
330 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
333 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
334 /* failure: DLL could not be loaded */
335 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
338 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
339 /* Note: failing to find DllCanUnloadNow is not a failure */
340 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
341 if (!DllGetClassObject
)
343 /* failure: the dll did not export DllGetClassObject */
344 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
345 FreeLibrary(hLibrary
);
346 return CO_E_DLLNOTFOUND
;
349 EnterCriticalSection( &csOpenDllList
);
351 *ret
= COMPOBJ_DllList_Get(library_name
);
354 /* another caller to this function already added the dll while we
355 * weren't in the critical section */
356 FreeLibrary(hLibrary
);
360 len
= strlenW(library_name
);
361 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
363 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
364 if (entry
&& entry
->library_name
)
366 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
367 entry
->library
= hLibrary
;
369 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
370 entry
->DllGetClassObject
= DllGetClassObject
;
371 list_add_tail(&openDllList
, &entry
->entry
);
376 HeapFree(GetProcessHeap(), 0, entry
);
378 FreeLibrary(hLibrary
);
382 LeaveCriticalSection( &csOpenDllList
);
387 /* pass FALSE for free_entry to release a reference without destroying the
388 * entry if it reaches zero or TRUE otherwise */
389 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
391 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
393 EnterCriticalSection(&csOpenDllList
);
394 list_remove(&entry
->entry
);
395 LeaveCriticalSection(&csOpenDllList
);
397 TRACE("freeing %p\n", entry
->library
);
398 FreeLibrary(entry
->library
);
400 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
401 HeapFree(GetProcessHeap(), 0, entry
);
405 /* frees memory associated with active dll list */
406 static void COMPOBJ_DllList_Free(void)
408 OpenDll
*entry
, *cursor2
;
409 EnterCriticalSection(&csOpenDllList
);
410 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
412 list_remove(&entry
->entry
);
414 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
415 HeapFree(GetProcessHeap(), 0, entry
);
417 LeaveCriticalSection(&csOpenDllList
);
418 DeleteCriticalSection(&csOpenDllList
);
421 /******************************************************************************
425 static DWORD
apartment_addref(struct apartment
*apt
)
427 DWORD refs
= InterlockedIncrement(&apt
->refs
);
428 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
432 /* allocates memory and fills in the necessary fields for a new apartment
433 * object. must be called inside apartment cs */
434 static APARTMENT
*apartment_construct(DWORD model
)
438 TRACE("creating new apartment, model=%d\n", model
);
440 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
441 apt
->tid
= GetCurrentThreadId();
443 list_init(&apt
->proxies
);
444 list_init(&apt
->stubmgrs
);
445 list_init(&apt
->psclsids
);
446 list_init(&apt
->loaded_dlls
);
449 apt
->remunk_exported
= FALSE
;
451 InitializeCriticalSection(&apt
->cs
);
452 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
454 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
456 if (apt
->multi_threaded
)
458 /* FIXME: should be randomly generated by in an RPC call to rpcss */
459 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
463 /* FIXME: should be randomly generated by in an RPC call to rpcss */
464 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
467 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
469 list_add_head(&apts
, &apt
->entry
);
474 /* gets and existing apartment if one exists or otherwise creates an apartment
475 * structure which stores OLE apartment-local information and stores a pointer
476 * to it in the thread-local storage */
477 static APARTMENT
*apartment_get_or_create(DWORD model
)
479 APARTMENT
*apt
= COM_CurrentApt();
483 if (model
& COINIT_APARTMENTTHREADED
)
485 EnterCriticalSection(&csApartment
);
487 apt
= apartment_construct(model
);
492 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
495 LeaveCriticalSection(&csApartment
);
498 apartment_createwindowifneeded(apt
);
502 EnterCriticalSection(&csApartment
);
504 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
505 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
509 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
510 apartment_addref(MTA
);
513 MTA
= apartment_construct(model
);
517 LeaveCriticalSection(&csApartment
);
519 COM_CurrentInfo()->apt
= apt
;
525 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
527 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
530 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
532 list_remove(&curClass
->entry
);
534 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
535 RPC_StopLocalServer(curClass
->RpcRegistration
);
537 IUnknown_Release(curClass
->classObject
);
538 HeapFree(GetProcessHeap(), 0, curClass
);
541 static void COM_RevokeAllClasses(const struct apartment
*apt
)
543 RegisteredClass
*curClass
, *cursor
;
545 EnterCriticalSection( &csRegisteredClassList
);
547 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
549 if (curClass
->apartment_id
== apt
->oxid
)
550 COM_RevokeRegisteredClassObject(curClass
);
553 LeaveCriticalSection( &csRegisteredClassList
);
556 /******************************************************************************
557 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
560 typedef struct ManualResetEvent
{
561 ISynchronize ISynchronize_iface
;
562 ISynchronizeHandle ISynchronizeHandle_iface
;
567 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
569 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
572 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
574 MREImpl
*This
= impl_from_ISynchronize(iface
);
576 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
578 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
579 *ppv
= &This
->ISynchronize_iface
;
580 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
581 *ppv
= &This
->ISynchronizeHandle_iface
;
583 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
585 return E_NOINTERFACE
;
588 IUnknown_AddRef((IUnknown
*)*ppv
);
592 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
594 MREImpl
*This
= impl_from_ISynchronize(iface
);
595 LONG ref
= InterlockedIncrement(&This
->ref
);
596 TRACE("%p - ref %d\n", This
, ref
);
601 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
603 MREImpl
*This
= impl_from_ISynchronize(iface
);
604 LONG ref
= InterlockedDecrement(&This
->ref
);
605 TRACE("%p - ref %d\n", This
, ref
);
609 CloseHandle(This
->event
);
610 HeapFree(GetProcessHeap(), 0, This
);
616 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
618 MREImpl
*This
= impl_from_ISynchronize(iface
);
620 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
621 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
624 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
626 MREImpl
*This
= impl_from_ISynchronize(iface
);
628 SetEvent(This
->event
);
632 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
634 MREImpl
*This
= impl_from_ISynchronize(iface
);
636 ResetEvent(This
->event
);
640 static ISynchronizeVtbl vt_ISynchronize
= {
641 ISynchronize_fnQueryInterface
,
642 ISynchronize_fnAddRef
,
643 ISynchronize_fnRelease
,
645 ISynchronize_fnSignal
,
649 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
651 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
654 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
656 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
657 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
660 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
662 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
663 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
666 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
668 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
669 return ISynchronize_Release(&This
->ISynchronize_iface
);
672 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
674 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
680 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
681 SynchronizeHandle_QueryInterface
,
682 SynchronizeHandle_AddRef
,
683 SynchronizeHandle_Release
,
684 SynchronizeHandle_GetHandle
687 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
689 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
693 FIXME("Aggregation not implemented.\n");
696 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
697 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
698 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
700 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
701 ISynchronize_Release(&This
->ISynchronize_iface
);
705 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
707 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
710 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
712 LocalServer
*This
= impl_from_IServiceProvider(iface
);
714 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
716 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
717 *ppv
= &This
->IServiceProvider_iface
;
720 return E_NOINTERFACE
;
723 IUnknown_AddRef((IUnknown
*)*ppv
);
727 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
729 LocalServer
*This
= impl_from_IServiceProvider(iface
);
730 LONG ref
= InterlockedIncrement(&This
->ref
);
732 TRACE("(%p) ref=%d\n", This
, ref
);
737 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
739 LocalServer
*This
= impl_from_IServiceProvider(iface
);
740 LONG ref
= InterlockedDecrement(&This
->ref
);
742 TRACE("(%p) ref=%d\n", This
, ref
);
746 HeapFree(GetProcessHeap(), 0, This
);
752 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
754 LocalServer
*This
= impl_from_IServiceProvider(iface
);
755 APARTMENT
*apt
= COM_CurrentApt();
756 RegisteredClass
*iter
;
757 HRESULT hres
= E_FAIL
;
759 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
764 EnterCriticalSection(&csRegisteredClassList
);
766 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
767 if(iter
->apartment_id
== apt
->oxid
768 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
769 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
770 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
775 LeaveCriticalSection( &csRegisteredClassList
);
780 static const IServiceProviderVtbl LocalServerVtbl
= {
781 LocalServer_QueryInterface
,
784 LocalServer_QueryService
787 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
791 EnterCriticalSection(&apt
->cs
);
793 if(!apt
->local_server
) {
796 obj
= heap_alloc(sizeof(*obj
));
798 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
802 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
803 if(SUCCEEDED(hres
)) {
804 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
805 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
807 IStream_Release(obj
->marshal_stream
);
811 apt
->local_server
= obj
;
815 hres
= E_OUTOFMEMORY
;
820 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
822 LeaveCriticalSection(&apt
->cs
);
825 ERR("Failed: %08x\n", hres
);
829 /***********************************************************************
830 * CoRevokeClassObject [OLE32.@]
832 * Removes a class object from the class registry.
835 * dwRegister [I] Cookie returned from CoRegisterClassObject().
839 * Failure: HRESULT code.
842 * Must be called from the same apartment that called CoRegisterClassObject(),
843 * otherwise it will fail with RPC_E_WRONG_THREAD.
846 * CoRegisterClassObject
848 HRESULT WINAPI
CoRevokeClassObject(
851 HRESULT hr
= E_INVALIDARG
;
852 RegisteredClass
*curClass
;
855 TRACE("(%08x)\n",dwRegister
);
857 apt
= COM_CurrentApt();
860 ERR("COM was not initialized\n");
861 return CO_E_NOTINITIALIZED
;
864 EnterCriticalSection( &csRegisteredClassList
);
866 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
869 * Check if we have a match on the cookie.
871 if (curClass
->dwCookie
== dwRegister
)
873 if (curClass
->apartment_id
== apt
->oxid
)
875 COM_RevokeRegisteredClassObject(curClass
);
880 ERR("called from wrong apartment, should be called from %s\n",
881 wine_dbgstr_longlong(curClass
->apartment_id
));
882 hr
= RPC_E_WRONG_THREAD
;
888 LeaveCriticalSection( &csRegisteredClassList
);
893 /* frees unused libraries loaded by apartment_getclassobject by calling the
894 * DLL's DllCanUnloadNow entry point */
895 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
897 struct apartment_loaded_dll
*entry
, *next
;
898 EnterCriticalSection(&apt
->cs
);
899 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
901 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
903 DWORD real_delay
= delay
;
905 if (real_delay
== INFINITE
)
907 /* DLLs that return multi-threaded objects aren't unloaded
908 * straight away to cope for programs that have races between
909 * last object destruction and threads in the DLLs that haven't
910 * finished, despite DllCanUnloadNow returning S_OK */
911 if (entry
->multi_threaded
)
912 real_delay
= 10 * 60 * 1000; /* 10 minutes */
917 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
919 list_remove(&entry
->entry
);
920 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
921 HeapFree(GetProcessHeap(), 0, entry
);
925 entry
->unload_time
= GetTickCount() + real_delay
;
926 if (!entry
->unload_time
) entry
->unload_time
= 1;
929 else if (entry
->unload_time
)
930 entry
->unload_time
= 0;
932 LeaveCriticalSection(&apt
->cs
);
935 DWORD
apartment_release(struct apartment
*apt
)
939 EnterCriticalSection(&csApartment
);
941 ret
= InterlockedDecrement(&apt
->refs
);
942 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
943 /* destruction stuff that needs to happen under csApartment CS */
946 if (apt
== MTA
) MTA
= NULL
;
947 else if (apt
== MainApartment
) MainApartment
= NULL
;
948 list_remove(&apt
->entry
);
951 LeaveCriticalSection(&csApartment
);
955 struct list
*cursor
, *cursor2
;
957 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
959 if(apt
->local_server
) {
960 LocalServer
*local_server
= apt
->local_server
;
963 memset(&zero
, 0, sizeof(zero
));
964 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
965 CoReleaseMarshalData(local_server
->marshal_stream
);
966 IStream_Release(local_server
->marshal_stream
);
967 local_server
->marshal_stream
= NULL
;
969 apt
->local_server
= NULL
;
970 local_server
->apt
= NULL
;
971 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
974 /* Release the references to the registered class objects */
975 COM_RevokeAllClasses(apt
);
977 /* no locking is needed for this apartment, because no other thread
978 * can access it at this point */
980 apartment_disconnectproxies(apt
);
982 if (apt
->win
) DestroyWindow(apt
->win
);
983 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
985 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
987 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
988 /* release the implicit reference given by the fact that the
989 * stub has external references (it must do since it is in the
990 * stub manager list in the apartment and all non-apartment users
991 * must have a ref on the apartment and so it cannot be destroyed).
993 stub_manager_int_release(stubmgr
);
996 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
998 struct registered_psclsid
*registered_psclsid
=
999 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1001 list_remove(®istered_psclsid
->entry
);
1002 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1005 /* if this assert fires, then another thread took a reference to a
1006 * stub manager without taking a reference to the containing
1007 * apartment, which it must do. */
1008 assert(list_empty(&apt
->stubmgrs
));
1010 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1012 /* free as many unused libraries as possible... */
1013 apartment_freeunusedlibraries(apt
, 0);
1015 /* ... and free the memory for the apartment loaded dll entry and
1016 * release the dll list reference without freeing the library for the
1018 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1020 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1021 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1022 list_remove(cursor
);
1023 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1026 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1027 DeleteCriticalSection(&apt
->cs
);
1029 HeapFree(GetProcessHeap(), 0, apt
);
1035 /* The given OXID must be local to this process:
1037 * The ref parameter is here mostly to ensure people remember that
1038 * they get one, you should normally take a ref for thread safety.
1040 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1042 APARTMENT
*result
= NULL
;
1043 struct list
*cursor
;
1045 EnterCriticalSection(&csApartment
);
1046 LIST_FOR_EACH( cursor
, &apts
)
1048 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1049 if (apt
->oxid
== oxid
)
1052 if (ref
) apartment_addref(result
);
1056 LeaveCriticalSection(&csApartment
);
1061 /* gets the apartment which has a given creator thread ID. The caller must
1062 * release the reference from the apartment as soon as the apartment pointer
1063 * is no longer required. */
1064 APARTMENT
*apartment_findfromtid(DWORD tid
)
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
->tid
== tid
)
1076 apartment_addref(result
);
1080 LeaveCriticalSection(&csApartment
);
1085 /* gets the main apartment if it exists. The caller must
1086 * release the reference from the apartment as soon as the apartment pointer
1087 * is no longer required. */
1088 static APARTMENT
*apartment_findmain(void)
1092 EnterCriticalSection(&csApartment
);
1094 result
= MainApartment
;
1095 if (result
) apartment_addref(result
);
1097 LeaveCriticalSection(&csApartment
);
1102 /* gets the multi-threaded apartment if it exists. The caller must
1103 * release the reference from the apartment as soon as the apartment pointer
1104 * is no longer required. */
1105 static APARTMENT
*apartment_find_multi_threaded(void)
1107 APARTMENT
*result
= NULL
;
1108 struct list
*cursor
;
1110 EnterCriticalSection(&csApartment
);
1112 LIST_FOR_EACH( cursor
, &apts
)
1114 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1115 if (apt
->multi_threaded
)
1118 apartment_addref(result
);
1123 LeaveCriticalSection(&csApartment
);
1127 /* gets the specified class object by loading the appropriate DLL, if
1128 * necessary and calls the DllGetClassObject function for the DLL */
1129 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1130 BOOL apartment_threaded
,
1131 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1133 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1136 struct apartment_loaded_dll
*apartment_loaded_dll
;
1138 if (!strcmpiW(dllpath
, wszOle32
))
1140 /* we don't need to control the lifetime of this dll, so use the local
1141 * implementation of DllGetClassObject directly */
1142 TRACE("calling ole32!DllGetClassObject\n");
1143 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1146 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1151 EnterCriticalSection(&apt
->cs
);
1153 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1154 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1156 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1163 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1164 if (!apartment_loaded_dll
)
1168 apartment_loaded_dll
->unload_time
= 0;
1169 apartment_loaded_dll
->multi_threaded
= FALSE
;
1170 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1172 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1176 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1177 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1181 LeaveCriticalSection(&apt
->cs
);
1185 /* one component being multi-threaded overrides any number of
1186 * apartment-threaded components */
1187 if (!apartment_threaded
)
1188 apartment_loaded_dll
->multi_threaded
= TRUE
;
1190 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1191 /* OK: get the ClassObject */
1192 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1195 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1201 /***********************************************************************
1202 * COM_RegReadPath [internal]
1204 * Reads a registry value and expands it when necessary
1206 static DWORD
COM_RegReadPath(HKEY hkeyroot
, WCHAR
* dst
, DWORD dstlen
)
1210 WCHAR src
[MAX_PATH
];
1211 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1213 if( (ret
= RegQueryValueExW(hkeyroot
, NULL
, NULL
, &keytype
, (LPBYTE
)src
, &dwLength
)) == ERROR_SUCCESS
) {
1214 if (keytype
== REG_EXPAND_SZ
) {
1215 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1217 const WCHAR
*quote_start
;
1218 quote_start
= strchrW(src
, '\"');
1220 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1222 memmove(src
, quote_start
+ 1,
1223 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1224 src
[quote_end
- quote_start
- 1] = '\0';
1227 lstrcpynW(dst
, src
, dstlen
);
1233 struct host_object_params
1236 CLSID clsid
; /* clsid of object to marshal */
1237 IID iid
; /* interface to marshal */
1238 HANDLE event
; /* event signalling when ready for multi-threaded case */
1239 HRESULT hr
; /* result for multi-threaded case */
1240 IStream
*stream
; /* stream that the object will be marshaled into */
1241 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1244 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1245 const struct host_object_params
*params
)
1249 static const LARGE_INTEGER llZero
;
1250 WCHAR dllpath
[MAX_PATH
+1];
1252 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1254 if (COM_RegReadPath(params
->hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1256 /* failure: CLSID is not found in registry */
1257 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1258 return REGDB_E_CLASSNOTREG
;
1261 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1262 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1266 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1268 IUnknown_Release(object
);
1269 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1274 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1279 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1282 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1284 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1288 struct host_thread_params
1290 COINIT threading_model
;
1292 HWND apartment_hwnd
;
1295 /* thread for hosting an object to allow an object to appear to be created in
1296 * an apartment with an incompatible threading model */
1297 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1299 struct host_thread_params
*params
= p
;
1302 struct apartment
*apt
;
1306 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1307 if (FAILED(hr
)) return hr
;
1309 apt
= COM_CurrentApt();
1310 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1312 apartment_createwindowifneeded(apt
);
1313 params
->apartment_hwnd
= apartment_getwindow(apt
);
1316 params
->apartment_hwnd
= NULL
;
1318 /* force the message queue to be created before signaling parent thread */
1319 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1321 SetEvent(params
->ready_event
);
1322 params
= NULL
; /* can't touch params after here as it may be invalid */
1324 while (GetMessageW(&msg
, NULL
, 0, 0))
1326 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1328 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1329 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1330 SetEvent(obj_params
->event
);
1334 TranslateMessage(&msg
);
1335 DispatchMessageW(&msg
);
1346 /* finds or creates a host apartment, creates the object inside it and returns
1347 * a proxy to it so that the object can be used in the apartment of the
1348 * caller of this function */
1349 static HRESULT
apartment_hostobject_in_hostapt(
1350 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1351 HKEY hkeydll
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1353 struct host_object_params params
;
1354 HWND apartment_hwnd
= NULL
;
1355 DWORD apartment_tid
= 0;
1358 if (!multi_threaded
&& main_apartment
)
1360 APARTMENT
*host_apt
= apartment_findmain();
1363 apartment_hwnd
= apartment_getwindow(host_apt
);
1364 apartment_release(host_apt
);
1368 if (!apartment_hwnd
)
1370 EnterCriticalSection(&apt
->cs
);
1372 if (!apt
->host_apt_tid
)
1374 struct host_thread_params thread_params
;
1378 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1379 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1380 thread_params
.apartment_hwnd
= NULL
;
1381 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1384 CloseHandle(handles
[0]);
1385 LeaveCriticalSection(&apt
->cs
);
1386 return E_OUTOFMEMORY
;
1388 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1389 CloseHandle(handles
[0]);
1390 CloseHandle(handles
[1]);
1391 if (wait_value
== WAIT_OBJECT_0
)
1392 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1395 LeaveCriticalSection(&apt
->cs
);
1396 return E_OUTOFMEMORY
;
1400 if (multi_threaded
|| !main_apartment
)
1402 apartment_hwnd
= apt
->host_apt_hwnd
;
1403 apartment_tid
= apt
->host_apt_tid
;
1406 LeaveCriticalSection(&apt
->cs
);
1409 /* another thread may have become the main apartment in the time it took
1410 * us to create the thread for the host apartment */
1411 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1413 APARTMENT
*host_apt
= apartment_findmain();
1416 apartment_hwnd
= apartment_getwindow(host_apt
);
1417 apartment_release(host_apt
);
1421 params
.hkeydll
= hkeydll
;
1422 params
.clsid
= *rclsid
;
1424 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1427 params
.apartment_threaded
= !multi_threaded
;
1431 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1432 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1436 WaitForSingleObject(params
.event
, INFINITE
);
1439 CloseHandle(params
.event
);
1443 if (!apartment_hwnd
)
1445 ERR("host apartment didn't create window\n");
1449 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1452 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1453 IStream_Release(params
.stream
);
1457 /* create a window for the apartment or return the current one if one has
1458 * already been created */
1459 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1461 if (apt
->multi_threaded
)
1466 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
1468 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1471 ERR("CreateWindow failed with error %d\n", GetLastError());
1472 return HRESULT_FROM_WIN32(GetLastError());
1474 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1475 /* someone beat us to it */
1476 DestroyWindow(hwnd
);
1482 /* retrieves the window for the main- or apartment-threaded apartment */
1483 HWND
apartment_getwindow(const struct apartment
*apt
)
1485 assert(!apt
->multi_threaded
);
1489 void apartment_joinmta(void)
1491 apartment_addref(MTA
);
1492 COM_CurrentInfo()->apt
= MTA
;
1495 static void COMPOBJ_InitProcess( void )
1499 /* Dispatching to the correct thread in an apartment is done through
1500 * window messages rather than RPC transports. When an interface is
1501 * marshalled into another apartment in the same process, a window of the
1502 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1503 * application) is responsible for pumping the message loop in that thread.
1504 * The WM_USER messages which point to the RPCs are then dispatched to
1505 * apartment_wndproc by the user's code from the apartment in which the
1506 * interface was unmarshalled.
1508 memset(&wclass
, 0, sizeof(wclass
));
1509 wclass
.lpfnWndProc
= apartment_wndproc
;
1510 wclass
.hInstance
= hProxyDll
;
1511 wclass
.lpszClassName
= wszAptWinClass
;
1512 RegisterClassW(&wclass
);
1515 static void COMPOBJ_UninitProcess( void )
1517 UnregisterClassW(wszAptWinClass
, hProxyDll
);
1520 static void COM_TlsDestroy(void)
1522 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1525 if (info
->apt
) apartment_release(info
->apt
);
1526 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1527 if (info
->state
) IUnknown_Release(info
->state
);
1528 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1529 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1530 HeapFree(GetProcessHeap(), 0, info
);
1531 NtCurrentTeb()->ReservedForOle
= NULL
;
1535 /******************************************************************************
1536 * CoBuildVersion [OLE32.@]
1538 * Gets the build version of the DLL.
1543 * Current build version, hiword is majornumber, loword is minornumber
1545 DWORD WINAPI
CoBuildVersion(void)
1547 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1548 return (rmm
<<16)+rup
;
1551 /******************************************************************************
1552 * CoRegisterInitializeSpy [OLE32.@]
1554 * Add a Spy that watches CoInitializeEx calls
1557 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1558 * cookie [II] cookie receiver
1561 * Success: S_OK if not already initialized, S_FALSE otherwise.
1562 * Failure: HRESULT code.
1567 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1569 struct oletls
*info
= COM_CurrentInfo();
1572 TRACE("(%p, %p)\n", spy
, cookie
);
1574 if (!spy
|| !cookie
|| !info
)
1577 WARN("Could not allocate tls\n");
1578 return E_INVALIDARG
;
1583 FIXME("Already registered?\n");
1584 return E_UNEXPECTED
;
1587 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1590 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1596 /******************************************************************************
1597 * CoRevokeInitializeSpy [OLE32.@]
1599 * Remove a spy that previously watched CoInitializeEx calls
1602 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1605 * Success: S_OK if a spy is removed
1606 * Failure: E_INVALIDARG
1611 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1613 struct oletls
*info
= COM_CurrentInfo();
1614 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1616 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1617 return E_INVALIDARG
;
1619 IInitializeSpy_Release(info
->spy
);
1625 /******************************************************************************
1626 * CoInitialize [OLE32.@]
1628 * Initializes the COM libraries by calling CoInitializeEx with
1629 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1632 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1635 * Success: S_OK if not already initialized, S_FALSE otherwise.
1636 * Failure: HRESULT code.
1641 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1644 * Just delegate to the newer method.
1646 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1649 /******************************************************************************
1650 * CoInitializeEx [OLE32.@]
1652 * Initializes the COM libraries.
1655 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1656 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1659 * S_OK if successful,
1660 * S_FALSE if this function was called already.
1661 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1666 * The behavior used to set the IMalloc used for memory management is
1668 * The dwCoInit parameter must specify one of the following apartment
1670 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1671 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1672 * The parameter may also specify zero or more of the following flags:
1673 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1674 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1679 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1681 struct oletls
*info
= COM_CurrentInfo();
1685 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1687 if (lpReserved
!=NULL
)
1689 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1693 * Check the lock count. If this is the first time going through the initialize
1694 * process, we have to initialize the libraries.
1696 * And crank-up that lock count.
1698 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1701 * Initialize the various COM libraries and data structures.
1703 TRACE("() - Initializing the COM libraries\n");
1705 /* we may need to defer this until after apartment initialisation */
1706 RunningObjectTableImpl_Initialize();
1710 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1712 if (!(apt
= info
->apt
))
1714 apt
= apartment_get_or_create(dwCoInit
);
1715 if (!apt
) return E_OUTOFMEMORY
;
1717 else if (!apartment_is_model(apt
, dwCoInit
))
1719 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1720 code then we are probably using the wrong threading model to implement that API. */
1721 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1722 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1723 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1724 return RPC_E_CHANGED_MODE
;
1732 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1737 /***********************************************************************
1738 * CoUninitialize [OLE32.@]
1740 * This method will decrement the refcount on the current apartment, freeing
1741 * the resources associated with it if it is the last thread in the apartment.
1742 * If the last apartment is freed, the function will additionally release
1743 * any COM resources associated with the process.
1753 void WINAPI
CoUninitialize(void)
1755 struct oletls
* info
= COM_CurrentInfo();
1760 /* will only happen on OOM */
1764 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1769 ERR("Mismatched CoUninitialize\n");
1772 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1778 apartment_release(info
->apt
);
1783 * Decrease the reference count.
1784 * If we are back to 0 locks on the COM library, make sure we free
1785 * all the associated data structures.
1787 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1790 TRACE("() - Releasing the COM libraries\n");
1792 RunningObjectTableImpl_UnInitialize();
1794 else if (lCOMRefCnt
<1) {
1795 ERR( "CoUninitialize() - not CoInitialized.\n" );
1796 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1799 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1802 /******************************************************************************
1803 * CoDisconnectObject [OLE32.@]
1805 * Disconnects all connections to this object from remote processes. Dispatches
1806 * pending RPCs while blocking new RPCs from occurring, and then calls
1807 * IMarshal::DisconnectObject on the given object.
1809 * Typically called when the object server is forced to shut down, for instance by
1813 * lpUnk [I] The object whose stub should be disconnected.
1814 * reserved [I] Reserved. Should be set to 0.
1818 * Failure: HRESULT code.
1821 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1823 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
1829 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
1831 if (!lpUnk
) return E_INVALIDARG
;
1833 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
1836 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
1837 IMarshal_Release(marshal
);
1841 apt
= COM_CurrentApt();
1843 return CO_E_NOTINITIALIZED
;
1845 apartment_disconnectobject(apt
, lpUnk
);
1847 /* Note: native is pretty broken here because it just silently
1848 * fails, without returning an appropriate error code if the object was
1849 * not found, making apps think that the object was disconnected, when
1850 * it actually wasn't */
1855 /******************************************************************************
1856 * CoCreateGuid [OLE32.@]
1858 * Simply forwards to UuidCreate in RPCRT4.
1861 * pguid [O] Points to the GUID to initialize.
1865 * Failure: HRESULT code.
1870 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
1872 DWORD status
= UuidCreate(pguid
);
1873 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
1874 return HRESULT_FROM_WIN32( status
);
1877 static inline BOOL
is_valid_hex(WCHAR c
)
1879 if (!(((c
>= '0') && (c
<= '9')) ||
1880 ((c
>= 'a') && (c
<= 'f')) ||
1881 ((c
>= 'A') && (c
<= 'F'))))
1886 /******************************************************************************
1887 * CLSIDFromString [OLE32.@]
1888 * IIDFromString [OLE32.@]
1890 * Converts a unique identifier from its string representation into
1894 * idstr [I] The string representation of the GUID.
1895 * id [O] GUID converted from the string.
1899 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1904 static HRESULT
__CLSIDFromString(LPCWSTR s
, LPCLSID id
)
1909 if (!s
|| s
[0]!='{') {
1910 memset( id
, 0, sizeof (CLSID
) );
1912 return CO_E_CLASSSTRING
;
1915 TRACE("%s -> %p\n", debugstr_w(s
), id
);
1917 /* quick lookup table */
1918 memset(table
, 0, 256);
1920 for (i
= 0; i
< 10; i
++) {
1923 for (i
= 0; i
< 6; i
++) {
1924 table
['A' + i
] = i
+10;
1925 table
['a' + i
] = i
+10;
1928 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1931 for (i
= 1; i
< 9; i
++) {
1932 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1933 id
->Data1
= (id
->Data1
<< 4) | table
[s
[i
]];
1935 if (s
[9]!='-') return CO_E_CLASSSTRING
;
1938 for (i
= 10; i
< 14; i
++) {
1939 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1940 id
->Data2
= (id
->Data2
<< 4) | table
[s
[i
]];
1942 if (s
[14]!='-') return CO_E_CLASSSTRING
;
1945 for (i
= 15; i
< 19; i
++) {
1946 if (!is_valid_hex(s
[i
])) return CO_E_CLASSSTRING
;
1947 id
->Data3
= (id
->Data3
<< 4) | table
[s
[i
]];
1949 if (s
[19]!='-') return CO_E_CLASSSTRING
;
1951 for (i
= 20; i
< 37; i
+=2) {
1953 if (s
[i
]!='-') return CO_E_CLASSSTRING
;
1956 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return CO_E_CLASSSTRING
;
1957 id
->Data4
[(i
-20)/2] = table
[s
[i
]] << 4 | table
[s
[i
+1]];
1960 if (s
[37] == '}' && s
[38] == '\0')
1963 return CO_E_CLASSSTRING
;
1966 /*****************************************************************************/
1968 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
1973 return E_INVALIDARG
;
1975 ret
= __CLSIDFromString(idstr
, id
);
1976 if(ret
!= S_OK
) { /* It appears a ProgID is also valid */
1978 ret
= CLSIDFromProgID(idstr
, &tmp_id
);
1986 /******************************************************************************
1987 * StringFromCLSID [OLE32.@]
1988 * StringFromIID [OLE32.@]
1990 * Converts a GUID into the respective string representation.
1991 * The target string is allocated using the OLE IMalloc.
1994 * id [I] the GUID to be converted.
1995 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2002 * StringFromGUID2, CLSIDFromString
2004 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2009 if ((ret
= CoGetMalloc(0,&mllc
))) return ret
;
2010 if (!(*idstr
= IMalloc_Alloc( mllc
, CHARS_IN_GUID
* sizeof(WCHAR
) ))) return E_OUTOFMEMORY
;
2011 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2015 /******************************************************************************
2016 * StringFromGUID2 [OLE32.@]
2018 * Modified version of StringFromCLSID that allows you to specify max
2022 * id [I] GUID to convert to string.
2023 * str [O] Buffer where the result will be stored.
2024 * cmax [I] Size of the buffer in characters.
2027 * Success: The length of the resulting string in characters.
2030 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2032 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2033 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2034 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2035 '%','0','2','X','%','0','2','X','}',0 };
2036 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2037 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2038 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2039 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2040 return CHARS_IN_GUID
;
2043 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2044 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2046 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2047 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2051 strcpyW(path
, wszCLSIDSlash
);
2052 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2053 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2054 if (res
== ERROR_FILE_NOT_FOUND
)
2055 return REGDB_E_CLASSNOTREG
;
2056 else if (res
!= ERROR_SUCCESS
)
2057 return REGDB_E_READREGDB
;
2065 res
= open_classes_key(key
, keyname
, access
, subkey
);
2067 if (res
== ERROR_FILE_NOT_FOUND
)
2068 return REGDB_E_KEYMISSING
;
2069 else if (res
!= ERROR_SUCCESS
)
2070 return REGDB_E_READREGDB
;
2075 /* open HKCR\\AppId\\{string form of appid clsid} key */
2076 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2078 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2079 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2081 WCHAR buf
[CHARS_IN_GUID
];
2082 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2088 /* read the AppID value under the class's key */
2089 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2094 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2096 if (res
== ERROR_FILE_NOT_FOUND
)
2097 return REGDB_E_KEYMISSING
;
2098 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2099 return REGDB_E_READREGDB
;
2101 strcpyW(keyname
, szAppIdKey
);
2102 strcatW(keyname
, buf
);
2103 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2104 if (res
== ERROR_FILE_NOT_FOUND
)
2105 return REGDB_E_KEYMISSING
;
2106 else if (res
!= ERROR_SUCCESS
)
2107 return REGDB_E_READREGDB
;
2112 /******************************************************************************
2113 * ProgIDFromCLSID [OLE32.@]
2115 * Converts a class id into the respective program ID.
2118 * clsid [I] Class ID, as found in registry.
2119 * ppszProgID [O] Associated ProgID.
2124 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2126 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2128 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2135 ERR("ppszProgId isn't optional\n");
2136 return E_INVALIDARG
;
2140 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2144 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2145 ret
= REGDB_E_CLASSNOTREG
;
2149 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2152 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2153 ret
= REGDB_E_CLASSNOTREG
;
2154 CoTaskMemFree(*ppszProgID
);
2159 ret
= E_OUTOFMEMORY
;
2166 /******************************************************************************
2167 * CLSIDFromProgID [OLE32.@]
2169 * Converts a program id into the respective GUID.
2172 * progid [I] Unicode program ID, as found in registry.
2173 * clsid [O] Associated CLSID.
2177 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2179 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2181 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2182 WCHAR buf2
[CHARS_IN_GUID
];
2183 LONG buf2len
= sizeof(buf2
);
2187 if (!progid
|| !clsid
)
2189 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid
, clsid
);
2190 return E_INVALIDARG
;
2193 /* initialise clsid in case of failure */
2194 memset(clsid
, 0, sizeof(*clsid
));
2196 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2197 strcpyW( buf
, progid
);
2198 strcatW( buf
, clsidW
);
2199 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2201 HeapFree(GetProcessHeap(),0,buf
);
2202 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2203 return CO_E_CLASSSTRING
;
2205 HeapFree(GetProcessHeap(),0,buf
);
2207 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2210 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2211 return CO_E_CLASSSTRING
;
2214 return __CLSIDFromString(buf2
,clsid
);
2217 /******************************************************************************
2218 * CLSIDFromProgIDEx [OLE32.@]
2220 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2222 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2224 return CLSIDFromProgID(progid
, clsid
);
2227 /*****************************************************************************
2228 * CoGetPSClsid [OLE32.@]
2230 * Retrieves the CLSID of the proxy/stub factory that implements
2231 * IPSFactoryBuffer for the specified interface.
2234 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2235 * pclsid [O] Where to store returned proxy/stub CLSID.
2240 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2244 * The standard marshaller activates the object with the CLSID
2245 * returned and uses the CreateProxy and CreateStub methods on its
2246 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2249 * CoGetPSClsid determines this CLSID by searching the
2250 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2251 * in the registry and any interface id registered by
2252 * CoRegisterPSClsid within the current process.
2256 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2257 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2258 * considered a bug in native unless an application depends on this (unlikely).
2261 * CoRegisterPSClsid.
2263 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2265 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2266 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2267 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2268 WCHAR value
[CHARS_IN_GUID
];
2271 APARTMENT
*apt
= COM_CurrentApt();
2272 struct registered_psclsid
*registered_psclsid
;
2274 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2278 ERR("apartment not initialised\n");
2279 return CO_E_NOTINITIALIZED
;
2284 ERR("pclsid isn't optional\n");
2285 return E_INVALIDARG
;
2288 EnterCriticalSection(&apt
->cs
);
2290 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2291 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2293 *pclsid
= registered_psclsid
->clsid
;
2294 LeaveCriticalSection(&apt
->cs
);
2298 LeaveCriticalSection(&apt
->cs
);
2300 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2301 strcpyW(path
, wszInterface
);
2302 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2303 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2305 /* Open the key.. */
2306 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2308 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2309 return REGDB_E_IIDNOTREG
;
2312 /* ... Once we have the key, query the registry to get the
2313 value of CLSID as a string, and convert it into a
2314 proper CLSID structure to be passed back to the app */
2315 len
= sizeof(value
);
2316 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2319 return REGDB_E_IIDNOTREG
;
2323 /* We have the CLSID we want back from the registry as a string, so
2324 let's convert it into a CLSID structure */
2325 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2326 return REGDB_E_IIDNOTREG
;
2328 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2332 /*****************************************************************************
2333 * CoRegisterPSClsid [OLE32.@]
2335 * Register a proxy/stub CLSID for the given interface in the current process
2339 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2340 * rclsid [I] CLSID of the proxy/stub.
2344 * Failure: E_OUTOFMEMORY
2348 * This function does not add anything to the registry and the effects are
2349 * limited to the lifetime of the current process.
2354 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2356 APARTMENT
*apt
= COM_CurrentApt();
2357 struct registered_psclsid
*registered_psclsid
;
2359 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2363 ERR("apartment not initialised\n");
2364 return CO_E_NOTINITIALIZED
;
2367 EnterCriticalSection(&apt
->cs
);
2369 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2370 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2372 registered_psclsid
->clsid
= *rclsid
;
2373 LeaveCriticalSection(&apt
->cs
);
2377 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2378 if (!registered_psclsid
)
2380 LeaveCriticalSection(&apt
->cs
);
2381 return E_OUTOFMEMORY
;
2384 registered_psclsid
->iid
= *riid
;
2385 registered_psclsid
->clsid
= *rclsid
;
2386 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2388 LeaveCriticalSection(&apt
->cs
);
2395 * COM_GetRegisteredClassObject
2397 * This internal method is used to scan the registered class list to
2398 * find a class object.
2401 * rclsid Class ID of the class to find.
2402 * dwClsContext Class context to match.
2403 * ppv [out] returns a pointer to the class object. Complying
2404 * to normal COM usage, this method will increase the
2405 * reference count on this object.
2407 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2408 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2410 HRESULT hr
= S_FALSE
;
2411 RegisteredClass
*curClass
;
2413 EnterCriticalSection( &csRegisteredClassList
);
2415 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2418 * Check if we have a match on the class ID and context.
2420 if ((apt
->oxid
== curClass
->apartment_id
) &&
2421 (dwClsContext
& curClass
->runContext
) &&
2422 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2425 * We have a match, return the pointer to the class object.
2427 *ppUnk
= curClass
->classObject
;
2429 IUnknown_AddRef(curClass
->classObject
);
2436 LeaveCriticalSection( &csRegisteredClassList
);
2441 /******************************************************************************
2442 * CoRegisterClassObject [OLE32.@]
2444 * Registers the class object for a given class ID. Servers housed in EXE
2445 * files use this method instead of exporting DllGetClassObject to allow
2446 * other code to connect to their objects.
2449 * rclsid [I] CLSID of the object to register.
2450 * pUnk [I] IUnknown of the object.
2451 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2452 * flags [I] REGCLS flags indicating how connections are made.
2453 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2457 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2458 * CO_E_OBJISREG if the object is already registered. We should not return this.
2461 * CoRevokeClassObject, CoGetClassObject
2464 * In-process objects are only registered for the current apartment.
2465 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2466 * in other apartments.
2469 * MSDN claims that multiple interface registrations are legal, but we
2470 * can't do that with our current implementation.
2472 HRESULT WINAPI
CoRegisterClassObject(
2477 LPDWORD lpdwRegister
)
2479 static LONG next_cookie
;
2480 RegisteredClass
* newClass
;
2481 LPUNKNOWN foundObject
;
2485 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2486 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2488 if ( (lpdwRegister
==0) || (pUnk
==0) )
2489 return E_INVALIDARG
;
2491 apt
= COM_CurrentApt();
2494 ERR("COM was not initialized\n");
2495 return CO_E_NOTINITIALIZED
;
2500 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2501 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2502 if (flags
& REGCLS_MULTIPLEUSE
)
2503 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2506 * First, check if the class is already registered.
2507 * If it is, this should cause an error.
2509 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2511 if (flags
& REGCLS_MULTIPLEUSE
) {
2512 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2513 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2514 IUnknown_Release(foundObject
);
2517 IUnknown_Release(foundObject
);
2518 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2519 return CO_E_OBJISREG
;
2522 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2523 if ( newClass
== NULL
)
2524 return E_OUTOFMEMORY
;
2526 newClass
->classIdentifier
= *rclsid
;
2527 newClass
->apartment_id
= apt
->oxid
;
2528 newClass
->runContext
= dwClsContext
;
2529 newClass
->connectFlags
= flags
;
2530 newClass
->RpcRegistration
= NULL
;
2532 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2533 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2536 * Since we're making a copy of the object pointer, we have to increase its
2539 newClass
->classObject
= pUnk
;
2540 IUnknown_AddRef(newClass
->classObject
);
2542 EnterCriticalSection( &csRegisteredClassList
);
2543 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2544 LeaveCriticalSection( &csRegisteredClassList
);
2546 *lpdwRegister
= newClass
->dwCookie
;
2548 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2549 IStream
*marshal_stream
;
2551 hr
= get_local_server_stream(apt
, &marshal_stream
);
2555 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2557 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2558 &newClass
->RpcRegistration
);
2559 IStream_Release(marshal_stream
);
2564 static void get_threading_model(HKEY key
, LPWSTR value
, DWORD len
)
2566 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2569 DWORD dwLength
= len
* sizeof(WCHAR
);
2571 ret
= RegQueryValueExW(key
, wszThreadingModel
, NULL
, &keytype
, (LPBYTE
)value
, &dwLength
);
2572 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2576 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, HKEY hkeydll
,
2577 REFCLSID rclsid
, REFIID riid
,
2578 BOOL hostifnecessary
, void **ppv
)
2580 WCHAR dllpath
[MAX_PATH
+1];
2581 BOOL apartment_threaded
;
2583 if (hostifnecessary
)
2585 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2586 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2587 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2588 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2590 get_threading_model(hkeydll
, threading_model
, ARRAYSIZE(threading_model
));
2592 if (!strcmpiW(threading_model
, wszApartment
))
2594 apartment_threaded
= TRUE
;
2595 if (apt
->multi_threaded
)
2596 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2599 else if (!strcmpiW(threading_model
, wszFree
))
2601 apartment_threaded
= FALSE
;
2602 if (!apt
->multi_threaded
)
2603 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, hkeydll
, rclsid
, riid
, ppv
);
2605 /* everything except "Apartment", "Free" and "Both" */
2606 else if (strcmpiW(threading_model
, wszBoth
))
2608 apartment_threaded
= TRUE
;
2609 /* everything else is main-threaded */
2610 if (threading_model
[0])
2611 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2612 debugstr_w(threading_model
), debugstr_guid(rclsid
));
2614 if (apt
->multi_threaded
|| !apt
->main
)
2615 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, hkeydll
, rclsid
, riid
, ppv
);
2618 apartment_threaded
= FALSE
;
2621 apartment_threaded
= !apt
->multi_threaded
;
2623 if (COM_RegReadPath(hkeydll
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2625 /* failure: CLSID is not found in registry */
2626 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2627 return REGDB_E_CLASSNOTREG
;
2630 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2634 /***********************************************************************
2635 * CoGetClassObject [OLE32.@]
2637 * Creates an object of the specified class.
2640 * rclsid [I] Class ID to create an instance of.
2641 * dwClsContext [I] Flags to restrict the location of the created instance.
2642 * pServerInfo [I] Optional. Details for connecting to a remote server.
2643 * iid [I] The ID of the interface of the instance to return.
2644 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2648 * Failure: HRESULT code.
2651 * The dwClsContext parameter can be one or more of the following:
2652 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2653 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2654 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2655 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2658 * CoCreateInstance()
2660 HRESULT WINAPI
CoGetClassObject(
2661 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2662 REFIID iid
, LPVOID
*ppv
)
2664 LPUNKNOWN regClassObject
;
2665 HRESULT hres
= E_UNEXPECTED
;
2667 BOOL release_apt
= FALSE
;
2669 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2672 return E_INVALIDARG
;
2676 if (!(apt
= COM_CurrentApt()))
2678 if (!(apt
= apartment_find_multi_threaded()))
2680 ERR("apartment not initialised\n");
2681 return CO_E_NOTINITIALIZED
;
2687 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2688 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2692 * First, try and see if we can't match the class ID with one of the
2693 * registered classes.
2695 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2698 /* Get the required interface from the retrieved pointer. */
2699 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
2702 * Since QI got another reference on the pointer, we want to release the
2703 * one we already have. If QI was unsuccessful, this will release the object. This
2704 * is good since we are not returning it in the "out" parameter.
2706 IUnknown_Release(regClassObject
);
2707 if (release_apt
) apartment_release(apt
);
2711 /* First try in-process server */
2712 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2714 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2717 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2719 if (release_apt
) apartment_release(apt
);
2720 return FTMarshalCF_Create(iid
, ppv
);
2723 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
2726 if (hres
== REGDB_E_CLASSNOTREG
)
2727 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2728 else if (hres
== REGDB_E_KEYMISSING
)
2730 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
2731 hres
= REGDB_E_CLASSNOTREG
;
2735 if (SUCCEEDED(hres
))
2737 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2738 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2742 /* return if we got a class, otherwise fall through to one of the
2744 if (SUCCEEDED(hres
))
2746 if (release_apt
) apartment_release(apt
);
2751 /* Next try in-process handler */
2752 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
2754 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2757 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
2760 if (hres
== REGDB_E_CLASSNOTREG
)
2761 ERR("class %s not registered\n", debugstr_guid(rclsid
));
2762 else if (hres
== REGDB_E_KEYMISSING
)
2764 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
2765 hres
= REGDB_E_CLASSNOTREG
;
2769 if (SUCCEEDED(hres
))
2771 hres
= get_inproc_class_object(apt
, hkey
, rclsid
, iid
,
2772 !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2776 /* return if we got a class, otherwise fall through to one of the
2778 if (SUCCEEDED(hres
))
2780 if (release_apt
) apartment_release(apt
);
2784 if (release_apt
) apartment_release(apt
);
2786 /* Next try out of process */
2787 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
2789 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
2790 if (SUCCEEDED(hres
))
2794 /* Finally try remote: this requires networked DCOM (a lot of work) */
2795 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
2797 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2798 hres
= REGDB_E_CLASSNOTREG
;
2802 ERR("no class object %s could be created for context 0x%x\n",
2803 debugstr_guid(rclsid
), dwClsContext
);
2807 /***********************************************************************
2808 * CoResumeClassObjects (OLE32.@)
2810 * Resumes all class objects registered with REGCLS_SUSPENDED.
2814 * Failure: HRESULT code.
2816 HRESULT WINAPI
CoResumeClassObjects(void)
2822 /***********************************************************************
2823 * CoCreateInstance [OLE32.@]
2825 * Creates an instance of the specified class.
2828 * rclsid [I] Class ID to create an instance of.
2829 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2830 * dwClsContext [I] Flags to restrict the location of the created instance.
2831 * iid [I] The ID of the interface of the instance to return.
2832 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2836 * Failure: HRESULT code.
2839 * The dwClsContext parameter can be one or more of the following:
2840 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2841 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2842 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2843 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2845 * Aggregation is the concept of deferring the IUnknown of an object to another
2846 * object. This allows a separate object to behave as though it was part of
2847 * the object and to allow this the pUnkOuter parameter can be set. Note that
2848 * not all objects support having an outer of unknown.
2851 * CoGetClassObject()
2853 HRESULT WINAPI
CoCreateInstance(
2855 LPUNKNOWN pUnkOuter
,
2861 LPCLASSFACTORY lpclf
= 0;
2864 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
2865 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
2872 if (!(apt
= COM_CurrentApt()))
2874 if (!(apt
= apartment_find_multi_threaded()))
2876 ERR("apartment not initialised\n");
2877 return CO_E_NOTINITIALIZED
;
2879 apartment_release(apt
);
2883 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2885 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
2887 IGlobalInterfaceTable
*git
= get_std_git();
2888 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
2889 if (hres
!= S_OK
) return hres
;
2891 TRACE("Retrieved GIT (%p)\n", *ppv
);
2895 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
2896 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
2899 * Get a class factory to construct the object we want.
2901 hres
= CoGetClassObject(rclsid
,
2911 * Create the object and don't forget to release the factory
2913 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
2914 IClassFactory_Release(lpclf
);
2917 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
2918 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
2920 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2922 debugstr_guid(rclsid
),hres
);
2928 /***********************************************************************
2929 * CoCreateInstanceEx [OLE32.@]
2931 HRESULT WINAPI
CoCreateInstanceEx(
2933 LPUNKNOWN pUnkOuter
,
2935 COSERVERINFO
* pServerInfo
,
2939 IUnknown
* pUnk
= NULL
;
2942 ULONG successCount
= 0;
2947 if ( (cmq
==0) || (pResults
==NULL
))
2948 return E_INVALIDARG
;
2950 if (pServerInfo
!=NULL
)
2951 FIXME("() non-NULL pServerInfo not supported!\n");
2954 * Initialize all the "out" parameters.
2956 for (index
= 0; index
< cmq
; index
++)
2958 pResults
[index
].pItf
= NULL
;
2959 pResults
[index
].hr
= E_NOINTERFACE
;
2963 * Get the object and get its IUnknown pointer.
2965 hr
= CoCreateInstance(rclsid
,
2975 * Then, query for all the interfaces requested.
2977 for (index
= 0; index
< cmq
; index
++)
2979 pResults
[index
].hr
= IUnknown_QueryInterface(pUnk
,
2980 pResults
[index
].pIID
,
2981 (VOID
**)&(pResults
[index
].pItf
));
2983 if (pResults
[index
].hr
== S_OK
)
2988 * Release our temporary unknown pointer.
2990 IUnknown_Release(pUnk
);
2992 if (successCount
== 0)
2993 return E_NOINTERFACE
;
2995 if (successCount
!=cmq
)
2996 return CO_S_NOTALLINTERFACES
;
3001 /***********************************************************************
3002 * CoLoadLibrary (OLE32.@)
3007 * lpszLibName [I] Path to library.
3008 * bAutoFree [I] Whether the library should automatically be freed.
3011 * Success: Handle to loaded library.
3015 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3017 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3019 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3021 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3024 /***********************************************************************
3025 * CoFreeLibrary [OLE32.@]
3027 * Unloads a library from memory.
3030 * hLibrary [I] Handle to library to unload.
3036 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3038 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3040 FreeLibrary(hLibrary
);
3044 /***********************************************************************
3045 * CoFreeAllLibraries [OLE32.@]
3047 * Function for backwards compatibility only. Does nothing.
3053 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3055 void WINAPI
CoFreeAllLibraries(void)
3060 /***********************************************************************
3061 * CoFreeUnusedLibrariesEx [OLE32.@]
3063 * Frees any previously unused libraries whose delay has expired and marks
3064 * currently unused libraries for unloading. Unused are identified as those that
3065 * return S_OK from their DllCanUnloadNow function.
3068 * dwUnloadDelay [I] Unload delay in milliseconds.
3069 * dwReserved [I] Reserved. Set to 0.
3075 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3077 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3079 struct apartment
*apt
= COM_CurrentApt();
3082 ERR("apartment not initialised\n");
3086 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3089 /***********************************************************************
3090 * CoFreeUnusedLibraries [OLE32.@]
3092 * Frees any unused libraries. Unused are identified as those that return
3093 * S_OK from their DllCanUnloadNow function.
3099 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3101 void WINAPI
CoFreeUnusedLibraries(void)
3103 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3106 /***********************************************************************
3107 * CoFileTimeNow [OLE32.@]
3109 * Retrieves the current time in FILETIME format.
3112 * lpFileTime [O] The current time.
3117 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3119 GetSystemTimeAsFileTime( lpFileTime
);
3123 /******************************************************************************
3124 * CoLockObjectExternal [OLE32.@]
3126 * Increments or decrements the external reference count of a stub object.
3129 * pUnk [I] Stub object.
3130 * fLock [I] If TRUE then increments the external ref-count,
3131 * otherwise decrements.
3132 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3133 * calling CoDisconnectObject.
3137 * Failure: HRESULT code.
3140 * If fLock is TRUE and an object is passed in that doesn't have a stub
3141 * manager then a new stub manager is created for the object.
3143 HRESULT WINAPI
CoLockObjectExternal(
3146 BOOL fLastUnlockReleases
)
3148 struct stub_manager
*stubmgr
;
3149 struct apartment
*apt
;
3151 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3152 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3154 apt
= COM_CurrentApt();
3155 if (!apt
) return CO_E_NOTINITIALIZED
;
3157 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3162 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3164 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3166 stub_manager_int_release(stubmgr
);
3172 stubmgr
= new_stub_manager(apt
, pUnk
);
3176 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3177 stub_manager_int_release(stubmgr
);
3184 WARN("stub object not found %p\n", pUnk
);
3185 /* Note: native is pretty broken here because it just silently
3186 * fails, without returning an appropriate error code, making apps
3187 * think that the object was disconnected, when it actually wasn't */
3192 /***********************************************************************
3193 * CoInitializeWOW (OLE32.@)
3195 * WOW equivalent of CoInitialize?
3204 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3206 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3210 /***********************************************************************
3211 * CoGetState [OLE32.@]
3213 * Retrieves the thread state object previously stored by CoSetState().
3216 * ppv [I] Address where pointer to object will be stored.
3220 * Failure: E_OUTOFMEMORY.
3223 * Crashes on all invalid ppv addresses, including NULL.
3224 * If the function returns a non-NULL object then the caller must release its
3225 * reference on the object when the object is no longer required.
3230 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3232 struct oletls
*info
= COM_CurrentInfo();
3233 if (!info
) return E_OUTOFMEMORY
;
3239 IUnknown_AddRef(info
->state
);
3241 TRACE("apt->state=%p\n", info
->state
);
3247 /***********************************************************************
3248 * CoSetState [OLE32.@]
3250 * Sets the thread state object.
3253 * pv [I] Pointer to state object to be stored.
3256 * The system keeps a reference on the object while the object stored.
3260 * Failure: E_OUTOFMEMORY.
3262 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3264 struct oletls
*info
= COM_CurrentInfo();
3265 if (!info
) return E_OUTOFMEMORY
;
3267 if (pv
) IUnknown_AddRef(pv
);
3271 TRACE("-- release %p now\n", info
->state
);
3272 IUnknown_Release(info
->state
);
3281 /******************************************************************************
3282 * CoTreatAsClass [OLE32.@]
3284 * Sets the TreatAs value of a class.
3287 * clsidOld [I] Class to set TreatAs value on.
3288 * clsidNew [I] The class the clsidOld should be treated as.
3292 * Failure: HRESULT code.
3297 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3299 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3300 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3302 WCHAR szClsidNew
[CHARS_IN_GUID
];
3304 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3305 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3308 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3311 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3313 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3314 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3316 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3318 res
= REGDB_E_WRITEREGDB
;
3324 RegDeleteKeyW(hkey
, wszTreatAs
);
3328 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3329 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3331 res
= REGDB_E_WRITEREGDB
;
3336 if (hkey
) RegCloseKey(hkey
);
3340 /******************************************************************************
3341 * CoGetTreatAsClass [OLE32.@]
3343 * Gets the TreatAs value of a class.
3346 * clsidOld [I] Class to get the TreatAs value of.
3347 * clsidNew [I] The class the clsidOld should be treated as.
3351 * Failure: HRESULT code.
3356 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3358 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3360 WCHAR szClsidNew
[CHARS_IN_GUID
];
3362 LONG len
= sizeof(szClsidNew
);
3364 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3365 *clsidNew
= *clsidOld
; /* copy over old value */
3367 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3373 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3378 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3380 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3382 if (hkey
) RegCloseKey(hkey
);
3386 /******************************************************************************
3387 * CoGetCurrentProcess [OLE32.@]
3389 * Gets the current process ID.
3392 * The current process ID.
3395 * Is DWORD really the correct return type for this function?
3397 DWORD WINAPI
CoGetCurrentProcess(void)
3399 return GetCurrentProcessId();
3402 /******************************************************************************
3403 * CoRegisterMessageFilter [OLE32.@]
3405 * Registers a message filter.
3408 * lpMessageFilter [I] Pointer to interface.
3409 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3413 * Failure: HRESULT code.
3416 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3417 * lpMessageFilter removes the message filter.
3419 * If lplpMessageFilter is not NULL the previous message filter will be
3420 * returned in the memory pointer to this parameter and the caller is
3421 * responsible for releasing the object.
3423 * The current thread be in an apartment otherwise the function will crash.
3425 HRESULT WINAPI
CoRegisterMessageFilter(
3426 LPMESSAGEFILTER lpMessageFilter
,
3427 LPMESSAGEFILTER
*lplpMessageFilter
)
3429 struct apartment
*apt
;
3430 IMessageFilter
*lpOldMessageFilter
;
3432 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3434 apt
= COM_CurrentApt();
3436 /* can't set a message filter in a multi-threaded apartment */
3437 if (!apt
|| apt
->multi_threaded
)
3439 WARN("can't set message filter in MTA or uninitialized apt\n");
3440 return CO_E_NOT_SUPPORTED
;
3443 if (lpMessageFilter
)
3444 IMessageFilter_AddRef(lpMessageFilter
);
3446 EnterCriticalSection(&apt
->cs
);
3448 lpOldMessageFilter
= apt
->filter
;
3449 apt
->filter
= lpMessageFilter
;
3451 LeaveCriticalSection(&apt
->cs
);
3453 if (lplpMessageFilter
)
3454 *lplpMessageFilter
= lpOldMessageFilter
;
3455 else if (lpOldMessageFilter
)
3456 IMessageFilter_Release(lpOldMessageFilter
);
3461 /***********************************************************************
3462 * CoIsOle1Class [OLE32.@]
3464 * Determines whether the specified class an OLE v1 class.
3467 * clsid [I] Class to test.
3470 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3472 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3474 FIXME("%s\n", debugstr_guid(clsid
));
3478 /***********************************************************************
3479 * IsEqualGUID [OLE32.@]
3481 * Compares two Unique Identifiers.
3484 * rguid1 [I] The first GUID to compare.
3485 * rguid2 [I] The other GUID to compare.
3491 BOOL WINAPI
IsEqualGUID(
3495 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3498 /***********************************************************************
3499 * CoInitializeSecurity [OLE32.@]
3501 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3502 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3503 void* pReserved1
, DWORD dwAuthnLevel
,
3504 DWORD dwImpLevel
, void* pReserved2
,
3505 DWORD dwCapabilities
, void* pReserved3
)
3507 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3508 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3509 dwCapabilities
, pReserved3
);
3513 /***********************************************************************
3514 * CoSuspendClassObjects [OLE32.@]
3516 * Suspends all registered class objects to prevent further requests coming in
3517 * for those objects.
3521 * Failure: HRESULT code.
3523 HRESULT WINAPI
CoSuspendClassObjects(void)
3529 /***********************************************************************
3530 * CoAddRefServerProcess [OLE32.@]
3532 * Helper function for incrementing the reference count of a local-server
3536 * New reference count.
3539 * CoReleaseServerProcess().
3541 ULONG WINAPI
CoAddRefServerProcess(void)
3547 EnterCriticalSection(&csRegisteredClassList
);
3548 refs
= ++s_COMServerProcessReferences
;
3549 LeaveCriticalSection(&csRegisteredClassList
);
3551 TRACE("refs before: %d\n", refs
- 1);
3556 /***********************************************************************
3557 * CoReleaseServerProcess [OLE32.@]
3559 * Helper function for decrementing the reference count of a local-server
3563 * New reference count.
3566 * When reference count reaches 0, this function suspends all registered
3567 * classes so no new connections are accepted.
3570 * CoAddRefServerProcess(), CoSuspendClassObjects().
3572 ULONG WINAPI
CoReleaseServerProcess(void)
3578 EnterCriticalSection(&csRegisteredClassList
);
3580 refs
= --s_COMServerProcessReferences
;
3581 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3583 LeaveCriticalSection(&csRegisteredClassList
);
3585 TRACE("refs after: %d\n", refs
);
3590 /***********************************************************************
3591 * CoIsHandlerConnected [OLE32.@]
3593 * Determines whether a proxy is connected to a remote stub.
3596 * pUnk [I] Pointer to object that may or may not be connected.
3599 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3602 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
3604 FIXME("%p\n", pUnk
);
3609 /***********************************************************************
3610 * CoAllowSetForegroundWindow [OLE32.@]
3613 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
3615 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
3619 /***********************************************************************
3620 * CoQueryProxyBlanket [OLE32.@]
3622 * Retrieves the security settings being used by a proxy.
3625 * pProxy [I] Pointer to the proxy object.
3626 * pAuthnSvc [O] The type of authentication service.
3627 * pAuthzSvc [O] The type of authorization service.
3628 * ppServerPrincName [O] Optional. The server prinicple name.
3629 * pAuthnLevel [O] The authentication level.
3630 * pImpLevel [O] The impersonation level.
3631 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3632 * pCapabilities [O] Flags affecting the security behaviour.
3636 * Failure: HRESULT code.
3639 * CoCopyProxy, CoSetProxyBlanket.
3641 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
3642 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
3643 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
3645 IClientSecurity
*pCliSec
;
3648 TRACE("%p\n", pProxy
);
3650 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3653 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
3654 pAuthzSvc
, ppServerPrincName
,
3655 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
3657 IClientSecurity_Release(pCliSec
);
3660 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3664 /***********************************************************************
3665 * CoSetProxyBlanket [OLE32.@]
3667 * Sets the security settings for a proxy.
3670 * pProxy [I] Pointer to the proxy object.
3671 * AuthnSvc [I] The type of authentication service.
3672 * AuthzSvc [I] The type of authorization service.
3673 * pServerPrincName [I] The server prinicple name.
3674 * AuthnLevel [I] The authentication level.
3675 * ImpLevel [I] The impersonation level.
3676 * pAuthInfo [I] Information specific to the authorization/authentication service.
3677 * Capabilities [I] Flags affecting the security behaviour.
3681 * Failure: HRESULT code.
3684 * CoQueryProxyBlanket, CoCopyProxy.
3686 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
3687 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
3688 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
3690 IClientSecurity
*pCliSec
;
3693 TRACE("%p\n", pProxy
);
3695 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3698 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
3699 AuthzSvc
, pServerPrincName
,
3700 AuthnLevel
, ImpLevel
, pAuthInfo
,
3702 IClientSecurity_Release(pCliSec
);
3705 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3709 /***********************************************************************
3710 * CoCopyProxy [OLE32.@]
3715 * pProxy [I] Pointer to the proxy object.
3716 * ppCopy [O] Copy of the proxy.
3720 * Failure: HRESULT code.
3723 * CoQueryProxyBlanket, CoSetProxyBlanket.
3725 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
3727 IClientSecurity
*pCliSec
;
3730 TRACE("%p\n", pProxy
);
3732 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
3735 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
3736 IClientSecurity_Release(pCliSec
);
3739 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
3744 /***********************************************************************
3745 * CoGetCallContext [OLE32.@]
3747 * Gets the context of the currently executing server call in the current
3751 * riid [I] Context interface to return.
3752 * ppv [O] Pointer to memory that will receive the context on return.
3756 * Failure: HRESULT code.
3758 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
3760 struct oletls
*info
= COM_CurrentInfo();
3762 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
3765 return E_OUTOFMEMORY
;
3767 if (!info
->call_state
)
3768 return RPC_E_CALL_COMPLETE
;
3770 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
3773 /***********************************************************************
3774 * CoSwitchCallContext [OLE32.@]
3776 * Switches the context of the currently executing server call in the current
3780 * pObject [I] Pointer to new context object
3781 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3785 * Failure: HRESULT code.
3787 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
3789 struct oletls
*info
= COM_CurrentInfo();
3791 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
3794 return E_OUTOFMEMORY
;
3796 *ppOldObject
= info
->call_state
;
3797 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
3802 /***********************************************************************
3803 * CoQueryClientBlanket [OLE32.@]
3805 * Retrieves the authentication information about the client of the currently
3806 * executing server call in the current thread.
3809 * pAuthnSvc [O] Optional. The type of authentication service.
3810 * pAuthzSvc [O] Optional. The type of authorization service.
3811 * pServerPrincName [O] Optional. The server prinicple name.
3812 * pAuthnLevel [O] Optional. The authentication level.
3813 * pImpLevel [O] Optional. The impersonation level.
3814 * pPrivs [O] Optional. Information about the privileges of the client.
3815 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3819 * Failure: HRESULT code.
3822 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3824 HRESULT WINAPI
CoQueryClientBlanket(
3827 OLECHAR
**pServerPrincName
,
3830 RPC_AUTHZ_HANDLE
*pPrivs
,
3831 DWORD
*pCapabilities
)
3833 IServerSecurity
*pSrvSec
;
3836 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3837 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
3838 pPrivs
, pCapabilities
);
3840 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3843 hr
= IServerSecurity_QueryBlanket(
3844 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
3845 pImpLevel
, pPrivs
, pCapabilities
);
3846 IServerSecurity_Release(pSrvSec
);
3852 /***********************************************************************
3853 * CoImpersonateClient [OLE32.@]
3855 * Impersonates the client of the currently executing server call in the
3863 * Failure: HRESULT code.
3866 * If this function fails then the current thread will not be impersonating
3867 * the client and all actions will take place on behalf of the server.
3868 * Therefore, it is important to check the return value from this function.
3871 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3873 HRESULT WINAPI
CoImpersonateClient(void)
3875 IServerSecurity
*pSrvSec
;
3880 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3883 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
3884 IServerSecurity_Release(pSrvSec
);
3890 /***********************************************************************
3891 * CoRevertToSelf [OLE32.@]
3893 * Ends the impersonation of the client of the currently executing server
3894 * call in the current thread.
3901 * Failure: HRESULT code.
3904 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3906 HRESULT WINAPI
CoRevertToSelf(void)
3908 IServerSecurity
*pSrvSec
;
3913 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
3916 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
3917 IServerSecurity_Release(pSrvSec
);
3923 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
3925 /* first try to retrieve messages for incoming COM calls to the apartment window */
3926 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
3927 /* next retrieve other messages necessary for the app to remain responsive */
3928 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
3929 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
3932 /***********************************************************************
3933 * CoWaitForMultipleHandles [OLE32.@]
3935 * Waits for one or more handles to become signaled.
3938 * dwFlags [I] Flags. See notes.
3939 * dwTimeout [I] Timeout in milliseconds.
3940 * cHandles [I] Number of handles pointed to by pHandles.
3941 * pHandles [I] Handles to wait for.
3942 * lpdwindex [O] Index of handle that was signaled.
3946 * Failure: RPC_S_CALLPENDING on timeout.
3950 * The dwFlags parameter can be zero or more of the following:
3951 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3952 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3955 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3957 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
3958 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
3961 DWORD start_time
= GetTickCount();
3962 APARTMENT
*apt
= COM_CurrentApt();
3963 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
3965 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
3966 pHandles
, lpdwindex
);
3970 DWORD now
= GetTickCount();
3973 if (now
- start_time
> dwTimeout
)
3975 hr
= RPC_S_CALLPENDING
;
3981 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
3982 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
3984 TRACE("waiting for rpc completion or window message\n");
3986 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
3987 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
3988 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
3990 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
3995 /* call message filter */
3997 if (COM_CurrentApt()->filter
)
3999 PENDINGTYPE pendingtype
=
4000 COM_CurrentInfo()->pending_call_count_server
?
4001 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4002 DWORD be_handled
= IMessageFilter_MessagePending(
4003 COM_CurrentApt()->filter
, 0 /* FIXME */,
4004 now
- start_time
, pendingtype
);
4005 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4008 case PENDINGMSG_CANCELCALL
:
4009 WARN("call canceled\n");
4010 hr
= RPC_E_CALL_CANCELED
;
4012 case PENDINGMSG_WAITNOPROCESS
:
4013 case PENDINGMSG_WAITDEFPROCESS
:
4015 /* FIXME: MSDN is very vague about the difference
4016 * between WAITNOPROCESS and WAITDEFPROCESS - there
4017 * appears to be none, so it is possibly a left-over
4018 * from the 16-bit world. */
4023 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4024 * so after processing 100 messages we go back to checking the wait handles */
4025 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4027 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4028 TranslateMessage(&msg
);
4029 DispatchMessageW(&msg
);
4030 if (msg
.message
== WM_QUIT
)
4032 TRACE("resending WM_QUIT to outer message loop\n");
4033 PostQuitMessage(msg
.wParam
);
4034 /* no longer need to process messages */
4035 message_loop
= FALSE
;
4044 TRACE("waiting for rpc completion\n");
4046 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4047 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4048 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4054 hr
= RPC_S_CALLPENDING
;
4057 hr
= HRESULT_FROM_WIN32( GetLastError() );
4065 TRACE("-- 0x%08x\n", hr
);
4070 /***********************************************************************
4071 * CoGetObject [OLE32.@]
4073 * Gets the object named by converting the name to a moniker and binding to it.
4076 * pszName [I] String representing the object.
4077 * pBindOptions [I] Parameters affecting the binding to the named object.
4078 * riid [I] Interface to bind to on the objecct.
4079 * ppv [O] On output, the interface riid of the object represented
4084 * Failure: HRESULT code.
4087 * MkParseDisplayName.
4089 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4090 REFIID riid
, void **ppv
)
4097 hr
= CreateBindCtx(0, &pbc
);
4101 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4108 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4111 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4112 IMoniker_Release(pmk
);
4116 IBindCtx_Release(pbc
);
4121 /***********************************************************************
4122 * CoRegisterChannelHook [OLE32.@]
4124 * Registers a process-wide hook that is called during ORPC calls.
4127 * guidExtension [I] GUID of the channel hook to register.
4128 * pChannelHook [I] Channel hook object to register.
4132 * Failure: HRESULT code.
4134 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4136 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4138 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4141 typedef struct Context
4143 IComThreadingInfo IComThreadingInfo_iface
;
4144 IContextCallback IContextCallback_iface
;
4145 IObjContext IObjContext_iface
;
4150 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4152 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4155 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4157 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4160 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4162 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4165 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4169 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4170 IsEqualIID(riid
, &IID_IUnknown
))
4172 *ppv
= &iface
->IComThreadingInfo_iface
;
4174 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4176 *ppv
= &iface
->IContextCallback_iface
;
4178 else if (IsEqualIID(riid
, &IID_IObjContext
))
4180 *ppv
= &iface
->IObjContext_iface
;
4185 IUnknown_AddRef((IUnknown
*)*ppv
);
4189 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4190 return E_NOINTERFACE
;
4193 static ULONG
Context_AddRef(Context
*This
)
4195 return InterlockedIncrement(&This
->refs
);
4198 static ULONG
Context_Release(Context
*This
)
4200 ULONG refs
= InterlockedDecrement(&This
->refs
);
4202 HeapFree(GetProcessHeap(), 0, This
);
4206 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4208 Context
*This
= impl_from_IComThreadingInfo(iface
);
4209 return Context_QueryInterface(This
, riid
, ppv
);
4212 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4214 Context
*This
= impl_from_IComThreadingInfo(iface
);
4215 return Context_AddRef(This
);
4218 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4220 Context
*This
= impl_from_IComThreadingInfo(iface
);
4221 return Context_Release(This
);
4224 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4226 Context
*This
= impl_from_IComThreadingInfo(iface
);
4228 TRACE("(%p)\n", apttype
);
4230 *apttype
= This
->apttype
;
4234 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4236 Context
*This
= impl_from_IComThreadingInfo(iface
);
4238 TRACE("(%p)\n", thdtype
);
4240 switch (This
->apttype
)
4243 case APTTYPE_MAINSTA
:
4244 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4247 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4253 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4255 FIXME("(%p): stub\n", logical_thread_id
);
4259 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4261 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4265 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4267 Context_CTI_QueryInterface
,
4269 Context_CTI_Release
,
4270 Context_CTI_GetCurrentApartmentType
,
4271 Context_CTI_GetCurrentThreadType
,
4272 Context_CTI_GetCurrentLogicalThreadId
,
4273 Context_CTI_SetCurrentLogicalThreadId
4276 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4278 Context
*This
= impl_from_IContextCallback(iface
);
4279 return Context_QueryInterface(This
, riid
, ppv
);
4282 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4284 Context
*This
= impl_from_IContextCallback(iface
);
4285 return Context_AddRef(This
);
4288 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4290 Context
*This
= impl_from_IContextCallback(iface
);
4291 return Context_Release(This
);
4294 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4295 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4297 Context
*This
= impl_from_IContextCallback(iface
);
4299 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4303 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4305 Context_CC_QueryInterface
,
4308 Context_CC_ContextCallback
4311 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4313 Context
*This
= impl_from_IObjContext(iface
);
4314 return Context_QueryInterface(This
, riid
, ppv
);
4317 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4319 Context
*This
= impl_from_IObjContext(iface
);
4320 return Context_AddRef(This
);
4323 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4325 Context
*This
= impl_from_IObjContext(iface
);
4326 return Context_Release(This
);
4329 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4331 Context
*This
= impl_from_IObjContext(iface
);
4333 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4337 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4339 Context
*This
= impl_from_IObjContext(iface
);
4341 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4345 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4347 Context
*This
= impl_from_IObjContext(iface
);
4349 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4353 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4355 Context
*This
= impl_from_IObjContext(iface
);
4357 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4361 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4363 Context
*This
= impl_from_IObjContext(iface
);
4364 FIXME("(%p/%p)\n", This
, iface
);
4367 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4369 Context
*This
= impl_from_IObjContext(iface
);
4370 FIXME("(%p/%p)\n", This
, iface
);
4373 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4375 Context
*This
= impl_from_IObjContext(iface
);
4376 FIXME("(%p/%p)\n", This
, iface
);
4379 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4381 Context
*This
= impl_from_IObjContext(iface
);
4382 FIXME("(%p/%p)\n", This
, iface
);
4385 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4387 Context
*This
= impl_from_IObjContext(iface
);
4388 FIXME("(%p/%p)\n", This
, iface
);
4391 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4393 Context
*This
= impl_from_IObjContext(iface
);
4394 FIXME("(%p/%p)\n", This
, iface
);
4397 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4399 Context
*This
= impl_from_IObjContext(iface
);
4400 FIXME("(%p/%p)\n", This
, iface
);
4403 static const IObjContextVtbl Context_Object_Vtbl
=
4405 Context_OC_QueryInterface
,
4408 Context_OC_SetProperty
,
4409 Context_OC_RemoveProperty
,
4410 Context_OC_GetProperty
,
4411 Context_OC_EnumContextProps
,
4412 Context_OC_Reserved1
,
4413 Context_OC_Reserved2
,
4414 Context_OC_Reserved3
,
4415 Context_OC_Reserved4
,
4416 Context_OC_Reserved5
,
4417 Context_OC_Reserved6
,
4418 Context_OC_Reserved7
4421 /***********************************************************************
4422 * CoGetObjectContext [OLE32.@]
4424 * Retrieves an object associated with the current context (i.e. apartment).
4427 * riid [I] ID of the interface of the object to retrieve.
4428 * ppv [O] Address where object will be stored on return.
4432 * Failure: HRESULT code.
4434 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4436 APARTMENT
*apt
= COM_CurrentApt();
4440 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4445 if (!(apt
= apartment_find_multi_threaded()))
4447 ERR("apartment not initialised\n");
4448 return CO_E_NOTINITIALIZED
;
4450 apartment_release(apt
);
4453 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4455 return E_OUTOFMEMORY
;
4457 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4458 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4459 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4461 if (apt
->multi_threaded
)
4462 context
->apttype
= APTTYPE_MTA
;
4464 context
->apttype
= APTTYPE_MAINSTA
;
4466 context
->apttype
= APTTYPE_STA
;
4468 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4469 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4475 /***********************************************************************
4476 * CoGetContextToken [OLE32.@]
4478 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4480 struct oletls
*info
= COM_CurrentInfo();
4482 TRACE("(%p)\n", token
);
4485 return E_OUTOFMEMORY
;
4490 if (!(apt
= apartment_find_multi_threaded()))
4492 ERR("apartment not initialised\n");
4493 return CO_E_NOTINITIALIZED
;
4495 apartment_release(apt
);
4501 if (!info
->context_token
)
4506 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4507 if (FAILED(hr
)) return hr
;
4508 info
->context_token
= ctx
;
4511 *token
= (ULONG_PTR
)info
->context_token
;
4512 TRACE("apt->context_token=%p\n", info
->context_token
);
4517 /***********************************************************************
4518 * CoGetDefaultContext [OLE32.@]
4520 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4522 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4523 return E_NOINTERFACE
;
4526 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4528 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4532 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4533 if (SUCCEEDED(hres
))
4535 WCHAR dllpath
[MAX_PATH
+1];
4537 if (COM_RegReadPath(hkey
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4539 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4540 if (!strcmpiW(dllpath
, wszOle32
))
4543 return HandlerCF_Create(rclsid
, riid
, ppv
);
4547 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4551 return CLASS_E_CLASSNOTAVAILABLE
;
4554 /***********************************************************************
4557 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4559 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4562 case DLL_PROCESS_ATTACH
:
4563 hProxyDll
= hinstDLL
;
4564 COMPOBJ_InitProcess();
4567 case DLL_PROCESS_DETACH
:
4568 if (reserved
) break;
4570 COMPOBJ_UninitProcess();
4571 RPC_UnregisterAllChannelHooks();
4572 COMPOBJ_DllList_Free();
4573 DeleteCriticalSection(&csRegisteredClassList
);
4574 DeleteCriticalSection(&csApartment
);
4577 case DLL_THREAD_DETACH
:
4584 /***********************************************************************
4585 * DllRegisterServer (OLE32.@)
4587 HRESULT WINAPI
DllRegisterServer(void)
4589 return OLE32_DllRegisterServer();
4592 /***********************************************************************
4593 * DllUnregisterServer (OLE32.@)
4595 HRESULT WINAPI
DllUnregisterServer(void)
4597 return OLE32_DllUnregisterServer();