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(void)
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
, MAXIMUM_ALLOWED
, &attr
)) return 0;
354 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
356 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
359 NtClose( hkey
); /* somebody beat us to it */
363 /* map the hkey from special root to normal key if necessary */
364 static inline HKEY
get_classes_root_hkey( HKEY hkey
)
368 if (hkey
== HKEY_CLASSES_ROOT
&& !(ret
= classes_root_hkey
))
369 ret
= create_classes_root_hkey();
374 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
376 OBJECT_ATTRIBUTES attr
;
377 UNICODE_STRING nameW
;
379 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
381 attr
.Length
= sizeof(attr
);
382 attr
.RootDirectory
= hkey
;
383 attr
.ObjectName
= &nameW
;
385 attr
.SecurityDescriptor
= NULL
;
386 attr
.SecurityQualityOfService
= NULL
;
387 RtlInitUnicodeString( &nameW
, name
);
389 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
392 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
394 OBJECT_ATTRIBUTES attr
;
395 UNICODE_STRING nameW
;
397 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
399 attr
.Length
= sizeof(attr
);
400 attr
.RootDirectory
= hkey
;
401 attr
.ObjectName
= &nameW
;
403 attr
.SecurityDescriptor
= NULL
;
404 attr
.SecurityQualityOfService
= NULL
;
405 RtlInitUnicodeString( &nameW
, name
);
407 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
410 /*****************************************************************************
411 * This section contains OpenDllList definitions
413 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
414 * other functions that do LoadLibrary _without_ giving back a HMODULE.
415 * Without this list these handles would never be freed.
417 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
418 * next unload-call but not before 600 sec.
421 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
422 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
424 typedef struct tagOpenDll
429 DllGetClassObjectFunc DllGetClassObject
;
430 DllCanUnloadNowFunc DllCanUnloadNow
;
434 static struct list openDllList
= LIST_INIT(openDllList
);
436 static CRITICAL_SECTION csOpenDllList
;
437 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
439 0, 0, &csOpenDllList
,
440 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
441 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
443 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
445 struct apartment_loaded_dll
453 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',' ',
454 '0','x','#','#','#','#','#','#','#','#',' ',0};
456 /*****************************************************************************
457 * This section contains OpenDllList implementation
460 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
464 EnterCriticalSection(&csOpenDllList
);
465 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
467 if (!strcmpiW(library_name
, ptr
->library_name
) &&
468 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
474 LeaveCriticalSection(&csOpenDllList
);
478 /* caller must ensure that library_name is not already in the open dll list */
479 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
485 DllCanUnloadNowFunc DllCanUnloadNow
;
486 DllGetClassObjectFunc DllGetClassObject
;
488 TRACE("%s\n", debugstr_w(library_name
));
490 *ret
= COMPOBJ_DllList_Get(library_name
);
491 if (*ret
) return S_OK
;
493 /* do this outside the csOpenDllList to avoid creating a lock dependency on
495 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
498 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
499 /* failure: DLL could not be loaded */
500 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
503 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
504 /* Note: failing to find DllCanUnloadNow is not a failure */
505 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
506 if (!DllGetClassObject
)
508 /* failure: the dll did not export DllGetClassObject */
509 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
510 FreeLibrary(hLibrary
);
511 return CO_E_DLLNOTFOUND
;
514 EnterCriticalSection( &csOpenDllList
);
516 *ret
= COMPOBJ_DllList_Get(library_name
);
519 /* another caller to this function already added the dll while we
520 * weren't in the critical section */
521 FreeLibrary(hLibrary
);
525 len
= strlenW(library_name
);
526 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
528 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
529 if (entry
&& entry
->library_name
)
531 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
532 entry
->library
= hLibrary
;
534 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
535 entry
->DllGetClassObject
= DllGetClassObject
;
536 list_add_tail(&openDllList
, &entry
->entry
);
541 HeapFree(GetProcessHeap(), 0, entry
);
543 FreeLibrary(hLibrary
);
547 LeaveCriticalSection( &csOpenDllList
);
552 /* pass FALSE for free_entry to release a reference without destroying the
553 * entry if it reaches zero or TRUE otherwise */
554 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
556 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
558 EnterCriticalSection(&csOpenDllList
);
559 list_remove(&entry
->entry
);
560 LeaveCriticalSection(&csOpenDllList
);
562 TRACE("freeing %p\n", entry
->library
);
563 FreeLibrary(entry
->library
);
565 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
566 HeapFree(GetProcessHeap(), 0, entry
);
570 /* frees memory associated with active dll list */
571 static void COMPOBJ_DllList_Free(void)
573 OpenDll
*entry
, *cursor2
;
574 EnterCriticalSection(&csOpenDllList
);
575 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
577 list_remove(&entry
->entry
);
579 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
580 HeapFree(GetProcessHeap(), 0, entry
);
582 LeaveCriticalSection(&csOpenDllList
);
583 DeleteCriticalSection(&csOpenDllList
);
586 /******************************************************************************
590 static DWORD
apartment_addref(struct apartment
*apt
)
592 DWORD refs
= InterlockedIncrement(&apt
->refs
);
593 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
597 /* allocates memory and fills in the necessary fields for a new apartment
598 * object. must be called inside apartment cs */
599 static APARTMENT
*apartment_construct(DWORD model
)
603 TRACE("creating new apartment, model=%d\n", model
);
605 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
606 apt
->tid
= GetCurrentThreadId();
608 list_init(&apt
->proxies
);
609 list_init(&apt
->stubmgrs
);
610 list_init(&apt
->psclsids
);
611 list_init(&apt
->loaded_dlls
);
614 apt
->remunk_exported
= FALSE
;
616 InitializeCriticalSection(&apt
->cs
);
617 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
619 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
621 if (apt
->multi_threaded
)
623 /* FIXME: should be randomly generated by in an RPC call to rpcss */
624 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
628 /* FIXME: should be randomly generated by in an RPC call to rpcss */
629 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
632 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
634 list_add_head(&apts
, &apt
->entry
);
639 /* gets and existing apartment if one exists or otherwise creates an apartment
640 * structure which stores OLE apartment-local information and stores a pointer
641 * to it in the thread-local storage */
642 static APARTMENT
*apartment_get_or_create(DWORD model
)
644 APARTMENT
*apt
= COM_CurrentApt();
648 if (model
& COINIT_APARTMENTTHREADED
)
650 EnterCriticalSection(&csApartment
);
652 apt
= apartment_construct(model
);
657 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
660 LeaveCriticalSection(&csApartment
);
663 apartment_createwindowifneeded(apt
);
667 EnterCriticalSection(&csApartment
);
669 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
670 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
674 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
675 apartment_addref(MTA
);
678 MTA
= apartment_construct(model
);
682 LeaveCriticalSection(&csApartment
);
684 COM_CurrentInfo()->apt
= apt
;
690 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
692 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
695 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
697 list_remove(&curClass
->entry
);
699 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
700 RPC_StopLocalServer(curClass
->RpcRegistration
);
702 IUnknown_Release(curClass
->classObject
);
703 HeapFree(GetProcessHeap(), 0, curClass
);
706 static void COM_RevokeAllClasses(const struct apartment
*apt
)
708 RegisteredClass
*curClass
, *cursor
;
710 EnterCriticalSection( &csRegisteredClassList
);
712 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
714 if (curClass
->apartment_id
== apt
->oxid
)
715 COM_RevokeRegisteredClassObject(curClass
);
718 LeaveCriticalSection( &csRegisteredClassList
);
721 /******************************************************************************
722 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
725 typedef struct ManualResetEvent
{
726 ISynchronize ISynchronize_iface
;
727 ISynchronizeHandle ISynchronizeHandle_iface
;
732 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
734 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
737 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
739 MREImpl
*This
= impl_from_ISynchronize(iface
);
741 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
743 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
744 *ppv
= &This
->ISynchronize_iface
;
745 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
746 *ppv
= &This
->ISynchronizeHandle_iface
;
748 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
750 return E_NOINTERFACE
;
753 IUnknown_AddRef((IUnknown
*)*ppv
);
757 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
759 MREImpl
*This
= impl_from_ISynchronize(iface
);
760 LONG ref
= InterlockedIncrement(&This
->ref
);
761 TRACE("%p - ref %d\n", This
, ref
);
766 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
768 MREImpl
*This
= impl_from_ISynchronize(iface
);
769 LONG ref
= InterlockedDecrement(&This
->ref
);
770 TRACE("%p - ref %d\n", This
, ref
);
774 CloseHandle(This
->event
);
775 HeapFree(GetProcessHeap(), 0, This
);
781 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
783 MREImpl
*This
= impl_from_ISynchronize(iface
);
785 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
786 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
789 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
791 MREImpl
*This
= impl_from_ISynchronize(iface
);
793 SetEvent(This
->event
);
797 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
799 MREImpl
*This
= impl_from_ISynchronize(iface
);
801 ResetEvent(This
->event
);
805 static ISynchronizeVtbl vt_ISynchronize
= {
806 ISynchronize_fnQueryInterface
,
807 ISynchronize_fnAddRef
,
808 ISynchronize_fnRelease
,
810 ISynchronize_fnSignal
,
814 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
816 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
819 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
821 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
822 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
825 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
827 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
828 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
831 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
833 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
834 return ISynchronize_Release(&This
->ISynchronize_iface
);
837 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
839 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
845 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
846 SynchronizeHandle_QueryInterface
,
847 SynchronizeHandle_AddRef
,
848 SynchronizeHandle_Release
,
849 SynchronizeHandle_GetHandle
852 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
854 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
858 FIXME("Aggregation not implemented.\n");
861 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
862 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
863 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
865 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
866 ISynchronize_Release(&This
->ISynchronize_iface
);
870 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
872 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
875 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
877 LocalServer
*This
= impl_from_IServiceProvider(iface
);
879 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
881 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
882 *ppv
= &This
->IServiceProvider_iface
;
885 return E_NOINTERFACE
;
888 IUnknown_AddRef((IUnknown
*)*ppv
);
892 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
894 LocalServer
*This
= impl_from_IServiceProvider(iface
);
895 LONG ref
= InterlockedIncrement(&This
->ref
);
897 TRACE("(%p) ref=%d\n", This
, ref
);
902 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
904 LocalServer
*This
= impl_from_IServiceProvider(iface
);
905 LONG ref
= InterlockedDecrement(&This
->ref
);
907 TRACE("(%p) ref=%d\n", This
, ref
);
911 HeapFree(GetProcessHeap(), 0, This
);
917 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
919 LocalServer
*This
= impl_from_IServiceProvider(iface
);
920 APARTMENT
*apt
= COM_CurrentApt();
921 RegisteredClass
*iter
;
922 HRESULT hres
= E_FAIL
;
924 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
929 EnterCriticalSection(&csRegisteredClassList
);
931 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
932 if(iter
->apartment_id
== apt
->oxid
933 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
934 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
935 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
940 LeaveCriticalSection( &csRegisteredClassList
);
945 static const IServiceProviderVtbl LocalServerVtbl
= {
946 LocalServer_QueryInterface
,
949 LocalServer_QueryService
952 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
956 EnterCriticalSection(&apt
->cs
);
958 if(!apt
->local_server
) {
961 obj
= heap_alloc(sizeof(*obj
));
963 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
967 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
968 if(SUCCEEDED(hres
)) {
969 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
970 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
972 IStream_Release(obj
->marshal_stream
);
976 apt
->local_server
= obj
;
980 hres
= E_OUTOFMEMORY
;
985 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
987 LeaveCriticalSection(&apt
->cs
);
990 ERR("Failed: %08x\n", hres
);
994 /***********************************************************************
995 * CoRevokeClassObject [OLE32.@]
997 * Removes a class object from the class registry.
1000 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1004 * Failure: HRESULT code.
1007 * Must be called from the same apartment that called CoRegisterClassObject(),
1008 * otherwise it will fail with RPC_E_WRONG_THREAD.
1011 * CoRegisterClassObject
1013 HRESULT WINAPI
CoRevokeClassObject(
1016 HRESULT hr
= E_INVALIDARG
;
1017 RegisteredClass
*curClass
;
1020 TRACE("(%08x)\n",dwRegister
);
1022 apt
= COM_CurrentApt();
1025 ERR("COM was not initialized\n");
1026 return CO_E_NOTINITIALIZED
;
1029 EnterCriticalSection( &csRegisteredClassList
);
1031 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1034 * Check if we have a match on the cookie.
1036 if (curClass
->dwCookie
== dwRegister
)
1038 if (curClass
->apartment_id
== apt
->oxid
)
1040 COM_RevokeRegisteredClassObject(curClass
);
1045 ERR("called from wrong apartment, should be called from %s\n",
1046 wine_dbgstr_longlong(curClass
->apartment_id
));
1047 hr
= RPC_E_WRONG_THREAD
;
1053 LeaveCriticalSection( &csRegisteredClassList
);
1058 /* frees unused libraries loaded by apartment_getclassobject by calling the
1059 * DLL's DllCanUnloadNow entry point */
1060 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1062 struct apartment_loaded_dll
*entry
, *next
;
1063 EnterCriticalSection(&apt
->cs
);
1064 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1066 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1068 DWORD real_delay
= delay
;
1070 if (real_delay
== INFINITE
)
1072 /* DLLs that return multi-threaded objects aren't unloaded
1073 * straight away to cope for programs that have races between
1074 * last object destruction and threads in the DLLs that haven't
1075 * finished, despite DllCanUnloadNow returning S_OK */
1076 if (entry
->multi_threaded
)
1077 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1082 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1084 list_remove(&entry
->entry
);
1085 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1086 HeapFree(GetProcessHeap(), 0, entry
);
1090 entry
->unload_time
= GetTickCount() + real_delay
;
1091 if (!entry
->unload_time
) entry
->unload_time
= 1;
1094 else if (entry
->unload_time
)
1095 entry
->unload_time
= 0;
1097 LeaveCriticalSection(&apt
->cs
);
1100 DWORD
apartment_release(struct apartment
*apt
)
1104 EnterCriticalSection(&csApartment
);
1106 ret
= InterlockedDecrement(&apt
->refs
);
1107 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1108 /* destruction stuff that needs to happen under csApartment CS */
1111 if (apt
== MTA
) MTA
= NULL
;
1112 else if (apt
== MainApartment
) MainApartment
= NULL
;
1113 list_remove(&apt
->entry
);
1116 LeaveCriticalSection(&csApartment
);
1120 struct list
*cursor
, *cursor2
;
1122 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1124 if(apt
->local_server
) {
1125 LocalServer
*local_server
= apt
->local_server
;
1128 memset(&zero
, 0, sizeof(zero
));
1129 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1130 CoReleaseMarshalData(local_server
->marshal_stream
);
1131 IStream_Release(local_server
->marshal_stream
);
1132 local_server
->marshal_stream
= NULL
;
1134 apt
->local_server
= NULL
;
1135 local_server
->apt
= NULL
;
1136 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1139 /* Release the references to the registered class objects */
1140 COM_RevokeAllClasses(apt
);
1142 /* no locking is needed for this apartment, because no other thread
1143 * can access it at this point */
1145 apartment_disconnectproxies(apt
);
1147 if (apt
->win
) DestroyWindow(apt
->win
);
1148 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1150 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1152 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1153 /* release the implicit reference given by the fact that the
1154 * stub has external references (it must do since it is in the
1155 * stub manager list in the apartment and all non-apartment users
1156 * must have a ref on the apartment and so it cannot be destroyed).
1158 stub_manager_int_release(stubmgr
);
1161 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1163 struct registered_psclsid
*registered_psclsid
=
1164 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1166 list_remove(®istered_psclsid
->entry
);
1167 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1170 /* if this assert fires, then another thread took a reference to a
1171 * stub manager without taking a reference to the containing
1172 * apartment, which it must do. */
1173 assert(list_empty(&apt
->stubmgrs
));
1175 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1177 /* free as many unused libraries as possible... */
1178 apartment_freeunusedlibraries(apt
, 0);
1180 /* ... and free the memory for the apartment loaded dll entry and
1181 * release the dll list reference without freeing the library for the
1183 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1185 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1186 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1187 list_remove(cursor
);
1188 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1191 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1192 DeleteCriticalSection(&apt
->cs
);
1194 HeapFree(GetProcessHeap(), 0, apt
);
1200 /* The given OXID must be local to this process:
1202 * The ref parameter is here mostly to ensure people remember that
1203 * they get one, you should normally take a ref for thread safety.
1205 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1207 APARTMENT
*result
= NULL
;
1208 struct list
*cursor
;
1210 EnterCriticalSection(&csApartment
);
1211 LIST_FOR_EACH( cursor
, &apts
)
1213 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1214 if (apt
->oxid
== oxid
)
1217 if (ref
) apartment_addref(result
);
1221 LeaveCriticalSection(&csApartment
);
1226 /* gets the apartment which has a given creator thread ID. The caller must
1227 * release the reference from the apartment as soon as the apartment pointer
1228 * is no longer required. */
1229 APARTMENT
*apartment_findfromtid(DWORD tid
)
1231 APARTMENT
*result
= NULL
;
1232 struct list
*cursor
;
1234 EnterCriticalSection(&csApartment
);
1235 LIST_FOR_EACH( cursor
, &apts
)
1237 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1238 if (apt
->tid
== tid
)
1241 apartment_addref(result
);
1245 LeaveCriticalSection(&csApartment
);
1250 /* gets the main apartment if it exists. The caller must
1251 * release the reference from the apartment as soon as the apartment pointer
1252 * is no longer required. */
1253 static APARTMENT
*apartment_findmain(void)
1257 EnterCriticalSection(&csApartment
);
1259 result
= MainApartment
;
1260 if (result
) apartment_addref(result
);
1262 LeaveCriticalSection(&csApartment
);
1267 /* gets the multi-threaded apartment if it exists. The caller must
1268 * release the reference from the apartment as soon as the apartment pointer
1269 * is no longer required. */
1270 static APARTMENT
*apartment_find_multi_threaded(void)
1272 APARTMENT
*result
= NULL
;
1273 struct list
*cursor
;
1275 EnterCriticalSection(&csApartment
);
1277 LIST_FOR_EACH( cursor
, &apts
)
1279 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1280 if (apt
->multi_threaded
)
1283 apartment_addref(result
);
1288 LeaveCriticalSection(&csApartment
);
1292 /* gets the specified class object by loading the appropriate DLL, if
1293 * necessary and calls the DllGetClassObject function for the DLL */
1294 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1295 BOOL apartment_threaded
,
1296 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1298 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1301 struct apartment_loaded_dll
*apartment_loaded_dll
;
1303 if (!strcmpiW(dllpath
, wszOle32
))
1305 /* we don't need to control the lifetime of this dll, so use the local
1306 * implementation of DllGetClassObject directly */
1307 TRACE("calling ole32!DllGetClassObject\n");
1308 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1311 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1316 EnterCriticalSection(&apt
->cs
);
1318 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1319 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1321 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1328 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1329 if (!apartment_loaded_dll
)
1333 apartment_loaded_dll
->unload_time
= 0;
1334 apartment_loaded_dll
->multi_threaded
= FALSE
;
1335 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1337 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1341 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1342 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1346 LeaveCriticalSection(&apt
->cs
);
1350 /* one component being multi-threaded overrides any number of
1351 * apartment-threaded components */
1352 if (!apartment_threaded
)
1353 apartment_loaded_dll
->multi_threaded
= TRUE
;
1355 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1356 /* OK: get the ClassObject */
1357 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1360 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1366 /***********************************************************************
1367 * COM_RegReadPath [internal]
1369 * Reads a registry value and expands it when necessary
1371 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1378 WCHAR src
[MAX_PATH
];
1379 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1381 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1382 if (keytype
== REG_EXPAND_SZ
) {
1383 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1385 const WCHAR
*quote_start
;
1386 quote_start
= strchrW(src
, '\"');
1388 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1390 memmove(src
, quote_start
+ 1,
1391 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1392 src
[quote_end
- quote_start
- 1] = '\0';
1395 lstrcpynW(dst
, src
, dstlen
);
1406 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1407 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1408 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1409 DeactivateActCtx(0, cookie
);
1414 struct host_object_params
1416 struct class_reg_data regdata
;
1417 CLSID clsid
; /* clsid of object to marshal */
1418 IID iid
; /* interface to marshal */
1419 HANDLE event
; /* event signalling when ready for multi-threaded case */
1420 HRESULT hr
; /* result for multi-threaded case */
1421 IStream
*stream
; /* stream that the object will be marshaled into */
1422 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1425 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1426 const struct host_object_params
*params
)
1430 static const LARGE_INTEGER llZero
;
1431 WCHAR dllpath
[MAX_PATH
+1];
1433 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1435 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1437 /* failure: CLSID is not found in registry */
1438 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1439 return REGDB_E_CLASSNOTREG
;
1442 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1443 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1447 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1449 IUnknown_Release(object
);
1450 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1455 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1460 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1463 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1465 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1469 struct host_thread_params
1471 COINIT threading_model
;
1473 HWND apartment_hwnd
;
1476 /* thread for hosting an object to allow an object to appear to be created in
1477 * an apartment with an incompatible threading model */
1478 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1480 struct host_thread_params
*params
= p
;
1483 struct apartment
*apt
;
1487 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1488 if (FAILED(hr
)) return hr
;
1490 apt
= COM_CurrentApt();
1491 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1493 apartment_createwindowifneeded(apt
);
1494 params
->apartment_hwnd
= apartment_getwindow(apt
);
1497 params
->apartment_hwnd
= NULL
;
1499 /* force the message queue to be created before signaling parent thread */
1500 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1502 SetEvent(params
->ready_event
);
1503 params
= NULL
; /* can't touch params after here as it may be invalid */
1505 while (GetMessageW(&msg
, NULL
, 0, 0))
1507 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1509 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1510 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1511 SetEvent(obj_params
->event
);
1515 TranslateMessage(&msg
);
1516 DispatchMessageW(&msg
);
1527 /* finds or creates a host apartment, creates the object inside it and returns
1528 * a proxy to it so that the object can be used in the apartment of the
1529 * caller of this function */
1530 static HRESULT
apartment_hostobject_in_hostapt(
1531 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1532 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1534 struct host_object_params params
;
1535 HWND apartment_hwnd
= NULL
;
1536 DWORD apartment_tid
= 0;
1539 if (!multi_threaded
&& main_apartment
)
1541 APARTMENT
*host_apt
= apartment_findmain();
1544 apartment_hwnd
= apartment_getwindow(host_apt
);
1545 apartment_release(host_apt
);
1549 if (!apartment_hwnd
)
1551 EnterCriticalSection(&apt
->cs
);
1553 if (!apt
->host_apt_tid
)
1555 struct host_thread_params thread_params
;
1559 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1560 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1561 thread_params
.apartment_hwnd
= NULL
;
1562 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1565 CloseHandle(handles
[0]);
1566 LeaveCriticalSection(&apt
->cs
);
1567 return E_OUTOFMEMORY
;
1569 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1570 CloseHandle(handles
[0]);
1571 CloseHandle(handles
[1]);
1572 if (wait_value
== WAIT_OBJECT_0
)
1573 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1576 LeaveCriticalSection(&apt
->cs
);
1577 return E_OUTOFMEMORY
;
1581 if (multi_threaded
|| !main_apartment
)
1583 apartment_hwnd
= apt
->host_apt_hwnd
;
1584 apartment_tid
= apt
->host_apt_tid
;
1587 LeaveCriticalSection(&apt
->cs
);
1590 /* another thread may have become the main apartment in the time it took
1591 * us to create the thread for the host apartment */
1592 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1594 APARTMENT
*host_apt
= apartment_findmain();
1597 apartment_hwnd
= apartment_getwindow(host_apt
);
1598 apartment_release(host_apt
);
1602 params
.regdata
= *regdata
;
1603 params
.clsid
= *rclsid
;
1605 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1608 params
.apartment_threaded
= !multi_threaded
;
1612 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1613 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1617 WaitForSingleObject(params
.event
, INFINITE
);
1620 CloseHandle(params
.event
);
1624 if (!apartment_hwnd
)
1626 ERR("host apartment didn't create window\n");
1630 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1633 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1634 IStream_Release(params
.stream
);
1638 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1642 /* Dispatching to the correct thread in an apartment is done through
1643 * window messages rather than RPC transports. When an interface is
1644 * marshalled into another apartment in the same process, a window of the
1645 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1646 * application) is responsible for pumping the message loop in that thread.
1647 * The WM_USER messages which point to the RPCs are then dispatched to
1648 * apartment_wndproc by the user's code from the apartment in which the
1649 * interface was unmarshalled.
1651 memset(&wclass
, 0, sizeof(wclass
));
1652 wclass
.lpfnWndProc
= apartment_wndproc
;
1653 wclass
.hInstance
= hProxyDll
;
1654 wclass
.lpszClassName
= wszAptWinClass
;
1655 RegisterClassW(&wclass
);
1659 /* create a window for the apartment or return the current one if one has
1660 * already been created */
1661 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1663 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1665 if (apt
->multi_threaded
)
1672 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1674 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1675 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1678 ERR("CreateWindow failed with error %d\n", GetLastError());
1679 return HRESULT_FROM_WIN32(GetLastError());
1681 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1682 /* someone beat us to it */
1683 DestroyWindow(hwnd
);
1689 /* retrieves the window for the main- or apartment-threaded apartment */
1690 HWND
apartment_getwindow(const struct apartment
*apt
)
1692 assert(!apt
->multi_threaded
);
1696 void apartment_joinmta(void)
1698 apartment_addref(MTA
);
1699 COM_CurrentInfo()->apt
= MTA
;
1702 static void COM_TlsDestroy(void)
1704 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1707 if (info
->apt
) apartment_release(info
->apt
);
1708 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1709 if (info
->state
) IUnknown_Release(info
->state
);
1710 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1711 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1712 HeapFree(GetProcessHeap(), 0, info
);
1713 NtCurrentTeb()->ReservedForOle
= NULL
;
1717 /******************************************************************************
1718 * CoBuildVersion [OLE32.@]
1720 * Gets the build version of the DLL.
1725 * Current build version, hiword is majornumber, loword is minornumber
1727 DWORD WINAPI
CoBuildVersion(void)
1729 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1730 return (rmm
<<16)+rup
;
1733 /******************************************************************************
1734 * CoRegisterInitializeSpy [OLE32.@]
1736 * Add a Spy that watches CoInitializeEx calls
1739 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1740 * cookie [II] cookie receiver
1743 * Success: S_OK if not already initialized, S_FALSE otherwise.
1744 * Failure: HRESULT code.
1749 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1751 struct oletls
*info
= COM_CurrentInfo();
1754 TRACE("(%p, %p)\n", spy
, cookie
);
1756 if (!spy
|| !cookie
|| !info
)
1759 WARN("Could not allocate tls\n");
1760 return E_INVALIDARG
;
1765 FIXME("Already registered?\n");
1766 return E_UNEXPECTED
;
1769 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1772 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1778 /******************************************************************************
1779 * CoRevokeInitializeSpy [OLE32.@]
1781 * Remove a spy that previously watched CoInitializeEx calls
1784 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1787 * Success: S_OK if a spy is removed
1788 * Failure: E_INVALIDARG
1793 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1795 struct oletls
*info
= COM_CurrentInfo();
1796 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1798 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1799 return E_INVALIDARG
;
1801 IInitializeSpy_Release(info
->spy
);
1807 /******************************************************************************
1808 * CoInitialize [OLE32.@]
1810 * Initializes the COM libraries by calling CoInitializeEx with
1811 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1814 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1817 * Success: S_OK if not already initialized, S_FALSE otherwise.
1818 * Failure: HRESULT code.
1823 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1826 * Just delegate to the newer method.
1828 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1831 /******************************************************************************
1832 * CoInitializeEx [OLE32.@]
1834 * Initializes the COM libraries.
1837 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1838 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1841 * S_OK if successful,
1842 * S_FALSE if this function was called already.
1843 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1848 * The behavior used to set the IMalloc used for memory management is
1850 * The dwCoInit parameter must specify one of the following apartment
1852 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1853 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1854 * The parameter may also specify zero or more of the following flags:
1855 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1856 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1861 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1863 struct oletls
*info
= COM_CurrentInfo();
1867 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1869 if (lpReserved
!=NULL
)
1871 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1875 * Check the lock count. If this is the first time going through the initialize
1876 * process, we have to initialize the libraries.
1878 * And crank-up that lock count.
1880 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1883 * Initialize the various COM libraries and data structures.
1885 TRACE("() - Initializing the COM libraries\n");
1887 /* we may need to defer this until after apartment initialisation */
1888 RunningObjectTableImpl_Initialize();
1892 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1894 if (!(apt
= info
->apt
))
1896 apt
= apartment_get_or_create(dwCoInit
);
1897 if (!apt
) return E_OUTOFMEMORY
;
1899 else if (!apartment_is_model(apt
, dwCoInit
))
1901 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1902 code then we are probably using the wrong threading model to implement that API. */
1903 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1904 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1905 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1906 return RPC_E_CHANGED_MODE
;
1914 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1919 /***********************************************************************
1920 * CoUninitialize [OLE32.@]
1922 * This method will decrement the refcount on the current apartment, freeing
1923 * the resources associated with it if it is the last thread in the apartment.
1924 * If the last apartment is freed, the function will additionally release
1925 * any COM resources associated with the process.
1935 void WINAPI
CoUninitialize(void)
1937 struct oletls
* info
= COM_CurrentInfo();
1942 /* will only happen on OOM */
1946 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1951 ERR("Mismatched CoUninitialize\n");
1954 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1960 apartment_release(info
->apt
);
1965 * Decrease the reference count.
1966 * If we are back to 0 locks on the COM library, make sure we free
1967 * all the associated data structures.
1969 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1972 TRACE("() - Releasing the COM libraries\n");
1974 RunningObjectTableImpl_UnInitialize();
1976 else if (lCOMRefCnt
<1) {
1977 ERR( "CoUninitialize() - not CoInitialized.\n" );
1978 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1981 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1984 /******************************************************************************
1985 * CoDisconnectObject [OLE32.@]
1987 * Disconnects all connections to this object from remote processes. Dispatches
1988 * pending RPCs while blocking new RPCs from occurring, and then calls
1989 * IMarshal::DisconnectObject on the given object.
1991 * Typically called when the object server is forced to shut down, for instance by
1995 * lpUnk [I] The object whose stub should be disconnected.
1996 * reserved [I] Reserved. Should be set to 0.
2000 * Failure: HRESULT code.
2003 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2005 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2011 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2013 if (!lpUnk
) return E_INVALIDARG
;
2015 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2018 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2019 IMarshal_Release(marshal
);
2023 apt
= COM_CurrentApt();
2025 return CO_E_NOTINITIALIZED
;
2027 apartment_disconnectobject(apt
, lpUnk
);
2029 /* Note: native is pretty broken here because it just silently
2030 * fails, without returning an appropriate error code if the object was
2031 * not found, making apps think that the object was disconnected, when
2032 * it actually wasn't */
2037 /******************************************************************************
2038 * CoCreateGuid [OLE32.@]
2040 * Simply forwards to UuidCreate in RPCRT4.
2043 * pguid [O] Points to the GUID to initialize.
2047 * Failure: HRESULT code.
2052 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2054 DWORD status
= UuidCreate(pguid
);
2055 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2056 return HRESULT_FROM_WIN32( status
);
2059 static inline BOOL
is_valid_hex(WCHAR c
)
2061 if (!(((c
>= '0') && (c
<= '9')) ||
2062 ((c
>= 'a') && (c
<= 'f')) ||
2063 ((c
>= 'A') && (c
<= 'F'))))
2068 static const BYTE guid_conv_table
[256] =
2070 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2071 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2072 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2073 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2074 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2075 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2076 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2079 /* conversion helper for CLSIDFromString/IIDFromString */
2080 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2084 if (!s
|| s
[0]!='{') {
2085 memset( id
, 0, sizeof (CLSID
) );
2090 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2092 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2095 for (i
= 1; i
< 9; i
++) {
2096 if (!is_valid_hex(s
[i
])) return FALSE
;
2097 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2099 if (s
[9]!='-') return FALSE
;
2102 for (i
= 10; i
< 14; i
++) {
2103 if (!is_valid_hex(s
[i
])) return FALSE
;
2104 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2106 if (s
[14]!='-') return FALSE
;
2109 for (i
= 15; i
< 19; i
++) {
2110 if (!is_valid_hex(s
[i
])) return FALSE
;
2111 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2113 if (s
[19]!='-') return FALSE
;
2115 for (i
= 20; i
< 37; i
+=2) {
2117 if (s
[i
]!='-') return FALSE
;
2120 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2121 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2124 if (s
[37] == '}' && s
[38] == '\0')
2130 /*****************************************************************************/
2132 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2134 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2135 WCHAR buf2
[CHARS_IN_GUID
];
2136 LONG buf2len
= sizeof(buf2
);
2140 memset(clsid
, 0, sizeof(*clsid
));
2141 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2142 if (!buf
) return E_OUTOFMEMORY
;
2143 strcpyW( buf
, progid
);
2144 strcatW( buf
, clsidW
);
2145 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2147 HeapFree(GetProcessHeap(),0,buf
);
2148 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2149 return CO_E_CLASSSTRING
;
2151 HeapFree(GetProcessHeap(),0,buf
);
2153 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2156 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2157 return CO_E_CLASSSTRING
;
2160 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2163 /******************************************************************************
2164 * CLSIDFromString [OLE32.@]
2166 * Converts a unique identifier from its string representation into
2170 * idstr [I] The string representation of the GUID.
2171 * id [O] GUID converted from the string.
2175 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2180 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2182 HRESULT ret
= CO_E_CLASSSTRING
;
2186 return E_INVALIDARG
;
2188 if (guid_from_string(idstr
, id
))
2191 /* It appears a ProgID is also valid */
2192 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2199 /******************************************************************************
2200 * IIDFromString [OLE32.@]
2202 * Converts a interface identifier from its string representation into
2206 * idstr [I] The string representation of the GUID.
2207 * id [O] IID converted from the string.
2211 * CO_E_IIDSTRING if idstr is not a valid IID
2216 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2218 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2222 memset(iid
, 0, sizeof(*iid
));
2226 /* length mismatch is a special case */
2227 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2228 return E_INVALIDARG
;
2231 return CO_E_IIDSTRING
;
2233 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2236 /******************************************************************************
2237 * StringFromCLSID [OLE32.@]
2238 * StringFromIID [OLE32.@]
2240 * Converts a GUID into the respective string representation.
2241 * The target string is allocated using the OLE IMalloc.
2244 * id [I] the GUID to be converted.
2245 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2252 * StringFromGUID2, CLSIDFromString
2254 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2256 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2257 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2261 /******************************************************************************
2262 * StringFromGUID2 [OLE32.@]
2264 * Modified version of StringFromCLSID that allows you to specify max
2268 * id [I] GUID to convert to string.
2269 * str [O] Buffer where the result will be stored.
2270 * cmax [I] Size of the buffer in characters.
2273 * Success: The length of the resulting string in characters.
2276 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2278 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2279 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2280 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2281 '%','0','2','X','%','0','2','X','}',0 };
2282 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2283 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2284 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2285 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2286 return CHARS_IN_GUID
;
2289 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2290 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2292 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2293 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2297 strcpyW(path
, wszCLSIDSlash
);
2298 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2299 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2300 if (res
== ERROR_FILE_NOT_FOUND
)
2301 return REGDB_E_CLASSNOTREG
;
2302 else if (res
!= ERROR_SUCCESS
)
2303 return REGDB_E_READREGDB
;
2311 res
= open_classes_key(key
, keyname
, access
, subkey
);
2313 if (res
== ERROR_FILE_NOT_FOUND
)
2314 return REGDB_E_KEYMISSING
;
2315 else if (res
!= ERROR_SUCCESS
)
2316 return REGDB_E_READREGDB
;
2321 /* open HKCR\\AppId\\{string form of appid clsid} key */
2322 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2324 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2325 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2327 WCHAR buf
[CHARS_IN_GUID
];
2328 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2334 /* read the AppID value under the class's key */
2335 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2340 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2342 if (res
== ERROR_FILE_NOT_FOUND
)
2343 return REGDB_E_KEYMISSING
;
2344 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2345 return REGDB_E_READREGDB
;
2347 strcpyW(keyname
, szAppIdKey
);
2348 strcatW(keyname
, buf
);
2349 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2350 if (res
== ERROR_FILE_NOT_FOUND
)
2351 return REGDB_E_KEYMISSING
;
2352 else if (res
!= ERROR_SUCCESS
)
2353 return REGDB_E_READREGDB
;
2358 /******************************************************************************
2359 * ProgIDFromCLSID [OLE32.@]
2361 * Converts a class id into the respective program ID.
2364 * clsid [I] Class ID, as found in registry.
2365 * ppszProgID [O] Associated ProgID.
2370 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2372 HRESULT WINAPI
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2374 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2375 ACTCTX_SECTION_KEYED_DATA data
;
2381 return E_INVALIDARG
;
2385 data
.cbSize
= sizeof(data
);
2386 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2389 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2390 if (comclass
->progid_len
)
2394 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2395 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2397 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2398 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2402 return REGDB_E_CLASSNOTREG
;
2405 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2409 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2410 ret
= REGDB_E_CLASSNOTREG
;
2414 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2417 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2418 ret
= REGDB_E_CLASSNOTREG
;
2419 CoTaskMemFree(*ppszProgID
);
2424 ret
= E_OUTOFMEMORY
;
2431 /******************************************************************************
2432 * CLSIDFromProgID [OLE32.@]
2434 * Converts a program id into the respective GUID.
2437 * progid [I] Unicode program ID, as found in registry.
2438 * clsid [O] Associated CLSID.
2442 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2444 HRESULT WINAPI
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2446 ACTCTX_SECTION_KEYED_DATA data
;
2448 if (!progid
|| !clsid
)
2449 return E_INVALIDARG
;
2451 data
.cbSize
= sizeof(data
);
2452 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2455 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2456 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2461 return clsid_from_string_reg(progid
, clsid
);
2464 /******************************************************************************
2465 * CLSIDFromProgIDEx [OLE32.@]
2467 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2469 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2471 return CLSIDFromProgID(progid
, clsid
);
2474 /*****************************************************************************
2475 * CoGetPSClsid [OLE32.@]
2477 * Retrieves the CLSID of the proxy/stub factory that implements
2478 * IPSFactoryBuffer for the specified interface.
2481 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2482 * pclsid [O] Where to store returned proxy/stub CLSID.
2487 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2491 * The standard marshaller activates the object with the CLSID
2492 * returned and uses the CreateProxy and CreateStub methods on its
2493 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2496 * CoGetPSClsid determines this CLSID by searching the
2497 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2498 * in the registry and any interface id registered by
2499 * CoRegisterPSClsid within the current process.
2503 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2504 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2505 * considered a bug in native unless an application depends on this (unlikely).
2508 * CoRegisterPSClsid.
2510 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2512 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2513 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2514 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2515 WCHAR value
[CHARS_IN_GUID
];
2518 APARTMENT
*apt
= COM_CurrentApt();
2519 struct registered_psclsid
*registered_psclsid
;
2520 ACTCTX_SECTION_KEYED_DATA data
;
2522 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2526 ERR("apartment not initialised\n");
2527 return CO_E_NOTINITIALIZED
;
2531 return E_INVALIDARG
;
2533 EnterCriticalSection(&apt
->cs
);
2535 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2536 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2538 *pclsid
= registered_psclsid
->clsid
;
2539 LeaveCriticalSection(&apt
->cs
);
2543 LeaveCriticalSection(&apt
->cs
);
2545 data
.cbSize
= sizeof(data
);
2546 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2549 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2550 *pclsid
= ifaceps
->iid
;
2554 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2555 strcpyW(path
, wszInterface
);
2556 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2557 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2559 /* Open the key.. */
2560 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2562 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2563 return REGDB_E_IIDNOTREG
;
2566 /* ... Once we have the key, query the registry to get the
2567 value of CLSID as a string, and convert it into a
2568 proper CLSID structure to be passed back to the app */
2569 len
= sizeof(value
);
2570 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2573 return REGDB_E_IIDNOTREG
;
2577 /* We have the CLSID we want back from the registry as a string, so
2578 let's convert it into a CLSID structure */
2579 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2580 return REGDB_E_IIDNOTREG
;
2582 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2586 /*****************************************************************************
2587 * CoRegisterPSClsid [OLE32.@]
2589 * Register a proxy/stub CLSID for the given interface in the current process
2593 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2594 * rclsid [I] CLSID of the proxy/stub.
2598 * Failure: E_OUTOFMEMORY
2602 * This function does not add anything to the registry and the effects are
2603 * limited to the lifetime of the current process.
2608 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2610 APARTMENT
*apt
= COM_CurrentApt();
2611 struct registered_psclsid
*registered_psclsid
;
2613 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2617 ERR("apartment not initialised\n");
2618 return CO_E_NOTINITIALIZED
;
2621 EnterCriticalSection(&apt
->cs
);
2623 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2624 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2626 registered_psclsid
->clsid
= *rclsid
;
2627 LeaveCriticalSection(&apt
->cs
);
2631 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2632 if (!registered_psclsid
)
2634 LeaveCriticalSection(&apt
->cs
);
2635 return E_OUTOFMEMORY
;
2638 registered_psclsid
->iid
= *riid
;
2639 registered_psclsid
->clsid
= *rclsid
;
2640 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2642 LeaveCriticalSection(&apt
->cs
);
2649 * COM_GetRegisteredClassObject
2651 * This internal method is used to scan the registered class list to
2652 * find a class object.
2655 * rclsid Class ID of the class to find.
2656 * dwClsContext Class context to match.
2657 * ppv [out] returns a pointer to the class object. Complying
2658 * to normal COM usage, this method will increase the
2659 * reference count on this object.
2661 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2662 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2664 HRESULT hr
= S_FALSE
;
2665 RegisteredClass
*curClass
;
2667 EnterCriticalSection( &csRegisteredClassList
);
2669 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2672 * Check if we have a match on the class ID and context.
2674 if ((apt
->oxid
== curClass
->apartment_id
) &&
2675 (dwClsContext
& curClass
->runContext
) &&
2676 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2679 * We have a match, return the pointer to the class object.
2681 *ppUnk
= curClass
->classObject
;
2683 IUnknown_AddRef(curClass
->classObject
);
2690 LeaveCriticalSection( &csRegisteredClassList
);
2695 /******************************************************************************
2696 * CoRegisterClassObject [OLE32.@]
2698 * Registers the class object for a given class ID. Servers housed in EXE
2699 * files use this method instead of exporting DllGetClassObject to allow
2700 * other code to connect to their objects.
2703 * rclsid [I] CLSID of the object to register.
2704 * pUnk [I] IUnknown of the object.
2705 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2706 * flags [I] REGCLS flags indicating how connections are made.
2707 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2711 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2712 * CO_E_OBJISREG if the object is already registered. We should not return this.
2715 * CoRevokeClassObject, CoGetClassObject
2718 * In-process objects are only registered for the current apartment.
2719 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2720 * in other apartments.
2723 * MSDN claims that multiple interface registrations are legal, but we
2724 * can't do that with our current implementation.
2726 HRESULT WINAPI
CoRegisterClassObject(
2731 LPDWORD lpdwRegister
)
2733 static LONG next_cookie
;
2734 RegisteredClass
* newClass
;
2735 LPUNKNOWN foundObject
;
2739 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2740 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2742 if ( (lpdwRegister
==0) || (pUnk
==0) )
2743 return E_INVALIDARG
;
2745 apt
= COM_CurrentApt();
2748 ERR("COM was not initialized\n");
2749 return CO_E_NOTINITIALIZED
;
2754 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2755 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2756 if (flags
& REGCLS_MULTIPLEUSE
)
2757 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2760 * First, check if the class is already registered.
2761 * If it is, this should cause an error.
2763 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2765 if (flags
& REGCLS_MULTIPLEUSE
) {
2766 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2767 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2768 IUnknown_Release(foundObject
);
2771 IUnknown_Release(foundObject
);
2772 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2773 return CO_E_OBJISREG
;
2776 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2777 if ( newClass
== NULL
)
2778 return E_OUTOFMEMORY
;
2780 newClass
->classIdentifier
= *rclsid
;
2781 newClass
->apartment_id
= apt
->oxid
;
2782 newClass
->runContext
= dwClsContext
;
2783 newClass
->connectFlags
= flags
;
2784 newClass
->RpcRegistration
= NULL
;
2786 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2787 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2790 * Since we're making a copy of the object pointer, we have to increase its
2793 newClass
->classObject
= pUnk
;
2794 IUnknown_AddRef(newClass
->classObject
);
2796 EnterCriticalSection( &csRegisteredClassList
);
2797 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2798 LeaveCriticalSection( &csRegisteredClassList
);
2800 *lpdwRegister
= newClass
->dwCookie
;
2802 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2803 IStream
*marshal_stream
;
2805 hr
= get_local_server_stream(apt
, &marshal_stream
);
2809 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2811 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2812 &newClass
->RpcRegistration
);
2813 IStream_Release(marshal_stream
);
2818 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2822 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2823 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2824 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2825 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2826 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2827 DWORD dwLength
= sizeof(threading_model
);
2831 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2832 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2833 threading_model
[0] = '\0';
2835 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2836 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2837 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2839 /* there's not specific handling for this case */
2840 if (threading_model
[0]) return ThreadingModel_Neutral
;
2841 return ThreadingModel_No
;
2844 return data
->u
.actctx
.data
->model
;
2847 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2848 REFCLSID rclsid
, REFIID riid
,
2849 BOOL hostifnecessary
, void **ppv
)
2851 WCHAR dllpath
[MAX_PATH
+1];
2852 BOOL apartment_threaded
;
2854 if (hostifnecessary
)
2856 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2858 if (model
== ThreadingModel_Apartment
)
2860 apartment_threaded
= TRUE
;
2861 if (apt
->multi_threaded
)
2862 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2864 else if (model
== ThreadingModel_Free
)
2866 apartment_threaded
= FALSE
;
2867 if (!apt
->multi_threaded
)
2868 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2870 /* everything except "Apartment", "Free" and "Both" */
2871 else if (model
!= ThreadingModel_Both
)
2873 apartment_threaded
= TRUE
;
2874 /* everything else is main-threaded */
2875 if (model
!= ThreadingModel_No
)
2876 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2878 if (apt
->multi_threaded
|| !apt
->main
)
2879 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2882 apartment_threaded
= FALSE
;
2885 apartment_threaded
= !apt
->multi_threaded
;
2887 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2889 /* failure: CLSID is not found in registry */
2890 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2891 return REGDB_E_CLASSNOTREG
;
2894 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2898 /***********************************************************************
2899 * CoGetClassObject [OLE32.@]
2901 * Creates an object of the specified class.
2904 * rclsid [I] Class ID to create an instance of.
2905 * dwClsContext [I] Flags to restrict the location of the created instance.
2906 * pServerInfo [I] Optional. Details for connecting to a remote server.
2907 * iid [I] The ID of the interface of the instance to return.
2908 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2912 * Failure: HRESULT code.
2915 * The dwClsContext parameter can be one or more of the following:
2916 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2917 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2918 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2919 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2922 * CoCreateInstance()
2924 HRESULT WINAPI
CoGetClassObject(
2925 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2926 REFIID iid
, LPVOID
*ppv
)
2928 struct class_reg_data clsreg
;
2929 IUnknown
*regClassObject
;
2930 HRESULT hres
= E_UNEXPECTED
;
2932 BOOL release_apt
= FALSE
;
2934 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2937 return E_INVALIDARG
;
2941 if (!(apt
= COM_CurrentApt()))
2943 if (!(apt
= apartment_find_multi_threaded()))
2945 ERR("apartment not initialised\n");
2946 return CO_E_NOTINITIALIZED
;
2952 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2953 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2956 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2958 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2960 if (release_apt
) apartment_release(apt
);
2961 return FTMarshalCF_Create(iid
, ppv
);
2965 if (CLSCTX_INPROC
& dwClsContext
)
2967 ACTCTX_SECTION_KEYED_DATA data
;
2969 data
.cbSize
= sizeof(data
);
2970 /* search activation context first */
2971 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
2972 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2975 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2977 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
2978 clsreg
.u
.actctx
.data
= data
.lpData
;
2979 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
2980 clsreg
.hkey
= FALSE
;
2982 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2983 ReleaseActCtx(data
.hActCtx
);
2984 if (release_apt
) apartment_release(apt
);
2990 * First, try and see if we can't match the class ID with one of the
2991 * registered classes.
2993 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2996 /* Get the required interface from the retrieved pointer. */
2997 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3000 * Since QI got another reference on the pointer, we want to release the
3001 * one we already have. If QI was unsuccessful, this will release the object. This
3002 * is good since we are not returning it in the "out" parameter.
3004 IUnknown_Release(regClassObject
);
3005 if (release_apt
) apartment_release(apt
);
3009 /* First try in-process server */
3010 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3012 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3015 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3018 if (hres
== REGDB_E_CLASSNOTREG
)
3019 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3020 else if (hres
== REGDB_E_KEYMISSING
)
3022 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3023 hres
= REGDB_E_CLASSNOTREG
;
3027 if (SUCCEEDED(hres
))
3029 clsreg
.u
.hkey
= hkey
;
3032 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3036 /* return if we got a class, otherwise fall through to one of the
3038 if (SUCCEEDED(hres
))
3040 if (release_apt
) apartment_release(apt
);
3045 /* Next try in-process handler */
3046 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3048 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3051 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3054 if (hres
== REGDB_E_CLASSNOTREG
)
3055 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3056 else if (hres
== REGDB_E_KEYMISSING
)
3058 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3059 hres
= REGDB_E_CLASSNOTREG
;
3063 if (SUCCEEDED(hres
))
3065 clsreg
.u
.hkey
= hkey
;
3068 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3072 /* return if we got a class, otherwise fall through to one of the
3074 if (SUCCEEDED(hres
))
3076 if (release_apt
) apartment_release(apt
);
3080 if (release_apt
) apartment_release(apt
);
3082 /* Next try out of process */
3083 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3085 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3086 if (SUCCEEDED(hres
))
3090 /* Finally try remote: this requires networked DCOM (a lot of work) */
3091 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3093 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3094 hres
= REGDB_E_CLASSNOTREG
;
3098 ERR("no class object %s could be created for context 0x%x\n",
3099 debugstr_guid(rclsid
), dwClsContext
);
3103 /***********************************************************************
3104 * CoResumeClassObjects (OLE32.@)
3106 * Resumes all class objects registered with REGCLS_SUSPENDED.
3110 * Failure: HRESULT code.
3112 HRESULT WINAPI
CoResumeClassObjects(void)
3118 /***********************************************************************
3119 * CoCreateInstance [OLE32.@]
3121 * Creates an instance of the specified class.
3124 * rclsid [I] Class ID to create an instance of.
3125 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3126 * dwClsContext [I] Flags to restrict the location of the created instance.
3127 * iid [I] The ID of the interface of the instance to return.
3128 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3132 * Failure: HRESULT code.
3135 * The dwClsContext parameter can be one or more of the following:
3136 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3137 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3138 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3139 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3141 * Aggregation is the concept of deferring the IUnknown of an object to another
3142 * object. This allows a separate object to behave as though it was part of
3143 * the object and to allow this the pUnkOuter parameter can be set. Note that
3144 * not all objects support having an outer of unknown.
3147 * CoGetClassObject()
3149 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3151 LPUNKNOWN pUnkOuter
,
3157 LPCLASSFACTORY lpclf
= 0;
3160 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3161 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3168 if (!(apt
= COM_CurrentApt()))
3170 if (!(apt
= apartment_find_multi_threaded()))
3172 ERR("apartment not initialised\n");
3173 return CO_E_NOTINITIALIZED
;
3175 apartment_release(apt
);
3179 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3181 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
3183 IGlobalInterfaceTable
*git
= get_std_git();
3184 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
3185 if (hres
!= S_OK
) return hres
;
3187 TRACE("Retrieved GIT (%p)\n", *ppv
);
3191 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
3192 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
3195 * Get a class factory to construct the object we want.
3197 hres
= CoGetClassObject(rclsid
,
3207 * Create the object and don't forget to release the factory
3209 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
3210 IClassFactory_Release(lpclf
);
3213 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3214 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
3216 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3218 debugstr_guid(rclsid
),hres
);
3224 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
)
3228 for (i
= 0; i
< count
; i
++)
3231 mqi
[i
].hr
= E_NOINTERFACE
;
3235 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
)
3237 ULONG index
, fetched
= 0;
3239 for (index
= 0; index
< count
; index
++)
3241 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3242 if (mqi
[index
].hr
== S_OK
)
3246 IUnknown_Release(unk
);
3249 return E_NOINTERFACE
;
3251 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3254 /***********************************************************************
3255 * CoCreateInstanceEx [OLE32.@]
3257 HRESULT WINAPI
CoCreateInstanceEx(
3259 LPUNKNOWN pUnkOuter
,
3261 COSERVERINFO
* pServerInfo
,
3265 IUnknown
* pUnk
= NULL
;
3271 if ( (cmq
==0) || (pResults
==NULL
))
3272 return E_INVALIDARG
;
3274 if (pServerInfo
!=NULL
)
3275 FIXME("() non-NULL pServerInfo not supported!\n");
3277 init_multi_qi(cmq
, pResults
);
3280 * Get the object and get its IUnknown pointer.
3282 hr
= CoCreateInstance(rclsid
,
3291 return return_multi_qi(pUnk
, cmq
, pResults
);
3294 /***********************************************************************
3295 * CoGetInstanceFromFile [OLE32.@]
3297 HRESULT WINAPI
CoGetInstanceFromFile(
3298 COSERVERINFO
*server_info
,
3308 IPersistFile
*pf
= NULL
;
3309 IUnknown
* unk
= NULL
;
3313 if (count
== 0 || !results
)
3314 return E_INVALIDARG
;
3317 FIXME("() non-NULL server_info not supported\n");
3319 init_multi_qi(count
, results
);
3321 /* optionaly get CLSID from a file */
3324 hr
= GetClassFile(filename
, &clsid
);
3327 ERR("failed to get CLSID from a file\n");
3334 hr
= CoCreateInstance(rclsid
,
3343 /* init from file */
3344 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3346 ERR("failed to get IPersistFile\n");
3350 IPersistFile_Load(pf
, filename
, grfmode
);
3351 IPersistFile_Release(pf
);
3354 return return_multi_qi(unk
, count
, results
);
3357 /***********************************************************************
3358 * CoGetInstanceFromIStorage [OLE32.@]
3360 HRESULT WINAPI
CoGetInstanceFromIStorage(
3361 COSERVERINFO
*server_info
,
3370 IPersistStorage
*ps
= NULL
;
3371 IUnknown
* unk
= NULL
;
3375 if (count
== 0 || !results
|| !storage
)
3376 return E_INVALIDARG
;
3379 FIXME("() non-NULL server_info not supported\n");
3381 init_multi_qi(count
, results
);
3383 /* optionaly get CLSID from a file */
3386 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3387 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3390 ERR("failed to get CLSID from a file\n");
3394 rclsid
= &stat
.clsid
;
3397 hr
= CoCreateInstance(rclsid
,
3406 /* init from IStorage */
3407 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3409 ERR("failed to get IPersistStorage\n");
3413 IPersistStorage_Load(ps
, storage
);
3414 IPersistStorage_Release(ps
);
3417 return return_multi_qi(unk
, count
, results
);
3420 /***********************************************************************
3421 * CoLoadLibrary (OLE32.@)
3426 * lpszLibName [I] Path to library.
3427 * bAutoFree [I] Whether the library should automatically be freed.
3430 * Success: Handle to loaded library.
3434 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3436 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3438 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3440 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3443 /***********************************************************************
3444 * CoFreeLibrary [OLE32.@]
3446 * Unloads a library from memory.
3449 * hLibrary [I] Handle to library to unload.
3455 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3457 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3459 FreeLibrary(hLibrary
);
3463 /***********************************************************************
3464 * CoFreeAllLibraries [OLE32.@]
3466 * Function for backwards compatibility only. Does nothing.
3472 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3474 void WINAPI
CoFreeAllLibraries(void)
3479 /***********************************************************************
3480 * CoFreeUnusedLibrariesEx [OLE32.@]
3482 * Frees any previously unused libraries whose delay has expired and marks
3483 * currently unused libraries for unloading. Unused are identified as those that
3484 * return S_OK from their DllCanUnloadNow function.
3487 * dwUnloadDelay [I] Unload delay in milliseconds.
3488 * dwReserved [I] Reserved. Set to 0.
3494 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3496 void WINAPI
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3498 struct apartment
*apt
= COM_CurrentApt();
3501 ERR("apartment not initialised\n");
3505 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3508 /***********************************************************************
3509 * CoFreeUnusedLibraries [OLE32.@]
3511 * Frees any unused libraries. Unused are identified as those that return
3512 * S_OK from their DllCanUnloadNow function.
3518 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3520 void WINAPI
CoFreeUnusedLibraries(void)
3522 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3525 /***********************************************************************
3526 * CoFileTimeNow [OLE32.@]
3528 * Retrieves the current time in FILETIME format.
3531 * lpFileTime [O] The current time.
3536 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3538 GetSystemTimeAsFileTime( lpFileTime
);
3542 /******************************************************************************
3543 * CoLockObjectExternal [OLE32.@]
3545 * Increments or decrements the external reference count of a stub object.
3548 * pUnk [I] Stub object.
3549 * fLock [I] If TRUE then increments the external ref-count,
3550 * otherwise decrements.
3551 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3552 * calling CoDisconnectObject.
3556 * Failure: HRESULT code.
3559 * If fLock is TRUE and an object is passed in that doesn't have a stub
3560 * manager then a new stub manager is created for the object.
3562 HRESULT WINAPI
CoLockObjectExternal(
3565 BOOL fLastUnlockReleases
)
3567 struct stub_manager
*stubmgr
;
3568 struct apartment
*apt
;
3570 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3571 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3573 apt
= COM_CurrentApt();
3574 if (!apt
) return CO_E_NOTINITIALIZED
;
3576 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3581 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3583 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3585 stub_manager_int_release(stubmgr
);
3591 stubmgr
= new_stub_manager(apt
, pUnk
);
3595 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3596 stub_manager_int_release(stubmgr
);
3603 WARN("stub object not found %p\n", pUnk
);
3604 /* Note: native is pretty broken here because it just silently
3605 * fails, without returning an appropriate error code, making apps
3606 * think that the object was disconnected, when it actually wasn't */
3611 /***********************************************************************
3612 * CoInitializeWOW (OLE32.@)
3614 * WOW equivalent of CoInitialize?
3623 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3625 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3629 /***********************************************************************
3630 * CoGetState [OLE32.@]
3632 * Retrieves the thread state object previously stored by CoSetState().
3635 * ppv [I] Address where pointer to object will be stored.
3639 * Failure: E_OUTOFMEMORY.
3642 * Crashes on all invalid ppv addresses, including NULL.
3643 * If the function returns a non-NULL object then the caller must release its
3644 * reference on the object when the object is no longer required.
3649 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3651 struct oletls
*info
= COM_CurrentInfo();
3652 if (!info
) return E_OUTOFMEMORY
;
3658 IUnknown_AddRef(info
->state
);
3660 TRACE("apt->state=%p\n", info
->state
);
3666 /***********************************************************************
3667 * CoSetState [OLE32.@]
3669 * Sets the thread state object.
3672 * pv [I] Pointer to state object to be stored.
3675 * The system keeps a reference on the object while the object stored.
3679 * Failure: E_OUTOFMEMORY.
3681 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3683 struct oletls
*info
= COM_CurrentInfo();
3684 if (!info
) return E_OUTOFMEMORY
;
3686 if (pv
) IUnknown_AddRef(pv
);
3690 TRACE("-- release %p now\n", info
->state
);
3691 IUnknown_Release(info
->state
);
3700 /******************************************************************************
3701 * CoTreatAsClass [OLE32.@]
3703 * Sets the TreatAs value of a class.
3706 * clsidOld [I] Class to set TreatAs value on.
3707 * clsidNew [I] The class the clsidOld should be treated as.
3711 * Failure: HRESULT code.
3716 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3718 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3719 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3721 WCHAR szClsidNew
[CHARS_IN_GUID
];
3723 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3724 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3727 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3730 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3732 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3733 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3735 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3737 res
= REGDB_E_WRITEREGDB
;
3743 RegDeleteKeyW(hkey
, wszTreatAs
);
3747 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3748 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3750 res
= REGDB_E_WRITEREGDB
;
3755 if (hkey
) RegCloseKey(hkey
);
3759 /******************************************************************************
3760 * CoGetTreatAsClass [OLE32.@]
3762 * Gets the TreatAs value of a class.
3765 * clsidOld [I] Class to get the TreatAs value of.
3766 * clsidNew [I] The class the clsidOld should be treated as.
3770 * Failure: HRESULT code.
3775 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3777 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3779 WCHAR szClsidNew
[CHARS_IN_GUID
];
3781 LONG len
= sizeof(szClsidNew
);
3783 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3784 *clsidNew
= *clsidOld
; /* copy over old value */
3786 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3792 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3797 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3799 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3801 if (hkey
) RegCloseKey(hkey
);
3805 /******************************************************************************
3806 * CoGetCurrentProcess [OLE32.@]
3808 * Gets the current process ID.
3811 * The current process ID.
3814 * Is DWORD really the correct return type for this function?
3816 DWORD WINAPI
CoGetCurrentProcess(void)
3818 return GetCurrentProcessId();
3821 /******************************************************************************
3822 * CoRegisterMessageFilter [OLE32.@]
3824 * Registers a message filter.
3827 * lpMessageFilter [I] Pointer to interface.
3828 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3832 * Failure: HRESULT code.
3835 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3836 * lpMessageFilter removes the message filter.
3838 * If lplpMessageFilter is not NULL the previous message filter will be
3839 * returned in the memory pointer to this parameter and the caller is
3840 * responsible for releasing the object.
3842 * The current thread be in an apartment otherwise the function will crash.
3844 HRESULT WINAPI
CoRegisterMessageFilter(
3845 LPMESSAGEFILTER lpMessageFilter
,
3846 LPMESSAGEFILTER
*lplpMessageFilter
)
3848 struct apartment
*apt
;
3849 IMessageFilter
*lpOldMessageFilter
;
3851 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3853 apt
= COM_CurrentApt();
3855 /* can't set a message filter in a multi-threaded apartment */
3856 if (!apt
|| apt
->multi_threaded
)
3858 WARN("can't set message filter in MTA or uninitialized apt\n");
3859 return CO_E_NOT_SUPPORTED
;
3862 if (lpMessageFilter
)
3863 IMessageFilter_AddRef(lpMessageFilter
);
3865 EnterCriticalSection(&apt
->cs
);
3867 lpOldMessageFilter
= apt
->filter
;
3868 apt
->filter
= lpMessageFilter
;
3870 LeaveCriticalSection(&apt
->cs
);
3872 if (lplpMessageFilter
)
3873 *lplpMessageFilter
= lpOldMessageFilter
;
3874 else if (lpOldMessageFilter
)
3875 IMessageFilter_Release(lpOldMessageFilter
);
3880 /***********************************************************************
3881 * CoIsOle1Class [OLE32.@]
3883 * Determines whether the specified class an OLE v1 class.
3886 * clsid [I] Class to test.
3889 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3891 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3893 FIXME("%s\n", debugstr_guid(clsid
));
3897 /***********************************************************************
3898 * IsEqualGUID [OLE32.@]
3900 * Compares two Unique Identifiers.
3903 * rguid1 [I] The first GUID to compare.
3904 * rguid2 [I] The other GUID to compare.
3910 BOOL WINAPI
IsEqualGUID(
3914 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3917 /***********************************************************************
3918 * CoInitializeSecurity [OLE32.@]
3920 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3921 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3922 void* pReserved1
, DWORD dwAuthnLevel
,
3923 DWORD dwImpLevel
, void* pReserved2
,
3924 DWORD dwCapabilities
, void* pReserved3
)
3926 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3927 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3928 dwCapabilities
, pReserved3
);
3932 /***********************************************************************
3933 * CoSuspendClassObjects [OLE32.@]
3935 * Suspends all registered class objects to prevent further requests coming in
3936 * for those objects.
3940 * Failure: HRESULT code.
3942 HRESULT WINAPI
CoSuspendClassObjects(void)
3948 /***********************************************************************
3949 * CoAddRefServerProcess [OLE32.@]
3951 * Helper function for incrementing the reference count of a local-server
3955 * New reference count.
3958 * CoReleaseServerProcess().
3960 ULONG WINAPI
CoAddRefServerProcess(void)
3966 EnterCriticalSection(&csRegisteredClassList
);
3967 refs
= ++s_COMServerProcessReferences
;
3968 LeaveCriticalSection(&csRegisteredClassList
);
3970 TRACE("refs before: %d\n", refs
- 1);
3975 /***********************************************************************
3976 * CoReleaseServerProcess [OLE32.@]
3978 * Helper function for decrementing the reference count of a local-server
3982 * New reference count.
3985 * When reference count reaches 0, this function suspends all registered
3986 * classes so no new connections are accepted.
3989 * CoAddRefServerProcess(), CoSuspendClassObjects().
3991 ULONG WINAPI
CoReleaseServerProcess(void)
3997 EnterCriticalSection(&csRegisteredClassList
);
3999 refs
= --s_COMServerProcessReferences
;
4000 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4002 LeaveCriticalSection(&csRegisteredClassList
);
4004 TRACE("refs after: %d\n", refs
);
4009 /***********************************************************************
4010 * CoIsHandlerConnected [OLE32.@]
4012 * Determines whether a proxy is connected to a remote stub.
4015 * pUnk [I] Pointer to object that may or may not be connected.
4018 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4021 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4023 FIXME("%p\n", pUnk
);
4028 /***********************************************************************
4029 * CoAllowSetForegroundWindow [OLE32.@]
4032 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4034 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4038 /***********************************************************************
4039 * CoQueryProxyBlanket [OLE32.@]
4041 * Retrieves the security settings being used by a proxy.
4044 * pProxy [I] Pointer to the proxy object.
4045 * pAuthnSvc [O] The type of authentication service.
4046 * pAuthzSvc [O] The type of authorization service.
4047 * ppServerPrincName [O] Optional. The server prinicple name.
4048 * pAuthnLevel [O] The authentication level.
4049 * pImpLevel [O] The impersonation level.
4050 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4051 * pCapabilities [O] Flags affecting the security behaviour.
4055 * Failure: HRESULT code.
4058 * CoCopyProxy, CoSetProxyBlanket.
4060 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4061 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4062 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4064 IClientSecurity
*pCliSec
;
4067 TRACE("%p\n", pProxy
);
4069 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4072 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4073 pAuthzSvc
, ppServerPrincName
,
4074 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4076 IClientSecurity_Release(pCliSec
);
4079 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4083 /***********************************************************************
4084 * CoSetProxyBlanket [OLE32.@]
4086 * Sets the security settings for a proxy.
4089 * pProxy [I] Pointer to the proxy object.
4090 * AuthnSvc [I] The type of authentication service.
4091 * AuthzSvc [I] The type of authorization service.
4092 * pServerPrincName [I] The server prinicple name.
4093 * AuthnLevel [I] The authentication level.
4094 * ImpLevel [I] The impersonation level.
4095 * pAuthInfo [I] Information specific to the authorization/authentication service.
4096 * Capabilities [I] Flags affecting the security behaviour.
4100 * Failure: HRESULT code.
4103 * CoQueryProxyBlanket, CoCopyProxy.
4105 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4106 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4107 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4109 IClientSecurity
*pCliSec
;
4112 TRACE("%p\n", pProxy
);
4114 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4117 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4118 AuthzSvc
, pServerPrincName
,
4119 AuthnLevel
, ImpLevel
, pAuthInfo
,
4121 IClientSecurity_Release(pCliSec
);
4124 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4128 /***********************************************************************
4129 * CoCopyProxy [OLE32.@]
4134 * pProxy [I] Pointer to the proxy object.
4135 * ppCopy [O] Copy of the proxy.
4139 * Failure: HRESULT code.
4142 * CoQueryProxyBlanket, CoSetProxyBlanket.
4144 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4146 IClientSecurity
*pCliSec
;
4149 TRACE("%p\n", pProxy
);
4151 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4154 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4155 IClientSecurity_Release(pCliSec
);
4158 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4163 /***********************************************************************
4164 * CoGetCallContext [OLE32.@]
4166 * Gets the context of the currently executing server call in the current
4170 * riid [I] Context interface to return.
4171 * ppv [O] Pointer to memory that will receive the context on return.
4175 * Failure: HRESULT code.
4177 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4179 struct oletls
*info
= COM_CurrentInfo();
4181 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4184 return E_OUTOFMEMORY
;
4186 if (!info
->call_state
)
4187 return RPC_E_CALL_COMPLETE
;
4189 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4192 /***********************************************************************
4193 * CoSwitchCallContext [OLE32.@]
4195 * Switches the context of the currently executing server call in the current
4199 * pObject [I] Pointer to new context object
4200 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4204 * Failure: HRESULT code.
4206 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4208 struct oletls
*info
= COM_CurrentInfo();
4210 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4213 return E_OUTOFMEMORY
;
4215 *ppOldObject
= info
->call_state
;
4216 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4221 /***********************************************************************
4222 * CoQueryClientBlanket [OLE32.@]
4224 * Retrieves the authentication information about the client of the currently
4225 * executing server call in the current thread.
4228 * pAuthnSvc [O] Optional. The type of authentication service.
4229 * pAuthzSvc [O] Optional. The type of authorization service.
4230 * pServerPrincName [O] Optional. The server prinicple name.
4231 * pAuthnLevel [O] Optional. The authentication level.
4232 * pImpLevel [O] Optional. The impersonation level.
4233 * pPrivs [O] Optional. Information about the privileges of the client.
4234 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4238 * Failure: HRESULT code.
4241 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4243 HRESULT WINAPI
CoQueryClientBlanket(
4246 OLECHAR
**pServerPrincName
,
4249 RPC_AUTHZ_HANDLE
*pPrivs
,
4250 DWORD
*pCapabilities
)
4252 IServerSecurity
*pSrvSec
;
4255 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4256 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4257 pPrivs
, pCapabilities
);
4259 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4262 hr
= IServerSecurity_QueryBlanket(
4263 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4264 pImpLevel
, pPrivs
, pCapabilities
);
4265 IServerSecurity_Release(pSrvSec
);
4271 /***********************************************************************
4272 * CoImpersonateClient [OLE32.@]
4274 * Impersonates the client of the currently executing server call in the
4282 * Failure: HRESULT code.
4285 * If this function fails then the current thread will not be impersonating
4286 * the client and all actions will take place on behalf of the server.
4287 * Therefore, it is important to check the return value from this function.
4290 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4292 HRESULT WINAPI
CoImpersonateClient(void)
4294 IServerSecurity
*pSrvSec
;
4299 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4302 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4303 IServerSecurity_Release(pSrvSec
);
4309 /***********************************************************************
4310 * CoRevertToSelf [OLE32.@]
4312 * Ends the impersonation of the client of the currently executing server
4313 * call in the current thread.
4320 * Failure: HRESULT code.
4323 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4325 HRESULT WINAPI
CoRevertToSelf(void)
4327 IServerSecurity
*pSrvSec
;
4332 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4335 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4336 IServerSecurity_Release(pSrvSec
);
4342 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4344 /* first try to retrieve messages for incoming COM calls to the apartment window */
4345 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
4346 /* next retrieve other messages necessary for the app to remain responsive */
4347 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4348 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4351 /***********************************************************************
4352 * CoWaitForMultipleHandles [OLE32.@]
4354 * Waits for one or more handles to become signaled.
4357 * dwFlags [I] Flags. See notes.
4358 * dwTimeout [I] Timeout in milliseconds.
4359 * cHandles [I] Number of handles pointed to by pHandles.
4360 * pHandles [I] Handles to wait for.
4361 * lpdwindex [O] Index of handle that was signaled.
4365 * Failure: RPC_S_CALLPENDING on timeout.
4369 * The dwFlags parameter can be zero or more of the following:
4370 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4371 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4374 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4376 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4377 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4380 DWORD start_time
= GetTickCount();
4381 APARTMENT
*apt
= COM_CurrentApt();
4382 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4384 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4385 pHandles
, lpdwindex
);
4389 DWORD now
= GetTickCount();
4392 if (now
- start_time
> dwTimeout
)
4394 hr
= RPC_S_CALLPENDING
;
4400 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4401 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4403 TRACE("waiting for rpc completion or window message\n");
4405 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4406 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4407 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4409 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4414 /* call message filter */
4416 if (COM_CurrentApt()->filter
)
4418 PENDINGTYPE pendingtype
=
4419 COM_CurrentInfo()->pending_call_count_server
?
4420 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4421 DWORD be_handled
= IMessageFilter_MessagePending(
4422 COM_CurrentApt()->filter
, 0 /* FIXME */,
4423 now
- start_time
, pendingtype
);
4424 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4427 case PENDINGMSG_CANCELCALL
:
4428 WARN("call canceled\n");
4429 hr
= RPC_E_CALL_CANCELED
;
4431 case PENDINGMSG_WAITNOPROCESS
:
4432 case PENDINGMSG_WAITDEFPROCESS
:
4434 /* FIXME: MSDN is very vague about the difference
4435 * between WAITNOPROCESS and WAITDEFPROCESS - there
4436 * appears to be none, so it is possibly a left-over
4437 * from the 16-bit world. */
4442 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4443 * so after processing 100 messages we go back to checking the wait handles */
4444 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4446 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4447 TranslateMessage(&msg
);
4448 DispatchMessageW(&msg
);
4449 if (msg
.message
== WM_QUIT
)
4451 TRACE("resending WM_QUIT to outer message loop\n");
4452 PostQuitMessage(msg
.wParam
);
4453 /* no longer need to process messages */
4454 message_loop
= FALSE
;
4463 TRACE("waiting for rpc completion\n");
4465 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4466 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4467 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4473 hr
= RPC_S_CALLPENDING
;
4476 hr
= HRESULT_FROM_WIN32( GetLastError() );
4484 TRACE("-- 0x%08x\n", hr
);
4489 /***********************************************************************
4490 * CoGetObject [OLE32.@]
4492 * Gets the object named by converting the name to a moniker and binding to it.
4495 * pszName [I] String representing the object.
4496 * pBindOptions [I] Parameters affecting the binding to the named object.
4497 * riid [I] Interface to bind to on the objecct.
4498 * ppv [O] On output, the interface riid of the object represented
4503 * Failure: HRESULT code.
4506 * MkParseDisplayName.
4508 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4509 REFIID riid
, void **ppv
)
4516 hr
= CreateBindCtx(0, &pbc
);
4520 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4527 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4530 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4531 IMoniker_Release(pmk
);
4535 IBindCtx_Release(pbc
);
4540 /***********************************************************************
4541 * CoRegisterChannelHook [OLE32.@]
4543 * Registers a process-wide hook that is called during ORPC calls.
4546 * guidExtension [I] GUID of the channel hook to register.
4547 * pChannelHook [I] Channel hook object to register.
4551 * Failure: HRESULT code.
4553 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4555 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4557 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4560 typedef struct Context
4562 IComThreadingInfo IComThreadingInfo_iface
;
4563 IContextCallback IContextCallback_iface
;
4564 IObjContext IObjContext_iface
;
4569 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4571 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4574 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4576 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4579 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4581 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4584 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4588 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4589 IsEqualIID(riid
, &IID_IUnknown
))
4591 *ppv
= &iface
->IComThreadingInfo_iface
;
4593 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4595 *ppv
= &iface
->IContextCallback_iface
;
4597 else if (IsEqualIID(riid
, &IID_IObjContext
))
4599 *ppv
= &iface
->IObjContext_iface
;
4604 IUnknown_AddRef((IUnknown
*)*ppv
);
4608 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4609 return E_NOINTERFACE
;
4612 static ULONG
Context_AddRef(Context
*This
)
4614 return InterlockedIncrement(&This
->refs
);
4617 static ULONG
Context_Release(Context
*This
)
4619 ULONG refs
= InterlockedDecrement(&This
->refs
);
4621 HeapFree(GetProcessHeap(), 0, This
);
4625 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4627 Context
*This
= impl_from_IComThreadingInfo(iface
);
4628 return Context_QueryInterface(This
, riid
, ppv
);
4631 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4633 Context
*This
= impl_from_IComThreadingInfo(iface
);
4634 return Context_AddRef(This
);
4637 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4639 Context
*This
= impl_from_IComThreadingInfo(iface
);
4640 return Context_Release(This
);
4643 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4645 Context
*This
= impl_from_IComThreadingInfo(iface
);
4647 TRACE("(%p)\n", apttype
);
4649 *apttype
= This
->apttype
;
4653 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4655 Context
*This
= impl_from_IComThreadingInfo(iface
);
4657 TRACE("(%p)\n", thdtype
);
4659 switch (This
->apttype
)
4662 case APTTYPE_MAINSTA
:
4663 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4666 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4672 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4674 FIXME("(%p): stub\n", logical_thread_id
);
4678 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4680 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4684 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4686 Context_CTI_QueryInterface
,
4688 Context_CTI_Release
,
4689 Context_CTI_GetCurrentApartmentType
,
4690 Context_CTI_GetCurrentThreadType
,
4691 Context_CTI_GetCurrentLogicalThreadId
,
4692 Context_CTI_SetCurrentLogicalThreadId
4695 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4697 Context
*This
= impl_from_IContextCallback(iface
);
4698 return Context_QueryInterface(This
, riid
, ppv
);
4701 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4703 Context
*This
= impl_from_IContextCallback(iface
);
4704 return Context_AddRef(This
);
4707 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4709 Context
*This
= impl_from_IContextCallback(iface
);
4710 return Context_Release(This
);
4713 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4714 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4716 Context
*This
= impl_from_IContextCallback(iface
);
4718 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4722 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4724 Context_CC_QueryInterface
,
4727 Context_CC_ContextCallback
4730 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4732 Context
*This
= impl_from_IObjContext(iface
);
4733 return Context_QueryInterface(This
, riid
, ppv
);
4736 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4738 Context
*This
= impl_from_IObjContext(iface
);
4739 return Context_AddRef(This
);
4742 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4744 Context
*This
= impl_from_IObjContext(iface
);
4745 return Context_Release(This
);
4748 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4750 Context
*This
= impl_from_IObjContext(iface
);
4752 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4756 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4758 Context
*This
= impl_from_IObjContext(iface
);
4760 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4764 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4766 Context
*This
= impl_from_IObjContext(iface
);
4768 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4772 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4774 Context
*This
= impl_from_IObjContext(iface
);
4776 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4780 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4782 Context
*This
= impl_from_IObjContext(iface
);
4783 FIXME("(%p/%p)\n", This
, iface
);
4786 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4788 Context
*This
= impl_from_IObjContext(iface
);
4789 FIXME("(%p/%p)\n", This
, iface
);
4792 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4794 Context
*This
= impl_from_IObjContext(iface
);
4795 FIXME("(%p/%p)\n", This
, iface
);
4798 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4800 Context
*This
= impl_from_IObjContext(iface
);
4801 FIXME("(%p/%p)\n", This
, iface
);
4804 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4806 Context
*This
= impl_from_IObjContext(iface
);
4807 FIXME("(%p/%p)\n", This
, iface
);
4810 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4812 Context
*This
= impl_from_IObjContext(iface
);
4813 FIXME("(%p/%p)\n", This
, iface
);
4816 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4818 Context
*This
= impl_from_IObjContext(iface
);
4819 FIXME("(%p/%p)\n", This
, iface
);
4822 static const IObjContextVtbl Context_Object_Vtbl
=
4824 Context_OC_QueryInterface
,
4827 Context_OC_SetProperty
,
4828 Context_OC_RemoveProperty
,
4829 Context_OC_GetProperty
,
4830 Context_OC_EnumContextProps
,
4831 Context_OC_Reserved1
,
4832 Context_OC_Reserved2
,
4833 Context_OC_Reserved3
,
4834 Context_OC_Reserved4
,
4835 Context_OC_Reserved5
,
4836 Context_OC_Reserved6
,
4837 Context_OC_Reserved7
4840 /***********************************************************************
4841 * CoGetObjectContext [OLE32.@]
4843 * Retrieves an object associated with the current context (i.e. apartment).
4846 * riid [I] ID of the interface of the object to retrieve.
4847 * ppv [O] Address where object will be stored on return.
4851 * Failure: HRESULT code.
4853 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4855 APARTMENT
*apt
= COM_CurrentApt();
4859 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4864 if (!(apt
= apartment_find_multi_threaded()))
4866 ERR("apartment not initialised\n");
4867 return CO_E_NOTINITIALIZED
;
4869 apartment_release(apt
);
4872 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4874 return E_OUTOFMEMORY
;
4876 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4877 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4878 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4880 if (apt
->multi_threaded
)
4881 context
->apttype
= APTTYPE_MTA
;
4883 context
->apttype
= APTTYPE_MAINSTA
;
4885 context
->apttype
= APTTYPE_STA
;
4887 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4888 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4894 /***********************************************************************
4895 * CoGetContextToken [OLE32.@]
4897 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4899 struct oletls
*info
= COM_CurrentInfo();
4901 TRACE("(%p)\n", token
);
4904 return E_OUTOFMEMORY
;
4909 if (!(apt
= apartment_find_multi_threaded()))
4911 ERR("apartment not initialised\n");
4912 return CO_E_NOTINITIALIZED
;
4914 apartment_release(apt
);
4920 if (!info
->context_token
)
4925 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4926 if (FAILED(hr
)) return hr
;
4927 info
->context_token
= ctx
;
4930 *token
= (ULONG_PTR
)info
->context_token
;
4931 TRACE("apt->context_token=%p\n", info
->context_token
);
4936 /***********************************************************************
4937 * CoGetDefaultContext [OLE32.@]
4939 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4941 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4942 return E_NOINTERFACE
;
4945 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4947 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4951 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4952 if (SUCCEEDED(hres
))
4954 struct class_reg_data regdata
;
4955 WCHAR dllpath
[MAX_PATH
+1];
4957 regdata
.u
.hkey
= hkey
;
4958 regdata
.hkey
= TRUE
;
4960 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4962 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4963 if (!strcmpiW(dllpath
, wszOle32
))
4966 return HandlerCF_Create(rclsid
, riid
, ppv
);
4970 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4974 return CLASS_E_CLASSNOTAVAILABLE
;
4977 /***********************************************************************
4980 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4982 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4985 case DLL_PROCESS_ATTACH
:
4986 hProxyDll
= hinstDLL
;
4989 case DLL_PROCESS_DETACH
:
4990 if (reserved
) break;
4992 UnregisterClassW( wszAptWinClass
, hProxyDll
);
4993 RPC_UnregisterAllChannelHooks();
4994 COMPOBJ_DllList_Free();
4995 DeleteCriticalSection(&csRegisteredClassList
);
4996 DeleteCriticalSection(&csApartment
);
4999 case DLL_THREAD_DETACH
:
5006 /***********************************************************************
5007 * DllRegisterServer (OLE32.@)
5009 HRESULT WINAPI
DllRegisterServer(void)
5011 return OLE32_DllRegisterServer();
5014 /***********************************************************************
5015 * DllUnregisterServer (OLE32.@)
5017 HRESULT WINAPI
DllUnregisterServer(void)
5019 return OLE32_DllUnregisterServer();