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
);
47 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
49 /****************************************************************************
50 * This section defines variables internal to the COM module.
53 static APARTMENT
*MTA
; /* protected by csApartment */
54 static APARTMENT
*MainApartment
; /* the first STA apartment */
55 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
57 static CRITICAL_SECTION csApartment
;
58 static CRITICAL_SECTION_DEBUG critsect_debug
=
61 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
62 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
64 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
66 enum comclass_threadingmodel
68 ThreadingModel_Apartment
= 1,
69 ThreadingModel_Free
= 2,
70 ThreadingModel_No
= 3,
71 ThreadingModel_Both
= 4,
72 ThreadingModel_Neutral
= 5
75 enum comclass_miscfields
79 MiscStatusContent
= 4,
80 MiscStatusThumbnail
= 8,
81 MiscStatusDocPrint
= 16
84 struct comclassredirect_data
100 ULONG clrdata_offset
;
102 DWORD miscstatuscontent
;
103 DWORD miscstatusthumbnail
;
104 DWORD miscstatusicon
;
105 DWORD miscstatusdocprint
;
108 struct ifacepsredirect_data
120 struct progidredirect_data
127 struct class_reg_data
133 struct comclassredirect_data
*data
;
142 struct registered_psclsid
150 * This is a marshallable object exposing registered local servers.
151 * IServiceProvider is used only because it happens meet requirements
152 * and already has proxy/stub code. If more functionality is needed,
153 * a custom interface may be used instead.
157 IServiceProvider IServiceProvider_iface
;
160 IStream
*marshal_stream
;
164 * This lock count counts the number of times CoInitialize is called. It is
165 * decreased every time CoUninitialize is called. When it hits 0, the COM
166 * libraries are freed
168 static LONG s_COMLockCount
= 0;
169 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
170 static LONG s_COMServerProcessReferences
= 0;
173 * This linked list contains the list of registered class objects. These
174 * are mostly used to register the factories for out-of-proc servers of OLE
177 * TODO: Make this data structure aware of inter-process communication. This
178 * means that parts of this will be exported to rpcss.
180 typedef struct tagRegisteredClass
183 CLSID classIdentifier
;
185 LPUNKNOWN classObject
;
189 void *RpcRegistration
;
192 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
194 static CRITICAL_SECTION csRegisteredClassList
;
195 static CRITICAL_SECTION_DEBUG class_cs_debug
=
197 0, 0, &csRegisteredClassList
,
198 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
199 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
201 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
203 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
207 case DVASPECT_CONTENT
:
208 return MiscStatusContent
;
209 case DVASPECT_THUMBNAIL
:
210 return MiscStatusThumbnail
;
212 return MiscStatusIcon
;
213 case DVASPECT_DOCPRINT
:
214 return MiscStatusDocPrint
;
220 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
222 ACTCTX_SECTION_KEYED_DATA data
;
224 data
.cbSize
= sizeof(data
);
225 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
228 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
229 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
231 if (!(comclass
->miscmask
& misc
))
233 if (!(comclass
->miscmask
& MiscStatus
))
244 *status
= comclass
->miscstatus
;
247 *status
= comclass
->miscstatusicon
;
249 case MiscStatusContent
:
250 *status
= comclass
->miscstatuscontent
;
252 case MiscStatusThumbnail
:
253 *status
= comclass
->miscstatusthumbnail
;
255 case MiscStatusDocPrint
:
256 *status
= comclass
->miscstatusdocprint
;
268 /* wrapper for NtCreateKey that creates the key recursively if necessary */
269 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
271 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
273 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
275 HANDLE subkey
, root
= attr
->RootDirectory
;
276 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
277 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
280 while (i
< len
&& buffer
[i
] != '\\') i
++;
281 if (i
== len
) return status
;
283 attrs
= attr
->Attributes
;
284 attr
->ObjectName
= &str
;
288 str
.Buffer
= buffer
+ pos
;
289 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
290 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
291 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
292 if (status
) return status
;
293 attr
->RootDirectory
= subkey
;
294 while (i
< len
&& buffer
[i
] == '\\') i
++;
296 while (i
< len
&& buffer
[i
] != '\\') i
++;
298 str
.Buffer
= buffer
+ pos
;
299 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
300 attr
->Attributes
= attrs
;
301 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
302 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
308 static const WCHAR classes_rootW
[] = L
"\\REGISTRY\\Machine\\Software\\Classes";
310 static const WCHAR classes_rootW
[] =
311 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
312 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
315 static HKEY classes_root_hkey
;
317 /* create the special HKEY_CLASSES_ROOT key */
318 static HKEY
create_classes_root_hkey(DWORD access
)
321 OBJECT_ATTRIBUTES attr
;
324 attr
.Length
= sizeof(attr
);
325 attr
.RootDirectory
= 0;
326 attr
.ObjectName
= &name
;
328 attr
.SecurityDescriptor
= NULL
;
329 attr
.SecurityQualityOfService
= NULL
;
330 RtlInitUnicodeString( &name
, classes_rootW
);
331 if (create_key( &hkey
, access
, &attr
)) return 0;
332 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
334 if (!(access
& KEY_WOW64_64KEY
))
336 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
339 NtClose( hkey
); /* somebody beat us to it */
346 /* map the hkey from special root to normal key if necessary */
347 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
350 const BOOL is_win64
= sizeof(void*) > sizeof(int);
351 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
353 if (hkey
== HKEY_CLASSES_ROOT
&&
354 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
355 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
356 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
358 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
359 access
&= ~KEY_WOW64_32KEY
;
360 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
368 LSTATUS
create_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
, access
))) 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( create_key( retkey
, access
, &attr
) );
386 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
388 OBJECT_ATTRIBUTES attr
;
389 UNICODE_STRING nameW
;
391 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
393 attr
.Length
= sizeof(attr
);
394 attr
.RootDirectory
= hkey
;
395 attr
.ObjectName
= &nameW
;
397 attr
.SecurityDescriptor
= NULL
;
398 attr
.SecurityQualityOfService
= NULL
;
399 RtlInitUnicodeString( &nameW
, name
);
401 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
404 /*****************************************************************************
405 * This section contains OpenDllList definitions
407 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
408 * other functions that do LoadLibrary _without_ giving back a HMODULE.
409 * Without this list these handles would never be freed.
411 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
412 * next unload-call but not before 600 sec.
415 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
416 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
418 typedef struct tagOpenDll
423 DllGetClassObjectFunc DllGetClassObject
;
424 DllCanUnloadNowFunc DllCanUnloadNow
;
428 static struct list openDllList
= LIST_INIT(openDllList
);
430 static CRITICAL_SECTION csOpenDllList
;
431 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
433 0, 0, &csOpenDllList
,
434 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
435 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
437 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
439 struct apartment_loaded_dll
447 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',0};
449 /*****************************************************************************
450 * This section contains OpenDllList implementation
453 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
457 EnterCriticalSection(&csOpenDllList
);
458 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
460 if (!strcmpiW(library_name
, ptr
->library_name
) &&
461 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
467 LeaveCriticalSection(&csOpenDllList
);
471 /* caller must ensure that library_name is not already in the open dll list */
472 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
478 DllCanUnloadNowFunc DllCanUnloadNow
;
479 DllGetClassObjectFunc DllGetClassObject
;
481 TRACE("%s\n", debugstr_w(library_name
));
483 *ret
= COMPOBJ_DllList_Get(library_name
);
484 if (*ret
) return S_OK
;
486 /* do this outside the csOpenDllList to avoid creating a lock dependency on
488 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
491 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
492 /* failure: DLL could not be loaded */
493 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
496 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
497 /* Note: failing to find DllCanUnloadNow is not a failure */
498 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
499 if (!DllGetClassObject
)
501 /* failure: the dll did not export DllGetClassObject */
502 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
503 FreeLibrary(hLibrary
);
504 return CO_E_DLLNOTFOUND
;
507 EnterCriticalSection( &csOpenDllList
);
509 *ret
= COMPOBJ_DllList_Get(library_name
);
512 /* another caller to this function already added the dll while we
513 * weren't in the critical section */
514 FreeLibrary(hLibrary
);
518 len
= strlenW(library_name
);
519 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
521 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
522 if (entry
&& entry
->library_name
)
524 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
525 entry
->library
= hLibrary
;
527 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
528 entry
->DllGetClassObject
= DllGetClassObject
;
529 list_add_tail(&openDllList
, &entry
->entry
);
534 HeapFree(GetProcessHeap(), 0, entry
);
536 FreeLibrary(hLibrary
);
540 LeaveCriticalSection( &csOpenDllList
);
545 /* pass FALSE for free_entry to release a reference without destroying the
546 * entry if it reaches zero or TRUE otherwise */
547 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
549 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
551 EnterCriticalSection(&csOpenDllList
);
552 list_remove(&entry
->entry
);
553 LeaveCriticalSection(&csOpenDllList
);
555 TRACE("freeing %p\n", entry
->library
);
556 FreeLibrary(entry
->library
);
558 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
559 HeapFree(GetProcessHeap(), 0, entry
);
563 /* frees memory associated with active dll list */
564 static void COMPOBJ_DllList_Free(void)
566 OpenDll
*entry
, *cursor2
;
567 EnterCriticalSection(&csOpenDllList
);
568 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
570 list_remove(&entry
->entry
);
572 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
573 HeapFree(GetProcessHeap(), 0, entry
);
575 LeaveCriticalSection(&csOpenDllList
);
576 DeleteCriticalSection(&csOpenDllList
);
579 /******************************************************************************
583 static DWORD
apartment_addref(struct apartment
*apt
)
585 DWORD refs
= InterlockedIncrement(&apt
->refs
);
586 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
590 /* allocates memory and fills in the necessary fields for a new apartment
591 * object. must be called inside apartment cs */
592 static APARTMENT
*apartment_construct(DWORD model
)
596 TRACE("creating new apartment, model=%d\n", model
);
598 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
599 apt
->tid
= GetCurrentThreadId();
601 list_init(&apt
->proxies
);
602 list_init(&apt
->stubmgrs
);
603 list_init(&apt
->psclsids
);
604 list_init(&apt
->loaded_dlls
);
607 apt
->remunk_exported
= FALSE
;
609 InitializeCriticalSection(&apt
->cs
);
610 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
612 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
614 if (apt
->multi_threaded
)
616 /* FIXME: should be randomly generated by in an RPC call to rpcss */
617 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
621 /* FIXME: should be randomly generated by in an RPC call to rpcss */
622 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
625 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
627 list_add_head(&apts
, &apt
->entry
);
632 /* gets and existing apartment if one exists or otherwise creates an apartment
633 * structure which stores OLE apartment-local information and stores a pointer
634 * to it in the thread-local storage */
635 static APARTMENT
*apartment_get_or_create(DWORD model
)
637 APARTMENT
*apt
= COM_CurrentApt();
641 if (model
& COINIT_APARTMENTTHREADED
)
643 EnterCriticalSection(&csApartment
);
645 apt
= apartment_construct(model
);
650 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
653 LeaveCriticalSection(&csApartment
);
656 apartment_createwindowifneeded(apt
);
660 EnterCriticalSection(&csApartment
);
662 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
663 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
667 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
668 apartment_addref(MTA
);
671 MTA
= apartment_construct(model
);
675 LeaveCriticalSection(&csApartment
);
677 COM_CurrentInfo()->apt
= apt
;
683 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
685 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
688 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
690 list_remove(&curClass
->entry
);
692 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
693 RPC_StopLocalServer(curClass
->RpcRegistration
);
695 IUnknown_Release(curClass
->classObject
);
696 HeapFree(GetProcessHeap(), 0, curClass
);
699 static void COM_RevokeAllClasses(const struct apartment
*apt
)
701 RegisteredClass
*curClass
, *cursor
;
703 EnterCriticalSection( &csRegisteredClassList
);
705 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
707 if (curClass
->apartment_id
== apt
->oxid
)
708 COM_RevokeRegisteredClassObject(curClass
);
711 LeaveCriticalSection( &csRegisteredClassList
);
714 /******************************************************************************
715 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
718 typedef struct ManualResetEvent
{
719 ISynchronize ISynchronize_iface
;
720 ISynchronizeHandle ISynchronizeHandle_iface
;
725 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
727 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
730 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
732 MREImpl
*This
= impl_from_ISynchronize(iface
);
734 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
736 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
737 *ppv
= &This
->ISynchronize_iface
;
738 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
739 *ppv
= &This
->ISynchronizeHandle_iface
;
741 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
743 return E_NOINTERFACE
;
746 IUnknown_AddRef((IUnknown
*)*ppv
);
750 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
752 MREImpl
*This
= impl_from_ISynchronize(iface
);
753 LONG ref
= InterlockedIncrement(&This
->ref
);
754 TRACE("%p - ref %d\n", This
, ref
);
759 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
761 MREImpl
*This
= impl_from_ISynchronize(iface
);
762 LONG ref
= InterlockedDecrement(&This
->ref
);
763 TRACE("%p - ref %d\n", This
, ref
);
767 CloseHandle(This
->event
);
768 HeapFree(GetProcessHeap(), 0, This
);
774 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
776 MREImpl
*This
= impl_from_ISynchronize(iface
);
778 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
779 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
782 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
784 MREImpl
*This
= impl_from_ISynchronize(iface
);
786 SetEvent(This
->event
);
790 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
792 MREImpl
*This
= impl_from_ISynchronize(iface
);
794 ResetEvent(This
->event
);
798 static ISynchronizeVtbl vt_ISynchronize
= {
799 ISynchronize_fnQueryInterface
,
800 ISynchronize_fnAddRef
,
801 ISynchronize_fnRelease
,
803 ISynchronize_fnSignal
,
807 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
809 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
812 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
814 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
815 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
818 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
820 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
821 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
824 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
826 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
827 return ISynchronize_Release(&This
->ISynchronize_iface
);
830 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
832 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
838 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
839 SynchronizeHandle_QueryInterface
,
840 SynchronizeHandle_AddRef
,
841 SynchronizeHandle_Release
,
842 SynchronizeHandle_GetHandle
845 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
847 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
851 FIXME("Aggregation not implemented.\n");
854 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
855 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
856 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
858 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
859 ISynchronize_Release(&This
->ISynchronize_iface
);
863 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
865 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
868 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
870 LocalServer
*This
= impl_from_IServiceProvider(iface
);
872 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
874 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
875 *ppv
= &This
->IServiceProvider_iface
;
878 return E_NOINTERFACE
;
881 IUnknown_AddRef((IUnknown
*)*ppv
);
885 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
887 LocalServer
*This
= impl_from_IServiceProvider(iface
);
888 LONG ref
= InterlockedIncrement(&This
->ref
);
890 TRACE("(%p) ref=%d\n", This
, ref
);
895 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
897 LocalServer
*This
= impl_from_IServiceProvider(iface
);
898 LONG ref
= InterlockedDecrement(&This
->ref
);
900 TRACE("(%p) ref=%d\n", This
, ref
);
904 HeapFree(GetProcessHeap(), 0, This
);
910 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
912 LocalServer
*This
= impl_from_IServiceProvider(iface
);
913 APARTMENT
*apt
= COM_CurrentApt();
914 RegisteredClass
*iter
;
915 HRESULT hres
= E_FAIL
;
917 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
922 EnterCriticalSection(&csRegisteredClassList
);
924 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
925 if(iter
->apartment_id
== apt
->oxid
926 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
927 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
928 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
933 LeaveCriticalSection( &csRegisteredClassList
);
938 static const IServiceProviderVtbl LocalServerVtbl
= {
939 LocalServer_QueryInterface
,
942 LocalServer_QueryService
945 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
949 EnterCriticalSection(&apt
->cs
);
951 if(!apt
->local_server
) {
954 obj
= heap_alloc(sizeof(*obj
));
956 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
960 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
961 if(SUCCEEDED(hres
)) {
962 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
963 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
965 IStream_Release(obj
->marshal_stream
);
969 apt
->local_server
= obj
;
973 hres
= E_OUTOFMEMORY
;
978 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
980 LeaveCriticalSection(&apt
->cs
);
983 ERR("Failed: %08x\n", hres
);
987 /***********************************************************************
988 * CoRevokeClassObject [OLE32.@]
990 * Removes a class object from the class registry.
993 * dwRegister [I] Cookie returned from CoRegisterClassObject().
997 * Failure: HRESULT code.
1000 * Must be called from the same apartment that called CoRegisterClassObject(),
1001 * otherwise it will fail with RPC_E_WRONG_THREAD.
1004 * CoRegisterClassObject
1006 HRESULT WINAPI DECLSPEC_HOTPATCH
CoRevokeClassObject(
1009 HRESULT hr
= E_INVALIDARG
;
1010 RegisteredClass
*curClass
;
1013 TRACE("(%08x)\n",dwRegister
);
1015 apt
= COM_CurrentApt();
1018 ERR("COM was not initialized\n");
1019 return CO_E_NOTINITIALIZED
;
1022 EnterCriticalSection( &csRegisteredClassList
);
1024 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1027 * Check if we have a match on the cookie.
1029 if (curClass
->dwCookie
== dwRegister
)
1031 if (curClass
->apartment_id
== apt
->oxid
)
1033 COM_RevokeRegisteredClassObject(curClass
);
1038 ERR("called from wrong apartment, should be called from %s\n",
1039 wine_dbgstr_longlong(curClass
->apartment_id
));
1040 hr
= RPC_E_WRONG_THREAD
;
1046 LeaveCriticalSection( &csRegisteredClassList
);
1051 /* frees unused libraries loaded by apartment_getclassobject by calling the
1052 * DLL's DllCanUnloadNow entry point */
1053 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1055 struct apartment_loaded_dll
*entry
, *next
;
1056 EnterCriticalSection(&apt
->cs
);
1057 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1059 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1061 DWORD real_delay
= delay
;
1063 if (real_delay
== INFINITE
)
1065 /* DLLs that return multi-threaded objects aren't unloaded
1066 * straight away to cope for programs that have races between
1067 * last object destruction and threads in the DLLs that haven't
1068 * finished, despite DllCanUnloadNow returning S_OK */
1069 if (entry
->multi_threaded
)
1070 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1075 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1077 list_remove(&entry
->entry
);
1078 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1079 HeapFree(GetProcessHeap(), 0, entry
);
1083 entry
->unload_time
= GetTickCount() + real_delay
;
1084 if (!entry
->unload_time
) entry
->unload_time
= 1;
1087 else if (entry
->unload_time
)
1088 entry
->unload_time
= 0;
1090 LeaveCriticalSection(&apt
->cs
);
1093 DWORD
apartment_release(struct apartment
*apt
)
1097 EnterCriticalSection(&csApartment
);
1099 ret
= InterlockedDecrement(&apt
->refs
);
1100 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1101 /* destruction stuff that needs to happen under csApartment CS */
1104 if (apt
== MTA
) MTA
= NULL
;
1105 else if (apt
== MainApartment
) MainApartment
= NULL
;
1106 list_remove(&apt
->entry
);
1109 LeaveCriticalSection(&csApartment
);
1113 struct list
*cursor
, *cursor2
;
1115 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1117 if(apt
->local_server
) {
1118 LocalServer
*local_server
= apt
->local_server
;
1121 memset(&zero
, 0, sizeof(zero
));
1122 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1123 CoReleaseMarshalData(local_server
->marshal_stream
);
1124 IStream_Release(local_server
->marshal_stream
);
1125 local_server
->marshal_stream
= NULL
;
1127 apt
->local_server
= NULL
;
1128 local_server
->apt
= NULL
;
1129 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1132 /* Release the references to the registered class objects */
1133 COM_RevokeAllClasses(apt
);
1135 /* no locking is needed for this apartment, because no other thread
1136 * can access it at this point */
1138 apartment_disconnectproxies(apt
);
1140 if (apt
->win
) DestroyWindow(apt
->win
);
1141 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1143 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1145 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1146 /* release the implicit reference given by the fact that the
1147 * stub has external references (it must do since it is in the
1148 * stub manager list in the apartment and all non-apartment users
1149 * must have a ref on the apartment and so it cannot be destroyed).
1151 stub_manager_int_release(stubmgr
);
1154 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->psclsids
)
1156 struct registered_psclsid
*registered_psclsid
=
1157 LIST_ENTRY(cursor
, struct registered_psclsid
, entry
);
1159 list_remove(®istered_psclsid
->entry
);
1160 HeapFree(GetProcessHeap(), 0, registered_psclsid
);
1163 /* if this assert fires, then another thread took a reference to a
1164 * stub manager without taking a reference to the containing
1165 * apartment, which it must do. */
1166 assert(list_empty(&apt
->stubmgrs
));
1168 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1170 /* free as many unused libraries as possible... */
1171 apartment_freeunusedlibraries(apt
, 0);
1173 /* ... and free the memory for the apartment loaded dll entry and
1174 * release the dll list reference without freeing the library for the
1176 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1178 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1179 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1180 list_remove(cursor
);
1181 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1184 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1185 DeleteCriticalSection(&apt
->cs
);
1187 HeapFree(GetProcessHeap(), 0, apt
);
1193 /* The given OXID must be local to this process:
1195 * The ref parameter is here mostly to ensure people remember that
1196 * they get one, you should normally take a ref for thread safety.
1198 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1200 APARTMENT
*result
= NULL
;
1201 struct list
*cursor
;
1203 EnterCriticalSection(&csApartment
);
1204 LIST_FOR_EACH( cursor
, &apts
)
1206 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1207 if (apt
->oxid
== oxid
)
1210 if (ref
) apartment_addref(result
);
1214 LeaveCriticalSection(&csApartment
);
1219 /* gets the apartment which has a given creator thread ID. The caller must
1220 * release the reference from the apartment as soon as the apartment pointer
1221 * is no longer required. */
1222 APARTMENT
*apartment_findfromtid(DWORD tid
)
1224 APARTMENT
*result
= NULL
;
1225 struct list
*cursor
;
1227 EnterCriticalSection(&csApartment
);
1228 LIST_FOR_EACH( cursor
, &apts
)
1230 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1231 if (apt
->tid
== tid
)
1234 apartment_addref(result
);
1238 LeaveCriticalSection(&csApartment
);
1243 /* gets the main 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_findmain(void)
1250 EnterCriticalSection(&csApartment
);
1252 result
= MainApartment
;
1253 if (result
) apartment_addref(result
);
1255 LeaveCriticalSection(&csApartment
);
1260 /* gets the multi-threaded apartment if it exists. The caller must
1261 * release the reference from the apartment as soon as the apartment pointer
1262 * is no longer required. */
1263 static APARTMENT
*apartment_find_multi_threaded(void)
1265 APARTMENT
*result
= NULL
;
1266 struct list
*cursor
;
1268 EnterCriticalSection(&csApartment
);
1270 LIST_FOR_EACH( cursor
, &apts
)
1272 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1273 if (apt
->multi_threaded
)
1276 apartment_addref(result
);
1281 LeaveCriticalSection(&csApartment
);
1285 /* gets the specified class object by loading the appropriate DLL, if
1286 * necessary and calls the DllGetClassObject function for the DLL */
1287 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1288 BOOL apartment_threaded
,
1289 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1291 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1294 struct apartment_loaded_dll
*apartment_loaded_dll
;
1296 if (!strcmpiW(dllpath
, wszOle32
))
1298 /* we don't need to control the lifetime of this dll, so use the local
1299 * implementation of DllGetClassObject directly */
1300 TRACE("calling ole32!DllGetClassObject\n");
1301 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1304 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1309 EnterCriticalSection(&apt
->cs
);
1311 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1312 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1314 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1321 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1322 if (!apartment_loaded_dll
)
1326 apartment_loaded_dll
->unload_time
= 0;
1327 apartment_loaded_dll
->multi_threaded
= FALSE
;
1328 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1330 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1334 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1335 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1339 LeaveCriticalSection(&apt
->cs
);
1343 /* one component being multi-threaded overrides any number of
1344 * apartment-threaded components */
1345 if (!apartment_threaded
)
1346 apartment_loaded_dll
->multi_threaded
= TRUE
;
1348 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1349 /* OK: get the ClassObject */
1350 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1353 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1359 /***********************************************************************
1360 * COM_RegReadPath [internal]
1362 * Reads a registry value and expands it when necessary
1364 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1371 WCHAR src
[MAX_PATH
];
1372 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1374 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1375 if (keytype
== REG_EXPAND_SZ
) {
1376 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1378 const WCHAR
*quote_start
;
1379 quote_start
= strchrW(src
, '\"');
1381 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1383 memmove(src
, quote_start
+ 1,
1384 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1385 src
[quote_end
- quote_start
- 1] = '\0';
1388 lstrcpynW(dst
, src
, dstlen
);
1399 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1400 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1401 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1402 DeactivateActCtx(0, cookie
);
1407 struct host_object_params
1409 struct class_reg_data regdata
;
1410 CLSID clsid
; /* clsid of object to marshal */
1411 IID iid
; /* interface to marshal */
1412 HANDLE event
; /* event signalling when ready for multi-threaded case */
1413 HRESULT hr
; /* result for multi-threaded case */
1414 IStream
*stream
; /* stream that the object will be marshaled into */
1415 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1418 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1419 const struct host_object_params
*params
)
1423 static const LARGE_INTEGER llZero
;
1424 WCHAR dllpath
[MAX_PATH
+1];
1426 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1428 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1430 /* failure: CLSID is not found in registry */
1431 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1432 return REGDB_E_CLASSNOTREG
;
1435 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1436 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1440 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1442 IUnknown_Release(object
);
1443 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1448 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1453 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1456 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1458 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1462 struct host_thread_params
1464 COINIT threading_model
;
1466 HWND apartment_hwnd
;
1469 /* thread for hosting an object to allow an object to appear to be created in
1470 * an apartment with an incompatible threading model */
1471 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1473 struct host_thread_params
*params
= p
;
1476 struct apartment
*apt
;
1480 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1481 if (FAILED(hr
)) return hr
;
1483 apt
= COM_CurrentApt();
1484 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1486 apartment_createwindowifneeded(apt
);
1487 params
->apartment_hwnd
= apartment_getwindow(apt
);
1490 params
->apartment_hwnd
= NULL
;
1492 /* force the message queue to be created before signaling parent thread */
1493 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1495 SetEvent(params
->ready_event
);
1496 params
= NULL
; /* can't touch params after here as it may be invalid */
1498 while (GetMessageW(&msg
, NULL
, 0, 0))
1500 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1502 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1503 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1504 SetEvent(obj_params
->event
);
1508 TranslateMessage(&msg
);
1509 DispatchMessageW(&msg
);
1520 /* finds or creates a host apartment, creates the object inside it and returns
1521 * a proxy to it so that the object can be used in the apartment of the
1522 * caller of this function */
1523 static HRESULT
apartment_hostobject_in_hostapt(
1524 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1525 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1527 struct host_object_params params
;
1528 HWND apartment_hwnd
= NULL
;
1529 DWORD apartment_tid
= 0;
1532 if (!multi_threaded
&& main_apartment
)
1534 APARTMENT
*host_apt
= apartment_findmain();
1537 apartment_hwnd
= apartment_getwindow(host_apt
);
1538 apartment_release(host_apt
);
1542 if (!apartment_hwnd
)
1544 EnterCriticalSection(&apt
->cs
);
1546 if (!apt
->host_apt_tid
)
1548 struct host_thread_params thread_params
;
1552 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1553 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1554 thread_params
.apartment_hwnd
= NULL
;
1555 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1558 CloseHandle(handles
[0]);
1559 LeaveCriticalSection(&apt
->cs
);
1560 return E_OUTOFMEMORY
;
1562 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1563 CloseHandle(handles
[0]);
1564 CloseHandle(handles
[1]);
1565 if (wait_value
== WAIT_OBJECT_0
)
1566 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1569 LeaveCriticalSection(&apt
->cs
);
1570 return E_OUTOFMEMORY
;
1574 if (multi_threaded
|| !main_apartment
)
1576 apartment_hwnd
= apt
->host_apt_hwnd
;
1577 apartment_tid
= apt
->host_apt_tid
;
1580 LeaveCriticalSection(&apt
->cs
);
1583 /* another thread may have become the main apartment in the time it took
1584 * us to create the thread for the host apartment */
1585 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1587 APARTMENT
*host_apt
= apartment_findmain();
1590 apartment_hwnd
= apartment_getwindow(host_apt
);
1591 apartment_release(host_apt
);
1595 params
.regdata
= *regdata
;
1596 params
.clsid
= *rclsid
;
1598 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1601 params
.apartment_threaded
= !multi_threaded
;
1605 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1606 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1610 WaitForSingleObject(params
.event
, INFINITE
);
1613 CloseHandle(params
.event
);
1617 if (!apartment_hwnd
)
1619 ERR("host apartment didn't create window\n");
1623 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1626 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1627 IStream_Release(params
.stream
);
1631 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1635 /* Dispatching to the correct thread in an apartment is done through
1636 * window messages rather than RPC transports. When an interface is
1637 * marshalled into another apartment in the same process, a window of the
1638 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1639 * application) is responsible for pumping the message loop in that thread.
1640 * The WM_USER messages which point to the RPCs are then dispatched to
1641 * apartment_wndproc by the user's code from the apartment in which the
1642 * interface was unmarshalled.
1644 memset(&wclass
, 0, sizeof(wclass
));
1645 wclass
.lpfnWndProc
= apartment_wndproc
;
1646 wclass
.hInstance
= hProxyDll
;
1647 wclass
.lpszClassName
= wszAptWinClass
;
1648 RegisterClassW(&wclass
);
1652 /* create a window for the apartment or return the current one if one has
1653 * already been created */
1654 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1656 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1658 if (apt
->multi_threaded
)
1665 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1667 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1668 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1671 ERR("CreateWindow failed with error %d\n", GetLastError());
1672 return HRESULT_FROM_WIN32(GetLastError());
1674 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1675 /* someone beat us to it */
1676 DestroyWindow(hwnd
);
1682 /* retrieves the window for the main- or apartment-threaded apartment */
1683 HWND
apartment_getwindow(const struct apartment
*apt
)
1685 assert(!apt
->multi_threaded
);
1689 void apartment_joinmta(void)
1691 apartment_addref(MTA
);
1692 COM_CurrentInfo()->apt
= MTA
;
1695 static void COM_TlsDestroy(void)
1697 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1700 if (info
->apt
) apartment_release(info
->apt
);
1701 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1702 if (info
->state
) IUnknown_Release(info
->state
);
1703 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1704 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1705 HeapFree(GetProcessHeap(), 0, info
);
1706 NtCurrentTeb()->ReservedForOle
= NULL
;
1710 /******************************************************************************
1711 * CoBuildVersion [OLE32.@]
1713 * Gets the build version of the DLL.
1718 * Current build version, hiword is majornumber, loword is minornumber
1720 DWORD WINAPI
CoBuildVersion(void)
1722 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1723 return (rmm
<<16)+rup
;
1726 /******************************************************************************
1727 * CoRegisterInitializeSpy [OLE32.@]
1729 * Add a Spy that watches CoInitializeEx calls
1732 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1733 * cookie [II] cookie receiver
1736 * Success: S_OK if not already initialized, S_FALSE otherwise.
1737 * Failure: HRESULT code.
1742 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1744 struct oletls
*info
= COM_CurrentInfo();
1747 TRACE("(%p, %p)\n", spy
, cookie
);
1749 if (!spy
|| !cookie
|| !info
)
1752 WARN("Could not allocate tls\n");
1753 return E_INVALIDARG
;
1758 FIXME("Already registered?\n");
1759 return E_UNEXPECTED
;
1762 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1765 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1771 /******************************************************************************
1772 * CoRevokeInitializeSpy [OLE32.@]
1774 * Remove a spy that previously watched CoInitializeEx calls
1777 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1780 * Success: S_OK if a spy is removed
1781 * Failure: E_INVALIDARG
1786 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1788 struct oletls
*info
= COM_CurrentInfo();
1789 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1791 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1792 return E_INVALIDARG
;
1794 IInitializeSpy_Release(info
->spy
);
1800 /******************************************************************************
1801 * CoInitialize [OLE32.@]
1803 * Initializes the COM libraries by calling CoInitializeEx with
1804 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1807 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1810 * Success: S_OK if not already initialized, S_FALSE otherwise.
1811 * Failure: HRESULT code.
1816 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1819 * Just delegate to the newer method.
1821 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1824 /******************************************************************************
1825 * CoInitializeEx [OLE32.@]
1827 * Initializes the COM libraries.
1830 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1831 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1834 * S_OK if successful,
1835 * S_FALSE if this function was called already.
1836 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1841 * The behavior used to set the IMalloc used for memory management is
1843 * The dwCoInit parameter must specify one of the following apartment
1845 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1846 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1847 * The parameter may also specify zero or more of the following flags:
1848 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1849 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1854 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1856 struct oletls
*info
= COM_CurrentInfo();
1860 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1862 if (lpReserved
!=NULL
)
1864 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1868 * Check the lock count. If this is the first time going through the initialize
1869 * process, we have to initialize the libraries.
1871 * And crank-up that lock count.
1873 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1876 * Initialize the various COM libraries and data structures.
1878 TRACE("() - Initializing the COM libraries\n");
1880 /* we may need to defer this until after apartment initialisation */
1881 RunningObjectTableImpl_Initialize();
1885 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1887 if (!(apt
= info
->apt
))
1889 apt
= apartment_get_or_create(dwCoInit
);
1890 if (!apt
) return E_OUTOFMEMORY
;
1892 else if (!apartment_is_model(apt
, dwCoInit
))
1894 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1895 code then we are probably using the wrong threading model to implement that API. */
1896 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1897 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1898 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1899 return RPC_E_CHANGED_MODE
;
1907 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1912 /***********************************************************************
1913 * CoUninitialize [OLE32.@]
1915 * This method will decrement the refcount on the current apartment, freeing
1916 * the resources associated with it if it is the last thread in the apartment.
1917 * If the last apartment is freed, the function will additionally release
1918 * any COM resources associated with the process.
1928 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1930 struct oletls
* info
= COM_CurrentInfo();
1935 /* will only happen on OOM */
1939 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1944 ERR("Mismatched CoUninitialize\n");
1947 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1953 if (info
->ole_inits
)
1954 WARN("uninitializing apartment while Ole is still initialized\n");
1955 apartment_release(info
->apt
);
1960 * Decrease the reference count.
1961 * If we are back to 0 locks on the COM library, make sure we free
1962 * all the associated data structures.
1964 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
1967 TRACE("() - Releasing the COM libraries\n");
1969 RunningObjectTableImpl_UnInitialize();
1971 else if (lCOMRefCnt
<1) {
1972 ERR( "CoUninitialize() - not CoInitialized.\n" );
1973 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
1976 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1979 /******************************************************************************
1980 * CoDisconnectObject [OLE32.@]
1982 * Disconnects all connections to this object from remote processes. Dispatches
1983 * pending RPCs while blocking new RPCs from occurring, and then calls
1984 * IMarshal::DisconnectObject on the given object.
1986 * Typically called when the object server is forced to shut down, for instance by
1990 * lpUnk [I] The object whose stub should be disconnected.
1991 * reserved [I] Reserved. Should be set to 0.
1995 * Failure: HRESULT code.
1998 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2000 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2002 struct stub_manager
*manager
;
2007 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2009 if (!lpUnk
) return E_INVALIDARG
;
2011 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2014 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2015 IMarshal_Release(marshal
);
2019 apt
= COM_CurrentApt();
2021 return CO_E_NOTINITIALIZED
;
2023 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2025 stub_manager_disconnect(manager
);
2026 /* Release stub manager twice, to remove the apartment reference. */
2027 stub_manager_int_release(manager
);
2028 stub_manager_int_release(manager
);
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
)
2058 if(!pguid
) return E_INVALIDARG
;
2060 status
= UuidCreate(pguid
);
2061 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2062 return HRESULT_FROM_WIN32( status
);
2065 static inline BOOL
is_valid_hex(WCHAR c
)
2067 if (!(((c
>= '0') && (c
<= '9')) ||
2068 ((c
>= 'a') && (c
<= 'f')) ||
2069 ((c
>= 'A') && (c
<= 'F'))))
2074 static const BYTE guid_conv_table
[256] =
2076 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2077 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2078 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2079 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2080 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2081 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2082 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2085 /* conversion helper for CLSIDFromString/IIDFromString */
2086 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2090 if (!s
|| s
[0]!='{') {
2091 memset( id
, 0, sizeof (CLSID
) );
2096 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2098 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2101 for (i
= 1; i
< 9; i
++) {
2102 if (!is_valid_hex(s
[i
])) return FALSE
;
2103 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2105 if (s
[9]!='-') return FALSE
;
2108 for (i
= 10; i
< 14; i
++) {
2109 if (!is_valid_hex(s
[i
])) return FALSE
;
2110 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2112 if (s
[14]!='-') return FALSE
;
2115 for (i
= 15; i
< 19; i
++) {
2116 if (!is_valid_hex(s
[i
])) return FALSE
;
2117 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2119 if (s
[19]!='-') return FALSE
;
2121 for (i
= 20; i
< 37; i
+=2) {
2123 if (s
[i
]!='-') return FALSE
;
2126 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2127 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2130 if (s
[37] == '}' && s
[38] == '\0')
2136 /*****************************************************************************/
2138 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2140 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2141 WCHAR buf2
[CHARS_IN_GUID
];
2142 LONG buf2len
= sizeof(buf2
);
2146 memset(clsid
, 0, sizeof(*clsid
));
2147 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2148 if (!buf
) return E_OUTOFMEMORY
;
2149 strcpyW( buf
, progid
);
2150 strcatW( buf
, clsidW
);
2151 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2153 HeapFree(GetProcessHeap(),0,buf
);
2154 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2155 return CO_E_CLASSSTRING
;
2157 HeapFree(GetProcessHeap(),0,buf
);
2159 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2162 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2163 return CO_E_CLASSSTRING
;
2166 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2169 /******************************************************************************
2170 * CLSIDFromString [OLE32.@]
2172 * Converts a unique identifier from its string representation into
2176 * idstr [I] The string representation of the GUID.
2177 * id [O] GUID converted from the string.
2181 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2186 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2188 HRESULT ret
= CO_E_CLASSSTRING
;
2192 return E_INVALIDARG
;
2194 if (guid_from_string(idstr
, id
))
2197 /* It appears a ProgID is also valid */
2198 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2205 /******************************************************************************
2206 * IIDFromString [OLE32.@]
2208 * Converts an interface identifier from its string representation to
2212 * idstr [I] The string representation of the GUID.
2213 * id [O] IID converted from the string.
2217 * CO_E_IIDSTRING if idstr is not a valid IID
2222 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2224 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2228 memset(iid
, 0, sizeof(*iid
));
2232 /* length mismatch is a special case */
2233 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2234 return E_INVALIDARG
;
2237 return CO_E_IIDSTRING
;
2239 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2242 /******************************************************************************
2243 * StringFromCLSID [OLE32.@]
2244 * StringFromIID [OLE32.@]
2246 * Converts a GUID into the respective string representation.
2247 * The target string is allocated using the OLE IMalloc.
2250 * id [I] the GUID to be converted.
2251 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2258 * StringFromGUID2, CLSIDFromString
2260 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2262 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2263 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2267 /******************************************************************************
2268 * StringFromGUID2 [OLE32.@]
2270 * Modified version of StringFromCLSID that allows you to specify max
2274 * id [I] GUID to convert to string.
2275 * str [O] Buffer where the result will be stored.
2276 * cmax [I] Size of the buffer in characters.
2279 * Success: The length of the resulting string in characters.
2282 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2284 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2285 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2286 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2287 '%','0','2','X','%','0','2','X','}',0 };
2288 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2289 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2290 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2291 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2292 return CHARS_IN_GUID
;
2295 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2296 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2298 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2299 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2303 strcpyW(path
, wszCLSIDSlash
);
2304 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2305 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2306 if (res
== ERROR_FILE_NOT_FOUND
)
2307 return REGDB_E_CLASSNOTREG
;
2308 else if (res
!= ERROR_SUCCESS
)
2309 return REGDB_E_READREGDB
;
2317 res
= open_classes_key(key
, keyname
, access
, subkey
);
2319 if (res
== ERROR_FILE_NOT_FOUND
)
2320 return REGDB_E_KEYMISSING
;
2321 else if (res
!= ERROR_SUCCESS
)
2322 return REGDB_E_READREGDB
;
2327 /* open HKCR\\AppId\\{string form of appid clsid} key */
2328 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2330 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2331 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2333 WCHAR buf
[CHARS_IN_GUID
];
2334 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2340 /* read the AppID value under the class's key */
2341 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2346 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2348 if (res
== ERROR_FILE_NOT_FOUND
)
2349 return REGDB_E_KEYMISSING
;
2350 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2351 return REGDB_E_READREGDB
;
2353 strcpyW(keyname
, szAppIdKey
);
2354 strcatW(keyname
, buf
);
2355 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2356 if (res
== ERROR_FILE_NOT_FOUND
)
2357 return REGDB_E_KEYMISSING
;
2358 else if (res
!= ERROR_SUCCESS
)
2359 return REGDB_E_READREGDB
;
2364 /******************************************************************************
2365 * ProgIDFromCLSID [OLE32.@]
2367 * Converts a class id into the respective program ID.
2370 * clsid [I] Class ID, as found in registry.
2371 * ppszProgID [O] Associated ProgID.
2376 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2378 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2380 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2381 ACTCTX_SECTION_KEYED_DATA data
;
2387 return E_INVALIDARG
;
2391 data
.cbSize
= sizeof(data
);
2392 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2395 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2396 if (comclass
->progid_len
)
2400 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2401 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2403 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2404 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2408 return REGDB_E_CLASSNOTREG
;
2411 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2415 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2416 ret
= REGDB_E_CLASSNOTREG
;
2420 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2423 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2424 ret
= REGDB_E_CLASSNOTREG
;
2425 CoTaskMemFree(*ppszProgID
);
2430 ret
= E_OUTOFMEMORY
;
2437 /******************************************************************************
2438 * CLSIDFromProgID [OLE32.@]
2440 * Converts a program id into the respective GUID.
2443 * progid [I] Unicode program ID, as found in registry.
2444 * clsid [O] Associated CLSID.
2448 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2450 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2452 ACTCTX_SECTION_KEYED_DATA data
;
2454 if (!progid
|| !clsid
)
2455 return E_INVALIDARG
;
2457 data
.cbSize
= sizeof(data
);
2458 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2461 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2462 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2467 return clsid_from_string_reg(progid
, clsid
);
2470 /******************************************************************************
2471 * CLSIDFromProgIDEx [OLE32.@]
2473 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2475 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2477 return CLSIDFromProgID(progid
, clsid
);
2480 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2483 WCHAR value
[CHARS_IN_GUID
];
2488 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2489 return REGDB_E_IIDNOTREG
;
2491 len
= sizeof(value
);
2492 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2493 return REGDB_E_IIDNOTREG
;
2496 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2497 return REGDB_E_IIDNOTREG
;
2502 /*****************************************************************************
2503 * CoGetPSClsid [OLE32.@]
2505 * Retrieves the CLSID of the proxy/stub factory that implements
2506 * IPSFactoryBuffer for the specified interface.
2509 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2510 * pclsid [O] Where to store returned proxy/stub CLSID.
2515 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2519 * The standard marshaller activates the object with the CLSID
2520 * returned and uses the CreateProxy and CreateStub methods on its
2521 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2524 * CoGetPSClsid determines this CLSID by searching the
2525 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2526 * in the registry and any interface id registered by
2527 * CoRegisterPSClsid within the current process.
2531 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2532 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2533 * considered a bug in native unless an application depends on this (unlikely).
2536 * CoRegisterPSClsid.
2538 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2540 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2541 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2542 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2543 APARTMENT
*apt
= COM_CurrentApt();
2544 struct registered_psclsid
*registered_psclsid
;
2545 ACTCTX_SECTION_KEYED_DATA data
;
2547 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2550 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2554 ERR("apartment not initialised\n");
2555 return CO_E_NOTINITIALIZED
;
2559 return E_INVALIDARG
;
2561 EnterCriticalSection(&apt
->cs
);
2563 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2564 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2566 *pclsid
= registered_psclsid
->clsid
;
2567 LeaveCriticalSection(&apt
->cs
);
2571 LeaveCriticalSection(&apt
->cs
);
2573 data
.cbSize
= sizeof(data
);
2574 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2577 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2578 *pclsid
= ifaceps
->iid
;
2582 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2583 strcpyW(path
, wszInterface
);
2584 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2585 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2587 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2588 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2589 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2590 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2593 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2595 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2600 /*****************************************************************************
2601 * CoRegisterPSClsid [OLE32.@]
2603 * Register a proxy/stub CLSID for the given interface in the current process
2607 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2608 * rclsid [I] CLSID of the proxy/stub.
2612 * Failure: E_OUTOFMEMORY
2616 * This function does not add anything to the registry and the effects are
2617 * limited to the lifetime of the current process.
2622 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2624 APARTMENT
*apt
= COM_CurrentApt();
2625 struct registered_psclsid
*registered_psclsid
;
2627 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2631 ERR("apartment not initialised\n");
2632 return CO_E_NOTINITIALIZED
;
2635 EnterCriticalSection(&apt
->cs
);
2637 LIST_FOR_EACH_ENTRY(registered_psclsid
, &apt
->psclsids
, struct registered_psclsid
, entry
)
2638 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2640 registered_psclsid
->clsid
= *rclsid
;
2641 LeaveCriticalSection(&apt
->cs
);
2645 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2646 if (!registered_psclsid
)
2648 LeaveCriticalSection(&apt
->cs
);
2649 return E_OUTOFMEMORY
;
2652 registered_psclsid
->iid
= *riid
;
2653 registered_psclsid
->clsid
= *rclsid
;
2654 list_add_head(&apt
->psclsids
, ®istered_psclsid
->entry
);
2656 LeaveCriticalSection(&apt
->cs
);
2663 * COM_GetRegisteredClassObject
2665 * This internal method is used to scan the registered class list to
2666 * find a class object.
2669 * rclsid Class ID of the class to find.
2670 * dwClsContext Class context to match.
2671 * ppv [out] returns a pointer to the class object. Complying
2672 * to normal COM usage, this method will increase the
2673 * reference count on this object.
2675 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2676 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2678 HRESULT hr
= S_FALSE
;
2679 RegisteredClass
*curClass
;
2681 EnterCriticalSection( &csRegisteredClassList
);
2683 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2686 * Check if we have a match on the class ID and context.
2688 if ((apt
->oxid
== curClass
->apartment_id
) &&
2689 (dwClsContext
& curClass
->runContext
) &&
2690 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2693 * We have a match, return the pointer to the class object.
2695 *ppUnk
= curClass
->classObject
;
2697 IUnknown_AddRef(curClass
->classObject
);
2704 LeaveCriticalSection( &csRegisteredClassList
);
2709 /******************************************************************************
2710 * CoRegisterClassObject [OLE32.@]
2712 * Registers the class object for a given class ID. Servers housed in EXE
2713 * files use this method instead of exporting DllGetClassObject to allow
2714 * other code to connect to their objects.
2717 * rclsid [I] CLSID of the object to register.
2718 * pUnk [I] IUnknown of the object.
2719 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2720 * flags [I] REGCLS flags indicating how connections are made.
2721 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2725 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2726 * CO_E_OBJISREG if the object is already registered. We should not return this.
2729 * CoRevokeClassObject, CoGetClassObject
2732 * In-process objects are only registered for the current apartment.
2733 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2734 * in other apartments.
2737 * MSDN claims that multiple interface registrations are legal, but we
2738 * can't do that with our current implementation.
2740 HRESULT WINAPI
CoRegisterClassObject(
2745 LPDWORD lpdwRegister
)
2747 static LONG next_cookie
;
2748 RegisteredClass
* newClass
;
2749 LPUNKNOWN foundObject
;
2753 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2754 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2756 if ( (lpdwRegister
==0) || (pUnk
==0) )
2757 return E_INVALIDARG
;
2759 apt
= COM_CurrentApt();
2762 ERR("COM was not initialized\n");
2763 return CO_E_NOTINITIALIZED
;
2768 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2769 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2770 if (flags
& REGCLS_MULTIPLEUSE
)
2771 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2774 * First, check if the class is already registered.
2775 * If it is, this should cause an error.
2777 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2779 if (flags
& REGCLS_MULTIPLEUSE
) {
2780 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2781 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2782 IUnknown_Release(foundObject
);
2785 IUnknown_Release(foundObject
);
2786 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2787 return CO_E_OBJISREG
;
2790 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2791 if ( newClass
== NULL
)
2792 return E_OUTOFMEMORY
;
2794 newClass
->classIdentifier
= *rclsid
;
2795 newClass
->apartment_id
= apt
->oxid
;
2796 newClass
->runContext
= dwClsContext
;
2797 newClass
->connectFlags
= flags
;
2798 newClass
->RpcRegistration
= NULL
;
2800 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2801 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2804 * Since we're making a copy of the object pointer, we have to increase its
2807 newClass
->classObject
= pUnk
;
2808 IUnknown_AddRef(newClass
->classObject
);
2810 EnterCriticalSection( &csRegisteredClassList
);
2811 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2812 LeaveCriticalSection( &csRegisteredClassList
);
2814 *lpdwRegister
= newClass
->dwCookie
;
2816 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2817 IStream
*marshal_stream
;
2819 hr
= get_local_server_stream(apt
, &marshal_stream
);
2823 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2825 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2826 &newClass
->RpcRegistration
);
2827 IStream_Release(marshal_stream
);
2832 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2836 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2837 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2838 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2839 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2840 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2841 DWORD dwLength
= sizeof(threading_model
);
2845 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2846 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2847 threading_model
[0] = '\0';
2849 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2850 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2851 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2853 /* there's not specific handling for this case */
2854 if (threading_model
[0]) return ThreadingModel_Neutral
;
2855 return ThreadingModel_No
;
2858 return data
->u
.actctx
.data
->model
;
2861 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2862 REFCLSID rclsid
, REFIID riid
,
2863 BOOL hostifnecessary
, void **ppv
)
2865 WCHAR dllpath
[MAX_PATH
+1];
2866 BOOL apartment_threaded
;
2868 if (hostifnecessary
)
2870 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2872 if (model
== ThreadingModel_Apartment
)
2874 apartment_threaded
= TRUE
;
2875 if (apt
->multi_threaded
)
2876 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2878 else if (model
== ThreadingModel_Free
)
2880 apartment_threaded
= FALSE
;
2881 if (!apt
->multi_threaded
)
2882 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2884 /* everything except "Apartment", "Free" and "Both" */
2885 else if (model
!= ThreadingModel_Both
)
2887 apartment_threaded
= TRUE
;
2888 /* everything else is main-threaded */
2889 if (model
!= ThreadingModel_No
)
2890 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2892 if (apt
->multi_threaded
|| !apt
->main
)
2893 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2896 apartment_threaded
= FALSE
;
2899 apartment_threaded
= !apt
->multi_threaded
;
2901 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2903 /* failure: CLSID is not found in registry */
2904 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2905 return REGDB_E_CLASSNOTREG
;
2908 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2912 /***********************************************************************
2913 * CoGetClassObject [OLE32.@]
2915 * Creates an object of the specified class.
2918 * rclsid [I] Class ID to create an instance of.
2919 * dwClsContext [I] Flags to restrict the location of the created instance.
2920 * pServerInfo [I] Optional. Details for connecting to a remote server.
2921 * iid [I] The ID of the interface of the instance to return.
2922 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2926 * Failure: HRESULT code.
2929 * The dwClsContext parameter can be one or more of the following:
2930 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2931 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2932 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2933 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2936 * CoCreateInstance()
2938 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2939 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2940 REFIID iid
, LPVOID
*ppv
)
2942 struct class_reg_data clsreg
;
2943 IUnknown
*regClassObject
;
2944 HRESULT hres
= E_UNEXPECTED
;
2946 BOOL release_apt
= FALSE
;
2948 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2951 return E_INVALIDARG
;
2955 if (!(apt
= COM_CurrentApt()))
2957 if (!(apt
= apartment_find_multi_threaded()))
2959 ERR("apartment not initialised\n");
2960 return CO_E_NOTINITIALIZED
;
2966 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2967 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
2970 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
2972 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
2974 if (release_apt
) apartment_release(apt
);
2975 return FTMarshalCF_Create(iid
, ppv
);
2979 if (CLSCTX_INPROC
& dwClsContext
)
2981 ACTCTX_SECTION_KEYED_DATA data
;
2983 data
.cbSize
= sizeof(data
);
2984 /* search activation context first */
2985 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
2986 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2989 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2991 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
2992 clsreg
.u
.actctx
.data
= data
.lpData
;
2993 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
2994 clsreg
.hkey
= FALSE
;
2996 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
2997 ReleaseActCtx(data
.hActCtx
);
2998 if (release_apt
) apartment_release(apt
);
3004 * First, try and see if we can't match the class ID with one of the
3005 * registered classes.
3007 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3010 /* Get the required interface from the retrieved pointer. */
3011 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3014 * Since QI got another reference on the pointer, we want to release the
3015 * one we already have. If QI was unsuccessful, this will release the object. This
3016 * is good since we are not returning it in the "out" parameter.
3018 IUnknown_Release(regClassObject
);
3019 if (release_apt
) apartment_release(apt
);
3023 /* First try in-process server */
3024 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3026 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3029 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3032 if (hres
== REGDB_E_CLASSNOTREG
)
3033 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3034 else if (hres
== REGDB_E_KEYMISSING
)
3036 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3037 hres
= REGDB_E_CLASSNOTREG
;
3041 if (SUCCEEDED(hres
))
3043 clsreg
.u
.hkey
= hkey
;
3046 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3050 /* return if we got a class, otherwise fall through to one of the
3052 if (SUCCEEDED(hres
))
3054 if (release_apt
) apartment_release(apt
);
3059 /* Next try in-process handler */
3060 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3062 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3065 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3068 if (hres
== REGDB_E_CLASSNOTREG
)
3069 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3070 else if (hres
== REGDB_E_KEYMISSING
)
3072 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3073 hres
= REGDB_E_CLASSNOTREG
;
3077 if (SUCCEEDED(hres
))
3079 clsreg
.u
.hkey
= hkey
;
3082 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3086 /* return if we got a class, otherwise fall through to one of the
3088 if (SUCCEEDED(hres
))
3090 if (release_apt
) apartment_release(apt
);
3094 if (release_apt
) apartment_release(apt
);
3096 /* Next try out of process */
3097 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3099 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3100 if (SUCCEEDED(hres
))
3104 /* Finally try remote: this requires networked DCOM (a lot of work) */
3105 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3107 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3108 hres
= REGDB_E_CLASSNOTREG
;
3112 ERR("no class object %s could be created for context 0x%x\n",
3113 debugstr_guid(rclsid
), dwClsContext
);
3117 /***********************************************************************
3118 * CoResumeClassObjects (OLE32.@)
3120 * Resumes all class objects registered with REGCLS_SUSPENDED.
3124 * Failure: HRESULT code.
3126 HRESULT WINAPI
CoResumeClassObjects(void)
3132 /***********************************************************************
3133 * CoCreateInstance [OLE32.@]
3135 * Creates an instance of the specified class.
3138 * rclsid [I] Class ID to create an instance of.
3139 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3140 * dwClsContext [I] Flags to restrict the location of the created instance.
3141 * iid [I] The ID of the interface of the instance to return.
3142 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3146 * Failure: HRESULT code.
3149 * The dwClsContext parameter can be one or more of the following:
3150 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3151 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3152 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3153 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3155 * Aggregation is the concept of deferring the IUnknown of an object to another
3156 * object. This allows a separate object to behave as though it was part of
3157 * the object and to allow this the pUnkOuter parameter can be set. Note that
3158 * not all objects support having an outer of unknown.
3161 * CoGetClassObject()
3163 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3165 LPUNKNOWN pUnkOuter
,
3170 MULTI_QI multi_qi
= { iid
};
3173 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3174 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3179 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3180 *ppv
= multi_qi
.pItf
;
3184 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
)
3188 for (i
= 0; i
< count
; i
++)
3191 mqi
[i
].hr
= E_NOINTERFACE
;
3195 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3197 ULONG index
= 0, fetched
= 0;
3203 index
= fetched
= 1;
3206 for (; index
< count
; index
++)
3208 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3209 if (mqi
[index
].hr
== S_OK
)
3214 IUnknown_Release(unk
);
3217 return E_NOINTERFACE
;
3219 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3222 /***********************************************************************
3223 * CoCreateInstanceEx [OLE32.@]
3225 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3227 LPUNKNOWN pUnkOuter
,
3229 COSERVERINFO
* pServerInfo
,
3233 IUnknown
*unk
= NULL
;
3239 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3241 if (!cmq
|| !pResults
)
3242 return E_INVALIDARG
;
3245 FIXME("() non-NULL pServerInfo not supported!\n");
3247 init_multi_qi(cmq
, pResults
);
3249 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3253 if (!(apt
= COM_CurrentApt()))
3255 if (!(apt
= apartment_find_multi_threaded()))
3257 ERR("apartment not initialised\n");
3258 return CO_E_NOTINITIALIZED
;
3260 apartment_release(apt
);
3264 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3266 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3268 IGlobalInterfaceTable
*git
= get_std_git();
3269 TRACE("Retrieving GIT\n");
3270 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3273 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3274 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3277 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3281 * Get a class factory to construct the object we want.
3283 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3288 * Create the object and don't forget to release the factory
3290 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3291 IClassFactory_Release(cf
);
3294 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3295 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3297 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3298 debugstr_guid(pResults
[0].pIID
),
3299 debugstr_guid(&clsid
),hres
);
3303 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3306 /***********************************************************************
3307 * CoGetInstanceFromFile [OLE32.@]
3309 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3310 COSERVERINFO
*server_info
,
3320 IPersistFile
*pf
= NULL
;
3321 IUnknown
* unk
= NULL
;
3325 if (count
== 0 || !results
)
3326 return E_INVALIDARG
;
3329 FIXME("() non-NULL server_info not supported\n");
3331 init_multi_qi(count
, results
);
3333 /* optionally get CLSID from a file */
3336 hr
= GetClassFile(filename
, &clsid
);
3339 ERR("failed to get CLSID from a file\n");
3346 hr
= CoCreateInstance(rclsid
,
3355 /* init from file */
3356 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3358 ERR("failed to get IPersistFile\n");
3362 IPersistFile_Load(pf
, filename
, grfmode
);
3363 IPersistFile_Release(pf
);
3366 return return_multi_qi(unk
, count
, results
, FALSE
);
3369 /***********************************************************************
3370 * CoGetInstanceFromIStorage [OLE32.@]
3372 HRESULT WINAPI
CoGetInstanceFromIStorage(
3373 COSERVERINFO
*server_info
,
3382 IPersistStorage
*ps
= NULL
;
3383 IUnknown
* unk
= NULL
;
3387 if (count
== 0 || !results
|| !storage
)
3388 return E_INVALIDARG
;
3391 FIXME("() non-NULL server_info not supported\n");
3393 init_multi_qi(count
, results
);
3395 /* optionally get CLSID from a file */
3398 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3399 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3402 ERR("failed to get CLSID from a file\n");
3406 rclsid
= &stat
.clsid
;
3409 hr
= CoCreateInstance(rclsid
,
3418 /* init from IStorage */
3419 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3421 ERR("failed to get IPersistStorage\n");
3425 IPersistStorage_Load(ps
, storage
);
3426 IPersistStorage_Release(ps
);
3429 return return_multi_qi(unk
, count
, results
, FALSE
);
3432 /***********************************************************************
3433 * CoLoadLibrary (OLE32.@)
3438 * lpszLibName [I] Path to library.
3439 * bAutoFree [I] Whether the library should automatically be freed.
3442 * Success: Handle to loaded library.
3446 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3448 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3450 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3452 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3455 /***********************************************************************
3456 * CoFreeLibrary [OLE32.@]
3458 * Unloads a library from memory.
3461 * hLibrary [I] Handle to library to unload.
3467 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3469 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3471 FreeLibrary(hLibrary
);
3475 /***********************************************************************
3476 * CoFreeAllLibraries [OLE32.@]
3478 * Function for backwards compatibility only. Does nothing.
3484 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3486 void WINAPI
CoFreeAllLibraries(void)
3491 /***********************************************************************
3492 * CoFreeUnusedLibrariesEx [OLE32.@]
3494 * Frees any previously unused libraries whose delay has expired and marks
3495 * currently unused libraries for unloading. Unused are identified as those that
3496 * return S_OK from their DllCanUnloadNow function.
3499 * dwUnloadDelay [I] Unload delay in milliseconds.
3500 * dwReserved [I] Reserved. Set to 0.
3506 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3508 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3510 struct apartment
*apt
= COM_CurrentApt();
3513 ERR("apartment not initialised\n");
3517 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3520 /***********************************************************************
3521 * CoFreeUnusedLibraries [OLE32.@]
3523 * Frees any unused libraries. Unused are identified as those that return
3524 * S_OK from their DllCanUnloadNow function.
3530 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3532 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3534 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3537 /***********************************************************************
3538 * CoFileTimeNow [OLE32.@]
3540 * Retrieves the current time in FILETIME format.
3543 * lpFileTime [O] The current time.
3548 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3550 GetSystemTimeAsFileTime( lpFileTime
);
3554 /******************************************************************************
3555 * CoLockObjectExternal [OLE32.@]
3557 * Increments or decrements the external reference count of a stub object.
3560 * pUnk [I] Stub object.
3561 * fLock [I] If TRUE then increments the external ref-count,
3562 * otherwise decrements.
3563 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3564 * calling CoDisconnectObject.
3568 * Failure: HRESULT code.
3571 * If fLock is TRUE and an object is passed in that doesn't have a stub
3572 * manager then a new stub manager is created for the object.
3574 HRESULT WINAPI
CoLockObjectExternal(
3577 BOOL fLastUnlockReleases
)
3579 struct stub_manager
*stubmgr
;
3580 struct apartment
*apt
;
3582 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3583 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3585 apt
= COM_CurrentApt();
3586 if (!apt
) return CO_E_NOTINITIALIZED
;
3588 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3591 WARN("stub object not found %p\n", pUnk
);
3592 /* Note: native is pretty broken here because it just silently
3593 * fails, without returning an appropriate error code, making apps
3594 * think that the object was disconnected, when it actually wasn't */
3599 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3601 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3603 stub_manager_int_release(stubmgr
);
3607 /***********************************************************************
3608 * CoInitializeWOW (OLE32.@)
3610 * WOW equivalent of CoInitialize?
3619 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3621 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3625 /***********************************************************************
3626 * CoGetState [OLE32.@]
3628 * Retrieves the thread state object previously stored by CoSetState().
3631 * ppv [I] Address where pointer to object will be stored.
3635 * Failure: E_OUTOFMEMORY.
3638 * Crashes on all invalid ppv addresses, including NULL.
3639 * If the function returns a non-NULL object then the caller must release its
3640 * reference on the object when the object is no longer required.
3645 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3647 struct oletls
*info
= COM_CurrentInfo();
3648 if (!info
) return E_OUTOFMEMORY
;
3654 IUnknown_AddRef(info
->state
);
3656 TRACE("apt->state=%p\n", info
->state
);
3662 /***********************************************************************
3663 * CoSetState [OLE32.@]
3665 * Sets the thread state object.
3668 * pv [I] Pointer to state object to be stored.
3671 * The system keeps a reference on the object while the object stored.
3675 * Failure: E_OUTOFMEMORY.
3677 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3679 struct oletls
*info
= COM_CurrentInfo();
3680 if (!info
) return E_OUTOFMEMORY
;
3682 if (pv
) IUnknown_AddRef(pv
);
3686 TRACE("-- release %p now\n", info
->state
);
3687 IUnknown_Release(info
->state
);
3696 /******************************************************************************
3697 * CoTreatAsClass [OLE32.@]
3699 * Sets the TreatAs value of a class.
3702 * clsidOld [I] Class to set TreatAs value on.
3703 * clsidNew [I] The class the clsidOld should be treated as.
3707 * Failure: HRESULT code.
3712 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3714 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3715 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3717 WCHAR szClsidNew
[CHARS_IN_GUID
];
3719 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3720 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3723 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3727 if (IsEqualGUID( clsidOld
, clsidNew
))
3729 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3730 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3732 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3734 res
= REGDB_E_WRITEREGDB
;
3740 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3741 res
= REGDB_E_WRITEREGDB
;
3747 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3748 RegDeleteKeyW(hkey
, wszTreatAs
);
3750 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3751 WARN("StringFromGUID2 failed\n");
3756 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3757 WARN("RegSetValue failed\n");
3758 res
= REGDB_E_WRITEREGDB
;
3765 if (hkey
) RegCloseKey(hkey
);
3769 /******************************************************************************
3770 * CoGetTreatAsClass [OLE32.@]
3772 * Gets the TreatAs value of a class.
3775 * clsidOld [I] Class to get the TreatAs value of.
3776 * clsidNew [I] The class the clsidOld should be treated as.
3780 * Failure: HRESULT code.
3785 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3787 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3789 WCHAR szClsidNew
[CHARS_IN_GUID
];
3791 LONG len
= sizeof(szClsidNew
);
3793 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3794 *clsidNew
= *clsidOld
; /* copy over old value */
3796 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3802 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3807 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3809 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3811 if (hkey
) RegCloseKey(hkey
);
3815 /******************************************************************************
3816 * CoGetCurrentProcess [OLE32.@]
3818 * Gets the current process ID.
3821 * The current process ID.
3824 * Is DWORD really the correct return type for this function?
3826 DWORD WINAPI
CoGetCurrentProcess(void)
3828 return GetCurrentProcessId();
3831 /******************************************************************************
3832 * CoRegisterMessageFilter [OLE32.@]
3834 * Registers a message filter.
3837 * lpMessageFilter [I] Pointer to interface.
3838 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3842 * Failure: HRESULT code.
3845 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3846 * lpMessageFilter removes the message filter.
3848 * If lplpMessageFilter is not NULL the previous message filter will be
3849 * returned in the memory pointer to this parameter and the caller is
3850 * responsible for releasing the object.
3852 * The current thread be in an apartment otherwise the function will crash.
3854 HRESULT WINAPI
CoRegisterMessageFilter(
3855 LPMESSAGEFILTER lpMessageFilter
,
3856 LPMESSAGEFILTER
*lplpMessageFilter
)
3858 struct apartment
*apt
;
3859 IMessageFilter
*lpOldMessageFilter
;
3861 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3863 apt
= COM_CurrentApt();
3865 /* can't set a message filter in a multi-threaded apartment */
3866 if (!apt
|| apt
->multi_threaded
)
3868 WARN("can't set message filter in MTA or uninitialized apt\n");
3869 return CO_E_NOT_SUPPORTED
;
3872 if (lpMessageFilter
)
3873 IMessageFilter_AddRef(lpMessageFilter
);
3875 EnterCriticalSection(&apt
->cs
);
3877 lpOldMessageFilter
= apt
->filter
;
3878 apt
->filter
= lpMessageFilter
;
3880 LeaveCriticalSection(&apt
->cs
);
3882 if (lplpMessageFilter
)
3883 *lplpMessageFilter
= lpOldMessageFilter
;
3884 else if (lpOldMessageFilter
)
3885 IMessageFilter_Release(lpOldMessageFilter
);
3890 /***********************************************************************
3891 * CoIsOle1Class [OLE32.@]
3893 * Determines whether the specified class an OLE v1 class.
3896 * clsid [I] Class to test.
3899 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3901 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3903 FIXME("%s\n", debugstr_guid(clsid
));
3907 /***********************************************************************
3908 * IsEqualGUID [OLE32.@]
3910 * Compares two Unique Identifiers.
3913 * rguid1 [I] The first GUID to compare.
3914 * rguid2 [I] The other GUID to compare.
3920 BOOL WINAPI
IsEqualGUID(
3924 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3927 /***********************************************************************
3928 * CoInitializeSecurity [OLE32.@]
3930 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
3931 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
3932 void* pReserved1
, DWORD dwAuthnLevel
,
3933 DWORD dwImpLevel
, void* pReserved2
,
3934 DWORD dwCapabilities
, void* pReserved3
)
3936 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
3937 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
3938 dwCapabilities
, pReserved3
);
3942 /***********************************************************************
3943 * CoSuspendClassObjects [OLE32.@]
3945 * Suspends all registered class objects to prevent further requests coming in
3946 * for those objects.
3950 * Failure: HRESULT code.
3952 HRESULT WINAPI
CoSuspendClassObjects(void)
3958 /***********************************************************************
3959 * CoAddRefServerProcess [OLE32.@]
3961 * Helper function for incrementing the reference count of a local-server
3965 * New reference count.
3968 * CoReleaseServerProcess().
3970 ULONG WINAPI
CoAddRefServerProcess(void)
3976 EnterCriticalSection(&csRegisteredClassList
);
3977 refs
= ++s_COMServerProcessReferences
;
3978 LeaveCriticalSection(&csRegisteredClassList
);
3980 TRACE("refs before: %d\n", refs
- 1);
3985 /***********************************************************************
3986 * CoReleaseServerProcess [OLE32.@]
3988 * Helper function for decrementing the reference count of a local-server
3992 * New reference count.
3995 * When reference count reaches 0, this function suspends all registered
3996 * classes so no new connections are accepted.
3999 * CoAddRefServerProcess(), CoSuspendClassObjects().
4001 ULONG WINAPI
CoReleaseServerProcess(void)
4007 EnterCriticalSection(&csRegisteredClassList
);
4009 refs
= --s_COMServerProcessReferences
;
4010 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4012 LeaveCriticalSection(&csRegisteredClassList
);
4014 TRACE("refs after: %d\n", refs
);
4019 /***********************************************************************
4020 * CoIsHandlerConnected [OLE32.@]
4022 * Determines whether a proxy is connected to a remote stub.
4025 * pUnk [I] Pointer to object that may or may not be connected.
4028 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4031 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4033 FIXME("%p\n", pUnk
);
4038 /***********************************************************************
4039 * CoAllowSetForegroundWindow [OLE32.@]
4042 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4044 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4048 /***********************************************************************
4049 * CoQueryProxyBlanket [OLE32.@]
4051 * Retrieves the security settings being used by a proxy.
4054 * pProxy [I] Pointer to the proxy object.
4055 * pAuthnSvc [O] The type of authentication service.
4056 * pAuthzSvc [O] The type of authorization service.
4057 * ppServerPrincName [O] Optional. The server prinicple name.
4058 * pAuthnLevel [O] The authentication level.
4059 * pImpLevel [O] The impersonation level.
4060 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4061 * pCapabilities [O] Flags affecting the security behaviour.
4065 * Failure: HRESULT code.
4068 * CoCopyProxy, CoSetProxyBlanket.
4070 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4071 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4072 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4074 IClientSecurity
*pCliSec
;
4077 TRACE("%p\n", pProxy
);
4079 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4082 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4083 pAuthzSvc
, ppServerPrincName
,
4084 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4086 IClientSecurity_Release(pCliSec
);
4089 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4093 /***********************************************************************
4094 * CoSetProxyBlanket [OLE32.@]
4096 * Sets the security settings for a proxy.
4099 * pProxy [I] Pointer to the proxy object.
4100 * AuthnSvc [I] The type of authentication service.
4101 * AuthzSvc [I] The type of authorization service.
4102 * pServerPrincName [I] The server prinicple name.
4103 * AuthnLevel [I] The authentication level.
4104 * ImpLevel [I] The impersonation level.
4105 * pAuthInfo [I] Information specific to the authorization/authentication service.
4106 * Capabilities [I] Flags affecting the security behaviour.
4110 * Failure: HRESULT code.
4113 * CoQueryProxyBlanket, CoCopyProxy.
4115 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4116 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4117 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4119 IClientSecurity
*pCliSec
;
4122 TRACE("%p\n", pProxy
);
4124 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4127 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4128 AuthzSvc
, pServerPrincName
,
4129 AuthnLevel
, ImpLevel
, pAuthInfo
,
4131 IClientSecurity_Release(pCliSec
);
4134 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4138 /***********************************************************************
4139 * CoCopyProxy [OLE32.@]
4144 * pProxy [I] Pointer to the proxy object.
4145 * ppCopy [O] Copy of the proxy.
4149 * Failure: HRESULT code.
4152 * CoQueryProxyBlanket, CoSetProxyBlanket.
4154 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4156 IClientSecurity
*pCliSec
;
4159 TRACE("%p\n", pProxy
);
4161 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4164 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4165 IClientSecurity_Release(pCliSec
);
4168 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4173 /***********************************************************************
4174 * CoGetCallContext [OLE32.@]
4176 * Gets the context of the currently executing server call in the current
4180 * riid [I] Context interface to return.
4181 * ppv [O] Pointer to memory that will receive the context on return.
4185 * Failure: HRESULT code.
4187 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4189 struct oletls
*info
= COM_CurrentInfo();
4191 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4194 return E_OUTOFMEMORY
;
4196 if (!info
->call_state
)
4197 return RPC_E_CALL_COMPLETE
;
4199 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4202 /***********************************************************************
4203 * CoSwitchCallContext [OLE32.@]
4205 * Switches the context of the currently executing server call in the current
4209 * pObject [I] Pointer to new context object
4210 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4214 * Failure: HRESULT code.
4216 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4218 struct oletls
*info
= COM_CurrentInfo();
4220 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4223 return E_OUTOFMEMORY
;
4225 *ppOldObject
= info
->call_state
;
4226 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4231 /***********************************************************************
4232 * CoQueryClientBlanket [OLE32.@]
4234 * Retrieves the authentication information about the client of the currently
4235 * executing server call in the current thread.
4238 * pAuthnSvc [O] Optional. The type of authentication service.
4239 * pAuthzSvc [O] Optional. The type of authorization service.
4240 * pServerPrincName [O] Optional. The server prinicple name.
4241 * pAuthnLevel [O] Optional. The authentication level.
4242 * pImpLevel [O] Optional. The impersonation level.
4243 * pPrivs [O] Optional. Information about the privileges of the client.
4244 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4248 * Failure: HRESULT code.
4251 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4253 HRESULT WINAPI
CoQueryClientBlanket(
4256 OLECHAR
**pServerPrincName
,
4259 RPC_AUTHZ_HANDLE
*pPrivs
,
4260 DWORD
*pCapabilities
)
4262 IServerSecurity
*pSrvSec
;
4265 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4266 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4267 pPrivs
, pCapabilities
);
4269 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4272 hr
= IServerSecurity_QueryBlanket(
4273 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4274 pImpLevel
, pPrivs
, pCapabilities
);
4275 IServerSecurity_Release(pSrvSec
);
4281 /***********************************************************************
4282 * CoImpersonateClient [OLE32.@]
4284 * Impersonates the client of the currently executing server call in the
4292 * Failure: HRESULT code.
4295 * If this function fails then the current thread will not be impersonating
4296 * the client and all actions will take place on behalf of the server.
4297 * Therefore, it is important to check the return value from this function.
4300 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4302 HRESULT WINAPI
CoImpersonateClient(void)
4304 IServerSecurity
*pSrvSec
;
4309 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4312 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4313 IServerSecurity_Release(pSrvSec
);
4319 /***********************************************************************
4320 * CoRevertToSelf [OLE32.@]
4322 * Ends the impersonation of the client of the currently executing server
4323 * call in the current thread.
4330 * Failure: HRESULT code.
4333 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4335 HRESULT WINAPI
CoRevertToSelf(void)
4337 IServerSecurity
*pSrvSec
;
4342 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4345 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4346 IServerSecurity_Release(pSrvSec
);
4352 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4354 /* first try to retrieve messages for incoming COM calls to the apartment window */
4355 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4356 /* next retrieve other messages necessary for the app to remain responsive */
4357 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4358 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4361 /***********************************************************************
4362 * CoWaitForMultipleHandles [OLE32.@]
4364 * Waits for one or more handles to become signaled.
4367 * dwFlags [I] Flags. See notes.
4368 * dwTimeout [I] Timeout in milliseconds.
4369 * cHandles [I] Number of handles pointed to by pHandles.
4370 * pHandles [I] Handles to wait for.
4371 * lpdwindex [O] Index of handle that was signaled.
4375 * Failure: RPC_S_CALLPENDING on timeout.
4379 * The dwFlags parameter can be zero or more of the following:
4380 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4381 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4384 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4386 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4387 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4390 DWORD start_time
= GetTickCount();
4391 APARTMENT
*apt
= COM_CurrentApt();
4392 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4393 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4395 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4396 pHandles
, lpdwindex
);
4399 return E_INVALIDARG
;
4404 return E_INVALIDARG
;
4407 return RPC_E_NO_SYNC
;
4411 DWORD now
= GetTickCount();
4414 if (now
- start_time
> dwTimeout
)
4416 hr
= RPC_S_CALLPENDING
;
4422 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4423 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4425 TRACE("waiting for rpc completion or window message\n");
4431 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4432 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4436 if (res
== WAIT_TIMEOUT
)
4437 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4438 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4439 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4441 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4446 /* call message filter */
4448 if (COM_CurrentApt()->filter
)
4450 PENDINGTYPE pendingtype
=
4451 COM_CurrentInfo()->pending_call_count_server
?
4452 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4453 DWORD be_handled
= IMessageFilter_MessagePending(
4454 COM_CurrentApt()->filter
, 0 /* FIXME */,
4455 now
- start_time
, pendingtype
);
4456 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4459 case PENDINGMSG_CANCELCALL
:
4460 WARN("call canceled\n");
4461 hr
= RPC_E_CALL_CANCELED
;
4463 case PENDINGMSG_WAITNOPROCESS
:
4464 case PENDINGMSG_WAITDEFPROCESS
:
4466 /* FIXME: MSDN is very vague about the difference
4467 * between WAITNOPROCESS and WAITDEFPROCESS - there
4468 * appears to be none, so it is possibly a left-over
4469 * from the 16-bit world. */
4474 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4475 * so after processing 100 messages we go back to checking the wait handles */
4476 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4478 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4479 TranslateMessage(&msg
);
4480 DispatchMessageW(&msg
);
4481 if (msg
.message
== WM_QUIT
)
4483 TRACE("resending WM_QUIT to outer message loop\n");
4484 PostQuitMessage(msg
.wParam
);
4485 /* no longer need to process messages */
4486 message_loop
= FALSE
;
4495 TRACE("waiting for rpc completion\n");
4497 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4498 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4499 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4505 hr
= RPC_S_CALLPENDING
;
4508 hr
= HRESULT_FROM_WIN32( GetLastError() );
4516 TRACE("-- 0x%08x\n", hr
);
4521 /***********************************************************************
4522 * CoGetObject [OLE32.@]
4524 * Gets the object named by converting the name to a moniker and binding to it.
4527 * pszName [I] String representing the object.
4528 * pBindOptions [I] Parameters affecting the binding to the named object.
4529 * riid [I] Interface to bind to on the objecct.
4530 * ppv [O] On output, the interface riid of the object represented
4535 * Failure: HRESULT code.
4538 * MkParseDisplayName.
4540 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4541 REFIID riid
, void **ppv
)
4548 hr
= CreateBindCtx(0, &pbc
);
4552 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4559 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4562 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4563 IMoniker_Release(pmk
);
4567 IBindCtx_Release(pbc
);
4572 /***********************************************************************
4573 * CoRegisterChannelHook [OLE32.@]
4575 * Registers a process-wide hook that is called during ORPC calls.
4578 * guidExtension [I] GUID of the channel hook to register.
4579 * pChannelHook [I] Channel hook object to register.
4583 * Failure: HRESULT code.
4585 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4587 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4589 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4592 typedef struct Context
4594 IComThreadingInfo IComThreadingInfo_iface
;
4595 IContextCallback IContextCallback_iface
;
4596 IObjContext IObjContext_iface
;
4601 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4603 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4606 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4608 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4611 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4613 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4616 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4620 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4621 IsEqualIID(riid
, &IID_IUnknown
))
4623 *ppv
= &iface
->IComThreadingInfo_iface
;
4625 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4627 *ppv
= &iface
->IContextCallback_iface
;
4629 else if (IsEqualIID(riid
, &IID_IObjContext
))
4631 *ppv
= &iface
->IObjContext_iface
;
4636 IUnknown_AddRef((IUnknown
*)*ppv
);
4640 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4641 return E_NOINTERFACE
;
4644 static ULONG
Context_AddRef(Context
*This
)
4646 return InterlockedIncrement(&This
->refs
);
4649 static ULONG
Context_Release(Context
*This
)
4651 ULONG refs
= InterlockedDecrement(&This
->refs
);
4653 HeapFree(GetProcessHeap(), 0, This
);
4657 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4659 Context
*This
= impl_from_IComThreadingInfo(iface
);
4660 return Context_QueryInterface(This
, riid
, ppv
);
4663 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4665 Context
*This
= impl_from_IComThreadingInfo(iface
);
4666 return Context_AddRef(This
);
4669 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4671 Context
*This
= impl_from_IComThreadingInfo(iface
);
4672 return Context_Release(This
);
4675 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4677 Context
*This
= impl_from_IComThreadingInfo(iface
);
4679 TRACE("(%p)\n", apttype
);
4681 *apttype
= This
->apttype
;
4685 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4687 Context
*This
= impl_from_IComThreadingInfo(iface
);
4689 TRACE("(%p)\n", thdtype
);
4691 switch (This
->apttype
)
4694 case APTTYPE_MAINSTA
:
4695 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4698 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4704 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4706 FIXME("(%p): stub\n", logical_thread_id
);
4710 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4712 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4716 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4718 Context_CTI_QueryInterface
,
4720 Context_CTI_Release
,
4721 Context_CTI_GetCurrentApartmentType
,
4722 Context_CTI_GetCurrentThreadType
,
4723 Context_CTI_GetCurrentLogicalThreadId
,
4724 Context_CTI_SetCurrentLogicalThreadId
4727 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4729 Context
*This
= impl_from_IContextCallback(iface
);
4730 return Context_QueryInterface(This
, riid
, ppv
);
4733 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4735 Context
*This
= impl_from_IContextCallback(iface
);
4736 return Context_AddRef(This
);
4739 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4741 Context
*This
= impl_from_IContextCallback(iface
);
4742 return Context_Release(This
);
4745 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4746 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4748 Context
*This
= impl_from_IContextCallback(iface
);
4750 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4754 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4756 Context_CC_QueryInterface
,
4759 Context_CC_ContextCallback
4762 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4764 Context
*This
= impl_from_IObjContext(iface
);
4765 return Context_QueryInterface(This
, riid
, ppv
);
4768 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4770 Context
*This
= impl_from_IObjContext(iface
);
4771 return Context_AddRef(This
);
4774 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4776 Context
*This
= impl_from_IObjContext(iface
);
4777 return Context_Release(This
);
4780 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4782 Context
*This
= impl_from_IObjContext(iface
);
4784 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4788 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4790 Context
*This
= impl_from_IObjContext(iface
);
4792 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4796 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4798 Context
*This
= impl_from_IObjContext(iface
);
4800 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4804 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4806 Context
*This
= impl_from_IObjContext(iface
);
4808 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4812 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4814 Context
*This
= impl_from_IObjContext(iface
);
4815 FIXME("(%p/%p)\n", This
, iface
);
4818 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4820 Context
*This
= impl_from_IObjContext(iface
);
4821 FIXME("(%p/%p)\n", This
, iface
);
4824 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4826 Context
*This
= impl_from_IObjContext(iface
);
4827 FIXME("(%p/%p)\n", This
, iface
);
4830 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4832 Context
*This
= impl_from_IObjContext(iface
);
4833 FIXME("(%p/%p)\n", This
, iface
);
4836 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4838 Context
*This
= impl_from_IObjContext(iface
);
4839 FIXME("(%p/%p)\n", This
, iface
);
4842 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4844 Context
*This
= impl_from_IObjContext(iface
);
4845 FIXME("(%p/%p)\n", This
, iface
);
4848 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4850 Context
*This
= impl_from_IObjContext(iface
);
4851 FIXME("(%p/%p)\n", This
, iface
);
4854 static const IObjContextVtbl Context_Object_Vtbl
=
4856 Context_OC_QueryInterface
,
4859 Context_OC_SetProperty
,
4860 Context_OC_RemoveProperty
,
4861 Context_OC_GetProperty
,
4862 Context_OC_EnumContextProps
,
4863 Context_OC_Reserved1
,
4864 Context_OC_Reserved2
,
4865 Context_OC_Reserved3
,
4866 Context_OC_Reserved4
,
4867 Context_OC_Reserved5
,
4868 Context_OC_Reserved6
,
4869 Context_OC_Reserved7
4872 /***********************************************************************
4873 * CoGetObjectContext [OLE32.@]
4875 * Retrieves an object associated with the current context (i.e. apartment).
4878 * riid [I] ID of the interface of the object to retrieve.
4879 * ppv [O] Address where object will be stored on return.
4883 * Failure: HRESULT code.
4885 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4887 APARTMENT
*apt
= COM_CurrentApt();
4891 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4896 if (!(apt
= apartment_find_multi_threaded()))
4898 ERR("apartment not initialised\n");
4899 return CO_E_NOTINITIALIZED
;
4901 apartment_release(apt
);
4904 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
4906 return E_OUTOFMEMORY
;
4908 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
4909 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
4910 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
4912 if (apt
->multi_threaded
)
4913 context
->apttype
= APTTYPE_MTA
;
4915 context
->apttype
= APTTYPE_MAINSTA
;
4917 context
->apttype
= APTTYPE_STA
;
4919 hr
= IComThreadingInfo_QueryInterface(&context
->IComThreadingInfo_iface
, riid
, ppv
);
4920 IComThreadingInfo_Release(&context
->IComThreadingInfo_iface
);
4926 /***********************************************************************
4927 * CoGetContextToken [OLE32.@]
4929 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4931 struct oletls
*info
= COM_CurrentInfo();
4933 TRACE("(%p)\n", token
);
4936 return E_OUTOFMEMORY
;
4941 if (!(apt
= apartment_find_multi_threaded()))
4943 ERR("apartment not initialised\n");
4944 return CO_E_NOTINITIALIZED
;
4946 apartment_release(apt
);
4952 if (!info
->context_token
)
4957 hr
= CoGetObjectContext(&IID_IObjContext
, (void **)&ctx
);
4958 if (FAILED(hr
)) return hr
;
4959 info
->context_token
= ctx
;
4962 *token
= (ULONG_PTR
)info
->context_token
;
4963 TRACE("apt->context_token=%p\n", info
->context_token
);
4968 /***********************************************************************
4969 * CoGetDefaultContext [OLE32.@]
4971 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
4973 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
4974 return E_NOINTERFACE
;
4977 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
4979 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4983 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
4984 if (SUCCEEDED(hres
))
4986 struct class_reg_data regdata
;
4987 WCHAR dllpath
[MAX_PATH
+1];
4989 regdata
.u
.hkey
= hkey
;
4990 regdata
.hkey
= TRUE
;
4992 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
4994 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
4995 if (!strcmpiW(dllpath
, wszOle32
))
4998 return HandlerCF_Create(rclsid
, riid
, ppv
);
5002 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5006 return CLASS_E_CLASSNOTAVAILABLE
;
5009 /***********************************************************************
5010 * CoGetApartmentType [OLE32.@]
5012 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5014 struct oletls
*info
= COM_CurrentInfo();
5016 FIXME("(%p %p): semi-stub\n", type
, qualifier
);
5018 if (!type
|| !qualifier
)
5019 return E_INVALIDARG
;
5022 return E_OUTOFMEMORY
;
5025 *type
= APTTYPE_CURRENT
;
5026 else if (info
->apt
->multi_threaded
)
5027 *type
= APTTYPE_MTA
;
5028 else if (info
->apt
->main
)
5029 *type
= APTTYPE_MAINSTA
;
5031 *type
= APTTYPE_STA
;
5033 *qualifier
= APTTYPEQUALIFIER_NONE
;
5035 return info
->apt
? ERROR_SUCCESS
: CO_E_NOTINITIALIZED
;
5038 /***********************************************************************
5041 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5043 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5046 case DLL_PROCESS_ATTACH
:
5047 hProxyDll
= hinstDLL
;
5050 case DLL_PROCESS_DETACH
:
5051 if (reserved
) break;
5053 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5054 RPC_UnregisterAllChannelHooks();
5055 COMPOBJ_DllList_Free();
5056 DeleteCriticalSection(&csRegisteredClassList
);
5057 DeleteCriticalSection(&csApartment
);
5060 case DLL_THREAD_DETACH
:
5067 /***********************************************************************
5068 * DllRegisterServer (OLE32.@)
5070 HRESULT WINAPI
DllRegisterServer(void)
5072 return OLE32_DllRegisterServer();
5075 /***********************************************************************
5076 * DllUnregisterServer (OLE32.@)
5078 HRESULT WINAPI
DllUnregisterServer(void)
5080 return OLE32_DllUnregisterServer();