4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
44 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
46 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
48 /****************************************************************************
49 * This section defines variables internal to the COM module.
52 static APARTMENT
*MTA
; /* protected by csApartment */
53 static APARTMENT
*MainApartment
; /* the first STA apartment */
54 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
56 static CRITICAL_SECTION csApartment
;
57 static CRITICAL_SECTION_DEBUG critsect_debug
=
60 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
61 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
63 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
65 enum comclass_threadingmodel
67 ThreadingModel_Apartment
= 1,
68 ThreadingModel_Free
= 2,
69 ThreadingModel_No
= 3,
70 ThreadingModel_Both
= 4,
71 ThreadingModel_Neutral
= 5
74 enum comclass_miscfields
78 MiscStatusContent
= 4,
79 MiscStatusThumbnail
= 8,
80 MiscStatusDocPrint
= 16
83 struct comclassredirect_data
101 DWORD miscstatuscontent
;
102 DWORD miscstatusthumbnail
;
103 DWORD miscstatusicon
;
104 DWORD miscstatusdocprint
;
107 struct ifacepsredirect_data
119 struct progidredirect_data
126 struct class_reg_data
132 struct comclassredirect_data
*data
;
141 struct registered_psclsid
149 * This is a marshallable object exposing registered local servers.
150 * IServiceProvider is used only because it happens meet requirements
151 * and already has proxy/stub code. If more functionality is needed,
152 * a custom interface may be used instead.
156 IServiceProvider IServiceProvider_iface
;
159 IStream
*marshal_stream
;
163 * This lock count counts the number of times CoInitialize is called. It is
164 * decreased every time CoUninitialize is called. When it hits 0, the COM
165 * libraries are freed
167 static LONG s_COMLockCount
= 0;
168 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
169 static LONG s_COMServerProcessReferences
= 0;
172 * This linked list contains the list of registered class objects. These
173 * are mostly used to register the factories for out-of-proc servers of OLE
176 * TODO: Make this data structure aware of inter-process communication. This
177 * means that parts of this will be exported to rpcss.
179 typedef struct tagRegisteredClass
182 CLSID classIdentifier
;
184 LPUNKNOWN classObject
;
188 void *RpcRegistration
;
191 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
193 static CRITICAL_SECTION csRegisteredClassList
;
194 static CRITICAL_SECTION_DEBUG class_cs_debug
=
196 0, 0, &csRegisteredClassList
,
197 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
198 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
200 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
202 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
206 case DVASPECT_CONTENT
:
207 return MiscStatusContent
;
208 case DVASPECT_THUMBNAIL
:
209 return MiscStatusThumbnail
;
211 return MiscStatusIcon
;
212 case DVASPECT_DOCPRINT
:
213 return MiscStatusDocPrint
;
219 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
221 ACTCTX_SECTION_KEYED_DATA data
;
223 data
.cbSize
= sizeof(data
);
224 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
227 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
228 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
230 if (!(comclass
->miscmask
& misc
))
232 if (!(comclass
->miscmask
& MiscStatus
))
243 *status
= comclass
->miscstatus
;
246 *status
= comclass
->miscstatusicon
;
248 case MiscStatusContent
:
249 *status
= comclass
->miscstatuscontent
;
251 case MiscStatusThumbnail
:
252 *status
= comclass
->miscstatusthumbnail
;
254 case MiscStatusDocPrint
:
255 *status
= comclass
->miscstatusdocprint
;
267 /* wrapper for NtCreateKey that creates the key recursively if necessary */
268 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
270 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
272 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
274 HANDLE subkey
, root
= attr
->RootDirectory
;
275 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
276 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
279 while (i
< len
&& buffer
[i
] != '\\') i
++;
280 if (i
== len
) return status
;
282 attrs
= attr
->Attributes
;
283 attr
->ObjectName
= &str
;
287 str
.Buffer
= buffer
+ pos
;
288 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
289 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
290 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
291 if (status
) return status
;
292 attr
->RootDirectory
= subkey
;
293 while (i
< len
&& buffer
[i
] == '\\') i
++;
295 while (i
< len
&& buffer
[i
] != '\\') i
++;
297 str
.Buffer
= buffer
+ pos
;
298 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
299 attr
->Attributes
= attrs
;
300 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
301 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
307 static const WCHAR classes_rootW
[] = L
"\\REGISTRY\\Machine\\Software\\Classes";
309 static const WCHAR classes_rootW
[] =
310 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
313 static HKEY classes_root_hkey
;
315 /* create the special HKEY_CLASSES_ROOT key */
316 static HKEY
create_classes_root_hkey(void)
319 OBJECT_ATTRIBUTES attr
;
322 attr
.Length
= sizeof(attr
);
323 attr
.RootDirectory
= 0;
324 attr
.ObjectName
= &name
;
326 attr
.SecurityDescriptor
= NULL
;
327 attr
.SecurityQualityOfService
= NULL
;
328 RtlInitUnicodeString( &name
, classes_rootW
);
329 if (create_key( &hkey
, MAXIMUM_ALLOWED
, &attr
)) return 0;
330 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
332 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
335 NtClose( hkey
); /* somebody beat us to it */
339 /* map the hkey from special root to normal key if necessary */
340 static inline HKEY
get_classes_root_hkey( HKEY hkey
)
344 if (hkey
== HKEY_CLASSES_ROOT
&& !(ret
= classes_root_hkey
))
345 ret
= create_classes_root_hkey();
350 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
352 OBJECT_ATTRIBUTES attr
;
353 UNICODE_STRING nameW
;
355 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
357 attr
.Length
= sizeof(attr
);
358 attr
.RootDirectory
= hkey
;
359 attr
.ObjectName
= &nameW
;
361 attr
.SecurityDescriptor
= NULL
;
362 attr
.SecurityQualityOfService
= NULL
;
363 RtlInitUnicodeString( &nameW
, name
);
365 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
368 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
370 OBJECT_ATTRIBUTES attr
;
371 UNICODE_STRING nameW
;
373 if (!(hkey
= get_classes_root_hkey( hkey
))) return ERROR_INVALID_HANDLE
;
375 attr
.Length
= sizeof(attr
);
376 attr
.RootDirectory
= hkey
;
377 attr
.ObjectName
= &nameW
;
379 attr
.SecurityDescriptor
= NULL
;
380 attr
.SecurityQualityOfService
= NULL
;
381 RtlInitUnicodeString( &nameW
, name
);
383 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
386 /*****************************************************************************
387 * This section contains OpenDllList definitions
389 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
390 * other functions that do LoadLibrary _without_ giving back a HMODULE.
391 * Without this list these handles would never be freed.
393 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
394 * next unload-call but not before 600 sec.
397 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
398 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
400 typedef struct tagOpenDll
405 DllGetClassObjectFunc DllGetClassObject
;
406 DllCanUnloadNowFunc DllCanUnloadNow
;
410 static struct list openDllList
= LIST_INIT(openDllList
);
412 static CRITICAL_SECTION csOpenDllList
;
413 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
415 0, 0, &csOpenDllList
,
416 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
417 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
419 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
421 struct apartment_loaded_dll
429 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',' ',
430 '0','x','#','#','#','#','#','#','#','#',' ',0};
432 /*****************************************************************************
433 * This section contains OpenDllList implementation
436 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
440 EnterCriticalSection(&csOpenDllList
);
441 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
443 if (!strcmpiW(library_name
, ptr
->library_name
) &&
444 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
450 LeaveCriticalSection(&csOpenDllList
);
454 /* caller must ensure that library_name is not already in the open dll list */
455 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
461 DllCanUnloadNowFunc DllCanUnloadNow
;
462 DllGetClassObjectFunc DllGetClassObject
;
464 TRACE("%s\n", debugstr_w(library_name
));
466 *ret
= COMPOBJ_DllList_Get(library_name
);
467 if (*ret
) return S_OK
;
469 /* do this outside the csOpenDllList to avoid creating a lock dependency on
471 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
474 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
475 /* failure: DLL could not be loaded */
476 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
479 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
480 /* Note: failing to find DllCanUnloadNow is not a failure */
481 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
482 if (!DllGetClassObject
)
484 /* failure: the dll did not export DllGetClassObject */
485 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
486 FreeLibrary(hLibrary
);
487 return CO_E_DLLNOTFOUND
;
490 EnterCriticalSection( &csOpenDllList
);
492 *ret
= COMPOBJ_DllList_Get(library_name
);
495 /* another caller to this function already added the dll while we
496 * weren't in the critical section */
497 FreeLibrary(hLibrary
);
501 len
= strlenW(library_name
);
502 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
504 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
505 if (entry
&& entry
->library_name
)
507 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
508 entry
->library
= hLibrary
;
510 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
511 entry
->DllGetClassObject
= DllGetClassObject
;
512 list_add_tail(&openDllList
, &entry
->entry
);
517 HeapFree(GetProcessHeap(), 0, entry
);
519 FreeLibrary(hLibrary
);
523 LeaveCriticalSection( &csOpenDllList
);
528 /* pass FALSE for free_entry to release a reference without destroying the
529 * entry if it reaches zero or TRUE otherwise */
530 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
532 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
534 EnterCriticalSection(&csOpenDllList
);
535 list_remove(&entry
->entry
);
536 LeaveCriticalSection(&csOpenDllList
);
538 TRACE("freeing %p\n", entry
->library
);
539 FreeLibrary(entry
->library
);
541 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
542 HeapFree(GetProcessHeap(), 0, entry
);
546 /* frees memory associated with active dll list */
547 static void COMPOBJ_DllList_Free(void)
549 OpenDll
*entry
, *cursor2
;
550 EnterCriticalSection(&csOpenDllList
);
551 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
553 list_remove(&entry
->entry
);
555 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
556 HeapFree(GetProcessHeap(), 0, entry
);
558 LeaveCriticalSection(&csOpenDllList
);
559 DeleteCriticalSection(&csOpenDllList
);
562 /******************************************************************************
566 static DWORD
apartment_addref(struct apartment
*apt
)
568 DWORD refs
= InterlockedIncrement(&apt
->refs
);
569 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
573 /* allocates memory and fills in the necessary fields for a new apartment
574 * object. must be called inside apartment cs */
575 static APARTMENT
*apartment_construct(DWORD model
)
579 TRACE("creating new apartment, model=%d\n", model
);
581 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
582 apt
->tid
= GetCurrentThreadId();
584 list_init(&apt
->proxies
);
585 list_init(&apt
->stubmgrs
);
586 list_init(&apt
->psclsids
);
587 list_init(&apt
->loaded_dlls
);
590 apt
->remunk_exported
= FALSE
;
592 InitializeCriticalSection(&apt
->cs
);
593 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
595 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
597 if (apt
->multi_threaded
)
599 /* FIXME: should be randomly generated by in an RPC call to rpcss */
600 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
604 /* FIXME: should be randomly generated by in an RPC call to rpcss */
605 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
608 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
610 list_add_head(&apts
, &apt
->entry
);
615 /* gets and existing apartment if one exists or otherwise creates an apartment
616 * structure which stores OLE apartment-local information and stores a pointer
617 * to it in the thread-local storage */
618 static APARTMENT
*apartment_get_or_create(DWORD model
)
620 APARTMENT
*apt
= COM_CurrentApt();
624 if (model
& COINIT_APARTMENTTHREADED
)
626 EnterCriticalSection(&csApartment
);
628 apt
= apartment_construct(model
);
633 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
636 LeaveCriticalSection(&csApartment
);
639 apartment_createwindowifneeded(apt
);
643 EnterCriticalSection(&csApartment
);
645 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
646 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
650 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
651 apartment_addref(MTA
);
654 MTA
= apartment_construct(model
);
658 LeaveCriticalSection(&csApartment
);
660 COM_CurrentInfo()->apt
= apt
;
666 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
668 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
671 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
673 list_remove(&curClass
->entry
);
675 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
676 RPC_StopLocalServer(curClass
->RpcRegistration
);
678 IUnknown_Release(curClass
->classObject
);
679 HeapFree(GetProcessHeap(), 0, curClass
);
682 static void COM_RevokeAllClasses(const struct apartment
*apt
)
684 RegisteredClass
*curClass
, *cursor
;
686 EnterCriticalSection( &csRegisteredClassList
);
688 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
690 if (curClass
->apartment_id
== apt
->oxid
)
691 COM_RevokeRegisteredClassObject(curClass
);
694 LeaveCriticalSection( &csRegisteredClassList
);
697 /******************************************************************************
698 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
701 typedef struct ManualResetEvent
{
702 ISynchronize ISynchronize_iface
;
703 ISynchronizeHandle ISynchronizeHandle_iface
;
708 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
710 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
713 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
715 MREImpl
*This
= impl_from_ISynchronize(iface
);
717 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
719 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
720 *ppv
= &This
->ISynchronize_iface
;
721 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
722 *ppv
= &This
->ISynchronizeHandle_iface
;
724 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
726 return E_NOINTERFACE
;
729 IUnknown_AddRef((IUnknown
*)*ppv
);
733 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
735 MREImpl
*This
= impl_from_ISynchronize(iface
);
736 LONG ref
= InterlockedIncrement(&This
->ref
);
737 TRACE("%p - ref %d\n", This
, ref
);
742 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
744 MREImpl
*This
= impl_from_ISynchronize(iface
);
745 LONG ref
= InterlockedDecrement(&This
->ref
);
746 TRACE("%p - ref %d\n", This
, ref
);
750 CloseHandle(This
->event
);
751 HeapFree(GetProcessHeap(), 0, This
);
757 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
759 MREImpl
*This
= impl_from_ISynchronize(iface
);
761 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
762 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
765 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
767 MREImpl
*This
= impl_from_ISynchronize(iface
);
769 SetEvent(This
->event
);
773 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
775 MREImpl
*This
= impl_from_ISynchronize(iface
);
777 ResetEvent(This
->event
);
781 static ISynchronizeVtbl vt_ISynchronize
= {
782 ISynchronize_fnQueryInterface
,
783 ISynchronize_fnAddRef
,
784 ISynchronize_fnRelease
,
786 ISynchronize_fnSignal
,
790 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
792 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
795 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
797 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
798 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
801 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
803 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
804 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
807 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
809 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
810 return ISynchronize_Release(&This
->ISynchronize_iface
);
813 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
815 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
821 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
822 SynchronizeHandle_QueryInterface
,
823 SynchronizeHandle_AddRef
,
824 SynchronizeHandle_Release
,
825 SynchronizeHandle_GetHandle
828 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
830 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
834 FIXME("Aggregation not implemented.\n");
837 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
838 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
839 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
841 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
842 ISynchronize_Release(&This
->ISynchronize_iface
);
846 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
848 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
851 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
853 LocalServer
*This
= impl_from_IServiceProvider(iface
);
855 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
857 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
858 *ppv
= &This
->IServiceProvider_iface
;
861 return E_NOINTERFACE
;
864 IUnknown_AddRef((IUnknown
*)*ppv
);
868 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
870 LocalServer
*This
= impl_from_IServiceProvider(iface
);
871 LONG ref
= InterlockedIncrement(&This
->ref
);
873 TRACE("(%p) ref=%d\n", This
, ref
);
878 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
880 LocalServer
*This
= impl_from_IServiceProvider(iface
);
881 LONG ref
= InterlockedDecrement(&This
->ref
);
883 TRACE("(%p) ref=%d\n", This
, ref
);
887 HeapFree(GetProcessHeap(), 0, This
);
893 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
895 LocalServer
*This
= impl_from_IServiceProvider(iface
);
896 APARTMENT
*apt
= COM_CurrentApt();
897 RegisteredClass
*iter
;
898 HRESULT hres
= E_FAIL
;
900 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
905 EnterCriticalSection(&csRegisteredClassList
);
907 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
908 if(iter
->apartment_id
== apt
->oxid
909 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
910 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
911 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
916 LeaveCriticalSection( &csRegisteredClassList
);
921 static const IServiceProviderVtbl LocalServerVtbl
= {
922 LocalServer_QueryInterface
,
925 LocalServer_QueryService
928 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
932 EnterCriticalSection(&apt
->cs
);
934 if(!apt
->local_server
) {
937 obj
= heap_alloc(sizeof(*obj
));
939 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
943 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
944 if(SUCCEEDED(hres
)) {
945 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
946 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
948 IStream_Release(obj
->marshal_stream
);
952 apt
->local_server
= obj
;
956 hres
= E_OUTOFMEMORY
;
961 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
963 LeaveCriticalSection(&apt
->cs
);
966 ERR("Failed: %08x\n", hres
);
970 /***********************************************************************
971 * CoRevokeClassObject [OLE32.@]
973 * Removes a class object from the class registry.
976 * dwRegister [I] Cookie returned from CoRegisterClassObject().
980 * Failure: HRESULT code.
983 * Must be called from the same apartment that called CoRegisterClassObject(),
984 * otherwise it will fail with RPC_E_WRONG_THREAD.
987 * CoRegisterClassObject
989 HRESULT WINAPI
CoRevokeClassObject(
992 HRESULT hr
= E_INVALIDARG
;
993 RegisteredClass
*curClass
;
996 TRACE("(%08x)\n",dwRegister
);
998 apt
= COM_CurrentApt();
1001 ERR("COM was not initialized\n");
1002 return CO_E_NOTINITIALIZED
;
1005 EnterCriticalSection( &csRegisteredClassList
);
1007 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1010 * Check if we have a match on the cookie.
1012 if (curClass
->dwCookie
== dwRegister
)
1014 if (curClass
->apartment_id
== apt
->oxid
)
1016 COM_RevokeRegisteredClassObject(curClass
);
1021 ERR("called from wrong apartment, should be called from %s\n",
1022 wine_dbgstr_longlong(curClass
->apartment_id
));
1023 hr
= RPC_E_WRONG_THREAD
;
1029 LeaveCriticalSection( &csRegisteredClassList
);
1034 /* frees unused libraries loaded by apartment_getclassobject by calling the
1035 * DLL's DllCanUnloadNow entry point */
1036 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1038 struct apartment_loaded_dll
*entry
, *next
;
1039 EnterCriticalSection(&apt
->cs
);
1040 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1042 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1044 DWORD real_delay
= delay
;
1046 if (real_delay
== INFINITE
)
1048 /* DLLs that return multi-threaded objects aren't unloaded
1049 * straight away to cope for programs that have races between
1050 * last object destruction and threads in the DLLs that haven't
1051 * finished, despite DllCanUnloadNow returning S_OK */
1052 if (entry
->multi_threaded
)
1053 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1058 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1060 list_remove(&entry
->entry
);
1061 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1062 HeapFree(GetProcessHeap(), 0, entry
);
1066 entry
->unload_time
= GetTickCount() + real_delay
;
1067 if (!entry
->unload_time
) entry
->unload_time
= 1;
1070 else if (entry
->unload_time
)
1071 entry
->unload_time
= 0;
1073 LeaveCriticalSection(&apt
->cs
);
1076 DWORD
apartment_release(struct apartment
*apt
)
1080 EnterCriticalSection(&csApartment
);
1082 ret
= InterlockedDecrement(&apt
->refs
);
1083 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1084 /* destruction stuff that needs to happen under csApartment CS */
1087 if (apt
== MTA
) MTA
= NULL
;
1088 else if (apt
== MainApartment
) MainApartment
= NULL
;
1089 list_remove(&apt
->entry
);
1092 LeaveCriticalSection(&csApartment
);
1096 struct list
*cursor
, *cursor2
;
1098 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1100 if(apt
->local_server
) {
1101 LocalServer
*local_server
= apt
->local_server
;
1104 memset(&zero
, 0, sizeof(zero
));
1105 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1106 CoReleaseMarshalData(local_server
->marshal_stream
);
1107 IStream_Release(local_server
->marshal_stream
);
1108 local_server
->marshal_stream
= NULL
;
1110 apt
->local_server
= NULL
;
1111 local_server
->apt
= NULL
;
1112 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1115 /* Release the references to the registered class objects */
1116 COM_RevokeAllClasses(apt
);
1118 /* no locking is needed for this apartment, because no other thread
1119 * can access it at this point */
1121 apartment_disconnectproxies(apt
);
1123 if (apt
->win
) DestroyWindow(apt
->win
);
1124 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1126 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1128 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1129 /* release the implicit reference given by the fact that the
1130 * stub has external references (it must do since it is in the
1131 * stub manager list in the apartment and all non-apartment users
1132 * must have a ref on the apartment and so it cannot be destroyed).
1134 stub_manager_int_release(stubmgr
);
1137 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1139 struct registered_psclsid
*registered_psclsid
=
1140 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1142 list_remove(®istered_psclsid
->entry
);
1143 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1146 /* if this assert fires, then another thread took a reference to a
1147 * stub manager without taking a reference to the containing
1148 * apartment, which it must do. */
1149 assert(list_empty(&apt
->stubmgrs
));
1151 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1153 /* free as many unused libraries as possible... */
1154 apartment_freeunusedlibraries(apt
, 0);
1156 /* ... and free the memory for the apartment loaded dll entry and
1157 * release the dll list reference without freeing the library for the
1159 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1161 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1162 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1163 list_remove(cursor
);
1164 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1167 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1168 DeleteCriticalSection(&apt
->cs
);
1170 HeapFree(GetProcessHeap(), 0, apt
);
1176 /* The given OXID must be local to this process:
1178 * The ref parameter is here mostly to ensure people remember that
1179 * they get one, you should normally take a ref for thread safety.
1181 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1183 APARTMENT
*result
= NULL
;
1184 struct list
*cursor
;
1186 EnterCriticalSection(&csApartment
);
1187 LIST_FOR_EACH( cursor
, &apts
)
1189 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1190 if (apt
->oxid
== oxid
)
1193 if (ref
) apartment_addref(result
);
1197 LeaveCriticalSection(&csApartment
);
1202 /* gets the apartment which has a given creator thread ID. The caller must
1203 * release the reference from the apartment as soon as the apartment pointer
1204 * is no longer required. */
1205 APARTMENT
*apartment_findfromtid(DWORD tid
)
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
->tid
== tid
)
1217 apartment_addref(result
);
1221 LeaveCriticalSection(&csApartment
);
1226 /* gets the main apartment if it exists. The caller must
1227 * release the reference from the apartment as soon as the apartment pointer
1228 * is no longer required. */
1229 static APARTMENT
*apartment_findmain(void)
1233 EnterCriticalSection(&csApartment
);
1235 result
= MainApartment
;
1236 if (result
) apartment_addref(result
);
1238 LeaveCriticalSection(&csApartment
);
1243 /* gets the multi-threaded apartment if it exists. The caller must
1244 * release the reference from the apartment as soon as the apartment pointer
1245 * is no longer required. */
1246 static APARTMENT
*apartment_find_multi_threaded(void)
1248 APARTMENT
*result
= NULL
;
1249 struct list
*cursor
;
1251 EnterCriticalSection(&csApartment
);
1253 LIST_FOR_EACH( cursor
, &apts
)
1255 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1256 if (apt
->multi_threaded
)
1259 apartment_addref(result
);
1264 LeaveCriticalSection(&csApartment
);
1268 /* gets the specified class object by loading the appropriate DLL, if
1269 * necessary and calls the DllGetClassObject function for the DLL */
1270 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1271 BOOL apartment_threaded
,
1272 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1274 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1277 struct apartment_loaded_dll
*apartment_loaded_dll
;
1279 if (!strcmpiW(dllpath
, wszOle32
))
1281 /* we don't need to control the lifetime of this dll, so use the local
1282 * implementation of DllGetClassObject directly */
1283 TRACE("calling ole32!DllGetClassObject\n");
1284 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1287 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1292 EnterCriticalSection(&apt
->cs
);
1294 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1295 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1297 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1304 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1305 if (!apartment_loaded_dll
)
1309 apartment_loaded_dll
->unload_time
= 0;
1310 apartment_loaded_dll
->multi_threaded
= FALSE
;
1311 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1313 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1317 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1318 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1322 LeaveCriticalSection(&apt
->cs
);
1326 /* one component being multi-threaded overrides any number of
1327 * apartment-threaded components */
1328 if (!apartment_threaded
)
1329 apartment_loaded_dll
->multi_threaded
= TRUE
;
1331 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1332 /* OK: get the ClassObject */
1333 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1336 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1342 /***********************************************************************
1343 * COM_RegReadPath [internal]
1345 * Reads a registry value and expands it when necessary
1347 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1354 WCHAR src
[MAX_PATH
];
1355 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1357 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1358 if (keytype
== REG_EXPAND_SZ
) {
1359 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1361 const WCHAR
*quote_start
;
1362 quote_start
= strchrW(src
, '\"');
1364 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1366 memmove(src
, quote_start
+ 1,
1367 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1368 src
[quote_end
- quote_start
- 1] = '\0';
1371 lstrcpynW(dst
, src
, dstlen
);
1382 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1383 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1384 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1385 DeactivateActCtx(0, cookie
);
1390 struct host_object_params
1392 struct class_reg_data regdata
;
1393 CLSID clsid
; /* clsid of object to marshal */
1394 IID iid
; /* interface to marshal */
1395 HANDLE event
; /* event signalling when ready for multi-threaded case */
1396 HRESULT hr
; /* result for multi-threaded case */
1397 IStream
*stream
; /* stream that the object will be marshaled into */
1398 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1401 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1402 const struct host_object_params
*params
)
1406 static const LARGE_INTEGER llZero
;
1407 WCHAR dllpath
[MAX_PATH
+1];
1409 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1411 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1413 /* failure: CLSID is not found in registry */
1414 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1415 return REGDB_E_CLASSNOTREG
;
1418 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1419 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1423 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1425 IUnknown_Release(object
);
1426 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1431 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1436 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1439 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1441 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1445 struct host_thread_params
1447 COINIT threading_model
;
1449 HWND apartment_hwnd
;
1452 /* thread for hosting an object to allow an object to appear to be created in
1453 * an apartment with an incompatible threading model */
1454 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1456 struct host_thread_params
*params
= p
;
1459 struct apartment
*apt
;
1463 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1464 if (FAILED(hr
)) return hr
;
1466 apt
= COM_CurrentApt();
1467 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1469 apartment_createwindowifneeded(apt
);
1470 params
->apartment_hwnd
= apartment_getwindow(apt
);
1473 params
->apartment_hwnd
= NULL
;
1475 /* force the message queue to be created before signaling parent thread */
1476 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1478 SetEvent(params
->ready_event
);
1479 params
= NULL
; /* can't touch params after here as it may be invalid */
1481 while (GetMessageW(&msg
, NULL
, 0, 0))
1483 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1485 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1486 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1487 SetEvent(obj_params
->event
);
1491 TranslateMessage(&msg
);
1492 DispatchMessageW(&msg
);
1503 /* finds or creates a host apartment, creates the object inside it and returns
1504 * a proxy to it so that the object can be used in the apartment of the
1505 * caller of this function */
1506 static HRESULT
apartment_hostobject_in_hostapt(
1507 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1508 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1510 struct host_object_params params
;
1511 HWND apartment_hwnd
= NULL
;
1512 DWORD apartment_tid
= 0;
1515 if (!multi_threaded
&& main_apartment
)
1517 APARTMENT
*host_apt
= apartment_findmain();
1520 apartment_hwnd
= apartment_getwindow(host_apt
);
1521 apartment_release(host_apt
);
1525 if (!apartment_hwnd
)
1527 EnterCriticalSection(&apt
->cs
);
1529 if (!apt
->host_apt_tid
)
1531 struct host_thread_params thread_params
;
1535 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1536 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1537 thread_params
.apartment_hwnd
= NULL
;
1538 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1541 CloseHandle(handles
[0]);
1542 LeaveCriticalSection(&apt
->cs
);
1543 return E_OUTOFMEMORY
;
1545 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1546 CloseHandle(handles
[0]);
1547 CloseHandle(handles
[1]);
1548 if (wait_value
== WAIT_OBJECT_0
)
1549 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1552 LeaveCriticalSection(&apt
->cs
);
1553 return E_OUTOFMEMORY
;
1557 if (multi_threaded
|| !main_apartment
)
1559 apartment_hwnd
= apt
->host_apt_hwnd
;
1560 apartment_tid
= apt
->host_apt_tid
;
1563 LeaveCriticalSection(&apt
->cs
);
1566 /* another thread may have become the main apartment in the time it took
1567 * us to create the thread for the host apartment */
1568 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1570 APARTMENT
*host_apt
= apartment_findmain();
1573 apartment_hwnd
= apartment_getwindow(host_apt
);
1574 apartment_release(host_apt
);
1578 params
.regdata
= *regdata
;
1579 params
.clsid
= *rclsid
;
1581 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1584 params
.apartment_threaded
= !multi_threaded
;
1588 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1589 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1593 WaitForSingleObject(params
.event
, INFINITE
);
1596 CloseHandle(params
.event
);
1600 if (!apartment_hwnd
)
1602 ERR("host apartment didn't create window\n");
1606 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1609 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1610 IStream_Release(params
.stream
);
1615 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1619 /* Dispatching to the correct thread in an apartment is done through
1620 * window messages rather than RPC transports. When an interface is
1621 * marshalled into another apartment in the same process, a window of the
1622 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1623 * application) is responsible for pumping the message loop in that thread.
1624 * The WM_USER messages which point to the RPCs are then dispatched to
1625 * apartment_wndproc by the user's code from the apartment in which the
1626 * interface was unmarshalled.
1628 memset(&wclass
, 0, sizeof(wclass
));
1629 wclass
.lpfnWndProc
= apartment_wndproc
;
1630 wclass
.hInstance
= hProxyDll
;
1631 wclass
.lpszClassName
= wszAptWinClass
;
1632 RegisterClassW(&wclass
);
1637 /* create a window for the apartment or return the current one if one has
1638 * already been created */
1639 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1641 if (apt
->multi_threaded
)
1646 HWND hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0,
1648 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1651 ERR("CreateWindow failed with error %d\n", GetLastError());
1652 return HRESULT_FROM_WIN32(GetLastError());
1654 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1655 /* someone beat us to it */
1656 DestroyWindow(hwnd
);
1662 /* retrieves the window for the main- or apartment-threaded apartment */
1663 HWND
apartment_getwindow(const struct apartment
*apt
)
1665 assert(!apt
->multi_threaded
);
1669 void apartment_joinmta(void)
1671 apartment_addref(MTA
);
1672 COM_CurrentInfo()->apt
= MTA
;
1677 static void COMPOBJ_InitProcess( void )
1681 /* Dispatching to the correct thread in an apartment is done through
1682 * window messages rather than RPC transports. When an interface is
1683 * marshalled into another apartment in the same process, a window of the
1684 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1685 * application) is responsible for pumping the message loop in that thread.
1686 * The WM_USER messages which point to the RPCs are then dispatched to
1687 * apartment_wndproc by the user's code from the apartment in which the
1688 * interface was unmarshalled.
1690 memset(&wclass
, 0, sizeof(wclass
));
1691 wclass
.lpfnWndProc
= apartment_wndproc
;
1692 wclass
.hInstance
= hProxyDll
;
1693 wclass
.lpszClassName
= wszAptWinClass
;
1694 RegisterClassW(&wclass
);
1697 static void COMPOBJ_UninitProcess( void )
1699 UnregisterClassW(wszAptWinClass
, hProxyDll
);
1704 static void COM_TlsDestroy(void)
1706 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1709 if (info
->apt
) apartment_release(info
->apt
);
1710 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1711 if (info
->state
) IUnknown_Release(info
->state
);
1712 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1713 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1714 HeapFree(GetProcessHeap(), 0, info
);
1715 NtCurrentTeb()->ReservedForOle
= NULL
;
1719 /******************************************************************************
1720 * CoBuildVersion [OLE32.@]
1722 * Gets the build version of the DLL.
1727 * Current build version, hiword is majornumber, loword is minornumber
1729 DWORD WINAPI
CoBuildVersion(void)
1731 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1732 return (rmm
<<16)+rup
;
1735 /******************************************************************************
1736 * CoRegisterInitializeSpy [OLE32.@]
1738 * Add a Spy that watches CoInitializeEx calls
1741 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1742 * cookie [II] cookie receiver
1745 * Success: S_OK if not already initialized, S_FALSE otherwise.
1746 * Failure: HRESULT code.
1751 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1753 struct oletls
*info
= COM_CurrentInfo();
1756 TRACE("(%p, %p)\n", spy
, cookie
);
1758 if (!spy
|| !cookie
|| !info
)
1761 WARN("Could not allocate tls\n");
1762 return E_INVALIDARG
;
1767 FIXME("Already registered?\n");
1768 return E_UNEXPECTED
;
1771 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1774 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1780 /******************************************************************************
1781 * CoRevokeInitializeSpy [OLE32.@]
1783 * Remove a spy that previously watched CoInitializeEx calls
1786 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1789 * Success: S_OK if a spy is removed
1790 * Failure: E_INVALIDARG
1795 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1797 struct oletls
*info
= COM_CurrentInfo();
1798 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1800 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1801 return E_INVALIDARG
;
1803 IInitializeSpy_Release(info
->spy
);
1809 /******************************************************************************
1810 * CoInitialize [OLE32.@]
1812 * Initializes the COM libraries by calling CoInitializeEx with
1813 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1816 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1819 * Success: S_OK if not already initialized, S_FALSE otherwise.
1820 * Failure: HRESULT code.
1825 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1828 * Just delegate to the newer method.
1830 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1833 /******************************************************************************
1834 * CoInitializeEx [OLE32.@]
1836 * Initializes the COM libraries.
1839 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1840 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1843 * S_OK if successful,
1844 * S_FALSE if this function was called already.
1845 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1850 * The behavior used to set the IMalloc used for memory management is
1852 * The dwCoInit parameter must specify one of the following apartment
1854 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1855 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1856 * The parameter may also specify zero or more of the following flags:
1857 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1858 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1863 HRESULT WINAPI
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1865 struct oletls
*info
= COM_CurrentInfo();
1869 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1871 if (lpReserved
!=NULL
)
1873 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1877 * Check the lock count. If this is the first time going through the initialize
1878 * process, we have to initialize the libraries.
1880 * And crank-up that lock count.
1882 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1885 * Initialize the various COM libraries and data structures.
1887 TRACE("() - Initializing the COM libraries\n");
1889 /* we may need to defer this until after apartment initialisation */
1890 RunningObjectTableImpl_Initialize();
1894 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1896 if (!(apt
= info
->apt
))
1898 apt
= apartment_get_or_create(dwCoInit
);
1899 if (!apt
) return E_OUTOFMEMORY
;
1901 else if (!apartment_is_model(apt
, dwCoInit
))
1903 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1904 code then we are probably using the wrong threading model to implement that API. */
1905 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1906 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1907 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1908 return RPC_E_CHANGED_MODE
;
1916 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1921 /***********************************************************************
1922 * CoUninitialize [OLE32.@]
1924 * This method will decrement the refcount on the current apartment, freeing
1925 * the resources associated with it if it is the last thread in the apartment.
1926 * If the last apartment is freed, the function will additionally release
1927 * any COM resources associated with the process.
1937 void WINAPI
CoUninitialize(void)
1939 struct oletls
* info
= COM_CurrentInfo();
1944 /* will only happen on OOM */
1948 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1953 ERR("Mismatched CoUninitialize\n");
1956 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1962 apartment_release(info
->apt
);
1967 * Decrease the reference count.
1968 * If we are back to 0 locks on the COM library, make sure we free
1969 * all the associated data structures.
1971 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1974 TRACE("() - Releasing the COM libraries\n");
1976 RunningObjectTableImpl_UnInitialize();
1978 else if (lCOMRefCnt
<1) {
1979 ERR( "CoUninitialize() - not CoInitialized.\n" );
1980 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1983 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1986 /******************************************************************************
1987 * CoDisconnectObject [OLE32.@]
1989 * Disconnects all connections to this object from remote processes. Dispatches
1990 * pending RPCs while blocking new RPCs from occurring, and then calls
1991 * IMarshal::DisconnectObject on the given object.
1993 * Typically called when the object server is forced to shut down, for instance by
1997 * lpUnk [I] The object whose stub should be disconnected.
1998 * reserved [I] Reserved. Should be set to 0.
2002 * Failure: HRESULT code.
2005 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2007 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2013 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2015 if (!lpUnk
) return E_INVALIDARG
;
2017 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2020 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2021 IMarshal_Release(marshal
);
2025 apt
= COM_CurrentApt();
2027 return CO_E_NOTINITIALIZED
;
2029 apartment_disconnectobject(apt
, lpUnk
);
2031 /* Note: native is pretty broken here because it just silently
2032 * fails, without returning an appropriate error code if the object was
2033 * not found, making apps think that the object was disconnected, when
2034 * it actually wasn't */
2039 /******************************************************************************
2040 * CoCreateGuid [OLE32.@]
2042 * Simply forwards to UuidCreate in RPCRT4.
2045 * pguid [O] Points to the GUID to initialize.
2049 * Failure: HRESULT code.
2054 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2056 DWORD status
= UuidCreate(pguid
);
2057 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2058 return HRESULT_FROM_WIN32( status
);
2061 static inline BOOL
is_valid_hex(WCHAR c
)
2063 if (!(((c
>= '0') && (c
<= '9')) ||
2064 ((c
>= 'a') && (c
<= 'f')) ||
2065 ((c
>= 'A') && (c
<= 'F'))))
2070 static const BYTE guid_conv_table
[256] =
2072 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2073 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2074 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2075 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2076 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2077 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2078 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2081 /* conversion helper for CLSIDFromString/IIDFromString */
2082 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2086 if (!s
|| s
[0]!='{') {
2087 memset( id
, 0, sizeof (CLSID
) );
2092 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2094 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2097 for (i
= 1; i
< 9; i
++) {
2098 if (!is_valid_hex(s
[i
])) return FALSE
;
2099 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2101 if (s
[9]!='-') return FALSE
;
2104 for (i
= 10; i
< 14; i
++) {
2105 if (!is_valid_hex(s
[i
])) return FALSE
;
2106 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2108 if (s
[14]!='-') return FALSE
;
2111 for (i
= 15; i
< 19; i
++) {
2112 if (!is_valid_hex(s
[i
])) return FALSE
;
2113 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2115 if (s
[19]!='-') return FALSE
;
2117 for (i
= 20; i
< 37; i
+=2) {
2119 if (s
[i
]!='-') return FALSE
;
2122 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2123 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2126 if (s
[37] == '}' && s
[38] == '\0')
2132 /*****************************************************************************/
2134 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2136 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2137 WCHAR buf2
[CHARS_IN_GUID
];
2138 LONG buf2len
= sizeof(buf2
);
2142 memset(clsid
, 0, sizeof(*clsid
));
2143 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2144 if (!buf
) return E_OUTOFMEMORY
;
2145 strcpyW( buf
, progid
);
2146 strcatW( buf
, clsidW
);
2147 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2149 HeapFree(GetProcessHeap(),0,buf
);
2150 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2151 return CO_E_CLASSSTRING
;
2153 HeapFree(GetProcessHeap(),0,buf
);
2155 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2158 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2159 return CO_E_CLASSSTRING
;
2162 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2165 /******************************************************************************
2166 * CLSIDFromString [OLE32.@]
2168 * Converts a unique identifier from its string representation into
2172 * idstr [I] The string representation of the GUID.
2173 * id [O] GUID converted from the string.
2177 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2182 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2184 HRESULT ret
= CO_E_CLASSSTRING
;
2188 return E_INVALIDARG
;
2190 if (guid_from_string(idstr
, id
))
2193 /* It appears a ProgID is also valid */
2194 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2201 /******************************************************************************
2202 * IIDFromString [OLE32.@]
2204 * Converts a interface identifier from its string representation into
2208 * idstr [I] The string representation of the GUID.
2209 * id [O] IID converted from the string.
2213 * CO_E_IIDSTRING if idstr is not a valid IID
2218 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2220 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2224 memset(iid
, 0, sizeof(*iid
));
2228 /* length mismatch is a special case */
2229 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2230 return E_INVALIDARG
;
2233 return CO_E_IIDSTRING
;
2235 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2238 /******************************************************************************
2239 * StringFromCLSID [OLE32.@]
2240 * StringFromIID [OLE32.@]
2242 * Converts a GUID into the respective string representation.
2243 * The target string is allocated using the OLE IMalloc.
2246 * id [I] the GUID to be converted.
2247 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2254 * StringFromGUID2, CLSIDFromString
2256 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2258 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2259 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2263 /******************************************************************************
2264 * StringFromGUID2 [OLE32.@]
2266 * Modified version of StringFromCLSID that allows you to specify max
2270 * id [I] GUID to convert to string.
2271 * str [O] Buffer where the result will be stored.
2272 * cmax [I] Size of the buffer in characters.
2275 * Success: The length of the resulting string in characters.
2278 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2280 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2281 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2282 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2283 '%','0','2','X','%','0','2','X','}',0 };
2284 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2285 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2286 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2287 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2288 return CHARS_IN_GUID
;
2291 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2292 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2294 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2295 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2299 strcpyW(path
, wszCLSIDSlash
);
2300 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2301 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2302 if (res
== ERROR_FILE_NOT_FOUND
)
2303 return REGDB_E_CLASSNOTREG
;
2304 else if (res
!= ERROR_SUCCESS
)
2305 return REGDB_E_READREGDB
;
2313 res
= open_classes_key(key
, keyname
, access
, subkey
);
2315 if (res
== ERROR_FILE_NOT_FOUND
)
2316 return REGDB_E_KEYMISSING
;
2317 else if (res
!= ERROR_SUCCESS
)
2318 return REGDB_E_READREGDB
;
2323 /* open HKCR\\AppId\\{string form of appid clsid} key */
2324 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2326 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2327 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2329 WCHAR buf
[CHARS_IN_GUID
];
2330 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2336 /* read the AppID value under the class's key */
2337 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2342 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2344 if (res
== ERROR_FILE_NOT_FOUND
)
2345 return REGDB_E_KEYMISSING
;
2346 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2347 return REGDB_E_READREGDB
;
2349 strcpyW(keyname
, szAppIdKey
);
2350 strcatW(keyname
, buf
);
2351 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2352 if (res
== ERROR_FILE_NOT_FOUND
)
2353 return REGDB_E_KEYMISSING
;
2354 else if (res
!= ERROR_SUCCESS
)
2355 return REGDB_E_READREGDB
;
2360 /******************************************************************************
2361 * ProgIDFromCLSID [OLE32.@]
2363 * Converts a class id into the respective program ID.
2366 * clsid [I] Class ID, as found in registry.
2367 * ppszProgID [O] Associated ProgID.
2372 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2374 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2376 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2377 ACTCTX_SECTION_KEYED_DATA data
;
2383 return E_INVALIDARG
;
2387 data
.cbSize
= sizeof(data
);
2388 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2391 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2392 if (comclass
->progid_len
)
2396 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2397 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2399 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2400 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2404 return REGDB_E_CLASSNOTREG
;
2407 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2411 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2412 ret
= REGDB_E_CLASSNOTREG
;
2416 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2419 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2420 ret
= REGDB_E_CLASSNOTREG
;
2421 CoTaskMemFree(*ppszProgID
);
2426 ret
= E_OUTOFMEMORY
;
2433 /******************************************************************************
2434 * CLSIDFromProgID [OLE32.@]
2436 * Converts a program id into the respective GUID.
2439 * progid [I] Unicode program ID, as found in registry.
2440 * clsid [O] Associated CLSID.
2444 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2446 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2448 ACTCTX_SECTION_KEYED_DATA data
;
2450 if (!progid
|| !clsid
)
2451 return E_INVALIDARG
;
2453 data
.cbSize
= sizeof(data
);
2454 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2457 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2458 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2463 return clsid_from_string_reg(progid
, clsid
);
2466 /******************************************************************************
2467 * CLSIDFromProgIDEx [OLE32.@]
2469 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2471 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2473 return CLSIDFromProgID(progid
, clsid
);
2476 /*****************************************************************************
2477 * CoGetPSClsid [OLE32.@]
2479 * Retrieves the CLSID of the proxy/stub factory that implements
2480 * IPSFactoryBuffer for the specified interface.
2483 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2484 * pclsid [O] Where to store returned proxy/stub CLSID.
2489 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2493 * The standard marshaller activates the object with the CLSID
2494 * returned and uses the CreateProxy and CreateStub methods on its
2495 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2498 * CoGetPSClsid determines this CLSID by searching the
2499 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2500 * in the registry and any interface id registered by
2501 * CoRegisterPSClsid within the current process.
2505 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2506 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2507 * considered a bug in native unless an application depends on this (unlikely).
2510 * CoRegisterPSClsid.
2512 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2514 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2515 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2516 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2517 WCHAR value
[CHARS_IN_GUID
];
2520 APARTMENT
*apt
= COM_CurrentApt();
2521 struct registered_psclsid
*registered_psclsid
;
2522 ACTCTX_SECTION_KEYED_DATA data
;
2524 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2528 ERR("apartment not initialised\n");
2529 return CO_E_NOTINITIALIZED
;
2533 return E_INVALIDARG
;
2535 EnterCriticalSection(&apt
->cs
);
2537 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2538 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2540 *pclsid
= registered_psclsid
->clsid
;
2541 LeaveCriticalSection(&apt
->cs
);
2545 LeaveCriticalSection(&apt
->cs
);
2547 data
.cbSize
= sizeof(data
);
2548 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2551 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2552 *pclsid
= ifaceps
->iid
;
2556 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2557 strcpyW(path
, wszInterface
);
2558 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2559 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2561 /* Open the key.. */
2562 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, KEY_READ
, &hkey
))
2564 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2565 return REGDB_E_IIDNOTREG
;
2568 /* ... Once we have the key, query the registry to get the
2569 value of CLSID as a string, and convert it into a
2570 proper CLSID structure to be passed back to the app */
2571 len
= sizeof(value
);
2572 if (ERROR_SUCCESS
!= RegQueryValueW(hkey
, NULL
, value
, &len
))
2575 return REGDB_E_IIDNOTREG
;
2579 /* We have the CLSID we want back from the registry as a string, so
2580 let's convert it into a CLSID structure */
2581 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2582 return REGDB_E_IIDNOTREG
;
2584 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2588 /*****************************************************************************
2589 * CoRegisterPSClsid [OLE32.@]
2591 * Register a proxy/stub CLSID for the given interface in the current process
2595 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2596 * rclsid [I] CLSID of the proxy/stub.
2600 * Failure: E_OUTOFMEMORY
2604 * This function does not add anything to the registry and the effects are
2605 * limited to the lifetime of the current process.
2610 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2612 APARTMENT
*apt
= COM_CurrentApt();
2613 struct registered_psclsid
*registered_psclsid
;
2615 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2619 ERR("apartment not initialised\n");
2620 return CO_E_NOTINITIALIZED
;
2623 EnterCriticalSection(&apt
->cs
);
2625 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2626 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2628 registered_psclsid
->clsid
= *rclsid
;
2629 LeaveCriticalSection(&apt
->cs
);
2633 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2634 if (!registered_psclsid
)
2636 LeaveCriticalSection(&apt
->cs
);
2637 return E_OUTOFMEMORY
;
2640 registered_psclsid
->iid
= *riid
;
2641 registered_psclsid
->clsid
= *rclsid
;
2642 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2644 LeaveCriticalSection(&apt
->cs
);
2651 * COM_GetRegisteredClassObject
2653 * This internal method is used to scan the registered class list to
2654 * find a class object.
2657 * rclsid Class ID of the class to find.
2658 * dwClsContext Class context to match.
2659 * ppv [out] returns a pointer to the class object. Complying
2660 * to normal COM usage, this method will increase the
2661 * reference count on this object.
2663 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2664 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2666 HRESULT hr
= S_FALSE
;
2667 RegisteredClass
*curClass
;
2669 EnterCriticalSection( &csRegisteredClassList
);
2671 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2674 * Check if we have a match on the class ID and context.
2676 if ((apt
->oxid
== curClass
->apartment_id
) &&
2677 (dwClsContext
& curClass
->runContext
) &&
2678 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2681 * We have a match, return the pointer to the class object.
2683 *ppUnk
= curClass
->classObject
;
2685 IUnknown_AddRef(curClass
->classObject
);
2692 LeaveCriticalSection( &csRegisteredClassList
);
2697 /******************************************************************************
2698 * CoRegisterClassObject [OLE32.@]
2700 * Registers the class object for a given class ID. Servers housed in EXE
2701 * files use this method instead of exporting DllGetClassObject to allow
2702 * other code to connect to their objects.
2705 * rclsid [I] CLSID of the object to register.
2706 * pUnk [I] IUnknown of the object.
2707 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2708 * flags [I] REGCLS flags indicating how connections are made.
2709 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2713 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2714 * CO_E_OBJISREG if the object is already registered. We should not return this.
2717 * CoRevokeClassObject, CoGetClassObject
2720 * In-process objects are only registered for the current apartment.
2721 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2722 * in other apartments.
2725 * MSDN claims that multiple interface registrations are legal, but we
2726 * can't do that with our current implementation.
2728 HRESULT WINAPI
CoRegisterClassObject(
2733 LPDWORD lpdwRegister
)
2735 static LONG next_cookie
;
2736 RegisteredClass
* newClass
;
2737 LPUNKNOWN foundObject
;
2741 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2742 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2744 if ( (lpdwRegister
==0) || (pUnk
==0) )
2745 return E_INVALIDARG
;
2747 apt
= COM_CurrentApt();
2750 ERR("COM was not initialized\n");
2751 return CO_E_NOTINITIALIZED
;
2756 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2757 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2758 if (flags
& REGCLS_MULTIPLEUSE
)
2759 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2762 * First, check if the class is already registered.
2763 * If it is, this should cause an error.
2765 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2767 if (flags
& REGCLS_MULTIPLEUSE
) {
2768 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2769 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2770 IUnknown_Release(foundObject
);
2773 IUnknown_Release(foundObject
);
2774 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2775 return CO_E_OBJISREG
;
2778 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2779 if ( newClass
== NULL
)
2780 return E_OUTOFMEMORY
;
2782 newClass
->classIdentifier
= *rclsid
;
2783 newClass
->apartment_id
= apt
->oxid
;
2784 newClass
->runContext
= dwClsContext
;
2785 newClass
->connectFlags
= flags
;
2786 newClass
->RpcRegistration
= NULL
;
2788 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2789 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2792 * Since we're making a copy of the object pointer, we have to increase its
2795 newClass
->classObject
= pUnk
;
2796 IUnknown_AddRef(newClass
->classObject
);
2798 EnterCriticalSection( &csRegisteredClassList
);
2799 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2800 LeaveCriticalSection( &csRegisteredClassList
);
2802 *lpdwRegister
= newClass
->dwCookie
;
2804 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2805 IStream
*marshal_stream
;
2807 hr
= get_local_server_stream(apt
, &marshal_stream
);
2811 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2813 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2814 &newClass
->RpcRegistration
);
2815 IStream_Release(marshal_stream
);
2820 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2824 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2825 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2826 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2827 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2828 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2829 DWORD dwLength
= sizeof(threading_model
);
2833 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2834 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2835 threading_model
[0] = '\0';
2837 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2838 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2839 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2841 /* there's not specific handling for this case */
2842 if (threading_model
[0]) return ThreadingModel_Neutral
;
2843 return ThreadingModel_No
;
2846 return data
->u
.actctx
.data
->model
;
2849 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2850 REFCLSID rclsid
, REFIID riid
,
2851 BOOL hostifnecessary
, void **ppv
)
2853 WCHAR dllpath
[MAX_PATH
+1];
2854 BOOL apartment_threaded
;
2856 if (hostifnecessary
)
2858 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2860 if (model
== ThreadingModel_Apartment
)
2862 apartment_threaded
= TRUE
;
2863 if (apt
->multi_threaded
)
2864 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2866 else if (model
== ThreadingModel_Free
)
2868 apartment_threaded
= FALSE
;
2869 if (!apt
->multi_threaded
)
2870 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2872 /* everything except "Apartment", "Free" and "Both" */
2873 else if (model
!= ThreadingModel_Both
)
2875 apartment_threaded
= TRUE
;
2876 /* everything else is main-threaded */
2877 if (model
!= ThreadingModel_No
)
2878 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2880 if (apt
->multi_threaded
|| !apt
->main
)
2881 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2884 apartment_threaded
= FALSE
;
2887 apartment_threaded
= !apt
->multi_threaded
;
2889 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2891 /* failure: CLSID is not found in registry */
2892 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2893 return REGDB_E_CLASSNOTREG
;
2896 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2900 /***********************************************************************
2901 * CoGetClassObject [OLE32.@]
2903 * Creates an object of the specified class.
2906 * rclsid [I] Class ID to create an instance of.
2907 * dwClsContext [I] Flags to restrict the location of the created instance.
2908 * pServerInfo [I] Optional. Details for connecting to a remote server.
2909 * iid [I] The ID of the interface of the instance to return.
2910 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2914 * Failure: HRESULT code.
2917 * The dwClsContext parameter can be one or more of the following:
2918 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2919 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2920 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2921 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2924 * CoCreateInstance()
2926 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2927 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2928 REFIID iid
, LPVOID
*ppv
)
2930 struct class_reg_data clsreg
;
2931 IUnknown
*regClassObject
;
2932 HRESULT hres
= E_UNEXPECTED
;
2934 BOOL release_apt
= FALSE
;
2936 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2939 return E_INVALIDARG
;
2943 if (!(apt
= COM_CurrentApt()))
2945 if (!(apt
= apartment_find_multi_threaded()))
2947 ERR("apartment not initialised\n");
2948 return CO_E_NOTINITIALIZED
;
2954 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2955 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2958 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2960 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2962 if (release_apt
) apartment_release(apt
);
2963 return FTMarshalCF_Create(iid
, ppv
);
2967 if (CLSCTX_INPROC
& dwClsContext
)
2969 ACTCTX_SECTION_KEYED_DATA data
;
2971 data
.cbSize
= sizeof(data
);
2972 /* search activation context first */
2973 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
2974 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2977 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2979 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
2980 clsreg
.u
.actctx
.data
= data
.lpData
;
2981 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
2982 clsreg
.hkey
= FALSE
;
2984 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2985 ReleaseActCtx(data
.hActCtx
);
2986 if (release_apt
) apartment_release(apt
);
2992 * First, try and see if we can't match the class ID with one of the
2993 * registered classes.
2995 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
2998 /* Get the required interface from the retrieved pointer. */
2999 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3002 * Since QI got another reference on the pointer, we want to release the
3003 * one we already have. If QI was unsuccessful, this will release the object. This
3004 * is good since we are not returning it in the "out" parameter.
3006 IUnknown_Release(regClassObject
);
3007 if (release_apt
) apartment_release(apt
);
3011 /* First try in-process server */
3012 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3014 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3017 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3020 if (hres
== REGDB_E_CLASSNOTREG
)
3021 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3022 else if (hres
== REGDB_E_KEYMISSING
)
3024 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3025 hres
= REGDB_E_CLASSNOTREG
;
3029 if (SUCCEEDED(hres
))
3031 clsreg
.u
.hkey
= hkey
;
3034 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3038 /* return if we got a class, otherwise fall through to one of the
3040 if (SUCCEEDED(hres
))
3042 if (release_apt
) apartment_release(apt
);
3047 /* Next try in-process handler */
3048 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3050 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3053 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3056 if (hres
== REGDB_E_CLASSNOTREG
)
3057 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3058 else if (hres
== REGDB_E_KEYMISSING
)
3060 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3061 hres
= REGDB_E_CLASSNOTREG
;
3065 if (SUCCEEDED(hres
))
3067 clsreg
.u
.hkey
= hkey
;
3070 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3074 /* return if we got a class, otherwise fall through to one of the
3076 if (SUCCEEDED(hres
))
3078 if (release_apt
) apartment_release(apt
);
3082 if (release_apt
) apartment_release(apt
);
3084 /* Next try out of process */
3085 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3087 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3088 if (SUCCEEDED(hres
))
3092 /* Finally try remote: this requires networked DCOM (a lot of work) */
3093 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3095 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3096 hres
= REGDB_E_CLASSNOTREG
;
3100 ERR("no class object %s could be created for context 0x%x\n",
3101 debugstr_guid(rclsid
), dwClsContext
);
3105 /***********************************************************************
3106 * CoResumeClassObjects (OLE32.@)
3108 * Resumes all class objects registered with REGCLS_SUSPENDED.
3112 * Failure: HRESULT code.
3114 HRESULT WINAPI
CoResumeClassObjects(void)
3120 /***********************************************************************
3121 * CoCreateInstance [OLE32.@]
3123 * Creates an instance of the specified class.
3126 * rclsid [I] Class ID to create an instance of.
3127 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3128 * dwClsContext [I] Flags to restrict the location of the created instance.
3129 * iid [I] The ID of the interface of the instance to return.
3130 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3134 * Failure: HRESULT code.
3137 * The dwClsContext parameter can be one or more of the following:
3138 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3139 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3140 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3141 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3143 * Aggregation is the concept of deferring the IUnknown of an object to another
3144 * object. This allows a separate object to behave as though it was part of
3145 * the object and to allow this the pUnkOuter parameter can be set. Note that
3146 * not all objects support having an outer of unknown.
3149 * CoGetClassObject()
3151 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3153 LPUNKNOWN pUnkOuter
,
3159 LPCLASSFACTORY lpclf
= 0;
3162 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3163 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3170 if (!(apt
= COM_CurrentApt()))
3172 if (!(apt
= apartment_find_multi_threaded()))
3174 ERR("apartment not initialised\n");
3175 return CO_E_NOTINITIALIZED
;
3177 apartment_release(apt
);
3181 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3183 if (IsEqualIID(rclsid
, &CLSID_StdGlobalInterfaceTable
))
3185 IGlobalInterfaceTable
*git
= get_std_git();
3186 hres
= IGlobalInterfaceTable_QueryInterface(git
, iid
, ppv
);
3187 if (hres
!= S_OK
) return hres
;
3189 TRACE("Retrieved GIT (%p)\n", *ppv
);
3193 if (IsEqualCLSID(rclsid
, &CLSID_ManualResetEvent
))
3194 return ManualResetEvent_Construct(pUnkOuter
, iid
, ppv
);
3197 * Get a class factory to construct the object we want.
3199 hres
= CoGetClassObject(rclsid
,
3209 * Create the object and don't forget to release the factory
3211 hres
= IClassFactory_CreateInstance(lpclf
, pUnkOuter
, iid
, ppv
);
3212 IClassFactory_Release(lpclf
);
3215 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3216 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid
));
3218 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3220 debugstr_guid(rclsid
),hres
);
3226 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
)
3230 for (i
= 0; i
< count
; i
++)
3233 mqi
[i
].hr
= E_NOINTERFACE
;
3237 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
)
3239 ULONG index
, fetched
= 0;
3241 for (index
= 0; index
< count
; index
++)
3243 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3244 if (mqi
[index
].hr
== S_OK
)
3248 IUnknown_Release(unk
);
3251 return E_NOINTERFACE
;
3253 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3256 /***********************************************************************
3257 * CoCreateInstanceEx [OLE32.@]
3259 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3261 LPUNKNOWN pUnkOuter
,
3263 COSERVERINFO
* pServerInfo
,
3267 IUnknown
* pUnk
= NULL
;
3273 if ( (cmq
==0) || (pResults
==NULL
))
3274 return E_INVALIDARG
;
3276 if (pServerInfo
!=NULL
)
3277 FIXME("() non-NULL pServerInfo not supported!\n");
3279 init_multi_qi(cmq
, pResults
);
3282 * Get the object and get its IUnknown pointer.
3284 hr
= CoCreateInstance(rclsid
,
3293 return return_multi_qi(pUnk
, cmq
, pResults
);
3296 /***********************************************************************
3297 * CoGetInstanceFromFile [OLE32.@]
3299 HRESULT WINAPI
CoGetInstanceFromFile(
3300 COSERVERINFO
*server_info
,
3310 IPersistFile
*pf
= NULL
;
3311 IUnknown
* unk
= NULL
;
3315 if (count
== 0 || !results
)
3316 return E_INVALIDARG
;
3319 FIXME("() non-NULL server_info not supported\n");
3321 init_multi_qi(count
, results
);
3323 /* optionaly get CLSID from a file */
3326 hr
= GetClassFile(filename
, &clsid
);
3329 ERR("failed to get CLSID from a file\n");
3336 hr
= CoCreateInstance(rclsid
,
3345 /* init from file */
3346 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3348 ERR("failed to get IPersistFile\n");
3352 IPersistFile_Load(pf
, filename
, grfmode
);
3353 IPersistFile_Release(pf
);
3356 return return_multi_qi(unk
, count
, results
);
3359 /***********************************************************************
3360 * CoGetInstanceFromIStorage [OLE32.@]
3362 HRESULT WINAPI
CoGetInstanceFromIStorage(
3363 COSERVERINFO
*server_info
,
3372 IPersistStorage
*ps
= NULL
;
3373 IUnknown
* unk
= NULL
;
3377 if (count
== 0 || !results
|| !storage
)
3378 return E_INVALIDARG
;
3381 FIXME("() non-NULL server_info not supported\n");
3383 init_multi_qi(count
, results
);
3385 /* optionaly get CLSID from a file */
3388 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3389 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3392 ERR("failed to get CLSID from a file\n");
3396 rclsid
= &stat
.clsid
;
3399 hr
= CoCreateInstance(rclsid
,
3408 /* init from IStorage */
3409 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3411 ERR("failed to get IPersistStorage\n");
3415 IPersistStorage_Load(ps
, storage
);
3416 IPersistStorage_Release(ps
);
3419 return return_multi_qi(unk
, count
, results
);
3422 /***********************************************************************
3423 * CoLoadLibrary (OLE32.@)
3428 * lpszLibName [I] Path to library.
3429 * bAutoFree [I] Whether the library should automatically be freed.
3432 * Success: Handle to loaded library.
3436 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3438 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3440 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3442 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3445 /***********************************************************************
3446 * CoFreeLibrary [OLE32.@]
3448 * Unloads a library from memory.
3451 * hLibrary [I] Handle to library to unload.
3457 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3459 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3461 FreeLibrary(hLibrary
);
3465 /***********************************************************************
3466 * CoFreeAllLibraries [OLE32.@]
3468 * Function for backwards compatibility only. Does nothing.
3474 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3476 void WINAPI
CoFreeAllLibraries(void)
3481 /***********************************************************************
3482 * CoFreeUnusedLibrariesEx [OLE32.@]
3484 * Frees any previously unused libraries whose delay has expired and marks
3485 * currently unused libraries for unloading. Unused are identified as those that
3486 * return S_OK from their DllCanUnloadNow function.
3489 * dwUnloadDelay [I] Unload delay in milliseconds.
3490 * dwReserved [I] Reserved. Set to 0.
3496 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3498 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3500 struct apartment
*apt
= COM_CurrentApt();
3503 ERR("apartment not initialised\n");
3507 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3510 /***********************************************************************
3511 * CoFreeUnusedLibraries [OLE32.@]
3513 * Frees any unused libraries. Unused are identified as those that return
3514 * S_OK from their DllCanUnloadNow function.
3520 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3522 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3524 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3527 /***********************************************************************
3528 * CoFileTimeNow [OLE32.@]
3530 * Retrieves the current time in FILETIME format.
3533 * lpFileTime [O] The current time.
3538 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3540 GetSystemTimeAsFileTime( lpFileTime
);
3544 /******************************************************************************
3545 * CoLockObjectExternal [OLE32.@]
3547 * Increments or decrements the external reference count of a stub object.
3550 * pUnk [I] Stub object.
3551 * fLock [I] If TRUE then increments the external ref-count,
3552 * otherwise decrements.
3553 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3554 * calling CoDisconnectObject.
3558 * Failure: HRESULT code.
3561 * If fLock is TRUE and an object is passed in that doesn't have a stub
3562 * manager then a new stub manager is created for the object.
3564 HRESULT WINAPI
CoLockObjectExternal(
3567 BOOL fLastUnlockReleases
)
3569 struct stub_manager
*stubmgr
;
3570 struct apartment
*apt
;
3572 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3573 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3575 apt
= COM_CurrentApt();
3576 if (!apt
) return CO_E_NOTINITIALIZED
;
3578 stubmgr
= get_stub_manager_from_object(apt
, pUnk
);
3583 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3585 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3587 stub_manager_int_release(stubmgr
);
3593 stubmgr
= new_stub_manager(apt
, pUnk
);
3597 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3598 stub_manager_int_release(stubmgr
);
3605 WARN("stub object not found %p\n", pUnk
);
3606 /* Note: native is pretty broken here because it just silently
3607 * fails, without returning an appropriate error code, making apps
3608 * think that the object was disconnected, when it actually wasn't */
3613 /***********************************************************************
3614 * CoInitializeWOW (OLE32.@)
3616 * WOW equivalent of CoInitialize?
3625 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3627 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3631 /***********************************************************************
3632 * CoGetState [OLE32.@]
3634 * Retrieves the thread state object previously stored by CoSetState().
3637 * ppv [I] Address where pointer to object will be stored.
3641 * Failure: E_OUTOFMEMORY.
3644 * Crashes on all invalid ppv addresses, including NULL.
3645 * If the function returns a non-NULL object then the caller must release its
3646 * reference on the object when the object is no longer required.
3651 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3653 struct oletls
*info
= COM_CurrentInfo();
3654 if (!info
) return E_OUTOFMEMORY
;
3660 IUnknown_AddRef(info
->state
);
3662 TRACE("apt->state=%p\n", info
->state
);
3668 /***********************************************************************
3669 * CoSetState [OLE32.@]
3671 * Sets the thread state object.
3674 * pv [I] Pointer to state object to be stored.
3677 * The system keeps a reference on the object while the object stored.
3681 * Failure: E_OUTOFMEMORY.
3683 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3685 struct oletls
*info
= COM_CurrentInfo();
3686 if (!info
) return E_OUTOFMEMORY
;
3688 if (pv
) IUnknown_AddRef(pv
);
3692 TRACE("-- release %p now\n", info
->state
);
3693 IUnknown_Release(info
->state
);
3702 /******************************************************************************
3703 * CoTreatAsClass [OLE32.@]
3705 * Sets the TreatAs value of a class.
3708 * clsidOld [I] Class to set TreatAs value on.
3709 * clsidNew [I] The class the clsidOld should be treated as.
3713 * Failure: HRESULT code.
3718 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3720 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3721 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3723 WCHAR szClsidNew
[CHARS_IN_GUID
];
3725 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3726 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3729 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3732 if (!memcmp( clsidOld
, clsidNew
, sizeof(*clsidOld
) ))
3734 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3735 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3737 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3739 res
= REGDB_E_WRITEREGDB
;
3745 RegDeleteKeyW(hkey
, wszTreatAs
);
3749 else if (!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
)) &&
3750 !RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)))
3752 res
= REGDB_E_WRITEREGDB
;
3757 if (hkey
) RegCloseKey(hkey
);
3761 /******************************************************************************
3762 * CoGetTreatAsClass [OLE32.@]
3764 * Gets the TreatAs value of a class.
3767 * clsidOld [I] Class to get the TreatAs value of.
3768 * clsidNew [I] The class the clsidOld should be treated as.
3772 * Failure: HRESULT code.
3777 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3779 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3781 WCHAR szClsidNew
[CHARS_IN_GUID
];
3783 LONG len
= sizeof(szClsidNew
);
3785 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3786 *clsidNew
= *clsidOld
; /* copy over old value */
3788 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3794 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3799 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3801 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3803 if (hkey
) RegCloseKey(hkey
);
3807 /******************************************************************************
3808 * CoGetCurrentProcess [OLE32.@]
3810 * Gets the current process ID.
3813 * The current process ID.
3816 * Is DWORD really the correct return type for this function?
3818 DWORD WINAPI
CoGetCurrentProcess(void)
3820 return GetCurrentProcessId();
3823 /******************************************************************************
3824 * CoRegisterMessageFilter [OLE32.@]
3826 * Registers a message filter.
3829 * lpMessageFilter [I] Pointer to interface.
3830 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3834 * Failure: HRESULT code.
3837 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3838 * lpMessageFilter removes the message filter.
3840 * If lplpMessageFilter is not NULL the previous message filter will be
3841 * returned in the memory pointer to this parameter and the caller is
3842 * responsible for releasing the object.
3844 * The current thread be in an apartment otherwise the function will crash.
3846 HRESULT WINAPI
CoRegisterMessageFilter(
3847 LPMESSAGEFILTER lpMessageFilter
,
3848 LPMESSAGEFILTER
*lplpMessageFilter
)
3850 struct apartment
*apt
;
3851 IMessageFilter
*lpOldMessageFilter
;
3853 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3855 apt
= COM_CurrentApt();
3857 /* can't set a message filter in a multi-threaded apartment */
3858 if (!apt
|| apt
->multi_threaded
)
3860 WARN("can't set message filter in MTA or uninitialized apt\n");
3861 return CO_E_NOT_SUPPORTED
;
3864 if (lpMessageFilter
)
3865 IMessageFilter_AddRef(lpMessageFilter
);
3867 EnterCriticalSection(&apt
->cs
);
3869 lpOldMessageFilter
= apt
->filter
;
3870 apt
->filter
= lpMessageFilter
;
3872 LeaveCriticalSection(&apt
->cs
);
3874 if (lplpMessageFilter
)
3875 *lplpMessageFilter
= lpOldMessageFilter
;
3876 else if (lpOldMessageFilter
)
3877 IMessageFilter_Release(lpOldMessageFilter
);
3882 /***********************************************************************
3883 * CoIsOle1Class [OLE32.@]
3885 * Determines whether the specified class an OLE v1 class.
3888 * clsid [I] Class to test.
3891 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3893 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3895 FIXME("%s\n", debugstr_guid(clsid
));
3899 /***********************************************************************
3900 * IsEqualGUID [OLE32.@]
3902 * Compares two Unique Identifiers.
3905 * rguid1 [I] The first GUID to compare.
3906 * rguid2 [I] The other GUID to compare.
3912 BOOL WINAPI
IsEqualGUID(
3916 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3919 /***********************************************************************
3920 * CoInitializeSecurity [OLE32.@]
3922 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3923 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3924 void* pReserved1
, DWORD dwAuthnLevel
,
3925 DWORD dwImpLevel
, void* pReserved2
,
3926 DWORD dwCapabilities
, void* pReserved3
)
3928 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3929 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3930 dwCapabilities
, pReserved3
);
3934 /***********************************************************************
3935 * CoSuspendClassObjects [OLE32.@]
3937 * Suspends all registered class objects to prevent further requests coming in
3938 * for those objects.
3942 * Failure: HRESULT code.
3944 HRESULT WINAPI
CoSuspendClassObjects(void)
3950 /***********************************************************************
3951 * CoAddRefServerProcess [OLE32.@]
3953 * Helper function for incrementing the reference count of a local-server
3957 * New reference count.
3960 * CoReleaseServerProcess().
3962 ULONG WINAPI
CoAddRefServerProcess(void)
3968 EnterCriticalSection(&csRegisteredClassList
);
3969 refs
= ++s_COMServerProcessReferences
;
3970 LeaveCriticalSection(&csRegisteredClassList
);
3972 TRACE("refs before: %d\n", refs
- 1);
3977 /***********************************************************************
3978 * CoReleaseServerProcess [OLE32.@]
3980 * Helper function for decrementing the reference count of a local-server
3984 * New reference count.
3987 * When reference count reaches 0, this function suspends all registered
3988 * classes so no new connections are accepted.
3991 * CoAddRefServerProcess(), CoSuspendClassObjects().
3993 ULONG WINAPI
CoReleaseServerProcess(void)
3999 EnterCriticalSection(&csRegisteredClassList
);
4001 refs
= --s_COMServerProcessReferences
;
4002 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4004 LeaveCriticalSection(&csRegisteredClassList
);
4006 TRACE("refs after: %d\n", refs
);
4011 /***********************************************************************
4012 * CoIsHandlerConnected [OLE32.@]
4014 * Determines whether a proxy is connected to a remote stub.
4017 * pUnk [I] Pointer to object that may or may not be connected.
4020 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4023 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4025 FIXME("%p\n", pUnk
);
4030 /***********************************************************************
4031 * CoAllowSetForegroundWindow [OLE32.@]
4034 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4036 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4040 /***********************************************************************
4041 * CoQueryProxyBlanket [OLE32.@]
4043 * Retrieves the security settings being used by a proxy.
4046 * pProxy [I] Pointer to the proxy object.
4047 * pAuthnSvc [O] The type of authentication service.
4048 * pAuthzSvc [O] The type of authorization service.
4049 * ppServerPrincName [O] Optional. The server prinicple name.
4050 * pAuthnLevel [O] The authentication level.
4051 * pImpLevel [O] The impersonation level.
4052 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4053 * pCapabilities [O] Flags affecting the security behaviour.
4057 * Failure: HRESULT code.
4060 * CoCopyProxy, CoSetProxyBlanket.
4062 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4063 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4064 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4066 IClientSecurity
*pCliSec
;
4069 TRACE("%p\n", pProxy
);
4071 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4074 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4075 pAuthzSvc
, ppServerPrincName
,
4076 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4078 IClientSecurity_Release(pCliSec
);
4081 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4085 /***********************************************************************
4086 * CoSetProxyBlanket [OLE32.@]
4088 * Sets the security settings for a proxy.
4091 * pProxy [I] Pointer to the proxy object.
4092 * AuthnSvc [I] The type of authentication service.
4093 * AuthzSvc [I] The type of authorization service.
4094 * pServerPrincName [I] The server prinicple name.
4095 * AuthnLevel [I] The authentication level.
4096 * ImpLevel [I] The impersonation level.
4097 * pAuthInfo [I] Information specific to the authorization/authentication service.
4098 * Capabilities [I] Flags affecting the security behaviour.
4102 * Failure: HRESULT code.
4105 * CoQueryProxyBlanket, CoCopyProxy.
4107 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4108 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4109 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4111 IClientSecurity
*pCliSec
;
4114 TRACE("%p\n", pProxy
);
4116 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4119 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4120 AuthzSvc
, pServerPrincName
,
4121 AuthnLevel
, ImpLevel
, pAuthInfo
,
4123 IClientSecurity_Release(pCliSec
);
4126 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4130 /***********************************************************************
4131 * CoCopyProxy [OLE32.@]
4136 * pProxy [I] Pointer to the proxy object.
4137 * ppCopy [O] Copy of the proxy.
4141 * Failure: HRESULT code.
4144 * CoQueryProxyBlanket, CoSetProxyBlanket.
4146 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4148 IClientSecurity
*pCliSec
;
4151 TRACE("%p\n", pProxy
);
4153 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4156 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4157 IClientSecurity_Release(pCliSec
);
4160 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4165 /***********************************************************************
4166 * CoGetCallContext [OLE32.@]
4168 * Gets the context of the currently executing server call in the current
4172 * riid [I] Context interface to return.
4173 * ppv [O] Pointer to memory that will receive the context on return.
4177 * Failure: HRESULT code.
4179 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4181 struct oletls
*info
= COM_CurrentInfo();
4183 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4186 return E_OUTOFMEMORY
;
4188 if (!info
->call_state
)
4189 return RPC_E_CALL_COMPLETE
;
4191 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4194 /***********************************************************************
4195 * CoSwitchCallContext [OLE32.@]
4197 * Switches the context of the currently executing server call in the current
4201 * pObject [I] Pointer to new context object
4202 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4206 * Failure: HRESULT code.
4208 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4210 struct oletls
*info
= COM_CurrentInfo();
4212 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4215 return E_OUTOFMEMORY
;
4217 *ppOldObject
= info
->call_state
;
4218 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4223 /***********************************************************************
4224 * CoQueryClientBlanket [OLE32.@]
4226 * Retrieves the authentication information about the client of the currently
4227 * executing server call in the current thread.
4230 * pAuthnSvc [O] Optional. The type of authentication service.
4231 * pAuthzSvc [O] Optional. The type of authorization service.
4232 * pServerPrincName [O] Optional. The server prinicple name.
4233 * pAuthnLevel [O] Optional. The authentication level.
4234 * pImpLevel [O] Optional. The impersonation level.
4235 * pPrivs [O] Optional. Information about the privileges of the client.
4236 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4240 * Failure: HRESULT code.
4243 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4245 HRESULT WINAPI
CoQueryClientBlanket(
4248 OLECHAR
**pServerPrincName
,
4251 RPC_AUTHZ_HANDLE
*pPrivs
,
4252 DWORD
*pCapabilities
)
4254 IServerSecurity
*pSrvSec
;
4257 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4258 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4259 pPrivs
, pCapabilities
);
4261 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4264 hr
= IServerSecurity_QueryBlanket(
4265 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4266 pImpLevel
, pPrivs
, pCapabilities
);
4267 IServerSecurity_Release(pSrvSec
);
4273 /***********************************************************************
4274 * CoImpersonateClient [OLE32.@]
4276 * Impersonates the client of the currently executing server call in the
4284 * Failure: HRESULT code.
4287 * If this function fails then the current thread will not be impersonating
4288 * the client and all actions will take place on behalf of the server.
4289 * Therefore, it is important to check the return value from this function.
4292 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4294 HRESULT WINAPI
CoImpersonateClient(void)
4296 IServerSecurity
*pSrvSec
;
4301 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4304 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4305 IServerSecurity_Release(pSrvSec
);
4311 /***********************************************************************
4312 * CoRevertToSelf [OLE32.@]
4314 * Ends the impersonation of the client of the currently executing server
4315 * call in the current thread.
4322 * Failure: HRESULT code.
4325 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4327 HRESULT WINAPI
CoRevertToSelf(void)
4329 IServerSecurity
*pSrvSec
;
4334 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4337 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4338 IServerSecurity_Release(pSrvSec
);
4344 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4346 /* first try to retrieve messages for incoming COM calls to the apartment window */
4347 return PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
) ||
4348 /* next retrieve other messages necessary for the app to remain responsive */
4349 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4350 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4353 /***********************************************************************
4354 * CoWaitForMultipleHandles [OLE32.@]
4356 * Waits for one or more handles to become signaled.
4359 * dwFlags [I] Flags. See notes.
4360 * dwTimeout [I] Timeout in milliseconds.
4361 * cHandles [I] Number of handles pointed to by pHandles.
4362 * pHandles [I] Handles to wait for.
4363 * lpdwindex [O] Index of handle that was signaled.
4367 * Failure: RPC_S_CALLPENDING on timeout.
4371 * The dwFlags parameter can be zero or more of the following:
4372 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4373 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4376 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4378 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4379 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4382 DWORD start_time
= GetTickCount();
4383 APARTMENT
*apt
= COM_CurrentApt();
4384 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4386 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4387 pHandles
, lpdwindex
);
4391 DWORD now
= GetTickCount();
4394 if (now
- start_time
> dwTimeout
)
4396 hr
= RPC_S_CALLPENDING
;
4402 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4403 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4405 TRACE("waiting for rpc completion or window message\n");
4407 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4408 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4409 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4411 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4416 /* call message filter */
4418 if (COM_CurrentApt()->filter
)
4420 PENDINGTYPE pendingtype
=
4421 COM_CurrentInfo()->pending_call_count_server
?
4422 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4423 DWORD be_handled
= IMessageFilter_MessagePending(
4424 COM_CurrentApt()->filter
, 0 /* FIXME */,
4425 now
- start_time
, pendingtype
);
4426 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4429 case PENDINGMSG_CANCELCALL
:
4430 WARN("call canceled\n");
4431 hr
= RPC_E_CALL_CANCELED
;
4433 case PENDINGMSG_WAITNOPROCESS
:
4434 case PENDINGMSG_WAITDEFPROCESS
:
4436 /* FIXME: MSDN is very vague about the difference
4437 * between WAITNOPROCESS and WAITDEFPROCESS - there
4438 * appears to be none, so it is possibly a left-over
4439 * from the 16-bit world. */
4444 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4445 * so after processing 100 messages we go back to checking the wait handles */
4446 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4448 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4449 TranslateMessage(&msg
);
4450 DispatchMessageW(&msg
);
4451 if (msg
.message
== WM_QUIT
)
4453 TRACE("resending WM_QUIT to outer message loop\n");
4454 PostQuitMessage(msg
.wParam
);
4455 /* no longer need to process messages */
4456 message_loop
= FALSE
;
4465 TRACE("waiting for rpc completion\n");
4467 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4468 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4469 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4475 hr
= RPC_S_CALLPENDING
;
4478 hr
= HRESULT_FROM_WIN32( GetLastError() );
4486 TRACE("-- 0x%08x\n", hr
);
4491 /***********************************************************************
4492 * CoGetObject [OLE32.@]
4494 * Gets the object named by converting the name to a moniker and binding to it.
4497 * pszName [I] String representing the object.
4498 * pBindOptions [I] Parameters affecting the binding to the named object.
4499 * riid [I] Interface to bind to on the objecct.
4500 * ppv [O] On output, the interface riid of the object represented
4505 * Failure: HRESULT code.
4508 * MkParseDisplayName.
4510 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4511 REFIID riid
, void **ppv
)
4518 hr
= CreateBindCtx(0, &pbc
);
4522 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4529 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4532 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4533 IMoniker_Release(pmk
);
4537 IBindCtx_Release(pbc
);
4542 /***********************************************************************
4543 * CoRegisterChannelHook [OLE32.@]
4545 * Registers a process-wide hook that is called during ORPC calls.
4548 * guidExtension [I] GUID of the channel hook to register.
4549 * pChannelHook [I] Channel hook object to register.
4553 * Failure: HRESULT code.
4555 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4557 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4559 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4562 typedef struct Context
4564 IComThreadingInfo IComThreadingInfo_iface
;
4565 IContextCallback IContextCallback_iface
;
4566 IObjContext IObjContext_iface
;
4571 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4573 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4576 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4578 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4581 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4583 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4586 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4590 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4591 IsEqualIID(riid
, &IID_IUnknown
))
4593 *ppv
= &iface
->IComThreadingInfo_iface
;
4595 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4597 *ppv
= &iface
->IContextCallback_iface
;
4599 else if (IsEqualIID(riid
, &IID_IObjContext
))
4601 *ppv
= &iface
->IObjContext_iface
;
4606 IUnknown_AddRef((IUnknown
*)*ppv
);
4610 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4611 return E_NOINTERFACE
;
4614 static ULONG
Context_AddRef(Context
*This
)
4616 return InterlockedIncrement(&This
->refs
);
4619 static ULONG
Context_Release(Context
*This
)
4621 ULONG refs
= InterlockedDecrement(&This
->refs
);
4623 HeapFree(GetProcessHeap(), 0, This
);
4627 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4629 Context
*This
= impl_from_IComThreadingInfo(iface
);
4630 return Context_QueryInterface(This
, riid
, ppv
);
4633 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4635 Context
*This
= impl_from_IComThreadingInfo(iface
);
4636 return Context_AddRef(This
);
4639 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4641 Context
*This
= impl_from_IComThreadingInfo(iface
);
4642 return Context_Release(This
);
4645 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4647 Context
*This
= impl_from_IComThreadingInfo(iface
);
4649 TRACE("(%p)\n", apttype
);
4651 *apttype
= This
->apttype
;
4655 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4657 Context
*This
= impl_from_IComThreadingInfo(iface
);
4659 TRACE("(%p)\n", thdtype
);
4661 switch (This
->apttype
)
4664 case APTTYPE_MAINSTA
:
4665 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4668 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4674 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4676 FIXME("(%p): stub\n", logical_thread_id
);
4680 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4682 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4686 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4688 Context_CTI_QueryInterface
,
4690 Context_CTI_Release
,
4691 Context_CTI_GetCurrentApartmentType
,
4692 Context_CTI_GetCurrentThreadType
,
4693 Context_CTI_GetCurrentLogicalThreadId
,
4694 Context_CTI_SetCurrentLogicalThreadId
4697 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4699 Context
*This
= impl_from_IContextCallback(iface
);
4700 return Context_QueryInterface(This
, riid
, ppv
);
4703 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4705 Context
*This
= impl_from_IContextCallback(iface
);
4706 return Context_AddRef(This
);
4709 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4711 Context
*This
= impl_from_IContextCallback(iface
);
4712 return Context_Release(This
);
4715 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4716 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4718 Context
*This
= impl_from_IContextCallback(iface
);
4720 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4724 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4726 Context_CC_QueryInterface
,
4729 Context_CC_ContextCallback
4732 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4734 Context
*This
= impl_from_IObjContext(iface
);
4735 return Context_QueryInterface(This
, riid
, ppv
);
4738 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4740 Context
*This
= impl_from_IObjContext(iface
);
4741 return Context_AddRef(This
);
4744 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4746 Context
*This
= impl_from_IObjContext(iface
);
4747 return Context_Release(This
);
4750 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4752 Context
*This
= impl_from_IObjContext(iface
);
4754 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4758 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4760 Context
*This
= impl_from_IObjContext(iface
);
4762 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4766 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4768 Context
*This
= impl_from_IObjContext(iface
);
4770 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4774 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4776 Context
*This
= impl_from_IObjContext(iface
);
4778 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4782 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4784 Context
*This
= impl_from_IObjContext(iface
);
4785 FIXME("(%p/%p)\n", This
, iface
);
4788 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4790 Context
*This
= impl_from_IObjContext(iface
);
4791 FIXME("(%p/%p)\n", This
, iface
);
4794 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4796 Context
*This
= impl_from_IObjContext(iface
);
4797 FIXME("(%p/%p)\n", This
, iface
);
4800 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4802 Context
*This
= impl_from_IObjContext(iface
);
4803 FIXME("(%p/%p)\n", This
, iface
);
4806 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4808 Context
*This
= impl_from_IObjContext(iface
);
4809 FIXME("(%p/%p)\n", This
, iface
);
4812 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4814 Context
*This
= impl_from_IObjContext(iface
);
4815 FIXME("(%p/%p)\n", This
, iface
);
4818 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4820 Context
*This
= impl_from_IObjContext(iface
);
4821 FIXME("(%p/%p)\n", This
, iface
);
4824 static const IObjContextVtbl Context_Object_Vtbl
=
4826 Context_OC_QueryInterface
,
4829 Context_OC_SetProperty
,
4830 Context_OC_RemoveProperty
,
4831 Context_OC_GetProperty
,
4832 Context_OC_EnumContextProps
,
4833 Context_OC_Reserved1
,
4834 Context_OC_Reserved2
,
4835 Context_OC_Reserved3
,
4836 Context_OC_Reserved4
,
4837 Context_OC_Reserved5
,
4838 Context_OC_Reserved6
,
4839 Context_OC_Reserved7
4842 /***********************************************************************
4843 * CoGetObjectContext [OLE32.@]
4845 * Retrieves an object associated with the current context (i.e. apartment).
4848 * riid [I] ID of the interface of the object to retrieve.
4849 * ppv [O] Address where object will be stored on return.
4853 * Failure: HRESULT code.
4855 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4857 APARTMENT
*apt
= COM_CurrentApt();
4861 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4866 if (!(apt
= apartment_find_multi_threaded()))
4868 ERR("apartment not initialised\n");
4869 return CO_E_NOTINITIALIZED
;
4871 apartment_release(apt
);
4874 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4876 return E_OUTOFMEMORY
;
4878 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4879 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4880 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4882 if (apt
->multi_threaded
)
4883 context
->apttype
= APTTYPE_MTA
;
4885 context
->apttype
= APTTYPE_MAINSTA
;
4887 context
->apttype
= APTTYPE_STA
;
4889 hr
= IUnknown_QueryInterface((IUnknown
*)&context
->IComThreadingInfo_iface
, riid
, ppv
);
4890 IUnknown_Release((IUnknown
*)&context
->IComThreadingInfo_iface
);
4896 /***********************************************************************
4897 * CoGetContextToken [OLE32.@]
4899 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4901 struct oletls
*info
= COM_CurrentInfo();
4903 TRACE("(%p)\n", token
);
4906 return E_OUTOFMEMORY
;
4911 if (!(apt
= apartment_find_multi_threaded()))
4913 ERR("apartment not initialised\n");
4914 return CO_E_NOTINITIALIZED
;
4916 apartment_release(apt
);
4922 if (!info
->context_token
)
4927 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4928 if (FAILED(hr
)) return hr
;
4929 info
->context_token
= ctx
;
4932 *token
= (ULONG_PTR
)info
->context_token
;
4933 TRACE("apt->context_token=%p\n", info
->context_token
);
4938 /***********************************************************************
4939 * CoGetDefaultContext [OLE32.@]
4941 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4943 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4944 return E_NOINTERFACE
;
4947 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4949 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4953 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4954 if (SUCCEEDED(hres
))
4956 struct class_reg_data regdata
;
4957 WCHAR dllpath
[MAX_PATH
+1];
4959 regdata
.u
.hkey
= hkey
;
4960 regdata
.hkey
= TRUE
;
4962 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4964 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4965 if (!strcmpiW(dllpath
, wszOle32
))
4968 return HandlerCF_Create(rclsid
, riid
, ppv
);
4972 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
4976 return CLASS_E_CLASSNOTAVAILABLE
;
4979 /***********************************************************************
4982 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
4984 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
4987 case DLL_PROCESS_ATTACH
:
4988 hProxyDll
= hinstDLL
;
4989 COMPOBJ_InitProcess();
4992 case DLL_PROCESS_DETACH
:
4993 if (reserved
) break;
4995 COMPOBJ_UninitProcess();
4996 RPC_UnregisterAllChannelHooks();
4997 COMPOBJ_DllList_Free();
4998 DeleteCriticalSection(&csRegisteredClassList
);
4999 DeleteCriticalSection(&csApartment
);
5002 case DLL_THREAD_DETACH
:
5009 /***********************************************************************
5010 * DllRegisterServer (OLE32.@)
5012 HRESULT WINAPI
DllRegisterServer(void)
5014 return OLE32_DllRegisterServer();
5017 /***********************************************************************
5018 * DllUnregisterServer (OLE32.@)
5020 HRESULT WINAPI
DllUnregisterServer(void)
5022 return OLE32_DllUnregisterServer();