4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
47 #define NONAMELESSUNION
50 #define WIN32_NO_STATUS
56 #define USE_COM_CONTEXT_DEF
65 #include "compobj_private.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
77 static APARTMENT
*MTA
; /* protected by csApartment */
78 static APARTMENT
*MainApartment
; /* the first STA apartment */
79 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
81 static CRITICAL_SECTION csApartment
;
82 static CRITICAL_SECTION_DEBUG critsect_debug
=
85 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
86 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
88 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
90 enum comclass_threadingmodel
92 ThreadingModel_Apartment
= 1,
93 ThreadingModel_Free
= 2,
94 ThreadingModel_No
= 3,
95 ThreadingModel_Both
= 4,
96 ThreadingModel_Neutral
= 5
99 enum comclass_miscfields
103 MiscStatusContent
= 4,
104 MiscStatusThumbnail
= 8,
105 MiscStatusDocPrint
= 16
108 struct comclassredirect_data
124 ULONG clrdata_offset
;
126 DWORD miscstatuscontent
;
127 DWORD miscstatusthumbnail
;
128 DWORD miscstatusicon
;
129 DWORD miscstatusdocprint
;
132 struct ifacepsredirect_data
144 struct progidredirect_data
151 struct class_reg_data
157 struct comclassredirect_data
*data
;
166 struct registered_psclsid
173 static struct list registered_psclsid_list
= LIST_INIT(registered_psclsid_list
);
175 static CRITICAL_SECTION cs_registered_psclsid_list
;
176 static CRITICAL_SECTION_DEBUG psclsid_cs_debug
=
178 0, 0, &cs_registered_psclsid_list
,
179 { &psclsid_cs_debug
.ProcessLocksList
, &psclsid_cs_debug
.ProcessLocksList
},
180 0, 0, { (DWORD_PTR
)(__FILE__
": cs_registered_psclsid_list") }
182 static CRITICAL_SECTION cs_registered_psclsid_list
= { &psclsid_cs_debug
, -1, 0, 0, 0, 0 };
185 * This is a marshallable object exposing registered local servers.
186 * IServiceProvider is used only because it happens meet requirements
187 * and already has proxy/stub code. If more functionality is needed,
188 * a custom interface may be used instead.
192 IServiceProvider IServiceProvider_iface
;
195 IStream
*marshal_stream
;
199 * This lock count counts the number of times CoInitialize is called. It is
200 * decreased every time CoUninitialize is called. When it hits 0, the COM
201 * libraries are freed
203 static LONG s_COMLockCount
= 0;
204 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
205 static LONG s_COMServerProcessReferences
= 0;
208 * This linked list contains the list of registered class objects. These
209 * are mostly used to register the factories for out-of-proc servers of OLE
212 * TODO: Make this data structure aware of inter-process communication. This
213 * means that parts of this will be exported to rpcss.
215 typedef struct tagRegisteredClass
218 CLSID classIdentifier
;
220 LPUNKNOWN classObject
;
224 void *RpcRegistration
;
227 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
229 static CRITICAL_SECTION csRegisteredClassList
;
230 static CRITICAL_SECTION_DEBUG class_cs_debug
=
232 0, 0, &csRegisteredClassList
,
233 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
234 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
236 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
238 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
242 case DVASPECT_CONTENT
:
243 return MiscStatusContent
;
244 case DVASPECT_THUMBNAIL
:
245 return MiscStatusThumbnail
;
247 return MiscStatusIcon
;
248 case DVASPECT_DOCPRINT
:
249 return MiscStatusDocPrint
;
255 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
257 ACTCTX_SECTION_KEYED_DATA data
;
259 data
.cbSize
= sizeof(data
);
260 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
263 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
264 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
266 if (!(comclass
->miscmask
& misc
))
268 if (!(comclass
->miscmask
& MiscStatus
))
279 *status
= comclass
->miscstatus
;
282 *status
= comclass
->miscstatusicon
;
284 case MiscStatusContent
:
285 *status
= comclass
->miscstatuscontent
;
287 case MiscStatusThumbnail
:
288 *status
= comclass
->miscstatusthumbnail
;
290 case MiscStatusDocPrint
:
291 *status
= comclass
->miscstatusdocprint
;
303 /* wrapper for NtCreateKey that creates the key recursively if necessary */
304 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
306 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
308 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
310 HANDLE subkey
, root
= attr
->RootDirectory
;
311 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
312 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
315 while (i
< len
&& buffer
[i
] != '\\') i
++;
316 if (i
== len
) return status
;
318 attrs
= attr
->Attributes
;
319 attr
->ObjectName
= &str
;
323 str
.Buffer
= buffer
+ pos
;
324 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
325 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
326 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
327 if (status
) return status
;
328 attr
->RootDirectory
= subkey
;
329 while (i
< len
&& buffer
[i
] == '\\') i
++;
331 while (i
< len
&& buffer
[i
] != '\\') i
++;
333 str
.Buffer
= buffer
+ pos
;
334 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
335 attr
->Attributes
= attrs
;
336 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
337 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
342 static const WCHAR classes_rootW
[] =
343 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
344 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
346 static HKEY classes_root_hkey
;
348 /* create the special HKEY_CLASSES_ROOT key */
349 static HKEY
create_classes_root_hkey(DWORD access
)
352 OBJECT_ATTRIBUTES attr
;
355 attr
.Length
= sizeof(attr
);
356 attr
.RootDirectory
= 0;
357 attr
.ObjectName
= &name
;
359 attr
.SecurityDescriptor
= NULL
;
360 attr
.SecurityQualityOfService
= NULL
;
361 RtlInitUnicodeString( &name
, classes_rootW
);
362 if (create_key( &hkey
, access
, &attr
)) return 0;
363 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
365 if (!(access
& KEY_WOW64_64KEY
))
367 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
370 NtClose( hkey
); /* somebody beat us to it */
377 /* map the hkey from special root to normal key if necessary */
378 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
381 const BOOL is_win64
= sizeof(void*) > sizeof(int);
382 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
384 if (hkey
== HKEY_CLASSES_ROOT
&&
385 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
386 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
387 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
389 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
390 access
&= ~KEY_WOW64_32KEY
;
391 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
399 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
401 OBJECT_ATTRIBUTES attr
;
402 UNICODE_STRING nameW
;
404 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
406 attr
.Length
= sizeof(attr
);
407 attr
.RootDirectory
= hkey
;
408 attr
.ObjectName
= &nameW
;
410 attr
.SecurityDescriptor
= NULL
;
411 attr
.SecurityQualityOfService
= NULL
;
412 RtlInitUnicodeString( &nameW
, name
);
414 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
417 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
419 OBJECT_ATTRIBUTES attr
;
420 UNICODE_STRING nameW
;
422 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
424 attr
.Length
= sizeof(attr
);
425 attr
.RootDirectory
= hkey
;
426 attr
.ObjectName
= &nameW
;
428 attr
.SecurityDescriptor
= NULL
;
429 attr
.SecurityQualityOfService
= NULL
;
430 RtlInitUnicodeString( &nameW
, name
);
432 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
435 /*****************************************************************************
436 * This section contains OpenDllList definitions
438 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
439 * other functions that do LoadLibrary _without_ giving back a HMODULE.
440 * Without this list these handles would never be freed.
442 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
443 * next unload-call but not before 600 sec.
446 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
447 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
449 typedef struct tagOpenDll
454 DllGetClassObjectFunc DllGetClassObject
;
455 DllCanUnloadNowFunc DllCanUnloadNow
;
459 static struct list openDllList
= LIST_INIT(openDllList
);
461 static CRITICAL_SECTION csOpenDllList
;
462 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
464 0, 0, &csOpenDllList
,
465 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
466 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
468 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
470 struct apartment_loaded_dll
478 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};
480 static ATOM apt_win_class
;
482 /*****************************************************************************
483 * This section contains OpenDllList implementation
486 static OpenDll
*COMPOBJ_DllList_Get(LPCWSTR library_name
)
490 EnterCriticalSection(&csOpenDllList
);
491 LIST_FOR_EACH_ENTRY(ptr
, &openDllList
, OpenDll
, entry
)
493 if (!strcmpiW(library_name
, ptr
->library_name
) &&
494 (InterlockedIncrement(&ptr
->refs
) != 1) /* entry is being destroy if == 1 */)
500 LeaveCriticalSection(&csOpenDllList
);
504 /* caller must ensure that library_name is not already in the open dll list */
505 static HRESULT
COMPOBJ_DllList_Add(LPCWSTR library_name
, OpenDll
**ret
)
511 DllCanUnloadNowFunc DllCanUnloadNow
;
512 DllGetClassObjectFunc DllGetClassObject
;
514 TRACE("%s\n", debugstr_w(library_name
));
516 *ret
= COMPOBJ_DllList_Get(library_name
);
517 if (*ret
) return S_OK
;
519 /* do this outside the csOpenDllList to avoid creating a lock dependency on
521 hLibrary
= LoadLibraryExW(library_name
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
524 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name
));
525 /* failure: DLL could not be loaded */
526 return E_ACCESSDENIED
; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
529 DllCanUnloadNow
= (void *)GetProcAddress(hLibrary
, "DllCanUnloadNow");
530 /* Note: failing to find DllCanUnloadNow is not a failure */
531 DllGetClassObject
= (void *)GetProcAddress(hLibrary
, "DllGetClassObject");
532 if (!DllGetClassObject
)
534 /* failure: the dll did not export DllGetClassObject */
535 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name
));
536 FreeLibrary(hLibrary
);
537 return CO_E_DLLNOTFOUND
;
540 EnterCriticalSection( &csOpenDllList
);
542 *ret
= COMPOBJ_DllList_Get(library_name
);
545 /* another caller to this function already added the dll while we
546 * weren't in the critical section */
547 FreeLibrary(hLibrary
);
551 len
= strlenW(library_name
);
552 entry
= HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll
));
554 entry
->library_name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1)*sizeof(WCHAR
));
555 if (entry
&& entry
->library_name
)
557 memcpy(entry
->library_name
, library_name
, (len
+ 1)*sizeof(WCHAR
));
558 entry
->library
= hLibrary
;
560 entry
->DllCanUnloadNow
= DllCanUnloadNow
;
561 entry
->DllGetClassObject
= DllGetClassObject
;
562 list_add_tail(&openDllList
, &entry
->entry
);
567 HeapFree(GetProcessHeap(), 0, entry
);
569 FreeLibrary(hLibrary
);
573 LeaveCriticalSection( &csOpenDllList
);
578 /* pass FALSE for free_entry to release a reference without destroying the
579 * entry if it reaches zero or TRUE otherwise */
580 static void COMPOBJ_DllList_ReleaseRef(OpenDll
*entry
, BOOL free_entry
)
582 if (!InterlockedDecrement(&entry
->refs
) && free_entry
)
584 EnterCriticalSection(&csOpenDllList
);
585 list_remove(&entry
->entry
);
586 LeaveCriticalSection(&csOpenDllList
);
588 TRACE("freeing %p\n", entry
->library
);
589 FreeLibrary(entry
->library
);
591 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
592 HeapFree(GetProcessHeap(), 0, entry
);
596 /* frees memory associated with active dll list */
597 static void COMPOBJ_DllList_Free(void)
599 OpenDll
*entry
, *cursor2
;
600 EnterCriticalSection(&csOpenDllList
);
601 LIST_FOR_EACH_ENTRY_SAFE(entry
, cursor2
, &openDllList
, OpenDll
, entry
)
603 list_remove(&entry
->entry
);
605 HeapFree(GetProcessHeap(), 0, entry
->library_name
);
606 HeapFree(GetProcessHeap(), 0, entry
);
608 LeaveCriticalSection(&csOpenDllList
);
609 DeleteCriticalSection(&csOpenDllList
);
612 /******************************************************************************
616 static DWORD
apartment_addref(struct apartment
*apt
)
618 DWORD refs
= InterlockedIncrement(&apt
->refs
);
619 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt
->oxid
), refs
- 1);
623 /* allocates memory and fills in the necessary fields for a new apartment
624 * object. must be called inside apartment cs */
625 static APARTMENT
*apartment_construct(DWORD model
)
629 TRACE("creating new apartment, model=%d\n", model
);
631 apt
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*apt
));
632 apt
->tid
= GetCurrentThreadId();
634 list_init(&apt
->proxies
);
635 list_init(&apt
->stubmgrs
);
636 list_init(&apt
->loaded_dlls
);
639 apt
->remunk_exported
= FALSE
;
641 InitializeCriticalSection(&apt
->cs
);
642 DEBUG_SET_CRITSEC_NAME(&apt
->cs
, "apartment");
644 apt
->multi_threaded
= !(model
& COINIT_APARTMENTTHREADED
);
646 if (apt
->multi_threaded
)
648 /* FIXME: should be randomly generated by in an RPC call to rpcss */
649 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | 0xcafe;
653 /* FIXME: should be randomly generated by in an RPC call to rpcss */
654 apt
->oxid
= ((OXID
)GetCurrentProcessId() << 32) | GetCurrentThreadId();
657 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
659 list_add_head(&apts
, &apt
->entry
);
664 /* gets and existing apartment if one exists or otherwise creates an apartment
665 * structure which stores OLE apartment-local information and stores a pointer
666 * to it in the thread-local storage */
667 static APARTMENT
*apartment_get_or_create(DWORD model
)
669 APARTMENT
*apt
= COM_CurrentApt();
673 if (model
& COINIT_APARTMENTTHREADED
)
675 EnterCriticalSection(&csApartment
);
677 apt
= apartment_construct(model
);
682 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt
->oxid
));
685 LeaveCriticalSection(&csApartment
);
688 apartment_createwindowifneeded(apt
);
692 EnterCriticalSection(&csApartment
);
694 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
695 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
699 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA
->oxid
));
700 apartment_addref(MTA
);
703 MTA
= apartment_construct(model
);
707 LeaveCriticalSection(&csApartment
);
709 COM_CurrentInfo()->apt
= apt
;
715 static inline BOOL
apartment_is_model(const APARTMENT
*apt
, DWORD model
)
717 return (apt
->multi_threaded
== !(model
& COINIT_APARTMENTTHREADED
));
720 /* gets the multi-threaded apartment if it exists. The caller must
721 * release the reference from the apartment as soon as the apartment pointer
722 * is no longer required. */
723 static APARTMENT
*apartment_find_mta(void)
727 EnterCriticalSection(&csApartment
);
730 apartment_addref(apt
);
732 LeaveCriticalSection(&csApartment
);
737 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
738 * must free the returned apartment in either case. */
739 APARTMENT
*apartment_get_current_or_mta(void)
741 APARTMENT
*apt
= COM_CurrentApt();
744 apartment_addref(apt
);
747 return apartment_find_mta();
750 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
752 list_remove(&curClass
->entry
);
754 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
755 RPC_StopLocalServer(curClass
->RpcRegistration
);
757 IUnknown_Release(curClass
->classObject
);
758 HeapFree(GetProcessHeap(), 0, curClass
);
761 static void COM_RevokeAllClasses(const struct apartment
*apt
)
763 RegisteredClass
*curClass
, *cursor
;
765 EnterCriticalSection( &csRegisteredClassList
);
767 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
769 if (curClass
->apartment_id
== apt
->oxid
)
770 COM_RevokeRegisteredClassObject(curClass
);
773 LeaveCriticalSection( &csRegisteredClassList
);
776 static void revoke_registered_psclsids(void)
778 struct registered_psclsid
*psclsid
, *psclsid2
;
780 EnterCriticalSection( &cs_registered_psclsid_list
);
782 LIST_FOR_EACH_ENTRY_SAFE(psclsid
, psclsid2
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
784 list_remove(&psclsid
->entry
);
785 HeapFree(GetProcessHeap(), 0, psclsid
);
788 LeaveCriticalSection( &cs_registered_psclsid_list
);
791 /******************************************************************************
792 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
795 typedef struct ManualResetEvent
{
796 ISynchronize ISynchronize_iface
;
797 ISynchronizeHandle ISynchronizeHandle_iface
;
802 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
804 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
807 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
809 MREImpl
*This
= impl_from_ISynchronize(iface
);
811 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
813 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
814 *ppv
= &This
->ISynchronize_iface
;
815 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
816 *ppv
= &This
->ISynchronizeHandle_iface
;
818 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
820 return E_NOINTERFACE
;
823 IUnknown_AddRef((IUnknown
*)*ppv
);
827 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
829 MREImpl
*This
= impl_from_ISynchronize(iface
);
830 LONG ref
= InterlockedIncrement(&This
->ref
);
831 TRACE("%p - ref %d\n", This
, ref
);
836 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
838 MREImpl
*This
= impl_from_ISynchronize(iface
);
839 LONG ref
= InterlockedDecrement(&This
->ref
);
840 TRACE("%p - ref %d\n", This
, ref
);
844 CloseHandle(This
->event
);
845 HeapFree(GetProcessHeap(), 0, This
);
851 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
853 MREImpl
*This
= impl_from_ISynchronize(iface
);
855 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
856 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
859 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
861 MREImpl
*This
= impl_from_ISynchronize(iface
);
863 SetEvent(This
->event
);
867 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
869 MREImpl
*This
= impl_from_ISynchronize(iface
);
871 ResetEvent(This
->event
);
875 static ISynchronizeVtbl vt_ISynchronize
= {
876 ISynchronize_fnQueryInterface
,
877 ISynchronize_fnAddRef
,
878 ISynchronize_fnRelease
,
880 ISynchronize_fnSignal
,
884 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
886 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
889 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
891 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
892 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
895 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
897 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
898 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
901 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
903 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
904 return ISynchronize_Release(&This
->ISynchronize_iface
);
907 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
909 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
915 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
916 SynchronizeHandle_QueryInterface
,
917 SynchronizeHandle_AddRef
,
918 SynchronizeHandle_Release
,
919 SynchronizeHandle_GetHandle
922 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
924 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
928 FIXME("Aggregation not implemented.\n");
931 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
932 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
933 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
935 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
936 ISynchronize_Release(&This
->ISynchronize_iface
);
940 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
942 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
945 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
947 LocalServer
*This
= impl_from_IServiceProvider(iface
);
949 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
951 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
952 *ppv
= &This
->IServiceProvider_iface
;
955 return E_NOINTERFACE
;
958 IUnknown_AddRef((IUnknown
*)*ppv
);
962 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
964 LocalServer
*This
= impl_from_IServiceProvider(iface
);
965 LONG ref
= InterlockedIncrement(&This
->ref
);
967 TRACE("(%p) ref=%d\n", This
, ref
);
972 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
974 LocalServer
*This
= impl_from_IServiceProvider(iface
);
975 LONG ref
= InterlockedDecrement(&This
->ref
);
977 TRACE("(%p) ref=%d\n", This
, ref
);
981 HeapFree(GetProcessHeap(), 0, This
);
987 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
989 LocalServer
*This
= impl_from_IServiceProvider(iface
);
990 APARTMENT
*apt
= COM_CurrentApt();
991 RegisteredClass
*iter
;
992 HRESULT hres
= E_FAIL
;
994 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
999 EnterCriticalSection(&csRegisteredClassList
);
1001 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
1002 if(iter
->apartment_id
== apt
->oxid
1003 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
1004 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
1005 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
1010 LeaveCriticalSection( &csRegisteredClassList
);
1015 static const IServiceProviderVtbl LocalServerVtbl
= {
1016 LocalServer_QueryInterface
,
1018 LocalServer_Release
,
1019 LocalServer_QueryService
1022 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
1024 HRESULT hres
= S_OK
;
1026 EnterCriticalSection(&apt
->cs
);
1028 if(!apt
->local_server
) {
1031 obj
= heap_alloc(sizeof(*obj
));
1033 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
1037 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
1038 if(SUCCEEDED(hres
)) {
1039 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
1040 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1042 IStream_Release(obj
->marshal_stream
);
1046 apt
->local_server
= obj
;
1050 hres
= E_OUTOFMEMORY
;
1055 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1057 LeaveCriticalSection(&apt
->cs
);
1060 ERR("Failed: %08x\n", hres
);
1064 /***********************************************************************
1065 * CoRevokeClassObject [OLE32.@]
1067 * Removes a class object from the class registry.
1070 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1074 * Failure: HRESULT code.
1077 * Must be called from the same apartment that called CoRegisterClassObject(),
1078 * otherwise it will fail with RPC_E_WRONG_THREAD.
1081 * CoRegisterClassObject
1083 HRESULT WINAPI DECLSPEC_HOTPATCH
CoRevokeClassObject(
1086 HRESULT hr
= E_INVALIDARG
;
1087 RegisteredClass
*curClass
;
1090 TRACE("(%08x)\n",dwRegister
);
1092 if (!(apt
= apartment_get_current_or_mta()))
1094 ERR("COM was not initialized\n");
1095 return CO_E_NOTINITIALIZED
;
1098 EnterCriticalSection( &csRegisteredClassList
);
1100 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1103 * Check if we have a match on the cookie.
1105 if (curClass
->dwCookie
== dwRegister
)
1107 if (curClass
->apartment_id
== apt
->oxid
)
1109 COM_RevokeRegisteredClassObject(curClass
);
1114 ERR("called from wrong apartment, should be called from %s\n",
1115 wine_dbgstr_longlong(curClass
->apartment_id
));
1116 hr
= RPC_E_WRONG_THREAD
;
1122 LeaveCriticalSection( &csRegisteredClassList
);
1123 apartment_release(apt
);
1127 /* frees unused libraries loaded by apartment_getclassobject by calling the
1128 * DLL's DllCanUnloadNow entry point */
1129 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1131 struct apartment_loaded_dll
*entry
, *next
;
1132 EnterCriticalSection(&apt
->cs
);
1133 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1135 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1137 DWORD real_delay
= delay
;
1139 if (real_delay
== INFINITE
)
1141 /* DLLs that return multi-threaded objects aren't unloaded
1142 * straight away to cope for programs that have races between
1143 * last object destruction and threads in the DLLs that haven't
1144 * finished, despite DllCanUnloadNow returning S_OK */
1145 if (entry
->multi_threaded
)
1146 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1151 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1153 list_remove(&entry
->entry
);
1154 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1155 HeapFree(GetProcessHeap(), 0, entry
);
1159 entry
->unload_time
= GetTickCount() + real_delay
;
1160 if (!entry
->unload_time
) entry
->unload_time
= 1;
1163 else if (entry
->unload_time
)
1164 entry
->unload_time
= 0;
1166 LeaveCriticalSection(&apt
->cs
);
1169 DWORD
apartment_release(struct apartment
*apt
)
1173 EnterCriticalSection(&csApartment
);
1175 ret
= InterlockedDecrement(&apt
->refs
);
1176 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1178 if (apt
->being_destroyed
)
1180 LeaveCriticalSection(&csApartment
);
1184 /* destruction stuff that needs to happen under csApartment CS */
1187 apt
->being_destroyed
= TRUE
;
1188 if (apt
== MTA
) MTA
= NULL
;
1189 else if (apt
== MainApartment
) MainApartment
= NULL
;
1190 list_remove(&apt
->entry
);
1193 LeaveCriticalSection(&csApartment
);
1197 struct list
*cursor
, *cursor2
;
1199 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1201 if(apt
->local_server
) {
1202 LocalServer
*local_server
= apt
->local_server
;
1205 memset(&zero
, 0, sizeof(zero
));
1206 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1207 CoReleaseMarshalData(local_server
->marshal_stream
);
1208 IStream_Release(local_server
->marshal_stream
);
1209 local_server
->marshal_stream
= NULL
;
1211 apt
->local_server
= NULL
;
1212 local_server
->apt
= NULL
;
1213 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1216 /* Release the references to the registered class objects */
1217 COM_RevokeAllClasses(apt
);
1219 /* no locking is needed for this apartment, because no other thread
1220 * can access it at this point */
1222 apartment_disconnectproxies(apt
);
1224 if (apt
->win
) DestroyWindow(apt
->win
);
1225 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1227 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1229 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1230 /* release the implicit reference given by the fact that the
1231 * stub has external references (it must do since it is in the
1232 * stub manager list in the apartment and all non-apartment users
1233 * must have a ref on the apartment and so it cannot be destroyed).
1235 stub_manager_int_release(stubmgr
);
1238 /* if this assert fires, then another thread took a reference to a
1239 * stub manager without taking a reference to the containing
1240 * apartment, which it must do. */
1241 assert(list_empty(&apt
->stubmgrs
));
1243 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1245 /* free as many unused libraries as possible... */
1246 apartment_freeunusedlibraries(apt
, 0);
1248 /* ... and free the memory for the apartment loaded dll entry and
1249 * release the dll list reference without freeing the library for the
1251 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1253 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1254 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1255 list_remove(cursor
);
1256 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1259 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1260 DeleteCriticalSection(&apt
->cs
);
1262 HeapFree(GetProcessHeap(), 0, apt
);
1268 /* The given OXID must be local to this process:
1270 * The ref parameter is here mostly to ensure people remember that
1271 * they get one, you should normally take a ref for thread safety.
1273 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1275 APARTMENT
*result
= NULL
;
1276 struct list
*cursor
;
1278 EnterCriticalSection(&csApartment
);
1279 LIST_FOR_EACH( cursor
, &apts
)
1281 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1282 if (apt
->oxid
== oxid
)
1285 if (ref
) apartment_addref(result
);
1289 LeaveCriticalSection(&csApartment
);
1294 /* gets the apartment which has a given creator thread ID. The caller must
1295 * release the reference from the apartment as soon as the apartment pointer
1296 * is no longer required. */
1297 APARTMENT
*apartment_findfromtid(DWORD tid
)
1299 APARTMENT
*result
= NULL
;
1300 struct list
*cursor
;
1302 EnterCriticalSection(&csApartment
);
1303 LIST_FOR_EACH( cursor
, &apts
)
1305 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1306 if (apt
->tid
== tid
)
1309 apartment_addref(result
);
1313 LeaveCriticalSection(&csApartment
);
1318 /* gets the main apartment if it exists. The caller must
1319 * release the reference from the apartment as soon as the apartment pointer
1320 * is no longer required. */
1321 static APARTMENT
*apartment_findmain(void)
1325 EnterCriticalSection(&csApartment
);
1327 result
= MainApartment
;
1328 if (result
) apartment_addref(result
);
1330 LeaveCriticalSection(&csApartment
);
1335 /* gets the specified class object by loading the appropriate DLL, if
1336 * necessary and calls the DllGetClassObject function for the DLL */
1337 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1338 BOOL apartment_threaded
,
1339 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1341 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1344 struct apartment_loaded_dll
*apartment_loaded_dll
;
1346 if (!strcmpiW(dllpath
, wszOle32
))
1348 /* we don't need to control the lifetime of this dll, so use the local
1349 * implementation of DllGetClassObject directly */
1350 TRACE("calling ole32!DllGetClassObject\n");
1351 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1354 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1359 EnterCriticalSection(&apt
->cs
);
1361 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1362 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1364 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1371 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1372 if (!apartment_loaded_dll
)
1376 apartment_loaded_dll
->unload_time
= 0;
1377 apartment_loaded_dll
->multi_threaded
= FALSE
;
1378 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1380 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1384 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1385 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1389 LeaveCriticalSection(&apt
->cs
);
1393 /* one component being multi-threaded overrides any number of
1394 * apartment-threaded components */
1395 if (!apartment_threaded
)
1396 apartment_loaded_dll
->multi_threaded
= TRUE
;
1398 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1399 /* OK: get the ClassObject */
1400 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1403 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr
, debugstr_w(dllpath
));
1409 /* Returns expanded dll path from the registry or activation context. */
1410 static BOOL
get_object_dll_path(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1417 WCHAR src
[MAX_PATH
];
1418 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1420 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1421 if (keytype
== REG_EXPAND_SZ
) {
1422 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1424 const WCHAR
*quote_start
;
1425 quote_start
= strchrW(src
, '\"');
1427 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1429 memmove(src
, quote_start
+ 1,
1430 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1431 src
[quote_end
- quote_start
- 1] = '\0';
1434 lstrcpynW(dst
, src
, dstlen
);
1441 static const WCHAR dllW
[] = {'.','d','l','l',0};
1446 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1447 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1448 ret
= SearchPathW(NULL
, nameW
, dllW
, dstlen
, dst
, NULL
);
1449 DeactivateActCtx(0, cookie
);
1454 struct host_object_params
1456 struct class_reg_data regdata
;
1457 CLSID clsid
; /* clsid of object to marshal */
1458 IID iid
; /* interface to marshal */
1459 HANDLE event
; /* event signalling when ready for multi-threaded case */
1460 HRESULT hr
; /* result for multi-threaded case */
1461 IStream
*stream
; /* stream that the object will be marshaled into */
1462 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1465 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1466 const struct host_object_params
*params
)
1470 static const LARGE_INTEGER llZero
;
1471 WCHAR dllpath
[MAX_PATH
+1];
1473 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1475 if (!get_object_dll_path(¶ms
->regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
1477 /* failure: CLSID is not found in registry */
1478 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1479 return REGDB_E_CLASSNOTREG
;
1482 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1483 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1487 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1489 IUnknown_Release(object
);
1490 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1495 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1500 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1503 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1505 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1509 struct host_thread_params
1511 COINIT threading_model
;
1513 HWND apartment_hwnd
;
1516 /* thread for hosting an object to allow an object to appear to be created in
1517 * an apartment with an incompatible threading model */
1518 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1520 struct host_thread_params
*params
= p
;
1523 struct apartment
*apt
;
1527 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1528 if (FAILED(hr
)) return hr
;
1530 apt
= COM_CurrentApt();
1531 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1533 apartment_createwindowifneeded(apt
);
1534 params
->apartment_hwnd
= apartment_getwindow(apt
);
1537 params
->apartment_hwnd
= NULL
;
1539 /* force the message queue to be created before signaling parent thread */
1540 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1542 SetEvent(params
->ready_event
);
1543 params
= NULL
; /* can't touch params after here as it may be invalid */
1545 while (GetMessageW(&msg
, NULL
, 0, 0))
1547 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1549 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1550 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1551 SetEvent(obj_params
->event
);
1555 TranslateMessage(&msg
);
1556 DispatchMessageW(&msg
);
1567 /* finds or creates a host apartment, creates the object inside it and returns
1568 * a proxy to it so that the object can be used in the apartment of the
1569 * caller of this function */
1570 static HRESULT
apartment_hostobject_in_hostapt(
1571 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1572 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1574 struct host_object_params params
;
1575 HWND apartment_hwnd
= NULL
;
1576 DWORD apartment_tid
= 0;
1579 if (!multi_threaded
&& main_apartment
)
1581 APARTMENT
*host_apt
= apartment_findmain();
1584 apartment_hwnd
= apartment_getwindow(host_apt
);
1585 apartment_release(host_apt
);
1589 if (!apartment_hwnd
)
1591 EnterCriticalSection(&apt
->cs
);
1593 if (!apt
->host_apt_tid
)
1595 struct host_thread_params thread_params
;
1599 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1600 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1601 thread_params
.apartment_hwnd
= NULL
;
1602 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1605 CloseHandle(handles
[0]);
1606 LeaveCriticalSection(&apt
->cs
);
1607 return E_OUTOFMEMORY
;
1609 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1610 CloseHandle(handles
[0]);
1611 CloseHandle(handles
[1]);
1612 if (wait_value
== WAIT_OBJECT_0
)
1613 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1616 LeaveCriticalSection(&apt
->cs
);
1617 return E_OUTOFMEMORY
;
1621 if (multi_threaded
|| !main_apartment
)
1623 apartment_hwnd
= apt
->host_apt_hwnd
;
1624 apartment_tid
= apt
->host_apt_tid
;
1627 LeaveCriticalSection(&apt
->cs
);
1630 /* another thread may have become the main apartment in the time it took
1631 * us to create the thread for the host apartment */
1632 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1634 APARTMENT
*host_apt
= apartment_findmain();
1637 apartment_hwnd
= apartment_getwindow(host_apt
);
1638 apartment_release(host_apt
);
1642 params
.regdata
= *regdata
;
1643 params
.clsid
= *rclsid
;
1645 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1648 params
.apartment_threaded
= !multi_threaded
;
1652 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1653 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1657 WaitForSingleObject(params
.event
, INFINITE
);
1660 CloseHandle(params
.event
);
1664 if (!apartment_hwnd
)
1666 ERR("host apartment didn't create window\n");
1670 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1673 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1674 IStream_Release(params
.stream
);
1678 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1682 /* Dispatching to the correct thread in an apartment is done through
1683 * window messages rather than RPC transports. When an interface is
1684 * marshalled into another apartment in the same process, a window of the
1685 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1686 * application) is responsible for pumping the message loop in that thread.
1687 * The WM_USER messages which point to the RPCs are then dispatched to
1688 * apartment_wndproc by the user's code from the apartment in which the
1689 * interface was unmarshalled.
1691 memset(&wclass
, 0, sizeof(wclass
));
1692 wclass
.lpfnWndProc
= apartment_wndproc
;
1693 wclass
.hInstance
= hProxyDll
;
1694 wclass
.lpszClassName
= wszAptWinClass
;
1695 apt_win_class
= RegisterClassW(&wclass
);
1699 /* create a window for the apartment or return the current one if one has
1700 * already been created */
1701 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1703 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1705 if (apt
->multi_threaded
)
1712 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1714 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1715 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1718 ERR("CreateWindow failed with error %d\n", GetLastError());
1719 return HRESULT_FROM_WIN32(GetLastError());
1721 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1722 /* someone beat us to it */
1723 DestroyWindow(hwnd
);
1729 /* retrieves the window for the main- or apartment-threaded apartment */
1730 HWND
apartment_getwindow(const struct apartment
*apt
)
1732 assert(!apt
->multi_threaded
);
1736 static void COM_TlsDestroy(void)
1738 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1741 struct init_spy
*cursor
, *cursor2
;
1743 if (info
->apt
) apartment_release(info
->apt
);
1744 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1745 if (info
->state
) IUnknown_Release(info
->state
);
1747 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &info
->spies
, struct init_spy
, entry
)
1749 list_remove(&cursor
->entry
);
1750 IInitializeSpy_Release(cursor
->spy
);
1754 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1756 HeapFree(GetProcessHeap(), 0, info
);
1757 NtCurrentTeb()->ReservedForOle
= NULL
;
1761 /******************************************************************************
1762 * CoBuildVersion [OLE32.@]
1764 * Gets the build version of the DLL.
1769 * Current build version, hiword is majornumber, loword is minornumber
1771 DWORD WINAPI
CoBuildVersion(void)
1773 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1774 return (rmm
<<16)+rup
;
1777 static struct init_spy
*get_spy_entry(struct oletls
*info
, unsigned int id
)
1779 struct init_spy
*spy
;
1781 LIST_FOR_EACH_ENTRY(spy
, &info
->spies
, struct init_spy
, entry
)
1790 /******************************************************************************
1791 * CoRegisterInitializeSpy [OLE32.@]
1793 * Add a Spy that watches CoInitializeEx calls
1796 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1797 * cookie [II] cookie receiver
1800 * Success: S_OK if not already initialized, S_FALSE otherwise.
1801 * Failure: HRESULT code.
1806 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1808 struct oletls
*info
= COM_CurrentInfo();
1809 struct init_spy
*entry
;
1813 TRACE("(%p, %p)\n", spy
, cookie
);
1815 if (!spy
|| !cookie
|| !info
)
1818 WARN("Could not allocate tls\n");
1819 return E_INVALIDARG
;
1822 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **)&spy
);
1826 entry
= heap_alloc(sizeof(*entry
));
1829 IInitializeSpy_Release(spy
);
1830 return E_OUTOFMEMORY
;
1836 while (get_spy_entry(info
, id
) != NULL
)
1842 list_add_head(&info
->spies
, &entry
->entry
);
1844 cookie
->HighPart
= GetCurrentThreadId();
1845 cookie
->LowPart
= entry
->id
;
1850 /******************************************************************************
1851 * CoRevokeInitializeSpy [OLE32.@]
1853 * Remove a spy that previously watched CoInitializeEx calls
1856 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1859 * Success: S_OK if a spy is removed
1860 * Failure: E_INVALIDARG
1865 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1867 struct oletls
*info
= COM_CurrentInfo();
1868 struct init_spy
*spy
;
1870 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1872 if (!info
|| cookie
.HighPart
!= GetCurrentThreadId())
1873 return E_INVALIDARG
;
1875 if ((spy
= get_spy_entry(info
, cookie
.LowPart
)))
1877 IInitializeSpy_Release(spy
->spy
);
1878 list_remove(&spy
->entry
);
1884 return E_INVALIDARG
;
1887 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1893 if (!apartment_get_or_create( model
))
1894 return E_OUTOFMEMORY
;
1896 else if (!apartment_is_model( info
->apt
, model
))
1898 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1899 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1900 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1901 return RPC_E_CHANGED_MODE
;
1911 void leave_apartment( struct oletls
*info
)
1915 if (info
->ole_inits
)
1916 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1917 apartment_release( info
->apt
);
1922 /******************************************************************************
1923 * CoInitialize [OLE32.@]
1925 * Initializes the COM libraries by calling CoInitializeEx with
1926 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1929 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1932 * Success: S_OK if not already initialized, S_FALSE otherwise.
1933 * Failure: HRESULT code.
1938 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1941 * Just delegate to the newer method.
1943 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1946 /******************************************************************************
1947 * CoInitializeEx [OLE32.@]
1949 * Initializes the COM libraries.
1952 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1953 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1956 * S_OK if successful,
1957 * S_FALSE if this function was called already.
1958 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1963 * The behavior used to set the IMalloc used for memory management is
1965 * The dwCoInit parameter must specify one of the following apartment
1967 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1968 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1969 * The parameter may also specify zero or more of the following flags:
1970 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1971 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1976 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1978 struct oletls
*info
= COM_CurrentInfo();
1979 struct init_spy
*cursor
;
1982 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1984 if (lpReserved
!=NULL
)
1986 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1990 * Check the lock count. If this is the first time going through the initialize
1991 * process, we have to initialize the libraries.
1993 * And crank-up that lock count.
1995 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1998 * Initialize the various COM libraries and data structures.
2000 TRACE("() - Initializing the COM libraries\n");
2002 /* we may need to defer this until after apartment initialisation */
2003 RunningObjectTableImpl_Initialize();
2006 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2008 IInitializeSpy_PreInitialize(cursor
->spy
, dwCoInit
, info
->inits
);
2011 hr
= enter_apartment( info
, dwCoInit
);
2013 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2015 hr
= IInitializeSpy_PostInitialize(cursor
->spy
, hr
, dwCoInit
, info
->inits
);
2021 /***********************************************************************
2022 * CoUninitialize [OLE32.@]
2024 * This method will decrement the refcount on the current apartment, freeing
2025 * the resources associated with it if it is the last thread in the apartment.
2026 * If the last apartment is freed, the function will additionally release
2027 * any COM resources associated with the process.
2037 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
2039 struct oletls
* info
= COM_CurrentInfo();
2040 struct init_spy
*cursor
;
2045 /* will only happen on OOM */
2048 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2050 IInitializeSpy_PreUninitialize(cursor
->spy
, info
->inits
);
2056 ERR("Mismatched CoUninitialize\n");
2058 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2060 IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2066 leave_apartment( info
);
2069 * Decrease the reference count.
2070 * If we are back to 0 locks on the COM library, make sure we free
2071 * all the associated data structures.
2073 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2076 TRACE("() - Releasing the COM libraries\n");
2078 revoke_registered_psclsids();
2079 RunningObjectTableImpl_UnInitialize();
2081 else if (lCOMRefCnt
<1) {
2082 ERR( "CoUninitialize() - not CoInitialized.\n" );
2083 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2086 LIST_FOR_EACH_ENTRY(cursor
, &info
->spies
, struct init_spy
, entry
)
2088 IInitializeSpy_PostUninitialize(cursor
->spy
, info
->inits
);
2092 /******************************************************************************
2093 * CoDisconnectObject [OLE32.@]
2095 * Disconnects all connections to this object from remote processes. Dispatches
2096 * pending RPCs while blocking new RPCs from occurring, and then calls
2097 * IMarshal::DisconnectObject on the given object.
2099 * Typically called when the object server is forced to shut down, for instance by
2103 * lpUnk [I] The object whose stub should be disconnected.
2104 * reserved [I] Reserved. Should be set to 0.
2108 * Failure: HRESULT code.
2111 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2113 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2115 struct stub_manager
*manager
;
2120 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2122 if (!lpUnk
) return E_INVALIDARG
;
2124 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2127 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2128 IMarshal_Release(marshal
);
2132 if (!(apt
= apartment_get_current_or_mta()))
2134 ERR("apartment not initialised\n");
2135 return CO_E_NOTINITIALIZED
;
2138 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2140 stub_manager_disconnect(manager
);
2141 /* Release stub manager twice, to remove the apartment reference. */
2142 stub_manager_int_release(manager
);
2143 stub_manager_int_release(manager
);
2146 /* Note: native is pretty broken here because it just silently
2147 * fails, without returning an appropriate error code if the object was
2148 * not found, making apps think that the object was disconnected, when
2149 * it actually wasn't */
2151 apartment_release(apt
);
2155 /******************************************************************************
2156 * CoCreateGuid [OLE32.@]
2158 * Simply forwards to UuidCreate in RPCRT4.
2161 * pguid [O] Points to the GUID to initialize.
2165 * Failure: HRESULT code.
2170 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2174 if(!pguid
) return E_INVALIDARG
;
2176 status
= UuidCreate(pguid
);
2177 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2178 return HRESULT_FROM_WIN32( status
);
2181 static inline BOOL
is_valid_hex(WCHAR c
)
2183 if (!(((c
>= '0') && (c
<= '9')) ||
2184 ((c
>= 'a') && (c
<= 'f')) ||
2185 ((c
>= 'A') && (c
<= 'F'))))
2190 static const BYTE guid_conv_table
[256] =
2192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2195 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2196 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2198 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2201 /* conversion helper for CLSIDFromString/IIDFromString */
2202 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2206 if (!s
|| s
[0]!='{') {
2207 memset( id
, 0, sizeof (CLSID
) );
2212 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2214 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2217 for (i
= 1; i
< 9; i
++) {
2218 if (!is_valid_hex(s
[i
])) return FALSE
;
2219 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2221 if (s
[9]!='-') return FALSE
;
2224 for (i
= 10; i
< 14; i
++) {
2225 if (!is_valid_hex(s
[i
])) return FALSE
;
2226 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2228 if (s
[14]!='-') return FALSE
;
2231 for (i
= 15; i
< 19; i
++) {
2232 if (!is_valid_hex(s
[i
])) return FALSE
;
2233 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2235 if (s
[19]!='-') return FALSE
;
2237 for (i
= 20; i
< 37; i
+=2) {
2239 if (s
[i
]!='-') return FALSE
;
2242 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2243 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2246 if (s
[37] == '}' && s
[38] == '\0')
2252 /*****************************************************************************/
2254 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2256 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2257 WCHAR buf2
[CHARS_IN_GUID
];
2258 LONG buf2len
= sizeof(buf2
);
2262 memset(clsid
, 0, sizeof(*clsid
));
2263 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2264 if (!buf
) return E_OUTOFMEMORY
;
2265 strcpyW( buf
, progid
);
2266 strcatW( buf
, clsidW
);
2267 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2269 HeapFree(GetProcessHeap(),0,buf
);
2270 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2271 return CO_E_CLASSSTRING
;
2273 HeapFree(GetProcessHeap(),0,buf
);
2275 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2278 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2279 return CO_E_CLASSSTRING
;
2282 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2285 /******************************************************************************
2286 * CLSIDFromString [OLE32.@]
2288 * Converts a unique identifier from its string representation into
2292 * idstr [I] The string representation of the GUID.
2293 * id [O] GUID converted from the string.
2297 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2302 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2304 HRESULT ret
= CO_E_CLASSSTRING
;
2308 return E_INVALIDARG
;
2310 if (guid_from_string(idstr
, id
))
2313 /* It appears a ProgID is also valid */
2314 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2321 /******************************************************************************
2322 * IIDFromString [OLE32.@]
2324 * Converts an interface identifier from its string representation to
2328 * idstr [I] The string representation of the GUID.
2329 * id [O] IID converted from the string.
2333 * CO_E_IIDSTRING if idstr is not a valid IID
2338 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2340 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2344 memset(iid
, 0, sizeof(*iid
));
2348 /* length mismatch is a special case */
2349 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2350 return E_INVALIDARG
;
2353 return CO_E_IIDSTRING
;
2355 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2358 /******************************************************************************
2359 * StringFromCLSID [OLE32.@]
2360 * StringFromIID [OLE32.@]
2362 * Converts a GUID into the respective string representation.
2363 * The target string is allocated using the OLE IMalloc.
2366 * id [I] the GUID to be converted.
2367 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2374 * StringFromGUID2, CLSIDFromString
2376 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2378 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2379 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2383 /******************************************************************************
2384 * StringFromGUID2 [OLE32.@]
2386 * Modified version of StringFromCLSID that allows you to specify max
2390 * id [I] GUID to convert to string.
2391 * str [O] Buffer where the result will be stored.
2392 * cmax [I] Size of the buffer in characters.
2395 * Success: The length of the resulting string in characters.
2398 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2400 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2401 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2402 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2403 '%','0','2','X','%','0','2','X','}',0 };
2404 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2405 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2406 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2407 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2408 return CHARS_IN_GUID
;
2411 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2412 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2414 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2415 WCHAR path
[CHARS_IN_GUID
+ ARRAY_SIZE(wszCLSIDSlash
) - 1];
2419 strcpyW(path
, wszCLSIDSlash
);
2420 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2421 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2422 if (res
== ERROR_FILE_NOT_FOUND
)
2423 return REGDB_E_CLASSNOTREG
;
2424 else if (res
!= ERROR_SUCCESS
)
2425 return REGDB_E_READREGDB
;
2433 res
= open_classes_key(key
, keyname
, access
, subkey
);
2435 if (res
== ERROR_FILE_NOT_FOUND
)
2436 return REGDB_E_KEYMISSING
;
2437 else if (res
!= ERROR_SUCCESS
)
2438 return REGDB_E_READREGDB
;
2443 /* open HKCR\\AppId\\{string form of appid clsid} key */
2444 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2446 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2447 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2449 WCHAR buf
[CHARS_IN_GUID
];
2450 WCHAR keyname
[ARRAY_SIZE(szAppIdKey
) + CHARS_IN_GUID
];
2456 /* read the AppID value under the class's key */
2457 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2462 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2464 if (res
== ERROR_FILE_NOT_FOUND
)
2465 return REGDB_E_KEYMISSING
;
2466 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2467 return REGDB_E_READREGDB
;
2469 strcpyW(keyname
, szAppIdKey
);
2470 strcatW(keyname
, buf
);
2471 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2472 if (res
== ERROR_FILE_NOT_FOUND
)
2473 return REGDB_E_KEYMISSING
;
2474 else if (res
!= ERROR_SUCCESS
)
2475 return REGDB_E_READREGDB
;
2480 /******************************************************************************
2481 * ProgIDFromCLSID [OLE32.@]
2483 * Converts a class id into the respective program ID.
2486 * clsid [I] Class ID, as found in registry.
2487 * ppszProgID [O] Associated ProgID.
2492 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2494 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2496 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2497 ACTCTX_SECTION_KEYED_DATA data
;
2503 return E_INVALIDARG
;
2507 data
.cbSize
= sizeof(data
);
2508 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2511 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2512 if (comclass
->progid_len
)
2516 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2517 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2519 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2520 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2524 return REGDB_E_CLASSNOTREG
;
2527 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2531 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2532 ret
= REGDB_E_CLASSNOTREG
;
2536 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2539 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2540 ret
= REGDB_E_CLASSNOTREG
;
2541 CoTaskMemFree(*ppszProgID
);
2546 ret
= E_OUTOFMEMORY
;
2553 /******************************************************************************
2554 * CLSIDFromProgID [OLE32.@]
2556 * Converts a program id into the respective GUID.
2559 * progid [I] Unicode program ID, as found in registry.
2560 * clsid [O] Associated CLSID.
2564 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2566 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2568 ACTCTX_SECTION_KEYED_DATA data
;
2570 if (!progid
|| !clsid
)
2571 return E_INVALIDARG
;
2573 data
.cbSize
= sizeof(data
);
2574 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2577 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2578 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2583 return clsid_from_string_reg(progid
, clsid
);
2586 /******************************************************************************
2587 * CLSIDFromProgIDEx [OLE32.@]
2589 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2591 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2593 return CLSIDFromProgID(progid
, clsid
);
2596 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2599 WCHAR value
[CHARS_IN_GUID
];
2604 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2605 return REGDB_E_IIDNOTREG
;
2607 len
= sizeof(value
);
2608 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2609 return REGDB_E_IIDNOTREG
;
2612 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2613 return REGDB_E_IIDNOTREG
;
2618 /*****************************************************************************
2619 * CoGetPSClsid [OLE32.@]
2621 * Retrieves the CLSID of the proxy/stub factory that implements
2622 * IPSFactoryBuffer for the specified interface.
2625 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2626 * pclsid [O] Where to store returned proxy/stub CLSID.
2631 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2635 * The standard marshaller activates the object with the CLSID
2636 * returned and uses the CreateProxy and CreateStub methods on its
2637 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2640 * CoGetPSClsid determines this CLSID by searching the
2641 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2642 * in the registry and any interface id registered by
2643 * CoRegisterPSClsid within the current process.
2647 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2648 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2649 * considered a bug in native unless an application depends on this (unlikely).
2652 * CoRegisterPSClsid.
2654 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2656 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2657 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2658 WCHAR path
[ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAY_SIZE(wszPSC
)];
2660 struct registered_psclsid
*registered_psclsid
;
2661 ACTCTX_SECTION_KEYED_DATA data
;
2663 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2666 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2668 if (!(apt
= apartment_get_current_or_mta()))
2670 ERR("apartment not initialised\n");
2671 return CO_E_NOTINITIALIZED
;
2673 apartment_release(apt
);
2676 return E_INVALIDARG
;
2678 EnterCriticalSection(&cs_registered_psclsid_list
);
2680 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2681 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2683 *pclsid
= registered_psclsid
->clsid
;
2684 LeaveCriticalSection(&cs_registered_psclsid_list
);
2688 LeaveCriticalSection(&cs_registered_psclsid_list
);
2690 data
.cbSize
= sizeof(data
);
2691 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2694 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2695 *pclsid
= ifaceps
->iid
;
2699 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2700 strcpyW(path
, wszInterface
);
2701 StringFromGUID2(riid
, path
+ ARRAY_SIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2702 strcpyW(path
+ ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2704 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2705 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2706 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2707 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2710 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2712 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2717 /*****************************************************************************
2718 * CoRegisterPSClsid [OLE32.@]
2720 * Register a proxy/stub CLSID for the given interface in the current process
2724 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2725 * rclsid [I] CLSID of the proxy/stub.
2729 * Failure: E_OUTOFMEMORY
2733 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2734 * will be returned from other apartments in the same process.
2736 * This function does not add anything to the registry and the effects are
2737 * limited to the lifetime of the current process.
2742 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2745 struct registered_psclsid
*registered_psclsid
;
2747 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2749 if (!(apt
= apartment_get_current_or_mta()))
2751 ERR("apartment not initialised\n");
2752 return CO_E_NOTINITIALIZED
;
2754 apartment_release(apt
);
2756 EnterCriticalSection(&cs_registered_psclsid_list
);
2758 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2759 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2761 registered_psclsid
->clsid
= *rclsid
;
2762 LeaveCriticalSection(&cs_registered_psclsid_list
);
2766 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2767 if (!registered_psclsid
)
2769 LeaveCriticalSection(&cs_registered_psclsid_list
);
2770 return E_OUTOFMEMORY
;
2773 registered_psclsid
->iid
= *riid
;
2774 registered_psclsid
->clsid
= *rclsid
;
2775 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2777 LeaveCriticalSection(&cs_registered_psclsid_list
);
2784 * COM_GetRegisteredClassObject
2786 * This internal method is used to scan the registered class list to
2787 * find a class object.
2790 * rclsid Class ID of the class to find.
2791 * dwClsContext Class context to match.
2792 * ppv [out] returns a pointer to the class object. Complying
2793 * to normal COM usage, this method will increase the
2794 * reference count on this object.
2796 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2797 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2799 HRESULT hr
= S_FALSE
;
2800 RegisteredClass
*curClass
;
2802 EnterCriticalSection( &csRegisteredClassList
);
2804 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2807 * Check if we have a match on the class ID and context.
2809 if ((apt
->oxid
== curClass
->apartment_id
) &&
2810 (dwClsContext
& curClass
->runContext
) &&
2811 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2814 * We have a match, return the pointer to the class object.
2816 *ppUnk
= curClass
->classObject
;
2818 IUnknown_AddRef(curClass
->classObject
);
2825 LeaveCriticalSection( &csRegisteredClassList
);
2830 /******************************************************************************
2831 * CoRegisterClassObject [OLE32.@]
2833 * Registers the class object for a given class ID. Servers housed in EXE
2834 * files use this method instead of exporting DllGetClassObject to allow
2835 * other code to connect to their objects.
2838 * rclsid [I] CLSID of the object to register.
2839 * pUnk [I] IUnknown of the object.
2840 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2841 * flags [I] REGCLS flags indicating how connections are made.
2842 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2846 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2847 * CO_E_OBJISREG if the object is already registered. We should not return this.
2850 * CoRevokeClassObject, CoGetClassObject
2853 * In-process objects are only registered for the current apartment.
2854 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2855 * in other apartments.
2858 * MSDN claims that multiple interface registrations are legal, but we
2859 * can't do that with our current implementation.
2861 HRESULT WINAPI
CoRegisterClassObject(
2866 LPDWORD lpdwRegister
)
2868 static LONG next_cookie
;
2869 RegisteredClass
* newClass
;
2870 LPUNKNOWN foundObject
;
2874 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2875 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2877 if ( (lpdwRegister
==0) || (pUnk
==0) )
2878 return E_INVALIDARG
;
2880 if (!(apt
= apartment_get_current_or_mta()))
2882 ERR("COM was not initialized\n");
2883 return CO_E_NOTINITIALIZED
;
2888 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2889 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2890 if (flags
& REGCLS_MULTIPLEUSE
)
2891 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2894 * First, check if the class is already registered.
2895 * If it is, this should cause an error.
2897 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2899 if (flags
& REGCLS_MULTIPLEUSE
) {
2900 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2901 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2902 IUnknown_Release(foundObject
);
2903 apartment_release(apt
);
2906 IUnknown_Release(foundObject
);
2907 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2908 apartment_release(apt
);
2909 return CO_E_OBJISREG
;
2912 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2913 if ( newClass
== NULL
)
2915 apartment_release(apt
);
2916 return E_OUTOFMEMORY
;
2919 newClass
->classIdentifier
= *rclsid
;
2920 newClass
->apartment_id
= apt
->oxid
;
2921 newClass
->runContext
= dwClsContext
;
2922 newClass
->connectFlags
= flags
;
2923 newClass
->RpcRegistration
= NULL
;
2925 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2926 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2929 * Since we're making a copy of the object pointer, we have to increase its
2932 newClass
->classObject
= pUnk
;
2933 IUnknown_AddRef(newClass
->classObject
);
2935 EnterCriticalSection( &csRegisteredClassList
);
2936 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2937 LeaveCriticalSection( &csRegisteredClassList
);
2939 *lpdwRegister
= newClass
->dwCookie
;
2941 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2942 IStream
*marshal_stream
;
2944 hr
= get_local_server_stream(apt
, &marshal_stream
);
2947 apartment_release(apt
);
2951 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2953 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2954 &newClass
->RpcRegistration
);
2955 IStream_Release(marshal_stream
);
2957 apartment_release(apt
);
2961 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2965 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2966 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2967 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2968 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2969 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2970 DWORD dwLength
= sizeof(threading_model
);
2974 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2975 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2976 threading_model
[0] = '\0';
2978 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2979 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2980 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2982 /* there's not specific handling for this case */
2983 if (threading_model
[0]) return ThreadingModel_Neutral
;
2984 return ThreadingModel_No
;
2987 return data
->u
.actctx
.data
->model
;
2990 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2991 REFCLSID rclsid
, REFIID riid
,
2992 BOOL hostifnecessary
, void **ppv
)
2994 WCHAR dllpath
[MAX_PATH
+1];
2995 BOOL apartment_threaded
;
2997 if (hostifnecessary
)
2999 enum comclass_threadingmodel model
= get_threading_model(regdata
);
3001 if (model
== ThreadingModel_Apartment
)
3003 apartment_threaded
= TRUE
;
3004 if (apt
->multi_threaded
)
3005 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
3007 else if (model
== ThreadingModel_Free
)
3009 apartment_threaded
= FALSE
;
3010 if (!apt
->multi_threaded
)
3011 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
3013 /* everything except "Apartment", "Free" and "Both" */
3014 else if (model
!= ThreadingModel_Both
)
3016 apartment_threaded
= TRUE
;
3017 /* everything else is main-threaded */
3018 if (model
!= ThreadingModel_No
)
3019 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
3021 if (apt
->multi_threaded
|| !apt
->main
)
3022 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
3025 apartment_threaded
= FALSE
;
3028 apartment_threaded
= !apt
->multi_threaded
;
3030 if (!get_object_dll_path(regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
3032 /* failure: CLSID is not found in registry */
3033 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
3034 return REGDB_E_CLASSNOTREG
;
3037 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
3041 /***********************************************************************
3042 * CoGetClassObject [OLE32.@]
3044 * Creates an object of the specified class.
3047 * rclsid [I] Class ID to create an instance of.
3048 * dwClsContext [I] Flags to restrict the location of the created instance.
3049 * pServerInfo [I] Optional. Details for connecting to a remote server.
3050 * iid [I] The ID of the interface of the instance to return.
3051 * ppv [O] On returns, contains a pointer to the specified interface of the object.
3055 * Failure: HRESULT code.
3058 * The dwClsContext parameter can be one or more of the following:
3059 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3060 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3061 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3062 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3065 * CoCreateInstance()
3067 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
3068 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
3069 REFIID iid
, LPVOID
*ppv
)
3071 struct class_reg_data clsreg
;
3072 IUnknown
*regClassObject
;
3073 HRESULT hres
= E_UNEXPECTED
;
3076 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
3079 return E_INVALIDARG
;
3083 if (!(apt
= apartment_get_current_or_mta()))
3085 ERR("apartment not initialised\n");
3086 return CO_E_NOTINITIALIZED
;
3090 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3091 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3094 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3096 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3098 apartment_release(apt
);
3099 return FTMarshalCF_Create(iid
, ppv
);
3101 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3102 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3105 if (CLSCTX_INPROC
& dwClsContext
)
3107 ACTCTX_SECTION_KEYED_DATA data
;
3109 data
.cbSize
= sizeof(data
);
3110 /* search activation context first */
3111 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3112 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3115 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3117 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3118 clsreg
.u
.actctx
.data
= data
.lpData
;
3119 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3120 clsreg
.hkey
= FALSE
;
3122 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3123 ReleaseActCtx(data
.hActCtx
);
3124 apartment_release(apt
);
3130 * First, try and see if we can't match the class ID with one of the
3131 * registered classes.
3133 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3136 /* Get the required interface from the retrieved pointer. */
3137 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3140 * Since QI got another reference on the pointer, we want to release the
3141 * one we already have. If QI was unsuccessful, this will release the object. This
3142 * is good since we are not returning it in the "out" parameter.
3144 IUnknown_Release(regClassObject
);
3145 apartment_release(apt
);
3149 /* First try in-process server */
3150 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3152 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3155 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3158 if (hres
== REGDB_E_CLASSNOTREG
)
3159 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3160 else if (hres
== REGDB_E_KEYMISSING
)
3162 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3163 hres
= REGDB_E_CLASSNOTREG
;
3167 if (SUCCEEDED(hres
))
3169 clsreg
.u
.hkey
= hkey
;
3172 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3176 /* return if we got a class, otherwise fall through to one of the
3178 if (SUCCEEDED(hres
))
3180 apartment_release(apt
);
3185 /* Next try in-process handler */
3186 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3188 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3191 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3194 if (hres
== REGDB_E_CLASSNOTREG
)
3195 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3196 else if (hres
== REGDB_E_KEYMISSING
)
3198 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3199 hres
= REGDB_E_CLASSNOTREG
;
3203 if (SUCCEEDED(hres
))
3205 clsreg
.u
.hkey
= hkey
;
3208 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3212 /* return if we got a class, otherwise fall through to one of the
3214 if (SUCCEEDED(hres
))
3216 apartment_release(apt
);
3220 apartment_release(apt
);
3222 /* Next try out of process */
3223 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3225 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3226 if (SUCCEEDED(hres
))
3230 /* Finally try remote: this requires networked DCOM (a lot of work) */
3231 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3233 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3234 hres
= REGDB_E_CLASSNOTREG
;
3238 ERR("no class object %s could be created for context 0x%x\n",
3239 debugstr_guid(rclsid
), dwClsContext
);
3243 /***********************************************************************
3244 * CoResumeClassObjects (OLE32.@)
3246 * Resumes all class objects registered with REGCLS_SUSPENDED.
3250 * Failure: HRESULT code.
3252 HRESULT WINAPI
CoResumeClassObjects(void)
3258 /***********************************************************************
3259 * CoCreateInstance [OLE32.@]
3261 * Creates an instance of the specified class.
3264 * rclsid [I] Class ID to create an instance of.
3265 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3266 * dwClsContext [I] Flags to restrict the location of the created instance.
3267 * iid [I] The ID of the interface of the instance to return.
3268 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3272 * Failure: HRESULT code.
3275 * The dwClsContext parameter can be one or more of the following:
3276 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3277 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3278 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3279 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3281 * Aggregation is the concept of deferring the IUnknown of an object to another
3282 * object. This allows a separate object to behave as though it was part of
3283 * the object and to allow this the pUnkOuter parameter can be set. Note that
3284 * not all objects support having an outer of unknown.
3287 * CoGetClassObject()
3289 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3291 LPUNKNOWN pUnkOuter
,
3296 MULTI_QI multi_qi
= { iid
};
3299 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3300 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3305 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3306 *ppv
= multi_qi
.pItf
;
3310 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3314 for (i
= 0; i
< count
; i
++)
3321 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3323 ULONG index
= 0, fetched
= 0;
3329 index
= fetched
= 1;
3332 for (; index
< count
; index
++)
3334 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3335 if (mqi
[index
].hr
== S_OK
)
3340 IUnknown_Release(unk
);
3343 return E_NOINTERFACE
;
3345 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3348 /***********************************************************************
3349 * CoCreateInstanceEx [OLE32.@]
3351 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3353 LPUNKNOWN pUnkOuter
,
3355 COSERVERINFO
* pServerInfo
,
3359 IUnknown
*unk
= NULL
;
3365 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3367 if (!cmq
|| !pResults
)
3368 return E_INVALIDARG
;
3371 FIXME("() non-NULL pServerInfo not supported!\n");
3373 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3375 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3379 if (!(apt
= apartment_get_current_or_mta()))
3381 ERR("apartment not initialised\n");
3382 return CO_E_NOTINITIALIZED
;
3384 apartment_release(apt
);
3387 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3389 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3391 IGlobalInterfaceTable
*git
= get_std_git();
3392 TRACE("Retrieving GIT\n");
3393 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3396 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3397 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3400 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3404 * Get a class factory to construct the object we want.
3406 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3411 * Create the object and don't forget to release the factory
3413 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3414 IClassFactory_Release(cf
);
3417 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3418 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3420 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3421 debugstr_guid(pResults
[0].pIID
),
3422 debugstr_guid(&clsid
),hres
);
3426 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3429 /***********************************************************************
3430 * CoGetInstanceFromFile [OLE32.@]
3432 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3433 COSERVERINFO
*server_info
,
3443 IPersistFile
*pf
= NULL
;
3444 IUnknown
* unk
= NULL
;
3448 if (count
== 0 || !results
)
3449 return E_INVALIDARG
;
3452 FIXME("() non-NULL server_info not supported\n");
3454 init_multi_qi(count
, results
, E_NOINTERFACE
);
3456 /* optionally get CLSID from a file */
3459 hr
= GetClassFile(filename
, &clsid
);
3462 ERR("failed to get CLSID from a file\n");
3469 hr
= CoCreateInstance(rclsid
,
3477 init_multi_qi(count
, results
, hr
);
3481 /* init from file */
3482 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3485 init_multi_qi(count
, results
, hr
);
3486 IUnknown_Release(unk
);
3490 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3491 IPersistFile_Release(pf
);
3493 return return_multi_qi(unk
, count
, results
, FALSE
);
3496 init_multi_qi(count
, results
, hr
);
3497 IUnknown_Release(unk
);
3502 /***********************************************************************
3503 * CoGetInstanceFromIStorage [OLE32.@]
3505 HRESULT WINAPI
CoGetInstanceFromIStorage(
3506 COSERVERINFO
*server_info
,
3515 IPersistStorage
*ps
= NULL
;
3516 IUnknown
* unk
= NULL
;
3520 if (count
== 0 || !results
|| !storage
)
3521 return E_INVALIDARG
;
3524 FIXME("() non-NULL server_info not supported\n");
3526 init_multi_qi(count
, results
, E_NOINTERFACE
);
3528 /* optionally get CLSID from a file */
3531 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3532 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3535 ERR("failed to get CLSID from a file\n");
3539 rclsid
= &stat
.clsid
;
3542 hr
= CoCreateInstance(rclsid
,
3551 /* init from IStorage */
3552 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3554 ERR("failed to get IPersistStorage\n");
3558 IPersistStorage_Load(ps
, storage
);
3559 IPersistStorage_Release(ps
);
3562 return return_multi_qi(unk
, count
, results
, FALSE
);
3565 /***********************************************************************
3566 * CoLoadLibrary (OLE32.@)
3571 * lpszLibName [I] Path to library.
3572 * bAutoFree [I] Whether the library should automatically be freed.
3575 * Success: Handle to loaded library.
3579 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3581 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3583 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3585 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3588 /***********************************************************************
3589 * CoFreeLibrary [OLE32.@]
3591 * Unloads a library from memory.
3594 * hLibrary [I] Handle to library to unload.
3600 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3602 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3604 FreeLibrary(hLibrary
);
3608 /***********************************************************************
3609 * CoFreeAllLibraries [OLE32.@]
3611 * Function for backwards compatibility only. Does nothing.
3617 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3619 void WINAPI
CoFreeAllLibraries(void)
3624 /***********************************************************************
3625 * CoFreeUnusedLibrariesEx [OLE32.@]
3627 * Frees any previously unused libraries whose delay has expired and marks
3628 * currently unused libraries for unloading. Unused are identified as those that
3629 * return S_OK from their DllCanUnloadNow function.
3632 * dwUnloadDelay [I] Unload delay in milliseconds.
3633 * dwReserved [I] Reserved. Set to 0.
3639 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3641 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3643 struct apartment
*apt
= COM_CurrentApt();
3646 ERR("apartment not initialised\n");
3650 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3653 /***********************************************************************
3654 * CoFreeUnusedLibraries [OLE32.@]
3656 * Frees any unused libraries. Unused are identified as those that return
3657 * S_OK from their DllCanUnloadNow function.
3663 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3665 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3667 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3670 /***********************************************************************
3671 * CoFileTimeNow [OLE32.@]
3673 * Retrieves the current time in FILETIME format.
3676 * lpFileTime [O] The current time.
3681 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3683 GetSystemTimeAsFileTime( lpFileTime
);
3687 /******************************************************************************
3688 * CoLockObjectExternal [OLE32.@]
3690 * Increments or decrements the external reference count of a stub object.
3693 * pUnk [I] Stub object.
3694 * fLock [I] If TRUE then increments the external ref-count,
3695 * otherwise decrements.
3696 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3697 * calling CoDisconnectObject.
3701 * Failure: HRESULT code.
3704 * If fLock is TRUE and an object is passed in that doesn't have a stub
3705 * manager then a new stub manager is created for the object.
3707 HRESULT WINAPI
CoLockObjectExternal(
3710 BOOL fLastUnlockReleases
)
3712 struct stub_manager
*stubmgr
;
3713 struct apartment
*apt
;
3715 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3716 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3718 if (!(apt
= apartment_get_current_or_mta()))
3720 ERR("apartment not initialised\n");
3721 return CO_E_NOTINITIALIZED
;
3724 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3727 WARN("stub object not found %p\n", pUnk
);
3728 /* Note: native is pretty broken here because it just silently
3729 * fails, without returning an appropriate error code, making apps
3730 * think that the object was disconnected, when it actually wasn't */
3731 apartment_release(apt
);
3736 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3738 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3740 stub_manager_int_release(stubmgr
);
3741 apartment_release(apt
);
3745 /***********************************************************************
3746 * CoInitializeWOW (OLE32.@)
3748 * WOW equivalent of CoInitialize?
3757 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3759 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3763 /***********************************************************************
3764 * CoGetState [OLE32.@]
3766 * Retrieves the thread state object previously stored by CoSetState().
3769 * ppv [I] Address where pointer to object will be stored.
3773 * Failure: E_OUTOFMEMORY.
3776 * Crashes on all invalid ppv addresses, including NULL.
3777 * If the function returns a non-NULL object then the caller must release its
3778 * reference on the object when the object is no longer required.
3783 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3785 struct oletls
*info
= COM_CurrentInfo();
3786 if (!info
) return E_OUTOFMEMORY
;
3792 IUnknown_AddRef(info
->state
);
3794 TRACE("apt->state=%p\n", info
->state
);
3800 /***********************************************************************
3801 * CoSetState [OLE32.@]
3803 * Sets the thread state object.
3806 * pv [I] Pointer to state object to be stored.
3809 * The system keeps a reference on the object while the object stored.
3813 * Failure: E_OUTOFMEMORY.
3815 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3817 struct oletls
*info
= COM_CurrentInfo();
3818 if (!info
) return E_OUTOFMEMORY
;
3820 if (pv
) IUnknown_AddRef(pv
);
3824 TRACE("-- release %p now\n", info
->state
);
3825 IUnknown_Release(info
->state
);
3834 /******************************************************************************
3835 * CoTreatAsClass [OLE32.@]
3837 * Sets the TreatAs value of a class.
3840 * clsidOld [I] Class to set TreatAs value on.
3841 * clsidNew [I] The class the clsidOld should be treated as.
3845 * Failure: HRESULT code.
3850 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3852 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3853 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3855 WCHAR szClsidNew
[CHARS_IN_GUID
];
3857 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3858 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3861 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3865 if (IsEqualGUID( clsidOld
, clsidNew
))
3867 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3868 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3870 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3872 res
= REGDB_E_WRITEREGDB
;
3878 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3879 res
= REGDB_E_WRITEREGDB
;
3885 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3886 RegDeleteKeyW(hkey
, wszTreatAs
);
3888 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAY_SIZE(szClsidNew
))){
3889 WARN("StringFromGUID2 failed\n");
3894 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3895 WARN("RegSetValue failed\n");
3896 res
= REGDB_E_WRITEREGDB
;
3903 if (hkey
) RegCloseKey(hkey
);
3907 /******************************************************************************
3908 * CoGetTreatAsClass [OLE32.@]
3910 * Gets the TreatAs value of a class.
3913 * clsidOld [I] Class to get the TreatAs value of.
3914 * clsidNew [I] The class the clsidOld should be treated as.
3918 * Failure: HRESULT code.
3923 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3925 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3927 WCHAR szClsidNew
[CHARS_IN_GUID
];
3929 LONG len
= sizeof(szClsidNew
);
3931 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3933 if (!clsidOld
|| !clsidNew
)
3934 return E_INVALIDARG
;
3936 *clsidNew
= *clsidOld
; /* copy over old value */
3938 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3944 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3949 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3951 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3953 if (hkey
) RegCloseKey(hkey
);
3957 /******************************************************************************
3958 * CoGetCurrentProcess [OLE32.@]
3960 * Gets the current process ID.
3963 * The current process ID.
3966 * Is DWORD really the correct return type for this function?
3968 DWORD WINAPI
CoGetCurrentProcess(void)
3970 return GetCurrentProcessId();
3973 /***********************************************************************
3974 * CoGetCurrentLogicalThreadId [OLE32.@]
3976 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3978 TRACE("(%p)\n", id
);
3981 return E_INVALIDARG
;
3983 *id
= COM_CurrentCausalityId();
3987 /******************************************************************************
3988 * CoRegisterMessageFilter [OLE32.@]
3990 * Registers a message filter.
3993 * lpMessageFilter [I] Pointer to interface.
3994 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3998 * Failure: HRESULT code.
4001 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4002 * lpMessageFilter removes the message filter.
4004 * If lplpMessageFilter is not NULL the previous message filter will be
4005 * returned in the memory pointer to this parameter and the caller is
4006 * responsible for releasing the object.
4008 * The current thread be in an apartment otherwise the function will crash.
4010 HRESULT WINAPI
CoRegisterMessageFilter(
4011 LPMESSAGEFILTER lpMessageFilter
,
4012 LPMESSAGEFILTER
*lplpMessageFilter
)
4014 struct apartment
*apt
;
4015 IMessageFilter
*lpOldMessageFilter
;
4017 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
4019 apt
= COM_CurrentApt();
4021 /* can't set a message filter in a multi-threaded apartment */
4022 if (!apt
|| apt
->multi_threaded
)
4024 WARN("can't set message filter in MTA or uninitialized apt\n");
4025 return CO_E_NOT_SUPPORTED
;
4028 if (lpMessageFilter
)
4029 IMessageFilter_AddRef(lpMessageFilter
);
4031 EnterCriticalSection(&apt
->cs
);
4033 lpOldMessageFilter
= apt
->filter
;
4034 apt
->filter
= lpMessageFilter
;
4036 LeaveCriticalSection(&apt
->cs
);
4038 if (lplpMessageFilter
)
4039 *lplpMessageFilter
= lpOldMessageFilter
;
4040 else if (lpOldMessageFilter
)
4041 IMessageFilter_Release(lpOldMessageFilter
);
4046 /***********************************************************************
4047 * CoIsOle1Class [OLE32.@]
4049 * Determines whether the specified class an OLE v1 class.
4052 * clsid [I] Class to test.
4055 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4057 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
4059 FIXME("%s\n", debugstr_guid(clsid
));
4063 /***********************************************************************
4064 * IsEqualGUID [OLE32.@]
4066 * Compares two Unique Identifiers.
4069 * rguid1 [I] The first GUID to compare.
4070 * rguid2 [I] The other GUID to compare.
4076 BOOL WINAPI
IsEqualGUID(
4080 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
4083 /***********************************************************************
4084 * CoInitializeSecurity [OLE32.@]
4086 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4087 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4088 void* pReserved1
, DWORD dwAuthnLevel
,
4089 DWORD dwImpLevel
, void* pReserved2
,
4090 DWORD dwCapabilities
, void* pReserved3
)
4092 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4093 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4094 dwCapabilities
, pReserved3
);
4098 /***********************************************************************
4099 * CoSuspendClassObjects [OLE32.@]
4101 * Suspends all registered class objects to prevent further requests coming in
4102 * for those objects.
4106 * Failure: HRESULT code.
4108 HRESULT WINAPI
CoSuspendClassObjects(void)
4114 /***********************************************************************
4115 * CoAddRefServerProcess [OLE32.@]
4117 * Helper function for incrementing the reference count of a local-server
4121 * New reference count.
4124 * CoReleaseServerProcess().
4126 ULONG WINAPI
CoAddRefServerProcess(void)
4132 EnterCriticalSection(&csRegisteredClassList
);
4133 refs
= ++s_COMServerProcessReferences
;
4134 LeaveCriticalSection(&csRegisteredClassList
);
4136 TRACE("refs before: %d\n", refs
- 1);
4141 /***********************************************************************
4142 * CoReleaseServerProcess [OLE32.@]
4144 * Helper function for decrementing the reference count of a local-server
4148 * New reference count.
4151 * When reference count reaches 0, this function suspends all registered
4152 * classes so no new connections are accepted.
4155 * CoAddRefServerProcess(), CoSuspendClassObjects().
4157 ULONG WINAPI
CoReleaseServerProcess(void)
4163 EnterCriticalSection(&csRegisteredClassList
);
4165 refs
= --s_COMServerProcessReferences
;
4166 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4168 LeaveCriticalSection(&csRegisteredClassList
);
4170 TRACE("refs after: %d\n", refs
);
4175 /***********************************************************************
4176 * CoIsHandlerConnected [OLE32.@]
4178 * Determines whether a proxy is connected to a remote stub.
4181 * pUnk [I] Pointer to object that may or may not be connected.
4184 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4187 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4189 FIXME("%p\n", pUnk
);
4194 /***********************************************************************
4195 * CoAllowSetForegroundWindow [OLE32.@]
4198 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4200 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4204 /***********************************************************************
4205 * CoQueryProxyBlanket [OLE32.@]
4207 * Retrieves the security settings being used by a proxy.
4210 * pProxy [I] Pointer to the proxy object.
4211 * pAuthnSvc [O] The type of authentication service.
4212 * pAuthzSvc [O] The type of authorization service.
4213 * ppServerPrincName [O] Optional. The server prinicple name.
4214 * pAuthnLevel [O] The authentication level.
4215 * pImpLevel [O] The impersonation level.
4216 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4217 * pCapabilities [O] Flags affecting the security behaviour.
4221 * Failure: HRESULT code.
4224 * CoCopyProxy, CoSetProxyBlanket.
4226 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4227 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4228 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4230 IClientSecurity
*pCliSec
;
4233 TRACE("%p\n", pProxy
);
4235 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4238 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4239 pAuthzSvc
, ppServerPrincName
,
4240 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4242 IClientSecurity_Release(pCliSec
);
4245 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4249 /***********************************************************************
4250 * CoSetProxyBlanket [OLE32.@]
4252 * Sets the security settings for a proxy.
4255 * pProxy [I] Pointer to the proxy object.
4256 * AuthnSvc [I] The type of authentication service.
4257 * AuthzSvc [I] The type of authorization service.
4258 * pServerPrincName [I] The server prinicple name.
4259 * AuthnLevel [I] The authentication level.
4260 * ImpLevel [I] The impersonation level.
4261 * pAuthInfo [I] Information specific to the authorization/authentication service.
4262 * Capabilities [I] Flags affecting the security behaviour.
4266 * Failure: HRESULT code.
4269 * CoQueryProxyBlanket, CoCopyProxy.
4271 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4272 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4273 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4275 IClientSecurity
*pCliSec
;
4278 TRACE("%p\n", pProxy
);
4280 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4283 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4284 AuthzSvc
, pServerPrincName
,
4285 AuthnLevel
, ImpLevel
, pAuthInfo
,
4287 IClientSecurity_Release(pCliSec
);
4290 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4294 /***********************************************************************
4295 * CoCopyProxy [OLE32.@]
4300 * pProxy [I] Pointer to the proxy object.
4301 * ppCopy [O] Copy of the proxy.
4305 * Failure: HRESULT code.
4308 * CoQueryProxyBlanket, CoSetProxyBlanket.
4310 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4312 IClientSecurity
*pCliSec
;
4315 TRACE("%p\n", pProxy
);
4317 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4320 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4321 IClientSecurity_Release(pCliSec
);
4324 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4329 /***********************************************************************
4330 * CoGetCallContext [OLE32.@]
4332 * Gets the context of the currently executing server call in the current
4336 * riid [I] Context interface to return.
4337 * ppv [O] Pointer to memory that will receive the context on return.
4341 * Failure: HRESULT code.
4343 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4345 struct oletls
*info
= COM_CurrentInfo();
4347 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4350 return E_OUTOFMEMORY
;
4352 if (!info
->call_state
)
4353 return RPC_E_CALL_COMPLETE
;
4355 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4358 /***********************************************************************
4359 * CoSwitchCallContext [OLE32.@]
4361 * Switches the context of the currently executing server call in the current
4365 * pObject [I] Pointer to new context object
4366 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4370 * Failure: HRESULT code.
4372 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4374 struct oletls
*info
= COM_CurrentInfo();
4376 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4379 return E_OUTOFMEMORY
;
4381 *ppOldObject
= info
->call_state
;
4382 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4387 /***********************************************************************
4388 * CoQueryClientBlanket [OLE32.@]
4390 * Retrieves the authentication information about the client of the currently
4391 * executing server call in the current thread.
4394 * pAuthnSvc [O] Optional. The type of authentication service.
4395 * pAuthzSvc [O] Optional. The type of authorization service.
4396 * pServerPrincName [O] Optional. The server prinicple name.
4397 * pAuthnLevel [O] Optional. The authentication level.
4398 * pImpLevel [O] Optional. The impersonation level.
4399 * pPrivs [O] Optional. Information about the privileges of the client.
4400 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4404 * Failure: HRESULT code.
4407 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4409 HRESULT WINAPI
CoQueryClientBlanket(
4412 OLECHAR
**pServerPrincName
,
4415 RPC_AUTHZ_HANDLE
*pPrivs
,
4416 DWORD
*pCapabilities
)
4418 IServerSecurity
*pSrvSec
;
4421 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4422 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4423 pPrivs
, pCapabilities
);
4425 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4428 hr
= IServerSecurity_QueryBlanket(
4429 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4430 pImpLevel
, pPrivs
, pCapabilities
);
4431 IServerSecurity_Release(pSrvSec
);
4437 /***********************************************************************
4438 * CoImpersonateClient [OLE32.@]
4440 * Impersonates the client of the currently executing server call in the
4448 * Failure: HRESULT code.
4451 * If this function fails then the current thread will not be impersonating
4452 * the client and all actions will take place on behalf of the server.
4453 * Therefore, it is important to check the return value from this function.
4456 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4458 HRESULT WINAPI
CoImpersonateClient(void)
4460 IServerSecurity
*pSrvSec
;
4465 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4468 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4469 IServerSecurity_Release(pSrvSec
);
4475 /***********************************************************************
4476 * CoRevertToSelf [OLE32.@]
4478 * Ends the impersonation of the client of the currently executing server
4479 * call in the current thread.
4486 * Failure: HRESULT code.
4489 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4491 HRESULT WINAPI
CoRevertToSelf(void)
4493 IServerSecurity
*pSrvSec
;
4498 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4501 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4502 IServerSecurity_Release(pSrvSec
);
4508 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4510 /* first try to retrieve messages for incoming COM calls to the apartment window */
4511 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4512 /* next retrieve other messages necessary for the app to remain responsive */
4513 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4514 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4517 /***********************************************************************
4518 * CoWaitForMultipleHandles [OLE32.@]
4520 * Waits for one or more handles to become signaled.
4523 * dwFlags [I] Flags. See notes.
4524 * dwTimeout [I] Timeout in milliseconds.
4525 * cHandles [I] Number of handles pointed to by pHandles.
4526 * pHandles [I] Handles to wait for.
4527 * lpdwindex [O] Index of handle that was signaled.
4531 * Failure: RPC_S_CALLPENDING on timeout.
4535 * The dwFlags parameter can be zero or more of the following:
4536 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4537 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4540 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4542 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4543 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4546 DWORD start_time
= GetTickCount();
4547 APARTMENT
*apt
= COM_CurrentApt();
4548 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4549 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4550 BOOL post_quit
= FALSE
;
4553 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4554 pHandles
, lpdwindex
);
4557 return E_INVALIDARG
;
4562 return E_INVALIDARG
;
4565 return RPC_E_NO_SYNC
;
4569 DWORD now
= GetTickCount();
4572 if (now
- start_time
> dwTimeout
)
4574 hr
= RPC_S_CALLPENDING
;
4580 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4581 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4583 TRACE("waiting for rpc completion or window message\n");
4589 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4590 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4594 if (res
== WAIT_TIMEOUT
)
4595 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4596 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4597 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4599 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4604 /* call message filter */
4606 if (COM_CurrentApt()->filter
)
4608 PENDINGTYPE pendingtype
=
4609 COM_CurrentInfo()->pending_call_count_server
?
4610 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4611 DWORD be_handled
= IMessageFilter_MessagePending(
4612 COM_CurrentApt()->filter
, 0 /* FIXME */,
4613 now
- start_time
, pendingtype
);
4614 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4617 case PENDINGMSG_CANCELCALL
:
4618 WARN("call canceled\n");
4619 hr
= RPC_E_CALL_CANCELED
;
4621 case PENDINGMSG_WAITNOPROCESS
:
4622 case PENDINGMSG_WAITDEFPROCESS
:
4624 /* FIXME: MSDN is very vague about the difference
4625 * between WAITNOPROCESS and WAITDEFPROCESS - there
4626 * appears to be none, so it is possibly a left-over
4627 * from the 16-bit world. */
4634 /* If window is NULL on apartment, peek at messages so that it will not trigger
4635 * MsgWaitForMultipleObjects next time. */
4636 PeekMessageW(NULL
, NULL
, 0, 0, PM_QS_POSTMESSAGE
| PM_NOREMOVE
| PM_NOYIELD
);
4638 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4639 * so after processing 100 messages we go back to checking the wait handles */
4640 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4642 if (msg
.message
== WM_QUIT
)
4644 TRACE("received WM_QUIT message\n");
4646 exit_code
= msg
.wParam
;
4650 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4651 TranslateMessage(&msg
);
4652 DispatchMessageW(&msg
);
4660 TRACE("waiting for rpc completion\n");
4662 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4663 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4664 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4670 hr
= RPC_S_CALLPENDING
;
4673 hr
= HRESULT_FROM_WIN32( GetLastError() );
4681 if (post_quit
) PostQuitMessage(exit_code
);
4682 TRACE("-- 0x%08x\n", hr
);
4687 /***********************************************************************
4688 * CoGetObject [OLE32.@]
4690 * Gets the object named by converting the name to a moniker and binding to it.
4693 * pszName [I] String representing the object.
4694 * pBindOptions [I] Parameters affecting the binding to the named object.
4695 * riid [I] Interface to bind to on the objecct.
4696 * ppv [O] On output, the interface riid of the object represented
4701 * Failure: HRESULT code.
4704 * MkParseDisplayName.
4706 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4707 REFIID riid
, void **ppv
)
4714 hr
= CreateBindCtx(0, &pbc
);
4718 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4725 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4728 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4729 IMoniker_Release(pmk
);
4733 IBindCtx_Release(pbc
);
4738 /***********************************************************************
4739 * CoRegisterChannelHook [OLE32.@]
4741 * Registers a process-wide hook that is called during ORPC calls.
4744 * guidExtension [I] GUID of the channel hook to register.
4745 * pChannelHook [I] Channel hook object to register.
4749 * Failure: HRESULT code.
4751 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4753 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4755 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4758 typedef struct Context
4760 IComThreadingInfo IComThreadingInfo_iface
;
4761 IContextCallback IContextCallback_iface
;
4762 IObjContext IObjContext_iface
;
4766 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4768 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4771 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4773 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4776 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4778 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4781 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4785 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4786 IsEqualIID(riid
, &IID_IUnknown
))
4788 *ppv
= &iface
->IComThreadingInfo_iface
;
4790 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4792 *ppv
= &iface
->IContextCallback_iface
;
4794 else if (IsEqualIID(riid
, &IID_IObjContext
))
4796 *ppv
= &iface
->IObjContext_iface
;
4801 IUnknown_AddRef((IUnknown
*)*ppv
);
4805 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4806 return E_NOINTERFACE
;
4809 static ULONG
Context_AddRef(Context
*This
)
4811 return InterlockedIncrement(&This
->refs
);
4814 static ULONG
Context_Release(Context
*This
)
4816 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4817 releasing context while refcount is at 0 destroys it. */
4820 HeapFree(GetProcessHeap(), 0, This
);
4824 return InterlockedDecrement(&This
->refs
);
4827 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4829 Context
*This
= impl_from_IComThreadingInfo(iface
);
4830 return Context_QueryInterface(This
, riid
, ppv
);
4833 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4835 Context
*This
= impl_from_IComThreadingInfo(iface
);
4836 return Context_AddRef(This
);
4839 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4841 Context
*This
= impl_from_IComThreadingInfo(iface
);
4842 return Context_Release(This
);
4845 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4847 APTTYPEQUALIFIER qualifier
;
4849 TRACE("(%p)\n", apttype
);
4851 return CoGetApartmentType(apttype
, &qualifier
);
4854 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4856 APTTYPEQUALIFIER qualifier
;
4860 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4864 TRACE("(%p)\n", thdtype
);
4869 case APTTYPE_MAINSTA
:
4870 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4873 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4879 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4881 TRACE("(%p)\n", logical_thread_id
);
4882 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4885 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4887 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4891 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4893 Context_CTI_QueryInterface
,
4895 Context_CTI_Release
,
4896 Context_CTI_GetCurrentApartmentType
,
4897 Context_CTI_GetCurrentThreadType
,
4898 Context_CTI_GetCurrentLogicalThreadId
,
4899 Context_CTI_SetCurrentLogicalThreadId
4902 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4904 Context
*This
= impl_from_IContextCallback(iface
);
4905 return Context_QueryInterface(This
, riid
, ppv
);
4908 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4910 Context
*This
= impl_from_IContextCallback(iface
);
4911 return Context_AddRef(This
);
4914 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4916 Context
*This
= impl_from_IContextCallback(iface
);
4917 return Context_Release(This
);
4920 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4921 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4923 Context
*This
= impl_from_IContextCallback(iface
);
4925 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4929 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4931 Context_CC_QueryInterface
,
4934 Context_CC_ContextCallback
4937 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4939 Context
*This
= impl_from_IObjContext(iface
);
4940 return Context_QueryInterface(This
, riid
, ppv
);
4943 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4945 Context
*This
= impl_from_IObjContext(iface
);
4946 return Context_AddRef(This
);
4949 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4951 Context
*This
= impl_from_IObjContext(iface
);
4952 return Context_Release(This
);
4955 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4957 Context
*This
= impl_from_IObjContext(iface
);
4959 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4963 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4965 Context
*This
= impl_from_IObjContext(iface
);
4967 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4971 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4973 Context
*This
= impl_from_IObjContext(iface
);
4975 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4979 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4981 Context
*This
= impl_from_IObjContext(iface
);
4983 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4987 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4989 Context
*This
= impl_from_IObjContext(iface
);
4990 FIXME("(%p/%p)\n", This
, iface
);
4993 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4995 Context
*This
= impl_from_IObjContext(iface
);
4996 FIXME("(%p/%p)\n", This
, iface
);
4999 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
5001 Context
*This
= impl_from_IObjContext(iface
);
5002 FIXME("(%p/%p)\n", This
, iface
);
5005 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
5007 Context
*This
= impl_from_IObjContext(iface
);
5008 FIXME("(%p/%p)\n", This
, iface
);
5011 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
5013 Context
*This
= impl_from_IObjContext(iface
);
5014 FIXME("(%p/%p)\n", This
, iface
);
5017 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
5019 Context
*This
= impl_from_IObjContext(iface
);
5020 FIXME("(%p/%p)\n", This
, iface
);
5023 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
5025 Context
*This
= impl_from_IObjContext(iface
);
5026 FIXME("(%p/%p)\n", This
, iface
);
5029 static const IObjContextVtbl Context_Object_Vtbl
=
5031 Context_OC_QueryInterface
,
5034 Context_OC_SetProperty
,
5035 Context_OC_RemoveProperty
,
5036 Context_OC_GetProperty
,
5037 Context_OC_EnumContextProps
,
5038 Context_OC_Reserved1
,
5039 Context_OC_Reserved2
,
5040 Context_OC_Reserved3
,
5041 Context_OC_Reserved4
,
5042 Context_OC_Reserved5
,
5043 Context_OC_Reserved6
,
5044 Context_OC_Reserved7
5047 /***********************************************************************
5048 * CoGetObjectContext [OLE32.@]
5050 * Retrieves an object associated with the current context (i.e. apartment).
5053 * riid [I] ID of the interface of the object to retrieve.
5054 * ppv [O] Address where object will be stored on return.
5058 * Failure: HRESULT code.
5060 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
5062 IObjContext
*context
;
5065 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
5068 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
5072 return IObjContext_QueryInterface(context
, riid
, ppv
);
5075 /***********************************************************************
5076 * CoGetContextToken [OLE32.@]
5078 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
5080 struct oletls
*info
= COM_CurrentInfo();
5083 TRACE("(%p)\n", token
);
5086 return E_OUTOFMEMORY
;
5088 if (!(apt
= apartment_get_current_or_mta()))
5090 ERR("apartment not initialised\n");
5091 return CO_E_NOTINITIALIZED
;
5093 apartment_release(apt
);
5098 if (!info
->context_token
)
5102 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5104 return E_OUTOFMEMORY
;
5106 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5107 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5108 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5109 /* Context token does not take a reference, it's always zero until the
5110 interface is explicitly requested with CoGetObjectContext(). */
5113 info
->context_token
= &context
->IObjContext_iface
;
5116 *token
= (ULONG_PTR
)info
->context_token
;
5117 TRACE("context_token=%p\n", info
->context_token
);
5122 /***********************************************************************
5123 * CoGetDefaultContext [OLE32.@]
5125 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5127 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5128 return E_NOINTERFACE
;
5131 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5133 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5137 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5138 if (SUCCEEDED(hres
))
5140 struct class_reg_data regdata
;
5141 WCHAR dllpath
[MAX_PATH
+1];
5143 regdata
.u
.hkey
= hkey
;
5144 regdata
.hkey
= TRUE
;
5146 if (get_object_dll_path(®data
, dllpath
, ARRAY_SIZE(dllpath
)))
5148 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5149 if (!strcmpiW(dllpath
, wszOle32
))
5152 return HandlerCF_Create(rclsid
, riid
, ppv
);
5156 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5160 return CLASS_E_CLASSNOTAVAILABLE
;
5163 /***********************************************************************
5164 * CoGetApartmentType [OLE32.@]
5166 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5168 struct oletls
*info
= COM_CurrentInfo();
5171 TRACE("(%p, %p)\n", type
, qualifier
);
5173 if (!type
|| !qualifier
)
5174 return E_INVALIDARG
;
5177 return E_OUTOFMEMORY
;
5180 *type
= APTTYPE_CURRENT
;
5181 else if (info
->apt
->multi_threaded
)
5182 *type
= APTTYPE_MTA
;
5183 else if (info
->apt
->main
)
5184 *type
= APTTYPE_MAINSTA
;
5186 *type
= APTTYPE_STA
;
5188 *qualifier
= APTTYPEQUALIFIER_NONE
;
5190 if (!info
->apt
&& (apt
= apartment_find_mta()))
5192 apartment_release(apt
);
5193 *type
= APTTYPE_MTA
;
5194 *qualifier
= APTTYPEQUALIFIER_IMPLICIT_MTA
;
5197 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5200 /***********************************************************************
5201 * CoRegisterSurrogate [OLE32.@]
5203 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5205 FIXME("(%p): stub\n", surrogate
);
5210 /***********************************************************************
5211 * CoRegisterSurrogateEx [OLE32.@]
5213 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5215 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5221 IGlobalOptions IGlobalOptions_iface
;
5225 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5227 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5230 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5232 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5234 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5236 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5243 return E_NOINTERFACE
;
5246 IUnknown_AddRef((IUnknown
*)*ppv
);
5250 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5252 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5253 LONG ref
= InterlockedIncrement(&This
->ref
);
5255 TRACE("(%p) ref=%d\n", This
, ref
);
5260 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5262 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5263 LONG ref
= InterlockedDecrement(&This
->ref
);
5265 TRACE("(%p) ref=%d\n", This
, ref
);
5273 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5275 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5276 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5280 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5282 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5283 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5287 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5288 GlobalOptions_QueryInterface
,
5289 GlobalOptions_AddRef
,
5290 GlobalOptions_Release
,
5295 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5297 GlobalOptions
*global_options
;
5300 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5303 return E_INVALIDARG
;
5305 global_options
= heap_alloc(sizeof(*global_options
));
5306 if (!global_options
)
5307 return E_OUTOFMEMORY
;
5308 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5309 global_options
->ref
= 1;
5311 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5312 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5316 /***********************************************************************
5319 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5321 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5324 case DLL_PROCESS_ATTACH
:
5325 hProxyDll
= hinstDLL
;
5328 case DLL_PROCESS_DETACH
:
5329 if (reserved
) break;
5332 UnregisterClassW( (const WCHAR
*)MAKEINTATOM(apt_win_class
), hProxyDll
);
5333 RPC_UnregisterAllChannelHooks();
5334 COMPOBJ_DllList_Free();
5335 DeleteCriticalSection(&csRegisteredClassList
);
5336 DeleteCriticalSection(&csApartment
);
5339 case DLL_THREAD_DETACH
:
5346 /***********************************************************************
5347 * DllRegisterServer (OLE32.@)
5349 HRESULT WINAPI
DllRegisterServer(void)
5351 return OLE32_DllRegisterServer();
5354 /***********************************************************************
5355 * DllUnregisterServer (OLE32.@)
5357 HRESULT WINAPI
DllUnregisterServer(void)
5359 return OLE32_DllUnregisterServer();