4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
51 #define WIN32_NO_STATUS
57 #define USE_COM_CONTEXT_DEF
66 #include "compobj_private.h"
69 #include "wine/unicode.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
80 static APARTMENT
*MTA
; /* protected by csApartment */
81 static APARTMENT
*MainApartment
; /* the first STA apartment */
82 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment
;
85 static CRITICAL_SECTION_DEBUG critsect_debug
=
88 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
89 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
91 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
93 enum comclass_threadingmodel
95 ThreadingModel_Apartment
= 1,
96 ThreadingModel_Free
= 2,
97 ThreadingModel_No
= 3,
98 ThreadingModel_Both
= 4,
99 ThreadingModel_Neutral
= 5
102 enum comclass_miscfields
106 MiscStatusContent
= 4,
107 MiscStatusThumbnail
= 8,
108 MiscStatusDocPrint
= 16
111 struct comclassredirect_data
127 ULONG clrdata_offset
;
129 DWORD miscstatuscontent
;
130 DWORD miscstatusthumbnail
;
131 DWORD miscstatusicon
;
132 DWORD miscstatusdocprint
;
135 struct ifacepsredirect_data
147 struct progidredirect_data
154 struct class_reg_data
160 struct comclassredirect_data
*data
;
169 struct registered_psclsid
177 * This is a marshallable object exposing registered local servers.
178 * IServiceProvider is used only because it happens meet requirements
179 * and already has proxy/stub code. If more functionality is needed,
180 * a custom interface may be used instead.
184 IServiceProvider IServiceProvider_iface
;
187 IStream
*marshal_stream
;
191 * This lock count counts the number of times CoInitialize is called. It is
192 * decreased every time CoUninitialize is called. When it hits 0, the COM
193 * libraries are freed
195 static LONG s_COMLockCount
= 0;
196 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
197 static LONG s_COMServerProcessReferences
= 0;
200 * This linked list contains the list of registered class objects. These
201 * are mostly used to register the factories for out-of-proc servers of OLE
204 * TODO: Make this data structure aware of inter-process communication. This
205 * means that parts of this will be exported to rpcss.
207 typedef struct tagRegisteredClass
210 CLSID classIdentifier
;
212 LPUNKNOWN classObject
;
216 void *RpcRegistration
;
219 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
221 static CRITICAL_SECTION csRegisteredClassList
;
222 static CRITICAL_SECTION_DEBUG class_cs_debug
=
224 0, 0, &csRegisteredClassList
,
225 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
226 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
228 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
230 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
234 case DVASPECT_CONTENT
:
235 return MiscStatusContent
;
236 case DVASPECT_THUMBNAIL
:
237 return MiscStatusThumbnail
;
239 return MiscStatusIcon
;
240 case DVASPECT_DOCPRINT
:
241 return MiscStatusDocPrint
;
247 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
249 ACTCTX_SECTION_KEYED_DATA data
;
251 data
.cbSize
= sizeof(data
);
252 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
255 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
256 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
258 if (!(comclass
->miscmask
& misc
))
260 if (!(comclass
->miscmask
& MiscStatus
))
271 *status
= comclass
->miscstatus
;
274 *status
= comclass
->miscstatusicon
;
276 case MiscStatusContent
:
277 *status
= comclass
->miscstatuscontent
;
279 case MiscStatusThumbnail
:
280 *status
= comclass
->miscstatusthumbnail
;
282 case MiscStatusDocPrint
:
283 *status
= comclass
->miscstatusdocprint
;
295 /* wrapper for NtCreateKey that creates the key recursively if necessary */
296 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
298 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
300 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
302 HANDLE subkey
, root
= attr
->RootDirectory
;
303 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
304 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
307 while (i
< len
&& buffer
[i
] != '\\') i
++;
308 if (i
== len
) return status
;
310 attrs
= attr
->Attributes
;
311 attr
->ObjectName
= &str
;
315 str
.Buffer
= buffer
+ pos
;
316 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
317 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
318 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
319 if (status
) return status
;
320 attr
->RootDirectory
= subkey
;
321 while (i
< len
&& buffer
[i
] == '\\') i
++;
323 while (i
< len
&& buffer
[i
] != '\\') i
++;
325 str
.Buffer
= buffer
+ pos
;
326 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
327 attr
->Attributes
= attrs
;
328 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
329 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
334 static const WCHAR classes_rootW
[] =
335 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
337 static HKEY classes_root_hkey
;
339 /* create the special HKEY_CLASSES_ROOT key */
340 static HKEY
create_classes_root_hkey(DWORD access
)
343 OBJECT_ATTRIBUTES attr
;
346 attr
.Length
= sizeof(attr
);
347 attr
.RootDirectory
= 0;
348 attr
.ObjectName
= &name
;
350 attr
.SecurityDescriptor
= NULL
;
351 attr
.SecurityQualityOfService
= NULL
;
352 RtlInitUnicodeString( &name
, classes_rootW
);
353 if (create_key( &hkey
, access
, &attr
)) return 0;
354 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
356 if (!(access
& KEY_WOW64_64KEY
))
358 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
361 NtClose( hkey
); /* somebody beat us to it */
368 /* map the hkey from special root to normal key if necessary */
369 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
372 const BOOL is_win64
= sizeof(void*) > sizeof(int);
373 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
375 if (hkey
== HKEY_CLASSES_ROOT
&&
376 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
377 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
378 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
380 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
381 access
&= ~KEY_WOW64_32KEY
;
382 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
390 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
392 OBJECT_ATTRIBUTES attr
;
393 UNICODE_STRING nameW
;
395 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
397 attr
.Length
= sizeof(attr
);
398 attr
.RootDirectory
= hkey
;
399 attr
.ObjectName
= &nameW
;
401 attr
.SecurityDescriptor
= NULL
;
402 attr
.SecurityQualityOfService
= NULL
;
403 RtlInitUnicodeString( &nameW
, name
);
405 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
408 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
410 OBJECT_ATTRIBUTES attr
;
411 UNICODE_STRING nameW
;
413 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
415 attr
.Length
= sizeof(attr
);
416 attr
.RootDirectory
= hkey
;
417 attr
.ObjectName
= &nameW
;
419 attr
.SecurityDescriptor
= NULL
;
420 attr
.SecurityQualityOfService
= NULL
;
421 RtlInitUnicodeString( &nameW
, name
);
423 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
426 /*****************************************************************************
427 * This section contains OpenDllList definitions
429 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
430 * other functions that do LoadLibrary _without_ giving back a HMODULE.
431 * Without this list these handles would never be freed.
433 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
434 * next unload-call but not before 600 sec.
437 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
438 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
440 typedef struct tagOpenDll
445 DllGetClassObjectFunc DllGetClassObject
;
446 DllCanUnloadNowFunc DllCanUnloadNow
;
450 static struct list openDllList
= LIST_INIT(openDllList
);
452 static CRITICAL_SECTION csOpenDllList
;
453 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
455 0, 0, &csOpenDllList
,
456 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
457 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
459 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
461 struct apartment_loaded_dll
469 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',' ',
470 '0','x','#','#','#','#','#','#','#','#',' ',0};
472 /*****************************************************************************
473 * This section contains OpenDllList implementation
476 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
480 EnterCriticalSection(&csOpenDllList
);
481 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
483 if (!strcmpiW(library_name
, ptr
->library_name
) &&
484 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
490 LeaveCriticalSection(&csOpenDllList
);
494 /* caller must ensure that library_name is not already in the open dll list */
495 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
501 DllCanUnloadNowFunc DllCanUnloadNow
;
502 DllGetClassObjectFunc DllGetClassObject
;
504 TRACE("%s\n", debugstr_w(library_name
));
506 *ret
= COMPOBJ_DllList_Get(library_name
);
507 if (*ret
) return S_OK
;
509 /* do this outside the csOpenDllList to avoid creating a lock dependency on
511 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
514 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
515 /* failure: DLL could not be loaded */
516 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
519 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
520 /* Note: failing to find DllCanUnloadNow is not a failure */
521 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
522 if (!DllGetClassObject
)
524 /* failure: the dll did not export DllGetClassObject */
525 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
526 FreeLibrary(hLibrary
);
527 return CO_E_DLLNOTFOUND
;
530 EnterCriticalSection( &csOpenDllList
);
532 *ret
= COMPOBJ_DllList_Get(library_name
);
535 /* another caller to this function already added the dll while we
536 * weren't in the critical section */
537 FreeLibrary(hLibrary
);
541 len
= strlenW(library_name
);
542 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
544 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
545 if (entry
&& entry
->library_name
)
547 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
548 entry
->library
= hLibrary
;
550 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
551 entry
->DllGetClassObject
= DllGetClassObject
;
552 list_add_tail(&openDllList
, &entry
->entry
);
557 HeapFree(GetProcessHeap(), 0, entry
);
559 FreeLibrary(hLibrary
);
563 LeaveCriticalSection( &csOpenDllList
);
568 /* pass FALSE for free_entry to release a reference without destroying the
569 * entry if it reaches zero or TRUE otherwise */
570 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
572 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
574 EnterCriticalSection(&csOpenDllList
);
575 list_remove(&entry
->entry
);
576 LeaveCriticalSection(&csOpenDllList
);
578 TRACE("freeing %p\n", entry
->library
);
579 FreeLibrary(entry
->library
);
581 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
582 HeapFree(GetProcessHeap(), 0, entry
);
586 /* frees memory associated with active dll list */
587 static void COMPOBJ_DllList_Free(void)
589 OpenDll
*entry
, *cursor2
;
590 EnterCriticalSection(&csOpenDllList
);
591 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
593 list_remove(&entry
->entry
);
595 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
596 HeapFree(GetProcessHeap(), 0, entry
);
598 LeaveCriticalSection(&csOpenDllList
);
599 DeleteCriticalSection(&csOpenDllList
);
602 /******************************************************************************
606 static DWORD
apartment_addref(struct apartment
*apt
)
608 DWORD refs
= InterlockedIncrement(&apt
->refs
);
609 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
613 /* allocates memory and fills in the necessary fields for a new apartment
614 * object. must be called inside apartment cs */
615 static APARTMENT
*apartment_construct(DWORD model
)
619 TRACE("creating new apartment, model=%d\n", model
);
621 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
622 apt
->tid
= GetCurrentThreadId();
624 list_init(&apt
->proxies
);
625 list_init(&apt
->stubmgrs
);
626 list_init(&apt
->psclsids
);
627 list_init(&apt
->loaded_dlls
);
630 apt
->remunk_exported
= FALSE
;
632 InitializeCriticalSection(&apt
->cs
);
633 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
635 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
637 if (apt
->multi_threaded
)
639 /* FIXME: should be randomly generated by in an RPC call to rpcss */
640 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
644 /* FIXME: should be randomly generated by in an RPC call to rpcss */
645 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
648 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
650 list_add_head(&apts
, &apt
->entry
);
655 /* gets and existing apartment if one exists or otherwise creates an apartment
656 * structure which stores OLE apartment-local information and stores a pointer
657 * to it in the thread-local storage */
658 static APARTMENT
*apartment_get_or_create(DWORD model
)
660 APARTMENT
*apt
= COM_CurrentApt();
664 if (model
& COINIT_APARTMENTTHREADED
)
666 EnterCriticalSection(&csApartment
);
668 apt
= apartment_construct(model
);
673 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
676 LeaveCriticalSection(&csApartment
);
679 apartment_createwindowifneeded(apt
);
683 EnterCriticalSection(&csApartment
);
685 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
686 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
690 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
691 apartment_addref(MTA
);
694 MTA
= apartment_construct(model
);
698 LeaveCriticalSection(&csApartment
);
700 COM_CurrentInfo()->apt
= apt
;
706 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
708 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
711 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
713 list_remove(&curClass
->entry
);
715 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
716 RPC_StopLocalServer(curClass
->RpcRegistration
);
718 IUnknown_Release(curClass
->classObject
);
719 HeapFree(GetProcessHeap(), 0, curClass
);
722 static void COM_RevokeAllClasses(const struct apartment
*apt
)
724 RegisteredClass
*curClass
, *cursor
;
726 EnterCriticalSection( &csRegisteredClassList
);
728 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
730 if (curClass
->apartment_id
== apt
->oxid
)
731 COM_RevokeRegisteredClassObject(curClass
);
734 LeaveCriticalSection( &csRegisteredClassList
);
737 /******************************************************************************
738 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
741 typedef struct ManualResetEvent
{
742 ISynchronize ISynchronize_iface
;
743 ISynchronizeHandle ISynchronizeHandle_iface
;
748 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
750 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
753 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
755 MREImpl
*This
= impl_from_ISynchronize(iface
);
757 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
759 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
760 *ppv
= &This
->ISynchronize_iface
;
761 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
762 *ppv
= &This
->ISynchronizeHandle_iface
;
764 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
766 return E_NOINTERFACE
;
769 IUnknown_AddRef((IUnknown
*)*ppv
);
773 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
775 MREImpl
*This
= impl_from_ISynchronize(iface
);
776 LONG ref
= InterlockedIncrement(&This
->ref
);
777 TRACE("%p - ref %d\n", This
, ref
);
782 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
784 MREImpl
*This
= impl_from_ISynchronize(iface
);
785 LONG ref
= InterlockedDecrement(&This
->ref
);
786 TRACE("%p - ref %d\n", This
, ref
);
790 CloseHandle(This
->event
);
791 HeapFree(GetProcessHeap(), 0, This
);
797 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
799 MREImpl
*This
= impl_from_ISynchronize(iface
);
801 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
802 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
805 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
807 MREImpl
*This
= impl_from_ISynchronize(iface
);
809 SetEvent(This
->event
);
813 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
815 MREImpl
*This
= impl_from_ISynchronize(iface
);
817 ResetEvent(This
->event
);
821 static ISynchronizeVtbl vt_ISynchronize
= {
822 ISynchronize_fnQueryInterface
,
823 ISynchronize_fnAddRef
,
824 ISynchronize_fnRelease
,
826 ISynchronize_fnSignal
,
830 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
832 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
835 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
837 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
838 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
841 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
843 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
844 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
847 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
849 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
850 return ISynchronize_Release(&This
->ISynchronize_iface
);
853 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
855 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
861 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
862 SynchronizeHandle_QueryInterface
,
863 SynchronizeHandle_AddRef
,
864 SynchronizeHandle_Release
,
865 SynchronizeHandle_GetHandle
868 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
870 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
874 FIXME("Aggregation not implemented.\n");
877 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
878 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
879 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
881 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
882 ISynchronize_Release(&This
->ISynchronize_iface
);
886 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
888 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
891 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
893 LocalServer
*This
= impl_from_IServiceProvider(iface
);
895 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
897 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
898 *ppv
= &This
->IServiceProvider_iface
;
901 return E_NOINTERFACE
;
904 IUnknown_AddRef((IUnknown
*)*ppv
);
908 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
910 LocalServer
*This
= impl_from_IServiceProvider(iface
);
911 LONG ref
= InterlockedIncrement(&This
->ref
);
913 TRACE("(%p) ref=%d\n", This
, ref
);
918 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
920 LocalServer
*This
= impl_from_IServiceProvider(iface
);
921 LONG ref
= InterlockedDecrement(&This
->ref
);
923 TRACE("(%p) ref=%d\n", This
, ref
);
927 HeapFree(GetProcessHeap(), 0, This
);
933 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
935 LocalServer
*This
= impl_from_IServiceProvider(iface
);
936 APARTMENT
*apt
= COM_CurrentApt();
937 RegisteredClass
*iter
;
938 HRESULT hres
= E_FAIL
;
940 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
945 EnterCriticalSection(&csRegisteredClassList
);
947 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
948 if(iter
->apartment_id
== apt
->oxid
949 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
950 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
951 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
956 LeaveCriticalSection( &csRegisteredClassList
);
961 static const IServiceProviderVtbl LocalServerVtbl
= {
962 LocalServer_QueryInterface
,
965 LocalServer_QueryService
968 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
972 EnterCriticalSection(&apt
->cs
);
974 if(!apt
->local_server
) {
977 obj
= heap_alloc(sizeof(*obj
));
979 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
983 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
984 if(SUCCEEDED(hres
)) {
985 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
986 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
988 IStream_Release(obj
->marshal_stream
);
992 apt
->local_server
= obj
;
996 hres
= E_OUTOFMEMORY
;
1001 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1003 LeaveCriticalSection(&apt
->cs
);
1006 ERR("Failed: %08x\n", hres
);
1010 /***********************************************************************
1011 * CoRevokeClassObject [OLE32.@]
1013 * Removes a class object from the class registry.
1016 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1020 * Failure: HRESULT code.
1023 * Must be called from the same apartment that called CoRegisterClassObject(),
1024 * otherwise it will fail with RPC_E_WRONG_THREAD.
1027 * CoRegisterClassObject
1029 HRESULT WINAPI
CoRevokeClassObject(
1032 HRESULT hr
= E_INVALIDARG
;
1033 RegisteredClass
*curClass
;
1036 TRACE("(%08x)\n",dwRegister
);
1038 apt
= COM_CurrentApt();
1041 ERR("COM was not initialized\n");
1042 return CO_E_NOTINITIALIZED
;
1045 EnterCriticalSection( &csRegisteredClassList
);
1047 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1050 * Check if we have a match on the cookie.
1052 if (curClass
->dwCookie
== dwRegister
)
1054 if (curClass
->apartment_id
== apt
->oxid
)
1056 COM_RevokeRegisteredClassObject(curClass
);
1061 ERR("called from wrong apartment, should be called from %s\n",
1062 wine_dbgstr_longlong(curClass
->apartment_id
));
1063 hr
= RPC_E_WRONG_THREAD
;
1069 LeaveCriticalSection( &csRegisteredClassList
);
1074 /* frees unused libraries loaded by apartment_getclassobject by calling the
1075 * DLL's DllCanUnloadNow entry point */
1076 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1078 struct apartment_loaded_dll
*entry
, *next
;
1079 EnterCriticalSection(&apt
->cs
);
1080 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1082 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1084 DWORD real_delay
= delay
;
1086 if (real_delay
== INFINITE
)
1088 /* DLLs that return multi-threaded objects aren't unloaded
1089 * straight away to cope for programs that have races between
1090 * last object destruction and threads in the DLLs that haven't
1091 * finished, despite DllCanUnloadNow returning S_OK */
1092 if (entry
->multi_threaded
)
1093 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1098 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1100 list_remove(&entry
->entry
);
1101 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1102 HeapFree(GetProcessHeap(), 0, entry
);
1106 entry
->unload_time
= GetTickCount() + real_delay
;
1107 if (!entry
->unload_time
) entry
->unload_time
= 1;
1110 else if (entry
->unload_time
)
1111 entry
->unload_time
= 0;
1113 LeaveCriticalSection(&apt
->cs
);
1116 DWORD
apartment_release(struct apartment
*apt
)
1120 EnterCriticalSection(&csApartment
);
1122 ret
= InterlockedDecrement(&apt
->refs
);
1123 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1124 /* destruction stuff that needs to happen under csApartment CS */
1127 if (apt
== MTA
) MTA
= NULL
;
1128 else if (apt
== MainApartment
) MainApartment
= NULL
;
1129 list_remove(&apt
->entry
);
1132 LeaveCriticalSection(&csApartment
);
1136 struct list
*cursor
, *cursor2
;
1138 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1140 if(apt
->local_server
) {
1141 LocalServer
*local_server
= apt
->local_server
;
1144 memset(&zero
, 0, sizeof(zero
));
1145 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1146 CoReleaseMarshalData(local_server
->marshal_stream
);
1147 IStream_Release(local_server
->marshal_stream
);
1148 local_server
->marshal_stream
= NULL
;
1150 apt
->local_server
= NULL
;
1151 local_server
->apt
= NULL
;
1152 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1155 /* Release the references to the registered class objects */
1156 COM_RevokeAllClasses(apt
);
1158 /* no locking is needed for this apartment, because no other thread
1159 * can access it at this point */
1161 apartment_disconnectproxies(apt
);
1163 if (apt
->win
) DestroyWindow(apt
->win
);
1164 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1166 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1168 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1169 /* release the implicit reference given by the fact that the
1170 * stub has external references (it must do since it is in the
1171 * stub manager list in the apartment and all non-apartment users
1172 * must have a ref on the apartment and so it cannot be destroyed).
1174 stub_manager_int_release(stubmgr
);
1177 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1179 struct registered_psclsid
*registered_psclsid
=
1180 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1182 list_remove(®istered_psclsid
->entry
);
1183 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1186 /* if this assert fires, then another thread took a reference to a
1187 * stub manager without taking a reference to the containing
1188 * apartment, which it must do. */
1189 assert(list_empty(&apt
->stubmgrs
));
1191 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1193 /* free as many unused libraries as possible... */
1194 apartment_freeunusedlibraries(apt
, 0);
1196 /* ... and free the memory for the apartment loaded dll entry and
1197 * release the dll list reference without freeing the library for the
1199 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1201 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1202 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1203 list_remove(cursor
);
1204 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1207 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1208 DeleteCriticalSection(&apt
->cs
);
1210 HeapFree(GetProcessHeap(), 0, apt
);
1216 /* The given OXID must be local to this process:
1218 * The ref parameter is here mostly to ensure people remember that
1219 * they get one, you should normally take a ref for thread safety.
1221 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1223 APARTMENT
*result
= NULL
;
1224 struct list
*cursor
;
1226 EnterCriticalSection(&csApartment
);
1227 LIST_FOR_EACH( cursor
, &apts
)
1229 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1230 if (apt
->oxid
== oxid
)
1233 if (ref
) apartment_addref(result
);
1237 LeaveCriticalSection(&csApartment
);
1242 /* gets the apartment which has a given creator thread ID. The caller must
1243 * release the reference from the apartment as soon as the apartment pointer
1244 * is no longer required. */
1245 APARTMENT
*apartment_findfromtid(DWORD tid
)
1247 APARTMENT
*result
= NULL
;
1248 struct list
*cursor
;
1250 EnterCriticalSection(&csApartment
);
1251 LIST_FOR_EACH( cursor
, &apts
)
1253 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1254 if (apt
->tid
== tid
)
1257 apartment_addref(result
);
1261 LeaveCriticalSection(&csApartment
);
1266 /* gets the main apartment if it exists. The caller must
1267 * release the reference from the apartment as soon as the apartment pointer
1268 * is no longer required. */
1269 static APARTMENT
*apartment_findmain(void)
1273 EnterCriticalSection(&csApartment
);
1275 result
= MainApartment
;
1276 if (result
) apartment_addref(result
);
1278 LeaveCriticalSection(&csApartment
);
1283 /* gets the multi-threaded apartment if it exists. The caller must
1284 * release the reference from the apartment as soon as the apartment pointer
1285 * is no longer required. */
1286 static APARTMENT
*apartment_find_multi_threaded(void)
1288 APARTMENT
*result
= NULL
;
1289 struct list
*cursor
;
1291 EnterCriticalSection(&csApartment
);
1293 LIST_FOR_EACH( cursor
, &apts
)
1295 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1296 if (apt
->multi_threaded
)
1299 apartment_addref(result
);
1304 LeaveCriticalSection(&csApartment
);
1308 /* gets the specified class object by loading the appropriate DLL, if
1309 * necessary and calls the DllGetClassObject function for the DLL */
1310 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1311 BOOL apartment_threaded
,
1312 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1314 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1317 struct apartment_loaded_dll
*apartment_loaded_dll
;
1319 if (!strcmpiW(dllpath
, wszOle32
))
1321 /* we don't need to control the lifetime of this dll, so use the local
1322 * implementation of DllGetClassObject directly */
1323 TRACE("calling ole32!DllGetClassObject\n");
1324 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1327 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1332 EnterCriticalSection(&apt
->cs
);
1334 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1335 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1337 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1344 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1345 if (!apartment_loaded_dll
)
1349 apartment_loaded_dll
->unload_time
= 0;
1350 apartment_loaded_dll
->multi_threaded
= FALSE
;
1351 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1353 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1357 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1358 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1362 LeaveCriticalSection(&apt
->cs
);
1366 /* one component being multi-threaded overrides any number of
1367 * apartment-threaded components */
1368 if (!apartment_threaded
)
1369 apartment_loaded_dll
->multi_threaded
= TRUE
;
1371 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1372 /* OK: get the ClassObject */
1373 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1376 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1382 /***********************************************************************
1383 * COM_RegReadPath [internal]
1385 * Reads a registry value and expands it when necessary
1387 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1394 WCHAR src
[MAX_PATH
];
1395 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1397 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1398 if (keytype
== REG_EXPAND_SZ
) {
1399 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1401 const WCHAR
*quote_start
;
1402 quote_start
= strchrW(src
, '\"');
1404 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1406 memmove(src
, quote_start
+ 1,
1407 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1408 src
[quote_end
- quote_start
- 1] = '\0';
1411 lstrcpynW(dst
, src
, dstlen
);
1422 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1423 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1424 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1425 DeactivateActCtx(0, cookie
);
1430 struct host_object_params
1432 struct class_reg_data regdata
;
1433 CLSID clsid
; /* clsid of object to marshal */
1434 IID iid
; /* interface to marshal */
1435 HANDLE event
; /* event signalling when ready for multi-threaded case */
1436 HRESULT hr
; /* result for multi-threaded case */
1437 IStream
*stream
; /* stream that the object will be marshaled into */
1438 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1441 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1442 const struct host_object_params
*params
)
1446 static const LARGE_INTEGER llZero
;
1447 WCHAR dllpath
[MAX_PATH
+1];
1449 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1451 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1453 /* failure: CLSID is not found in registry */
1454 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1455 return REGDB_E_CLASSNOTREG
;
1458 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1459 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1463 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1465 IUnknown_Release(object
);
1466 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1471 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1476 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1479 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1481 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1485 struct host_thread_params
1487 COINIT threading_model
;
1489 HWND apartment_hwnd
;
1492 /* thread for hosting an object to allow an object to appear to be created in
1493 * an apartment with an incompatible threading model */
1494 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1496 struct host_thread_params
*params
= p
;
1499 struct apartment
*apt
;
1503 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1504 if (FAILED(hr
)) return hr
;
1506 apt
= COM_CurrentApt();
1507 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1509 apartment_createwindowifneeded(apt
);
1510 params
->apartment_hwnd
= apartment_getwindow(apt
);
1513 params
->apartment_hwnd
= NULL
;
1515 /* force the message queue to be created before signaling parent thread */
1516 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1518 SetEvent(params
->ready_event
);
1519 params
= NULL
; /* can't touch params after here as it may be invalid */
1521 while (GetMessageW(&msg
, NULL
, 0, 0))
1523 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1525 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1526 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1527 SetEvent(obj_params
->event
);
1531 TranslateMessage(&msg
);
1532 DispatchMessageW(&msg
);
1543 /* finds or creates a host apartment, creates the object inside it and returns
1544 * a proxy to it so that the object can be used in the apartment of the
1545 * caller of this function */
1546 static HRESULT
apartment_hostobject_in_hostapt(
1547 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1548 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1550 struct host_object_params params
;
1551 HWND apartment_hwnd
= NULL
;
1552 DWORD apartment_tid
= 0;
1555 if (!multi_threaded
&& main_apartment
)
1557 APARTMENT
*host_apt
= apartment_findmain();
1560 apartment_hwnd
= apartment_getwindow(host_apt
);
1561 apartment_release(host_apt
);
1565 if (!apartment_hwnd
)
1567 EnterCriticalSection(&apt
->cs
);
1569 if (!apt
->host_apt_tid
)
1571 struct host_thread_params thread_params
;
1575 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1576 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1577 thread_params
.apartment_hwnd
= NULL
;
1578 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1581 CloseHandle(handles
[0]);
1582 LeaveCriticalSection(&apt
->cs
);
1583 return E_OUTOFMEMORY
;
1585 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1586 CloseHandle(handles
[0]);
1587 CloseHandle(handles
[1]);
1588 if (wait_value
== WAIT_OBJECT_0
)
1589 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1592 LeaveCriticalSection(&apt
->cs
);
1593 return E_OUTOFMEMORY
;
1597 if (multi_threaded
|| !main_apartment
)
1599 apartment_hwnd
= apt
->host_apt_hwnd
;
1600 apartment_tid
= apt
->host_apt_tid
;
1603 LeaveCriticalSection(&apt
->cs
);
1606 /* another thread may have become the main apartment in the time it took
1607 * us to create the thread for the host apartment */
1608 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1610 APARTMENT
*host_apt
= apartment_findmain();
1613 apartment_hwnd
= apartment_getwindow(host_apt
);
1614 apartment_release(host_apt
);
1618 params
.regdata
= *regdata
;
1619 params
.clsid
= *rclsid
;
1621 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1624 params
.apartment_threaded
= !multi_threaded
;
1628 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1629 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1633 WaitForSingleObject(params
.event
, INFINITE
);
1636 CloseHandle(params
.event
);
1640 if (!apartment_hwnd
)
1642 ERR("host apartment didn't create window\n");
1646 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1649 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1650 IStream_Release(params
.stream
);
1654 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1658 /* Dispatching to the correct thread in an apartment is done through
1659 * window messages rather than RPC transports. When an interface is
1660 * marshalled into another apartment in the same process, a window of the
1661 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1662 * application) is responsible for pumping the message loop in that thread.
1663 * The WM_USER messages which point to the RPCs are then dispatched to
1664 * apartment_wndproc by the user's code from the apartment in which the
1665 * interface was unmarshalled.
1667 memset(&wclass
, 0, sizeof(wclass
));
1668 wclass
.lpfnWndProc
= apartment_wndproc
;
1669 wclass
.hInstance
= hProxyDll
;
1670 wclass
.lpszClassName
= wszAptWinClass
;
1671 RegisterClassW(&wclass
);
1675 /* create a window for the apartment or return the current one if one has
1676 * already been created */
1677 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1679 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1681 if (apt
->multi_threaded
)
1688 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1690 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1691 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1694 ERR("CreateWindow failed with error %d\n", GetLastError());
1695 return HRESULT_FROM_WIN32(GetLastError());
1697 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1698 /* someone beat us to it */
1699 DestroyWindow(hwnd
);
1705 /* retrieves the window for the main- or apartment-threaded apartment */
1706 HWND
apartment_getwindow(const struct apartment
*apt
)
1708 assert(!apt
->multi_threaded
);
1712 void apartment_joinmta(void)
1714 apartment_addref(MTA
);
1715 COM_CurrentInfo()->apt
= MTA
;
1718 static void COM_TlsDestroy(void)
1720 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1723 if (info
->apt
) apartment_release(info
->apt
);
1724 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1725 if (info
->state
) IUnknown_Release(info
->state
);
1726 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1727 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1728 HeapFree(GetProcessHeap(), 0, info
);
1729 NtCurrentTeb()->ReservedForOle
= NULL
;
1733 /******************************************************************************
1734 * CoBuildVersion [OLE32.@]
1736 * Gets the build version of the DLL.
1741 * Current build version, hiword is majornumber, loword is minornumber
1743 DWORD WINAPI
CoBuildVersion(void)
1745 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1746 return (rmm
<<16)+rup
;
1749 /******************************************************************************
1750 * CoRegisterInitializeSpy [OLE32.@]
1752 * Add a Spy that watches CoInitializeEx calls
1755 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1756 * cookie [II] cookie receiver
1759 * Success: S_OK if not already initialized, S_FALSE otherwise.
1760 * Failure: HRESULT code.
1765 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1767 struct oletls
*info
= COM_CurrentInfo();
1770 TRACE("(%p, %p)\n", spy
, cookie
);
1772 if (!spy
|| !cookie
|| !info
)
1775 WARN("Could not allocate tls\n");
1776 return E_INVALIDARG
;
1781 FIXME("Already registered?\n");
1782 return E_UNEXPECTED
;
1785 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1788 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1794 /******************************************************************************
1795 * CoRevokeInitializeSpy [OLE32.@]
1797 * Remove a spy that previously watched CoInitializeEx calls
1800 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1803 * Success: S_OK if a spy is removed
1804 * Failure: E_INVALIDARG
1809 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1811 struct oletls
*info
= COM_CurrentInfo();
1812 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1814 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1815 return E_INVALIDARG
;
1817 IInitializeSpy_Release(info
->spy
);
1823 /******************************************************************************
1824 * CoInitialize [OLE32.@]
1826 * Initializes the COM libraries by calling CoInitializeEx with
1827 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1830 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1833 * Success: S_OK if not already initialized, S_FALSE otherwise.
1834 * Failure: HRESULT code.
1839 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1842 * Just delegate to the newer method.
1844 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1847 /******************************************************************************
1848 * CoInitializeEx [OLE32.@]
1850 * Initializes the COM libraries.
1853 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1854 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1857 * S_OK if successful,
1858 * S_FALSE if this function was called already.
1859 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1864 * The behavior used to set the IMalloc used for memory management is
1866 * The dwCoInit parameter must specify one of the following apartment
1868 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1869 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1870 * The parameter may also specify zero or more of the following flags:
1871 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1872 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1877 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1879 struct oletls
*info
= COM_CurrentInfo();
1883 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1885 if (lpReserved
!=NULL
)
1887 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1891 * Check the lock count. If this is the first time going through the initialize
1892 * process, we have to initialize the libraries.
1894 * And crank-up that lock count.
1896 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1899 * Initialize the various COM libraries and data structures.
1901 TRACE("() - Initializing the COM libraries\n");
1903 /* we may need to defer this until after apartment initialisation */
1904 RunningObjectTableImpl_Initialize();
1908 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1910 if (!(apt
= info
->apt
))
1912 apt
= apartment_get_or_create(dwCoInit
);
1913 if (!apt
) return E_OUTOFMEMORY
;
1915 else if (!apartment_is_model(apt
, dwCoInit
))
1917 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1918 code then we are probably using the wrong threading model to implement that API. */
1919 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1920 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1921 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1922 return RPC_E_CHANGED_MODE
;
1930 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1935 /***********************************************************************
1936 * CoUninitialize [OLE32.@]
1938 * This method will decrement the refcount on the current apartment, freeing
1939 * the resources associated with it if it is the last thread in the apartment.
1940 * If the last apartment is freed, the function will additionally release
1941 * any COM resources associated with the process.
1951 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1953 struct oletls
* info
= COM_CurrentInfo();
1958 /* will only happen on OOM */
1962 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1967 ERR("Mismatched CoUninitialize\n");
1970 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1976 apartment_release(info
->apt
);
1981 * Decrease the reference count.
1982 * If we are back to 0 locks on the COM library, make sure we free
1983 * all the associated data structures.
1985 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1988 TRACE("() - Releasing the COM libraries\n");
1990 RunningObjectTableImpl_UnInitialize();
1992 else if (lCOMRefCnt
<1) {
1993 ERR( "CoUninitialize() - not CoInitialized.\n" );
1994 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1997 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2000 /******************************************************************************
2001 * CoDisconnectObject [OLE32.@]
2003 * Disconnects all connections to this object from remote processes. Dispatches
2004 * pending RPCs while blocking new RPCs from occurring, and then calls
2005 * IMarshal::DisconnectObject on the given object.
2007 * Typically called when the object server is forced to shut down, for instance by
2011 * lpUnk [I] The object whose stub should be disconnected.
2012 * reserved [I] Reserved. Should be set to 0.
2016 * Failure: HRESULT code.
2019 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2021 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2027 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2029 if (!lpUnk
) return E_INVALIDARG
;
2031 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2034 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2035 IMarshal_Release(marshal
);
2039 apt
= COM_CurrentApt();
2041 return CO_E_NOTINITIALIZED
;
2043 apartment_disconnectobject(apt
, lpUnk
);
2045 /* Note: native is pretty broken here because it just silently
2046 * fails, without returning an appropriate error code if the object was
2047 * not found, making apps think that the object was disconnected, when
2048 * it actually wasn't */
2053 /******************************************************************************
2054 * CoCreateGuid [OLE32.@]
2056 * Simply forwards to UuidCreate in RPCRT4.
2059 * pguid [O] Points to the GUID to initialize.
2063 * Failure: HRESULT code.
2068 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2072 if(!pguid
) return E_INVALIDARG
;
2074 status
= UuidCreate(pguid
);
2075 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2076 return HRESULT_FROM_WIN32( status
);
2079 static inline BOOL
is_valid_hex(WCHAR c
)
2081 if (!(((c
>= '0') && (c
<= '9')) ||
2082 ((c
>= 'a') && (c
<= 'f')) ||
2083 ((c
>= 'A') && (c
<= 'F'))))
2088 static const BYTE guid_conv_table
[256] =
2090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2091 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2092 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2093 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2094 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2095 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2096 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2099 /* conversion helper for CLSIDFromString/IIDFromString */
2100 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2104 if (!s
|| s
[0]!='{') {
2105 memset( id
, 0, sizeof (CLSID
) );
2110 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2112 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2115 for (i
= 1; i
< 9; i
++) {
2116 if (!is_valid_hex(s
[i
])) return FALSE
;
2117 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2119 if (s
[9]!='-') return FALSE
;
2122 for (i
= 10; i
< 14; i
++) {
2123 if (!is_valid_hex(s
[i
])) return FALSE
;
2124 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2126 if (s
[14]!='-') return FALSE
;
2129 for (i
= 15; i
< 19; i
++) {
2130 if (!is_valid_hex(s
[i
])) return FALSE
;
2131 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2133 if (s
[19]!='-') return FALSE
;
2135 for (i
= 20; i
< 37; i
+=2) {
2137 if (s
[i
]!='-') return FALSE
;
2140 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2141 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2144 if (s
[37] == '}' && s
[38] == '\0')
2150 /*****************************************************************************/
2152 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2154 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2155 WCHAR buf2
[CHARS_IN_GUID
];
2156 LONG buf2len
= sizeof(buf2
);
2160 memset(clsid
, 0, sizeof(*clsid
));
2161 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2162 if (!buf
) return E_OUTOFMEMORY
;
2163 strcpyW( buf
, progid
);
2164 strcatW( buf
, clsidW
);
2165 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2167 HeapFree(GetProcessHeap(),0,buf
);
2168 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2169 return CO_E_CLASSSTRING
;
2171 HeapFree(GetProcessHeap(),0,buf
);
2173 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2176 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2177 return CO_E_CLASSSTRING
;
2180 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2183 /******************************************************************************
2184 * CLSIDFromString [OLE32.@]
2186 * Converts a unique identifier from its string representation into
2190 * idstr [I] The string representation of the GUID.
2191 * id [O] GUID converted from the string.
2195 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2200 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2202 HRESULT ret
= CO_E_CLASSSTRING
;
2206 return E_INVALIDARG
;
2208 if (guid_from_string(idstr
, id
))
2211 /* It appears a ProgID is also valid */
2212 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2219 /******************************************************************************
2220 * IIDFromString [OLE32.@]
2222 * Converts a interface identifier from its string representation into
2226 * idstr [I] The string representation of the GUID.
2227 * id [O] IID converted from the string.
2231 * CO_E_IIDSTRING if idstr is not a valid IID
2236 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2238 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2242 memset(iid
, 0, sizeof(*iid
));
2246 /* length mismatch is a special case */
2247 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2248 return E_INVALIDARG
;
2251 return CO_E_IIDSTRING
;
2253 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2256 /******************************************************************************
2257 * StringFromCLSID [OLE32.@]
2258 * StringFromIID [OLE32.@]
2260 * Converts a GUID into the respective string representation.
2261 * The target string is allocated using the OLE IMalloc.
2264 * id [I] the GUID to be converted.
2265 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2272 * StringFromGUID2, CLSIDFromString
2274 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2276 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2277 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2281 /******************************************************************************
2282 * StringFromGUID2 [OLE32.@]
2284 * Modified version of StringFromCLSID that allows you to specify max
2288 * id [I] GUID to convert to string.
2289 * str [O] Buffer where the result will be stored.
2290 * cmax [I] Size of the buffer in characters.
2293 * Success: The length of the resulting string in characters.
2296 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2298 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2299 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2300 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2301 '%','0','2','X','%','0','2','X','}',0 };
2302 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2303 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2304 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2305 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2306 return CHARS_IN_GUID
;
2309 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2310 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2312 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2313 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2317 strcpyW(path
, wszCLSIDSlash
);
2318 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2319 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2320 if (res
== ERROR_FILE_NOT_FOUND
)
2321 return REGDB_E_CLASSNOTREG
;
2322 else if (res
!= ERROR_SUCCESS
)
2323 return REGDB_E_READREGDB
;
2331 res
= open_classes_key(key
, keyname
, access
, subkey
);
2333 if (res
== ERROR_FILE_NOT_FOUND
)
2334 return REGDB_E_KEYMISSING
;
2335 else if (res
!= ERROR_SUCCESS
)
2336 return REGDB_E_READREGDB
;
2341 /* open HKCR\\AppId\\{string form of appid clsid} key */
2342 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2344 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2345 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2347 WCHAR buf
[CHARS_IN_GUID
];
2348 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2354 /* read the AppID value under the class's key */
2355 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2360 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2362 if (res
== ERROR_FILE_NOT_FOUND
)
2363 return REGDB_E_KEYMISSING
;
2364 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2365 return REGDB_E_READREGDB
;
2367 strcpyW(keyname
, szAppIdKey
);
2368 strcatW(keyname
, buf
);
2369 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2370 if (res
== ERROR_FILE_NOT_FOUND
)
2371 return REGDB_E_KEYMISSING
;
2372 else if (res
!= ERROR_SUCCESS
)
2373 return REGDB_E_READREGDB
;
2378 /******************************************************************************
2379 * ProgIDFromCLSID [OLE32.@]
2381 * Converts a class id into the respective program ID.
2384 * clsid [I] Class ID, as found in registry.
2385 * ppszProgID [O] Associated ProgID.
2390 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2392 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2394 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2395 ACTCTX_SECTION_KEYED_DATA data
;
2401 return E_INVALIDARG
;
2405 data
.cbSize
= sizeof(data
);
2406 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2409 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2410 if (comclass
->progid_len
)
2414 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2415 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2417 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2418 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2422 return REGDB_E_CLASSNOTREG
;
2425 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2429 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2430 ret
= REGDB_E_CLASSNOTREG
;
2434 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2437 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2438 ret
= REGDB_E_CLASSNOTREG
;
2439 CoTaskMemFree(*ppszProgID
);
2444 ret
= E_OUTOFMEMORY
;
2451 /******************************************************************************
2452 * CLSIDFromProgID [OLE32.@]
2454 * Converts a program id into the respective GUID.
2457 * progid [I] Unicode program ID, as found in registry.
2458 * clsid [O] Associated CLSID.
2462 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2464 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2466 ACTCTX_SECTION_KEYED_DATA data
;
2468 if (!progid
|| !clsid
)
2469 return E_INVALIDARG
;
2471 data
.cbSize
= sizeof(data
);
2472 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2475 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2476 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2481 return clsid_from_string_reg(progid
, clsid
);
2484 /******************************************************************************
2485 * CLSIDFromProgIDEx [OLE32.@]
2487 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2489 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2491 return CLSIDFromProgID(progid
, clsid
);
2494 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2497 WCHAR value
[CHARS_IN_GUID
];
2502 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2503 return REGDB_E_IIDNOTREG
;
2505 len
= sizeof(value
);
2506 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2507 return REGDB_E_IIDNOTREG
;
2510 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2511 return REGDB_E_IIDNOTREG
;
2516 /*****************************************************************************
2517 * CoGetPSClsid [OLE32.@]
2519 * Retrieves the CLSID of the proxy/stub factory that implements
2520 * IPSFactoryBuffer for the specified interface.
2523 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2524 * pclsid [O] Where to store returned proxy/stub CLSID.
2529 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2533 * The standard marshaller activates the object with the CLSID
2534 * returned and uses the CreateProxy and CreateStub methods on its
2535 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2538 * CoGetPSClsid determines this CLSID by searching the
2539 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2540 * in the registry and any interface id registered by
2541 * CoRegisterPSClsid within the current process.
2545 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2546 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2547 * considered a bug in native unless an application depends on this (unlikely).
2550 * CoRegisterPSClsid.
2552 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2554 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2555 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2556 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2557 APARTMENT
*apt
= COM_CurrentApt();
2558 struct registered_psclsid
*registered_psclsid
;
2559 ACTCTX_SECTION_KEYED_DATA data
;
2561 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2564 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2568 ERR("apartment not initialised\n");
2569 return CO_E_NOTINITIALIZED
;
2573 return E_INVALIDARG
;
2575 EnterCriticalSection(&apt
->cs
);
2577 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2578 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2580 *pclsid
= registered_psclsid
->clsid
;
2581 LeaveCriticalSection(&apt
->cs
);
2585 LeaveCriticalSection(&apt
->cs
);
2587 data
.cbSize
= sizeof(data
);
2588 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2591 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2592 *pclsid
= ifaceps
->iid
;
2596 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2597 strcpyW(path
, wszInterface
);
2598 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2599 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2601 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2602 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2603 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2604 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2607 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2609 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2614 /*****************************************************************************
2615 * CoRegisterPSClsid [OLE32.@]
2617 * Register a proxy/stub CLSID for the given interface in the current process
2621 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2622 * rclsid [I] CLSID of the proxy/stub.
2626 * Failure: E_OUTOFMEMORY
2630 * This function does not add anything to the registry and the effects are
2631 * limited to the lifetime of the current process.
2636 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2638 APARTMENT
*apt
= COM_CurrentApt();
2639 struct registered_psclsid
*registered_psclsid
;
2641 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2645 ERR("apartment not initialised\n");
2646 return CO_E_NOTINITIALIZED
;
2649 EnterCriticalSection(&apt
->cs
);
2651 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2652 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2654 registered_psclsid
->clsid
= *rclsid
;
2655 LeaveCriticalSection(&apt
->cs
);
2659 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2660 if (!registered_psclsid
)
2662 LeaveCriticalSection(&apt
->cs
);
2663 return E_OUTOFMEMORY
;
2666 registered_psclsid
->iid
= *riid
;
2667 registered_psclsid
->clsid
= *rclsid
;
2668 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2670 LeaveCriticalSection(&apt
->cs
);
2677 * COM_GetRegisteredClassObject
2679 * This internal method is used to scan the registered class list to
2680 * find a class object.
2683 * rclsid Class ID of the class to find.
2684 * dwClsContext Class context to match.
2685 * ppv [out] returns a pointer to the class object. Complying
2686 * to normal COM usage, this method will increase the
2687 * reference count on this object.
2689 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2690 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2692 HRESULT hr
= S_FALSE
;
2693 RegisteredClass
*curClass
;
2695 EnterCriticalSection( &csRegisteredClassList
);
2697 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2700 * Check if we have a match on the class ID and context.
2702 if ((apt
->oxid
== curClass
->apartment_id
) &&
2703 (dwClsContext
& curClass
->runContext
) &&
2704 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2707 * We have a match, return the pointer to the class object.
2709 *ppUnk
= curClass
->classObject
;
2711 IUnknown_AddRef(curClass
->classObject
);
2718 LeaveCriticalSection( &csRegisteredClassList
);
2723 /******************************************************************************
2724 * CoRegisterClassObject [OLE32.@]
2726 * Registers the class object for a given class ID. Servers housed in EXE
2727 * files use this method instead of exporting DllGetClassObject to allow
2728 * other code to connect to their objects.
2731 * rclsid [I] CLSID of the object to register.
2732 * pUnk [I] IUnknown of the object.
2733 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2734 * flags [I] REGCLS flags indicating how connections are made.
2735 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2739 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2740 * CO_E_OBJISREG if the object is already registered. We should not return this.
2743 * CoRevokeClassObject, CoGetClassObject
2746 * In-process objects are only registered for the current apartment.
2747 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2748 * in other apartments.
2751 * MSDN claims that multiple interface registrations are legal, but we
2752 * can't do that with our current implementation.
2754 HRESULT WINAPI
CoRegisterClassObject(
2759 LPDWORD lpdwRegister
)
2761 static LONG next_cookie
;
2762 RegisteredClass
* newClass
;
2763 LPUNKNOWN foundObject
;
2767 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2768 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2770 if ( (lpdwRegister
==0) || (pUnk
==0) )
2771 return E_INVALIDARG
;
2773 apt
= COM_CurrentApt();
2776 ERR("COM was not initialized\n");
2777 return CO_E_NOTINITIALIZED
;
2782 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2783 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2784 if (flags
& REGCLS_MULTIPLEUSE
)
2785 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2788 * First, check if the class is already registered.
2789 * If it is, this should cause an error.
2791 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2793 if (flags
& REGCLS_MULTIPLEUSE
) {
2794 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2795 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2796 IUnknown_Release(foundObject
);
2799 IUnknown_Release(foundObject
);
2800 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2801 return CO_E_OBJISREG
;
2804 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2805 if ( newClass
== NULL
)
2806 return E_OUTOFMEMORY
;
2808 newClass
->classIdentifier
= *rclsid
;
2809 newClass
->apartment_id
= apt
->oxid
;
2810 newClass
->runContext
= dwClsContext
;
2811 newClass
->connectFlags
= flags
;
2812 newClass
->RpcRegistration
= NULL
;
2814 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2815 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2818 * Since we're making a copy of the object pointer, we have to increase its
2821 newClass
->classObject
= pUnk
;
2822 IUnknown_AddRef(newClass
->classObject
);
2824 EnterCriticalSection( &csRegisteredClassList
);
2825 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2826 LeaveCriticalSection( &csRegisteredClassList
);
2828 *lpdwRegister
= newClass
->dwCookie
;
2830 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2831 IStream
*marshal_stream
;
2833 hr
= get_local_server_stream(apt
, &marshal_stream
);
2837 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2839 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2840 &newClass
->RpcRegistration
);
2841 IStream_Release(marshal_stream
);
2846 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2850 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2851 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2852 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2853 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2854 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2855 DWORD dwLength
= sizeof(threading_model
);
2859 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2860 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2861 threading_model
[0] = '\0';
2863 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2864 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2865 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2867 /* there's not specific handling for this case */
2868 if (threading_model
[0]) return ThreadingModel_Neutral
;
2869 return ThreadingModel_No
;
2872 return data
->u
.actctx
.data
->model
;
2875 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2876 REFCLSID rclsid
, REFIID riid
,
2877 BOOL hostifnecessary
, void **ppv
)
2879 WCHAR dllpath
[MAX_PATH
+1];
2880 BOOL apartment_threaded
;
2882 if (hostifnecessary
)
2884 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2886 if (model
== ThreadingModel_Apartment
)
2888 apartment_threaded
= TRUE
;
2889 if (apt
->multi_threaded
)
2890 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2892 else if (model
== ThreadingModel_Free
)
2894 apartment_threaded
= FALSE
;
2895 if (!apt
->multi_threaded
)
2896 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2898 /* everything except "Apartment", "Free" and "Both" */
2899 else if (model
!= ThreadingModel_Both
)
2901 apartment_threaded
= TRUE
;
2902 /* everything else is main-threaded */
2903 if (model
!= ThreadingModel_No
)
2904 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2906 if (apt
->multi_threaded
|| !apt
->main
)
2907 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2910 apartment_threaded
= FALSE
;
2913 apartment_threaded
= !apt
->multi_threaded
;
2915 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2917 /* failure: CLSID is not found in registry */
2918 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2919 return REGDB_E_CLASSNOTREG
;
2922 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2926 /***********************************************************************
2927 * CoGetClassObject [OLE32.@]
2929 * Creates an object of the specified class.
2932 * rclsid [I] Class ID to create an instance of.
2933 * dwClsContext [I] Flags to restrict the location of the created instance.
2934 * pServerInfo [I] Optional. Details for connecting to a remote server.
2935 * iid [I] The ID of the interface of the instance to return.
2936 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2940 * Failure: HRESULT code.
2943 * The dwClsContext parameter can be one or more of the following:
2944 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2945 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2946 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2947 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2950 * CoCreateInstance()
2952 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2953 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2954 REFIID iid
, LPVOID
*ppv
)
2956 struct class_reg_data clsreg
;
2957 IUnknown
*regClassObject
;
2958 HRESULT hres
= E_UNEXPECTED
;
2960 BOOL release_apt
= FALSE
;
2962 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2965 return E_INVALIDARG
;
2969 if (!(apt
= COM_CurrentApt()))
2971 if (!(apt
= apartment_find_multi_threaded()))
2973 ERR("apartment not initialised\n");
2974 return CO_E_NOTINITIALIZED
;
2980 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2981 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2984 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2986 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2988 if (release_apt
) apartment_release(apt
);
2989 return FTMarshalCF_Create(iid
, ppv
);
2993 if (CLSCTX_INPROC
& dwClsContext
)
2995 ACTCTX_SECTION_KEYED_DATA data
;
2997 data
.cbSize
= sizeof(data
);
2998 /* search activation context first */
2999 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3000 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3003 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3005 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3006 clsreg
.u
.actctx
.data
= data
.lpData
;
3007 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3008 clsreg
.hkey
= FALSE
;
3010 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3011 ReleaseActCtx(data
.hActCtx
);
3012 if (release_apt
) apartment_release(apt
);
3018 * First, try and see if we can't match the class ID with one of the
3019 * registered classes.
3021 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3024 /* Get the required interface from the retrieved pointer. */
3025 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3028 * Since QI got another reference on the pointer, we want to release the
3029 * one we already have. If QI was unsuccessful, this will release the object. This
3030 * is good since we are not returning it in the "out" parameter.
3032 IUnknown_Release(regClassObject
);
3033 if (release_apt
) apartment_release(apt
);
3037 /* First try in-process server */
3038 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3040 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3043 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3046 if (hres
== REGDB_E_CLASSNOTREG
)
3047 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3048 else if (hres
== REGDB_E_KEYMISSING
)
3050 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3051 hres
= REGDB_E_CLASSNOTREG
;
3055 if (SUCCEEDED(hres
))
3057 clsreg
.u
.hkey
= hkey
;
3060 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3064 /* return if we got a class, otherwise fall through to one of the
3066 if (SUCCEEDED(hres
))
3068 if (release_apt
) apartment_release(apt
);
3073 /* Next try in-process handler */
3074 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3076 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3079 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3082 if (hres
== REGDB_E_CLASSNOTREG
)
3083 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3084 else if (hres
== REGDB_E_KEYMISSING
)
3086 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3087 hres
= REGDB_E_CLASSNOTREG
;
3091 if (SUCCEEDED(hres
))
3093 clsreg
.u
.hkey
= hkey
;
3096 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3100 /* return if we got a class, otherwise fall through to one of the
3102 if (SUCCEEDED(hres
))
3104 if (release_apt
) apartment_release(apt
);
3108 if (release_apt
) apartment_release(apt
);
3110 /* Next try out of process */
3111 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3113 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3114 if (SUCCEEDED(hres
))
3118 /* Finally try remote: this requires networked DCOM (a lot of work) */
3119 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3121 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3122 hres
= REGDB_E_CLASSNOTREG
;
3126 ERR("no class object %s could be created for context 0x%x\n",
3127 debugstr_guid(rclsid
), dwClsContext
);
3131 /***********************************************************************
3132 * CoResumeClassObjects (OLE32.@)
3134 * Resumes all class objects registered with REGCLS_SUSPENDED.
3138 * Failure: HRESULT code.
3140 HRESULT WINAPI
CoResumeClassObjects(void)
3146 /***********************************************************************
3147 * CoCreateInstance [OLE32.@]
3149 * Creates an instance of the specified class.
3152 * rclsid [I] Class ID to create an instance of.
3153 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3154 * dwClsContext [I] Flags to restrict the location of the created instance.
3155 * iid [I] The ID of the interface of the instance to return.
3156 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3160 * Failure: HRESULT code.
3163 * The dwClsContext parameter can be one or more of the following:
3164 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3165 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3166 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3167 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3169 * Aggregation is the concept of deferring the IUnknown of an object to another
3170 * object. This allows a separate object to behave as though it was part of
3171 * the object and to allow this the pUnkOuter parameter can be set. Note that
3172 * not all objects support having an outer of unknown.
3175 * CoGetClassObject()
3177 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3179 LPUNKNOWN pUnkOuter
,
3185 LPCLASSFACTORY lpclf
= 0;
3189 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3190 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3195 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3201 if (!(apt
= COM_CurrentApt()))
3203 if (!(apt
= apartment_find_multi_threaded()))
3205 ERR("apartment not initialised\n");
3206 return CO_E_NOTINITIALIZED
;
3208 apartment_release(apt
);
3212 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3214 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3216 IGlobalInterfaceTable
*git
= get_std_git();
3217 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
3218 if (hres
!= S_OK
) return hres
;
3220 TRACE("Retrieved GIT (%p)\n", *ppv
);
3224 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
))
3225 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
3228 * Get a class factory to construct the object we want.
3230 hres
= CoGetClassObject(&clsid
,
3240 * Create the object and don't forget to release the factory
3242 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
3243 IClassFactory_Release(lpclf
);
3246 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3247 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3249 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3251 debugstr_guid(&clsid
),hres
);
3257 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
)
3261 for (i
= 0; i
< count
; i
++)
3264 mqi
[i
].hr
= E_NOINTERFACE
;
3268 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
)
3270 ULONG index
, fetched
= 0;
3272 for (index
= 0; index
< count
; index
++)
3274 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3275 if (mqi
[index
].hr
== S_OK
)
3279 IUnknown_Release(unk
);
3282 return E_NOINTERFACE
;
3284 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3287 /***********************************************************************
3288 * CoCreateInstanceEx [OLE32.@]
3290 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3292 LPUNKNOWN pUnkOuter
,
3294 COSERVERINFO
* pServerInfo
,
3298 IUnknown
* pUnk
= NULL
;
3304 if ( (cmq
==0) || (pResults
==NULL
))
3305 return E_INVALIDARG
;
3307 if (pServerInfo
!=NULL
)
3308 FIXME("() non-NULL pServerInfo not supported!\n");
3310 init_multi_qi(cmq
, pResults
);
3313 * Get the object and get its IUnknown pointer.
3315 hr
= CoCreateInstance(rclsid
,
3324 return return_multi_qi(pUnk
, cmq
, pResults
);
3327 /***********************************************************************
3328 * CoGetInstanceFromFile [OLE32.@]
3330 HRESULT WINAPI
CoGetInstanceFromFile(
3331 COSERVERINFO
*server_info
,
3341 IPersistFile
*pf
= NULL
;
3342 IUnknown
* unk
= NULL
;
3346 if (count
== 0 || !results
)
3347 return E_INVALIDARG
;
3350 FIXME("() non-NULL server_info not supported\n");
3352 init_multi_qi(count
, results
);
3354 /* optionally get CLSID from a file */
3357 hr
= GetClassFile(filename
, &clsid
);
3360 ERR("failed to get CLSID from a file\n");
3367 hr
= CoCreateInstance(rclsid
,
3376 /* init from file */
3377 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3379 ERR("failed to get IPersistFile\n");
3383 IPersistFile_Load(pf
, filename
, grfmode
);
3384 IPersistFile_Release(pf
);
3387 return return_multi_qi(unk
, count
, results
);
3390 /***********************************************************************
3391 * CoGetInstanceFromIStorage [OLE32.@]
3393 HRESULT WINAPI
CoGetInstanceFromIStorage(
3394 COSERVERINFO
*server_info
,
3403 IPersistStorage
*ps
= NULL
;
3404 IUnknown
* unk
= NULL
;
3408 if (count
== 0 || !results
|| !storage
)
3409 return E_INVALIDARG
;
3412 FIXME("() non-NULL server_info not supported\n");
3414 init_multi_qi(count
, results
);
3416 /* optionally get CLSID from a file */
3419 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3420 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3423 ERR("failed to get CLSID from a file\n");
3427 rclsid
= &stat
.clsid
;
3430 hr
= CoCreateInstance(rclsid
,
3439 /* init from IStorage */
3440 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3442 ERR("failed to get IPersistStorage\n");
3446 IPersistStorage_Load(ps
, storage
);
3447 IPersistStorage_Release(ps
);
3450 return return_multi_qi(unk
, count
, results
);
3453 /***********************************************************************
3454 * CoLoadLibrary (OLE32.@)
3459 * lpszLibName [I] Path to library.
3460 * bAutoFree [I] Whether the library should automatically be freed.
3463 * Success: Handle to loaded library.
3467 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3469 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3471 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3473 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3476 /***********************************************************************
3477 * CoFreeLibrary [OLE32.@]
3479 * Unloads a library from memory.
3482 * hLibrary [I] Handle to library to unload.
3488 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3490 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3492 FreeLibrary(hLibrary
);
3496 /***********************************************************************
3497 * CoFreeAllLibraries [OLE32.@]
3499 * Function for backwards compatibility only. Does nothing.
3505 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3507 void WINAPI
CoFreeAllLibraries(void)
3512 /***********************************************************************
3513 * CoFreeUnusedLibrariesEx [OLE32.@]
3515 * Frees any previously unused libraries whose delay has expired and marks
3516 * currently unused libraries for unloading. Unused are identified as those that
3517 * return S_OK from their DllCanUnloadNow function.
3520 * dwUnloadDelay [I] Unload delay in milliseconds.
3521 * dwReserved [I] Reserved. Set to 0.
3527 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3529 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3531 struct apartment
*apt
= COM_CurrentApt();
3534 ERR("apartment not initialised\n");
3538 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3541 /***********************************************************************
3542 * CoFreeUnusedLibraries [OLE32.@]
3544 * Frees any unused libraries. Unused are identified as those that return
3545 * S_OK from their DllCanUnloadNow function.
3551 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3553 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3555 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3558 /***********************************************************************
3559 * CoFileTimeNow [OLE32.@]
3561 * Retrieves the current time in FILETIME format.
3564 * lpFileTime [O] The current time.
3569 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3571 GetSystemTimeAsFileTime( lpFileTime
);
3575 /******************************************************************************
3576 * CoLockObjectExternal [OLE32.@]
3578 * Increments or decrements the external reference count of a stub object.
3581 * pUnk [I] Stub object.
3582 * fLock [I] If TRUE then increments the external ref-count,
3583 * otherwise decrements.
3584 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3585 * calling CoDisconnectObject.
3589 * Failure: HRESULT code.
3592 * If fLock is TRUE and an object is passed in that doesn't have a stub
3593 * manager then a new stub manager is created for the object.
3595 HRESULT WINAPI
CoLockObjectExternal(
3598 BOOL fLastUnlockReleases
)
3600 struct stub_manager
*stubmgr
;
3601 struct apartment
*apt
;
3603 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3604 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3606 apt
= COM_CurrentApt();
3607 if (!apt
) return CO_E_NOTINITIALIZED
;
3609 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3614 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3616 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3618 stub_manager_int_release(stubmgr
);
3624 stubmgr
= new_stub_manager(apt
, pUnk
);
3628 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3629 stub_manager_int_release(stubmgr
);
3636 WARN("stub object not found %p\n", pUnk
);
3637 /* Note: native is pretty broken here because it just silently
3638 * fails, without returning an appropriate error code, making apps
3639 * think that the object was disconnected, when it actually wasn't */
3644 /***********************************************************************
3645 * CoInitializeWOW (OLE32.@)
3647 * WOW equivalent of CoInitialize?
3656 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3658 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3662 /***********************************************************************
3663 * CoGetState [OLE32.@]
3665 * Retrieves the thread state object previously stored by CoSetState().
3668 * ppv [I] Address where pointer to object will be stored.
3672 * Failure: E_OUTOFMEMORY.
3675 * Crashes on all invalid ppv addresses, including NULL.
3676 * If the function returns a non-NULL object then the caller must release its
3677 * reference on the object when the object is no longer required.
3682 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3684 struct oletls
*info
= COM_CurrentInfo();
3685 if (!info
) return E_OUTOFMEMORY
;
3691 IUnknown_AddRef(info
->state
);
3693 TRACE("apt->state=%p\n", info
->state
);
3699 /***********************************************************************
3700 * CoSetState [OLE32.@]
3702 * Sets the thread state object.
3705 * pv [I] Pointer to state object to be stored.
3708 * The system keeps a reference on the object while the object stored.
3712 * Failure: E_OUTOFMEMORY.
3714 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3716 struct oletls
*info
= COM_CurrentInfo();
3717 if (!info
) return E_OUTOFMEMORY
;
3719 if (pv
) IUnknown_AddRef(pv
);
3723 TRACE("-- release %p now\n", info
->state
);
3724 IUnknown_Release(info
->state
);
3733 /******************************************************************************
3734 * CoTreatAsClass [OLE32.@]
3736 * Sets the TreatAs value of a class.
3739 * clsidOld [I] Class to set TreatAs value on.
3740 * clsidNew [I] The class the clsidOld should be treated as.
3744 * Failure: HRESULT code.
3749 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3751 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3752 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3754 WCHAR szClsidNew
[CHARS_IN_GUID
];
3756 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3757 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3760 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3764 if (IsEqualGUID( clsidOld
, clsidNew
))
3766 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3767 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3769 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3771 res
= REGDB_E_WRITEREGDB
;
3777 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3778 res
= REGDB_E_WRITEREGDB
;
3784 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3785 RegDeleteKeyW(hkey
, wszTreatAs
);
3787 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3788 WARN("StringFromGUID2 failed\n");
3793 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3794 WARN("RegSetValue failed\n");
3795 res
= REGDB_E_WRITEREGDB
;
3802 if (hkey
) RegCloseKey(hkey
);
3806 /******************************************************************************
3807 * CoGetTreatAsClass [OLE32.@]
3809 * Gets the TreatAs value of a class.
3812 * clsidOld [I] Class to get the TreatAs value of.
3813 * clsidNew [I] The class the clsidOld should be treated as.
3817 * Failure: HRESULT code.
3822 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3824 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3826 WCHAR szClsidNew
[CHARS_IN_GUID
];
3828 LONG len
= sizeof(szClsidNew
);
3830 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3831 *clsidNew
= *clsidOld
; /* copy over old value */
3833 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3839 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3844 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3846 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3848 if (hkey
) RegCloseKey(hkey
);
3852 /******************************************************************************
3853 * CoGetCurrentProcess [OLE32.@]
3855 * Gets the current process ID.
3858 * The current process ID.
3861 * Is DWORD really the correct return type for this function?
3863 DWORD WINAPI
CoGetCurrentProcess(void)
3865 return GetCurrentProcessId();
3868 /******************************************************************************
3869 * CoRegisterMessageFilter [OLE32.@]
3871 * Registers a message filter.
3874 * lpMessageFilter [I] Pointer to interface.
3875 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3879 * Failure: HRESULT code.
3882 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3883 * lpMessageFilter removes the message filter.
3885 * If lplpMessageFilter is not NULL the previous message filter will be
3886 * returned in the memory pointer to this parameter and the caller is
3887 * responsible for releasing the object.
3889 * The current thread be in an apartment otherwise the function will crash.
3891 HRESULT WINAPI
CoRegisterMessageFilter(
3892 LPMESSAGEFILTER lpMessageFilter
,
3893 LPMESSAGEFILTER
*lplpMessageFilter
)
3895 struct apartment
*apt
;
3896 IMessageFilter
*lpOldMessageFilter
;
3898 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3900 apt
= COM_CurrentApt();
3902 /* can't set a message filter in a multi-threaded apartment */
3903 if (!apt
|| apt
->multi_threaded
)
3905 WARN("can't set message filter in MTA or uninitialized apt\n");
3906 return CO_E_NOT_SUPPORTED
;
3909 if (lpMessageFilter
)
3910 IMessageFilter_AddRef(lpMessageFilter
);
3912 EnterCriticalSection(&apt
->cs
);
3914 lpOldMessageFilter
= apt
->filter
;
3915 apt
->filter
= lpMessageFilter
;
3917 LeaveCriticalSection(&apt
->cs
);
3919 if (lplpMessageFilter
)
3920 *lplpMessageFilter
= lpOldMessageFilter
;
3921 else if (lpOldMessageFilter
)
3922 IMessageFilter_Release(lpOldMessageFilter
);
3927 /***********************************************************************
3928 * CoIsOle1Class [OLE32.@]
3930 * Determines whether the specified class an OLE v1 class.
3933 * clsid [I] Class to test.
3936 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3938 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3940 FIXME("%s\n", debugstr_guid(clsid
));
3944 /***********************************************************************
3945 * IsEqualGUID [OLE32.@]
3947 * Compares two Unique Identifiers.
3950 * rguid1 [I] The first GUID to compare.
3951 * rguid2 [I] The other GUID to compare.
3957 BOOL WINAPI
IsEqualGUID(
3961 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3964 /***********************************************************************
3965 * CoInitializeSecurity [OLE32.@]
3967 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3968 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3969 void* pReserved1
, DWORD dwAuthnLevel
,
3970 DWORD dwImpLevel
, void* pReserved2
,
3971 DWORD dwCapabilities
, void* pReserved3
)
3973 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3974 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3975 dwCapabilities
, pReserved3
);
3979 /***********************************************************************
3980 * CoSuspendClassObjects [OLE32.@]
3982 * Suspends all registered class objects to prevent further requests coming in
3983 * for those objects.
3987 * Failure: HRESULT code.
3989 HRESULT WINAPI
CoSuspendClassObjects(void)
3995 /***********************************************************************
3996 * CoAddRefServerProcess [OLE32.@]
3998 * Helper function for incrementing the reference count of a local-server
4002 * New reference count.
4005 * CoReleaseServerProcess().
4007 ULONG WINAPI
CoAddRefServerProcess(void)
4013 EnterCriticalSection(&csRegisteredClassList
);
4014 refs
= ++s_COMServerProcessReferences
;
4015 LeaveCriticalSection(&csRegisteredClassList
);
4017 TRACE("refs before: %d\n", refs
- 1);
4022 /***********************************************************************
4023 * CoReleaseServerProcess [OLE32.@]
4025 * Helper function for decrementing the reference count of a local-server
4029 * New reference count.
4032 * When reference count reaches 0, this function suspends all registered
4033 * classes so no new connections are accepted.
4036 * CoAddRefServerProcess(), CoSuspendClassObjects().
4038 ULONG WINAPI
CoReleaseServerProcess(void)
4044 EnterCriticalSection(&csRegisteredClassList
);
4046 refs
= --s_COMServerProcessReferences
;
4047 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4049 LeaveCriticalSection(&csRegisteredClassList
);
4051 TRACE("refs after: %d\n", refs
);
4056 /***********************************************************************
4057 * CoIsHandlerConnected [OLE32.@]
4059 * Determines whether a proxy is connected to a remote stub.
4062 * pUnk [I] Pointer to object that may or may not be connected.
4065 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4068 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4070 FIXME("%p\n", pUnk
);
4075 /***********************************************************************
4076 * CoAllowSetForegroundWindow [OLE32.@]
4079 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4081 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4085 /***********************************************************************
4086 * CoQueryProxyBlanket [OLE32.@]
4088 * Retrieves the security settings being used by a proxy.
4091 * pProxy [I] Pointer to the proxy object.
4092 * pAuthnSvc [O] The type of authentication service.
4093 * pAuthzSvc [O] The type of authorization service.
4094 * ppServerPrincName [O] Optional. The server prinicple name.
4095 * pAuthnLevel [O] The authentication level.
4096 * pImpLevel [O] The impersonation level.
4097 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4098 * pCapabilities [O] Flags affecting the security behaviour.
4102 * Failure: HRESULT code.
4105 * CoCopyProxy, CoSetProxyBlanket.
4107 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4108 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4109 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4111 IClientSecurity
*pCliSec
;
4114 TRACE("%p\n", pProxy
);
4116 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4119 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4120 pAuthzSvc
, ppServerPrincName
,
4121 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4123 IClientSecurity_Release(pCliSec
);
4126 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4130 /***********************************************************************
4131 * CoSetProxyBlanket [OLE32.@]
4133 * Sets the security settings for a proxy.
4136 * pProxy [I] Pointer to the proxy object.
4137 * AuthnSvc [I] The type of authentication service.
4138 * AuthzSvc [I] The type of authorization service.
4139 * pServerPrincName [I] The server prinicple name.
4140 * AuthnLevel [I] The authentication level.
4141 * ImpLevel [I] The impersonation level.
4142 * pAuthInfo [I] Information specific to the authorization/authentication service.
4143 * Capabilities [I] Flags affecting the security behaviour.
4147 * Failure: HRESULT code.
4150 * CoQueryProxyBlanket, CoCopyProxy.
4152 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4153 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4154 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4156 IClientSecurity
*pCliSec
;
4159 TRACE("%p\n", pProxy
);
4161 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4164 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4165 AuthzSvc
, pServerPrincName
,
4166 AuthnLevel
, ImpLevel
, pAuthInfo
,
4168 IClientSecurity_Release(pCliSec
);
4171 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4175 /***********************************************************************
4176 * CoCopyProxy [OLE32.@]
4181 * pProxy [I] Pointer to the proxy object.
4182 * ppCopy [O] Copy of the proxy.
4186 * Failure: HRESULT code.
4189 * CoQueryProxyBlanket, CoSetProxyBlanket.
4191 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4193 IClientSecurity
*pCliSec
;
4196 TRACE("%p\n", pProxy
);
4198 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4201 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4202 IClientSecurity_Release(pCliSec
);
4205 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4210 /***********************************************************************
4211 * CoGetCallContext [OLE32.@]
4213 * Gets the context of the currently executing server call in the current
4217 * riid [I] Context interface to return.
4218 * ppv [O] Pointer to memory that will receive the context on return.
4222 * Failure: HRESULT code.
4224 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4226 struct oletls
*info
= COM_CurrentInfo();
4228 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4231 return E_OUTOFMEMORY
;
4233 if (!info
->call_state
)
4234 return RPC_E_CALL_COMPLETE
;
4236 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4239 /***********************************************************************
4240 * CoSwitchCallContext [OLE32.@]
4242 * Switches the context of the currently executing server call in the current
4246 * pObject [I] Pointer to new context object
4247 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4251 * Failure: HRESULT code.
4253 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4255 struct oletls
*info
= COM_CurrentInfo();
4257 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4260 return E_OUTOFMEMORY
;
4262 *ppOldObject
= info
->call_state
;
4263 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4268 /***********************************************************************
4269 * CoQueryClientBlanket [OLE32.@]
4271 * Retrieves the authentication information about the client of the currently
4272 * executing server call in the current thread.
4275 * pAuthnSvc [O] Optional. The type of authentication service.
4276 * pAuthzSvc [O] Optional. The type of authorization service.
4277 * pServerPrincName [O] Optional. The server prinicple name.
4278 * pAuthnLevel [O] Optional. The authentication level.
4279 * pImpLevel [O] Optional. The impersonation level.
4280 * pPrivs [O] Optional. Information about the privileges of the client.
4281 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4285 * Failure: HRESULT code.
4288 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4290 HRESULT WINAPI
CoQueryClientBlanket(
4293 OLECHAR
**pServerPrincName
,
4296 RPC_AUTHZ_HANDLE
*pPrivs
,
4297 DWORD
*pCapabilities
)
4299 IServerSecurity
*pSrvSec
;
4302 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4303 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4304 pPrivs
, pCapabilities
);
4306 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4309 hr
= IServerSecurity_QueryBlanket(
4310 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4311 pImpLevel
, pPrivs
, pCapabilities
);
4312 IServerSecurity_Release(pSrvSec
);
4318 /***********************************************************************
4319 * CoImpersonateClient [OLE32.@]
4321 * Impersonates the client of the currently executing server call in the
4329 * Failure: HRESULT code.
4332 * If this function fails then the current thread will not be impersonating
4333 * the client and all actions will take place on behalf of the server.
4334 * Therefore, it is important to check the return value from this function.
4337 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4339 HRESULT WINAPI
CoImpersonateClient(void)
4341 IServerSecurity
*pSrvSec
;
4346 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4349 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4350 IServerSecurity_Release(pSrvSec
);
4356 /***********************************************************************
4357 * CoRevertToSelf [OLE32.@]
4359 * Ends the impersonation of the client of the currently executing server
4360 * call in the current thread.
4367 * Failure: HRESULT code.
4370 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4372 HRESULT WINAPI
CoRevertToSelf(void)
4374 IServerSecurity
*pSrvSec
;
4379 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4382 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4383 IServerSecurity_Release(pSrvSec
);
4389 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4391 /* first try to retrieve messages for incoming COM calls to the apartment window */
4392 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
4393 /* next retrieve other messages necessary for the app to remain responsive */
4394 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4395 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4398 /***********************************************************************
4399 * CoWaitForMultipleHandles [OLE32.@]
4401 * Waits for one or more handles to become signaled.
4404 * dwFlags [I] Flags. See notes.
4405 * dwTimeout [I] Timeout in milliseconds.
4406 * cHandles [I] Number of handles pointed to by pHandles.
4407 * pHandles [I] Handles to wait for.
4408 * lpdwindex [O] Index of handle that was signaled.
4412 * Failure: RPC_S_CALLPENDING on timeout.
4416 * The dwFlags parameter can be zero or more of the following:
4417 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4418 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4421 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4423 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4424 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4427 DWORD start_time
= GetTickCount();
4428 APARTMENT
*apt
= COM_CurrentApt();
4429 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4430 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4432 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4433 pHandles
, lpdwindex
);
4436 return E_INVALIDARG
;
4441 return E_INVALIDARG
;
4444 return RPC_E_NO_SYNC
;
4448 DWORD now
= GetTickCount();
4451 if (now
- start_time
> dwTimeout
)
4453 hr
= RPC_S_CALLPENDING
;
4459 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4460 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4462 TRACE("waiting for rpc completion or window message\n");
4468 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4469 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4473 if (res
== WAIT_TIMEOUT
)
4474 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4475 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4476 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4478 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4483 /* call message filter */
4485 if (COM_CurrentApt()->filter
)
4487 PENDINGTYPE pendingtype
=
4488 COM_CurrentInfo()->pending_call_count_server
?
4489 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4490 DWORD be_handled
= IMessageFilter_MessagePending(
4491 COM_CurrentApt()->filter
, 0 /* FIXME */,
4492 now
- start_time
, pendingtype
);
4493 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4496 case PENDINGMSG_CANCELCALL
:
4497 WARN("call canceled\n");
4498 hr
= RPC_E_CALL_CANCELED
;
4500 case PENDINGMSG_WAITNOPROCESS
:
4501 case PENDINGMSG_WAITDEFPROCESS
:
4503 /* FIXME: MSDN is very vague about the difference
4504 * between WAITNOPROCESS and WAITDEFPROCESS - there
4505 * appears to be none, so it is possibly a left-over
4506 * from the 16-bit world. */
4511 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4512 * so after processing 100 messages we go back to checking the wait handles */
4513 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4515 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4516 TranslateMessage(&msg
);
4517 DispatchMessageW(&msg
);
4518 if (msg
.message
== WM_QUIT
)
4520 TRACE("resending WM_QUIT to outer message loop\n");
4521 PostQuitMessage(msg
.wParam
);
4522 /* no longer need to process messages */
4523 message_loop
= FALSE
;
4532 TRACE("waiting for rpc completion\n");
4534 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4535 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4536 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4542 hr
= RPC_S_CALLPENDING
;
4545 hr
= HRESULT_FROM_WIN32( GetLastError() );
4553 TRACE("-- 0x%08x\n", hr
);
4558 /***********************************************************************
4559 * CoGetObject [OLE32.@]
4561 * Gets the object named by converting the name to a moniker and binding to it.
4564 * pszName [I] String representing the object.
4565 * pBindOptions [I] Parameters affecting the binding to the named object.
4566 * riid [I] Interface to bind to on the objecct.
4567 * ppv [O] On output, the interface riid of the object represented
4572 * Failure: HRESULT code.
4575 * MkParseDisplayName.
4577 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4578 REFIID riid
, void **ppv
)
4585 hr
= CreateBindCtx(0, &pbc
);
4589 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4596 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4599 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4600 IMoniker_Release(pmk
);
4604 IBindCtx_Release(pbc
);
4609 /***********************************************************************
4610 * CoRegisterChannelHook [OLE32.@]
4612 * Registers a process-wide hook that is called during ORPC calls.
4615 * guidExtension [I] GUID of the channel hook to register.
4616 * pChannelHook [I] Channel hook object to register.
4620 * Failure: HRESULT code.
4622 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4624 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4626 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4629 typedef struct Context
4631 IComThreadingInfo IComThreadingInfo_iface
;
4632 IContextCallback IContextCallback_iface
;
4633 IObjContext IObjContext_iface
;
4638 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4640 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4643 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4645 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4648 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4650 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4653 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4657 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4658 IsEqualIID(riid
, &IID_IUnknown
))
4660 *ppv
= &iface
->IComThreadingInfo_iface
;
4662 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4664 *ppv
= &iface
->IContextCallback_iface
;
4666 else if (IsEqualIID(riid
, &IID_IObjContext
))
4668 *ppv
= &iface
->IObjContext_iface
;
4673 IUnknown_AddRef((IUnknown
*)*ppv
);
4677 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4678 return E_NOINTERFACE
;
4681 static ULONG
Context_AddRef(Context
*This
)
4683 return InterlockedIncrement(&This
->refs
);
4686 static ULONG
Context_Release(Context
*This
)
4688 ULONG refs
= InterlockedDecrement(&This
->refs
);
4690 HeapFree(GetProcessHeap(), 0, This
);
4694 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4696 Context
*This
= impl_from_IComThreadingInfo(iface
);
4697 return Context_QueryInterface(This
, riid
, ppv
);
4700 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4702 Context
*This
= impl_from_IComThreadingInfo(iface
);
4703 return Context_AddRef(This
);
4706 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4708 Context
*This
= impl_from_IComThreadingInfo(iface
);
4709 return Context_Release(This
);
4712 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4714 Context
*This
= impl_from_IComThreadingInfo(iface
);
4716 TRACE("(%p)\n", apttype
);
4718 *apttype
= This
->apttype
;
4722 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4724 Context
*This
= impl_from_IComThreadingInfo(iface
);
4726 TRACE("(%p)\n", thdtype
);
4728 switch (This
->apttype
)
4731 case APTTYPE_MAINSTA
:
4732 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4735 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4741 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4743 FIXME("(%p): stub\n", logical_thread_id
);
4747 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4749 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4753 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4755 Context_CTI_QueryInterface
,
4757 Context_CTI_Release
,
4758 Context_CTI_GetCurrentApartmentType
,
4759 Context_CTI_GetCurrentThreadType
,
4760 Context_CTI_GetCurrentLogicalThreadId
,
4761 Context_CTI_SetCurrentLogicalThreadId
4764 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4766 Context
*This
= impl_from_IContextCallback(iface
);
4767 return Context_QueryInterface(This
, riid
, ppv
);
4770 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4772 Context
*This
= impl_from_IContextCallback(iface
);
4773 return Context_AddRef(This
);
4776 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4778 Context
*This
= impl_from_IContextCallback(iface
);
4779 return Context_Release(This
);
4782 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4783 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4785 Context
*This
= impl_from_IContextCallback(iface
);
4787 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4791 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4793 Context_CC_QueryInterface
,
4796 Context_CC_ContextCallback
4799 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4801 Context
*This
= impl_from_IObjContext(iface
);
4802 return Context_QueryInterface(This
, riid
, ppv
);
4805 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4807 Context
*This
= impl_from_IObjContext(iface
);
4808 return Context_AddRef(This
);
4811 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4813 Context
*This
= impl_from_IObjContext(iface
);
4814 return Context_Release(This
);
4817 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4819 Context
*This
= impl_from_IObjContext(iface
);
4821 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4825 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4827 Context
*This
= impl_from_IObjContext(iface
);
4829 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4833 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4835 Context
*This
= impl_from_IObjContext(iface
);
4837 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4841 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4843 Context
*This
= impl_from_IObjContext(iface
);
4845 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4849 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4851 Context
*This
= impl_from_IObjContext(iface
);
4852 FIXME("(%p/%p)\n", This
, iface
);
4855 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4857 Context
*This
= impl_from_IObjContext(iface
);
4858 FIXME("(%p/%p)\n", This
, iface
);
4861 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4863 Context
*This
= impl_from_IObjContext(iface
);
4864 FIXME("(%p/%p)\n", This
, iface
);
4867 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4869 Context
*This
= impl_from_IObjContext(iface
);
4870 FIXME("(%p/%p)\n", This
, iface
);
4873 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4875 Context
*This
= impl_from_IObjContext(iface
);
4876 FIXME("(%p/%p)\n", This
, iface
);
4879 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4881 Context
*This
= impl_from_IObjContext(iface
);
4882 FIXME("(%p/%p)\n", This
, iface
);
4885 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4887 Context
*This
= impl_from_IObjContext(iface
);
4888 FIXME("(%p/%p)\n", This
, iface
);
4891 static const IObjContextVtbl Context_Object_Vtbl
=
4893 Context_OC_QueryInterface
,
4896 Context_OC_SetProperty
,
4897 Context_OC_RemoveProperty
,
4898 Context_OC_GetProperty
,
4899 Context_OC_EnumContextProps
,
4900 Context_OC_Reserved1
,
4901 Context_OC_Reserved2
,
4902 Context_OC_Reserved3
,
4903 Context_OC_Reserved4
,
4904 Context_OC_Reserved5
,
4905 Context_OC_Reserved6
,
4906 Context_OC_Reserved7
4909 /***********************************************************************
4910 * CoGetObjectContext [OLE32.@]
4912 * Retrieves an object associated with the current context (i.e. apartment).
4915 * riid [I] ID of the interface of the object to retrieve.
4916 * ppv [O] Address where object will be stored on return.
4920 * Failure: HRESULT code.
4922 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4924 APARTMENT
*apt
= COM_CurrentApt();
4928 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4933 if (!(apt
= apartment_find_multi_threaded()))
4935 ERR("apartment not initialised\n");
4936 return CO_E_NOTINITIALIZED
;
4938 apartment_release(apt
);
4941 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4943 return E_OUTOFMEMORY
;
4945 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4946 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4947 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4949 if (apt
->multi_threaded
)
4950 context
->apttype
= APTTYPE_MTA
;
4952 context
->apttype
= APTTYPE_MAINSTA
;
4954 context
->apttype
= APTTYPE_STA
;
4956 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4957 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4963 /***********************************************************************
4964 * CoGetContextToken [OLE32.@]
4966 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4968 struct oletls
*info
= COM_CurrentInfo();
4970 TRACE("(%p)\n", token
);
4973 return E_OUTOFMEMORY
;
4978 if (!(apt
= apartment_find_multi_threaded()))
4980 ERR("apartment not initialised\n");
4981 return CO_E_NOTINITIALIZED
;
4983 apartment_release(apt
);
4989 if (!info
->context_token
)
4994 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4995 if (FAILED(hr
)) return hr
;
4996 info
->context_token
= ctx
;
4999 *token
= (ULONG_PTR
)info
->context_token
;
5000 TRACE("apt->context_token=%p\n", info
->context_token
);
5005 /***********************************************************************
5006 * CoGetDefaultContext [OLE32.@]
5008 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5010 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5011 return E_NOINTERFACE
;
5014 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5016 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5020 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5021 if (SUCCEEDED(hres
))
5023 struct class_reg_data regdata
;
5024 WCHAR dllpath
[MAX_PATH
+1];
5026 regdata
.u
.hkey
= hkey
;
5027 regdata
.hkey
= TRUE
;
5029 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
5031 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5032 if (!strcmpiW(dllpath
, wszOle32
))
5035 return HandlerCF_Create(rclsid
, riid
, ppv
);
5039 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5043 return CLASS_E_CLASSNOTAVAILABLE
;
5046 /***********************************************************************
5049 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5051 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5054 case DLL_PROCESS_ATTACH
:
5055 hProxyDll
= hinstDLL
;
5058 case DLL_PROCESS_DETACH
:
5059 if (reserved
) break;
5061 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5062 RPC_UnregisterAllChannelHooks();
5063 COMPOBJ_DllList_Free();
5064 DeleteCriticalSection(&csRegisteredClassList
);
5065 DeleteCriticalSection(&csApartment
);
5068 case DLL_THREAD_DETACH
:
5075 /***********************************************************************
5076 * DllRegisterServer (OLE32.@)
5078 HRESULT WINAPI
DllRegisterServer(void)
5080 return OLE32_DllRegisterServer();
5083 /***********************************************************************
5084 * DllUnregisterServer (OLE32.@)
5086 HRESULT WINAPI
DllUnregisterServer(void)
5088 return OLE32_DllUnregisterServer();