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 if (info
->apt
) apartment_release(info
->apt
);
1742 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1743 if (info
->state
) IUnknown_Release(info
->state
);
1744 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1745 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1746 HeapFree(GetProcessHeap(), 0, info
);
1747 NtCurrentTeb()->ReservedForOle
= NULL
;
1751 /******************************************************************************
1752 * CoBuildVersion [OLE32.@]
1754 * Gets the build version of the DLL.
1759 * Current build version, hiword is majornumber, loword is minornumber
1761 DWORD WINAPI
CoBuildVersion(void)
1763 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1764 return (rmm
<<16)+rup
;
1767 /******************************************************************************
1768 * CoRegisterInitializeSpy [OLE32.@]
1770 * Add a Spy that watches CoInitializeEx calls
1773 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1774 * cookie [II] cookie receiver
1777 * Success: S_OK if not already initialized, S_FALSE otherwise.
1778 * Failure: HRESULT code.
1783 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1785 struct oletls
*info
= COM_CurrentInfo();
1788 TRACE("(%p, %p)\n", spy
, cookie
);
1790 if (!spy
|| !cookie
|| !info
)
1793 WARN("Could not allocate tls\n");
1794 return E_INVALIDARG
;
1799 FIXME("Already registered?\n");
1800 return E_UNEXPECTED
;
1803 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1806 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1812 /******************************************************************************
1813 * CoRevokeInitializeSpy [OLE32.@]
1815 * Remove a spy that previously watched CoInitializeEx calls
1818 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1821 * Success: S_OK if a spy is removed
1822 * Failure: E_INVALIDARG
1827 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1829 struct oletls
*info
= COM_CurrentInfo();
1830 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1832 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1833 return E_INVALIDARG
;
1835 IInitializeSpy_Release(info
->spy
);
1840 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1846 if (!apartment_get_or_create( model
))
1847 return E_OUTOFMEMORY
;
1849 else if (!apartment_is_model( info
->apt
, model
))
1851 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1852 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1853 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1854 return RPC_E_CHANGED_MODE
;
1864 void leave_apartment( struct oletls
*info
)
1868 if (info
->ole_inits
)
1869 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1870 apartment_release( info
->apt
);
1875 /******************************************************************************
1876 * CoInitialize [OLE32.@]
1878 * Initializes the COM libraries by calling CoInitializeEx with
1879 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1882 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1885 * Success: S_OK if not already initialized, S_FALSE otherwise.
1886 * Failure: HRESULT code.
1891 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1894 * Just delegate to the newer method.
1896 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1899 /******************************************************************************
1900 * CoInitializeEx [OLE32.@]
1902 * Initializes the COM libraries.
1905 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1906 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1909 * S_OK if successful,
1910 * S_FALSE if this function was called already.
1911 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1916 * The behavior used to set the IMalloc used for memory management is
1918 * The dwCoInit parameter must specify one of the following apartment
1920 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1921 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1922 * The parameter may also specify zero or more of the following flags:
1923 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1924 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1929 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1931 struct oletls
*info
= COM_CurrentInfo();
1934 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1936 if (lpReserved
!=NULL
)
1938 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1942 * Check the lock count. If this is the first time going through the initialize
1943 * process, we have to initialize the libraries.
1945 * And crank-up that lock count.
1947 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1950 * Initialize the various COM libraries and data structures.
1952 TRACE("() - Initializing the COM libraries\n");
1954 /* we may need to defer this until after apartment initialisation */
1955 RunningObjectTableImpl_Initialize();
1959 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1961 hr
= enter_apartment( info
, dwCoInit
);
1964 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1969 /***********************************************************************
1970 * CoUninitialize [OLE32.@]
1972 * This method will decrement the refcount on the current apartment, freeing
1973 * the resources associated with it if it is the last thread in the apartment.
1974 * If the last apartment is freed, the function will additionally release
1975 * any COM resources associated with the process.
1985 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1987 struct oletls
* info
= COM_CurrentInfo();
1992 /* will only happen on OOM */
1996 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
2001 ERR("Mismatched CoUninitialize\n");
2004 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2008 leave_apartment( info
);
2011 * Decrease the reference count.
2012 * If we are back to 0 locks on the COM library, make sure we free
2013 * all the associated data structures.
2015 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2018 TRACE("() - Releasing the COM libraries\n");
2020 revoke_registered_psclsids();
2021 RunningObjectTableImpl_UnInitialize();
2023 else if (lCOMRefCnt
<1) {
2024 ERR( "CoUninitialize() - not CoInitialized.\n" );
2025 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2028 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2031 /******************************************************************************
2032 * CoDisconnectObject [OLE32.@]
2034 * Disconnects all connections to this object from remote processes. Dispatches
2035 * pending RPCs while blocking new RPCs from occurring, and then calls
2036 * IMarshal::DisconnectObject on the given object.
2038 * Typically called when the object server is forced to shut down, for instance by
2042 * lpUnk [I] The object whose stub should be disconnected.
2043 * reserved [I] Reserved. Should be set to 0.
2047 * Failure: HRESULT code.
2050 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2052 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2054 struct stub_manager
*manager
;
2059 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2061 if (!lpUnk
) return E_INVALIDARG
;
2063 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2066 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2067 IMarshal_Release(marshal
);
2071 if (!(apt
= apartment_get_current_or_mta()))
2073 ERR("apartment not initialised\n");
2074 return CO_E_NOTINITIALIZED
;
2077 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2079 stub_manager_disconnect(manager
);
2080 /* Release stub manager twice, to remove the apartment reference. */
2081 stub_manager_int_release(manager
);
2082 stub_manager_int_release(manager
);
2085 /* Note: native is pretty broken here because it just silently
2086 * fails, without returning an appropriate error code if the object was
2087 * not found, making apps think that the object was disconnected, when
2088 * it actually wasn't */
2090 apartment_release(apt
);
2094 /******************************************************************************
2095 * CoCreateGuid [OLE32.@]
2097 * Simply forwards to UuidCreate in RPCRT4.
2100 * pguid [O] Points to the GUID to initialize.
2104 * Failure: HRESULT code.
2109 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2113 if(!pguid
) return E_INVALIDARG
;
2115 status
= UuidCreate(pguid
);
2116 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2117 return HRESULT_FROM_WIN32( status
);
2120 static inline BOOL
is_valid_hex(WCHAR c
)
2122 if (!(((c
>= '0') && (c
<= '9')) ||
2123 ((c
>= 'a') && (c
<= 'f')) ||
2124 ((c
>= 'A') && (c
<= 'F'))))
2129 static const BYTE guid_conv_table
[256] =
2131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2134 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2135 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2137 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2140 /* conversion helper for CLSIDFromString/IIDFromString */
2141 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2145 if (!s
|| s
[0]!='{') {
2146 memset( id
, 0, sizeof (CLSID
) );
2151 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2153 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2156 for (i
= 1; i
< 9; i
++) {
2157 if (!is_valid_hex(s
[i
])) return FALSE
;
2158 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2160 if (s
[9]!='-') return FALSE
;
2163 for (i
= 10; i
< 14; i
++) {
2164 if (!is_valid_hex(s
[i
])) return FALSE
;
2165 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2167 if (s
[14]!='-') return FALSE
;
2170 for (i
= 15; i
< 19; i
++) {
2171 if (!is_valid_hex(s
[i
])) return FALSE
;
2172 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2174 if (s
[19]!='-') return FALSE
;
2176 for (i
= 20; i
< 37; i
+=2) {
2178 if (s
[i
]!='-') return FALSE
;
2181 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2182 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2185 if (s
[37] == '}' && s
[38] == '\0')
2191 /*****************************************************************************/
2193 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2195 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2196 WCHAR buf2
[CHARS_IN_GUID
];
2197 LONG buf2len
= sizeof(buf2
);
2201 memset(clsid
, 0, sizeof(*clsid
));
2202 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2203 if (!buf
) return E_OUTOFMEMORY
;
2204 strcpyW( buf
, progid
);
2205 strcatW( buf
, clsidW
);
2206 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2208 HeapFree(GetProcessHeap(),0,buf
);
2209 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2210 return CO_E_CLASSSTRING
;
2212 HeapFree(GetProcessHeap(),0,buf
);
2214 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2217 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2218 return CO_E_CLASSSTRING
;
2221 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2224 /******************************************************************************
2225 * CLSIDFromString [OLE32.@]
2227 * Converts a unique identifier from its string representation into
2231 * idstr [I] The string representation of the GUID.
2232 * id [O] GUID converted from the string.
2236 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2241 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2243 HRESULT ret
= CO_E_CLASSSTRING
;
2247 return E_INVALIDARG
;
2249 if (guid_from_string(idstr
, id
))
2252 /* It appears a ProgID is also valid */
2253 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2260 /******************************************************************************
2261 * IIDFromString [OLE32.@]
2263 * Converts an interface identifier from its string representation to
2267 * idstr [I] The string representation of the GUID.
2268 * id [O] IID converted from the string.
2272 * CO_E_IIDSTRING if idstr is not a valid IID
2277 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2279 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2283 memset(iid
, 0, sizeof(*iid
));
2287 /* length mismatch is a special case */
2288 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2289 return E_INVALIDARG
;
2292 return CO_E_IIDSTRING
;
2294 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2297 /******************************************************************************
2298 * StringFromCLSID [OLE32.@]
2299 * StringFromIID [OLE32.@]
2301 * Converts a GUID into the respective string representation.
2302 * The target string is allocated using the OLE IMalloc.
2305 * id [I] the GUID to be converted.
2306 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2313 * StringFromGUID2, CLSIDFromString
2315 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2317 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2318 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2322 /******************************************************************************
2323 * StringFromGUID2 [OLE32.@]
2325 * Modified version of StringFromCLSID that allows you to specify max
2329 * id [I] GUID to convert to string.
2330 * str [O] Buffer where the result will be stored.
2331 * cmax [I] Size of the buffer in characters.
2334 * Success: The length of the resulting string in characters.
2337 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2339 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2340 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2341 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2342 '%','0','2','X','%','0','2','X','}',0 };
2343 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2344 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2345 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2346 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2347 return CHARS_IN_GUID
;
2350 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2351 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2353 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2354 WCHAR path
[CHARS_IN_GUID
+ ARRAY_SIZE(wszCLSIDSlash
) - 1];
2358 strcpyW(path
, wszCLSIDSlash
);
2359 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2360 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2361 if (res
== ERROR_FILE_NOT_FOUND
)
2362 return REGDB_E_CLASSNOTREG
;
2363 else if (res
!= ERROR_SUCCESS
)
2364 return REGDB_E_READREGDB
;
2372 res
= open_classes_key(key
, keyname
, access
, subkey
);
2374 if (res
== ERROR_FILE_NOT_FOUND
)
2375 return REGDB_E_KEYMISSING
;
2376 else if (res
!= ERROR_SUCCESS
)
2377 return REGDB_E_READREGDB
;
2382 /* open HKCR\\AppId\\{string form of appid clsid} key */
2383 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2385 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2386 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2388 WCHAR buf
[CHARS_IN_GUID
];
2389 WCHAR keyname
[ARRAY_SIZE(szAppIdKey
) + CHARS_IN_GUID
];
2395 /* read the AppID value under the class's key */
2396 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2401 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2403 if (res
== ERROR_FILE_NOT_FOUND
)
2404 return REGDB_E_KEYMISSING
;
2405 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2406 return REGDB_E_READREGDB
;
2408 strcpyW(keyname
, szAppIdKey
);
2409 strcatW(keyname
, buf
);
2410 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2411 if (res
== ERROR_FILE_NOT_FOUND
)
2412 return REGDB_E_KEYMISSING
;
2413 else if (res
!= ERROR_SUCCESS
)
2414 return REGDB_E_READREGDB
;
2419 /******************************************************************************
2420 * ProgIDFromCLSID [OLE32.@]
2422 * Converts a class id into the respective program ID.
2425 * clsid [I] Class ID, as found in registry.
2426 * ppszProgID [O] Associated ProgID.
2431 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2433 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2435 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2436 ACTCTX_SECTION_KEYED_DATA data
;
2442 return E_INVALIDARG
;
2446 data
.cbSize
= sizeof(data
);
2447 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2450 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2451 if (comclass
->progid_len
)
2455 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2456 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2458 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2459 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2463 return REGDB_E_CLASSNOTREG
;
2466 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2470 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2471 ret
= REGDB_E_CLASSNOTREG
;
2475 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2478 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2479 ret
= REGDB_E_CLASSNOTREG
;
2480 CoTaskMemFree(*ppszProgID
);
2485 ret
= E_OUTOFMEMORY
;
2492 /******************************************************************************
2493 * CLSIDFromProgID [OLE32.@]
2495 * Converts a program id into the respective GUID.
2498 * progid [I] Unicode program ID, as found in registry.
2499 * clsid [O] Associated CLSID.
2503 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2505 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2507 ACTCTX_SECTION_KEYED_DATA data
;
2509 if (!progid
|| !clsid
)
2510 return E_INVALIDARG
;
2512 data
.cbSize
= sizeof(data
);
2513 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2516 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2517 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2522 return clsid_from_string_reg(progid
, clsid
);
2525 /******************************************************************************
2526 * CLSIDFromProgIDEx [OLE32.@]
2528 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2530 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2532 return CLSIDFromProgID(progid
, clsid
);
2535 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2538 WCHAR value
[CHARS_IN_GUID
];
2543 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2544 return REGDB_E_IIDNOTREG
;
2546 len
= sizeof(value
);
2547 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2548 return REGDB_E_IIDNOTREG
;
2551 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2552 return REGDB_E_IIDNOTREG
;
2557 /*****************************************************************************
2558 * CoGetPSClsid [OLE32.@]
2560 * Retrieves the CLSID of the proxy/stub factory that implements
2561 * IPSFactoryBuffer for the specified interface.
2564 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2565 * pclsid [O] Where to store returned proxy/stub CLSID.
2570 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2574 * The standard marshaller activates the object with the CLSID
2575 * returned and uses the CreateProxy and CreateStub methods on its
2576 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2579 * CoGetPSClsid determines this CLSID by searching the
2580 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2581 * in the registry and any interface id registered by
2582 * CoRegisterPSClsid within the current process.
2586 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2587 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2588 * considered a bug in native unless an application depends on this (unlikely).
2591 * CoRegisterPSClsid.
2593 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2595 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2596 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2597 WCHAR path
[ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAY_SIZE(wszPSC
)];
2599 struct registered_psclsid
*registered_psclsid
;
2600 ACTCTX_SECTION_KEYED_DATA data
;
2602 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2605 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2607 if (!(apt
= apartment_get_current_or_mta()))
2609 ERR("apartment not initialised\n");
2610 return CO_E_NOTINITIALIZED
;
2612 apartment_release(apt
);
2615 return E_INVALIDARG
;
2617 EnterCriticalSection(&cs_registered_psclsid_list
);
2619 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2620 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2622 *pclsid
= registered_psclsid
->clsid
;
2623 LeaveCriticalSection(&cs_registered_psclsid_list
);
2627 LeaveCriticalSection(&cs_registered_psclsid_list
);
2629 data
.cbSize
= sizeof(data
);
2630 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2633 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2634 *pclsid
= ifaceps
->iid
;
2638 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2639 strcpyW(path
, wszInterface
);
2640 StringFromGUID2(riid
, path
+ ARRAY_SIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2641 strcpyW(path
+ ARRAY_SIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2643 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2644 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2645 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2646 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2649 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2651 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2656 /*****************************************************************************
2657 * CoRegisterPSClsid [OLE32.@]
2659 * Register a proxy/stub CLSID for the given interface in the current process
2663 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2664 * rclsid [I] CLSID of the proxy/stub.
2668 * Failure: E_OUTOFMEMORY
2672 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2673 * will be returned from other apartments in the same process.
2675 * This function does not add anything to the registry and the effects are
2676 * limited to the lifetime of the current process.
2681 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2684 struct registered_psclsid
*registered_psclsid
;
2686 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2688 if (!(apt
= apartment_get_current_or_mta()))
2690 ERR("apartment not initialised\n");
2691 return CO_E_NOTINITIALIZED
;
2693 apartment_release(apt
);
2695 EnterCriticalSection(&cs_registered_psclsid_list
);
2697 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2698 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2700 registered_psclsid
->clsid
= *rclsid
;
2701 LeaveCriticalSection(&cs_registered_psclsid_list
);
2705 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2706 if (!registered_psclsid
)
2708 LeaveCriticalSection(&cs_registered_psclsid_list
);
2709 return E_OUTOFMEMORY
;
2712 registered_psclsid
->iid
= *riid
;
2713 registered_psclsid
->clsid
= *rclsid
;
2714 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2716 LeaveCriticalSection(&cs_registered_psclsid_list
);
2723 * COM_GetRegisteredClassObject
2725 * This internal method is used to scan the registered class list to
2726 * find a class object.
2729 * rclsid Class ID of the class to find.
2730 * dwClsContext Class context to match.
2731 * ppv [out] returns a pointer to the class object. Complying
2732 * to normal COM usage, this method will increase the
2733 * reference count on this object.
2735 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2736 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2738 HRESULT hr
= S_FALSE
;
2739 RegisteredClass
*curClass
;
2741 EnterCriticalSection( &csRegisteredClassList
);
2743 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2746 * Check if we have a match on the class ID and context.
2748 if ((apt
->oxid
== curClass
->apartment_id
) &&
2749 (dwClsContext
& curClass
->runContext
) &&
2750 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2753 * We have a match, return the pointer to the class object.
2755 *ppUnk
= curClass
->classObject
;
2757 IUnknown_AddRef(curClass
->classObject
);
2764 LeaveCriticalSection( &csRegisteredClassList
);
2769 /******************************************************************************
2770 * CoRegisterClassObject [OLE32.@]
2772 * Registers the class object for a given class ID. Servers housed in EXE
2773 * files use this method instead of exporting DllGetClassObject to allow
2774 * other code to connect to their objects.
2777 * rclsid [I] CLSID of the object to register.
2778 * pUnk [I] IUnknown of the object.
2779 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2780 * flags [I] REGCLS flags indicating how connections are made.
2781 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2785 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2786 * CO_E_OBJISREG if the object is already registered. We should not return this.
2789 * CoRevokeClassObject, CoGetClassObject
2792 * In-process objects are only registered for the current apartment.
2793 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2794 * in other apartments.
2797 * MSDN claims that multiple interface registrations are legal, but we
2798 * can't do that with our current implementation.
2800 HRESULT WINAPI
CoRegisterClassObject(
2805 LPDWORD lpdwRegister
)
2807 static LONG next_cookie
;
2808 RegisteredClass
* newClass
;
2809 LPUNKNOWN foundObject
;
2813 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2814 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2816 if ( (lpdwRegister
==0) || (pUnk
==0) )
2817 return E_INVALIDARG
;
2819 if (!(apt
= apartment_get_current_or_mta()))
2821 ERR("COM was not initialized\n");
2822 return CO_E_NOTINITIALIZED
;
2827 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2828 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2829 if (flags
& REGCLS_MULTIPLEUSE
)
2830 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2833 * First, check if the class is already registered.
2834 * If it is, this should cause an error.
2836 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2838 if (flags
& REGCLS_MULTIPLEUSE
) {
2839 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2840 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2841 IUnknown_Release(foundObject
);
2842 apartment_release(apt
);
2845 IUnknown_Release(foundObject
);
2846 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2847 apartment_release(apt
);
2848 return CO_E_OBJISREG
;
2851 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2852 if ( newClass
== NULL
)
2854 apartment_release(apt
);
2855 return E_OUTOFMEMORY
;
2858 newClass
->classIdentifier
= *rclsid
;
2859 newClass
->apartment_id
= apt
->oxid
;
2860 newClass
->runContext
= dwClsContext
;
2861 newClass
->connectFlags
= flags
;
2862 newClass
->RpcRegistration
= NULL
;
2864 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2865 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2868 * Since we're making a copy of the object pointer, we have to increase its
2871 newClass
->classObject
= pUnk
;
2872 IUnknown_AddRef(newClass
->classObject
);
2874 EnterCriticalSection( &csRegisteredClassList
);
2875 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2876 LeaveCriticalSection( &csRegisteredClassList
);
2878 *lpdwRegister
= newClass
->dwCookie
;
2880 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2881 IStream
*marshal_stream
;
2883 hr
= get_local_server_stream(apt
, &marshal_stream
);
2886 apartment_release(apt
);
2890 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2892 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2893 &newClass
->RpcRegistration
);
2894 IStream_Release(marshal_stream
);
2896 apartment_release(apt
);
2900 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2904 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2905 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2906 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2907 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2908 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2909 DWORD dwLength
= sizeof(threading_model
);
2913 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2914 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2915 threading_model
[0] = '\0';
2917 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2918 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2919 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2921 /* there's not specific handling for this case */
2922 if (threading_model
[0]) return ThreadingModel_Neutral
;
2923 return ThreadingModel_No
;
2926 return data
->u
.actctx
.data
->model
;
2929 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2930 REFCLSID rclsid
, REFIID riid
,
2931 BOOL hostifnecessary
, void **ppv
)
2933 WCHAR dllpath
[MAX_PATH
+1];
2934 BOOL apartment_threaded
;
2936 if (hostifnecessary
)
2938 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2940 if (model
== ThreadingModel_Apartment
)
2942 apartment_threaded
= TRUE
;
2943 if (apt
->multi_threaded
)
2944 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2946 else if (model
== ThreadingModel_Free
)
2948 apartment_threaded
= FALSE
;
2949 if (!apt
->multi_threaded
)
2950 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2952 /* everything except "Apartment", "Free" and "Both" */
2953 else if (model
!= ThreadingModel_Both
)
2955 apartment_threaded
= TRUE
;
2956 /* everything else is main-threaded */
2957 if (model
!= ThreadingModel_No
)
2958 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2960 if (apt
->multi_threaded
|| !apt
->main
)
2961 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2964 apartment_threaded
= FALSE
;
2967 apartment_threaded
= !apt
->multi_threaded
;
2969 if (!get_object_dll_path(regdata
, dllpath
, ARRAY_SIZE(dllpath
)))
2971 /* failure: CLSID is not found in registry */
2972 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2973 return REGDB_E_CLASSNOTREG
;
2976 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2980 /***********************************************************************
2981 * CoGetClassObject [OLE32.@]
2983 * Creates an object of the specified class.
2986 * rclsid [I] Class ID to create an instance of.
2987 * dwClsContext [I] Flags to restrict the location of the created instance.
2988 * pServerInfo [I] Optional. Details for connecting to a remote server.
2989 * iid [I] The ID of the interface of the instance to return.
2990 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2994 * Failure: HRESULT code.
2997 * The dwClsContext parameter can be one or more of the following:
2998 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2999 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3000 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3001 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3004 * CoCreateInstance()
3006 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
3007 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
3008 REFIID iid
, LPVOID
*ppv
)
3010 struct class_reg_data clsreg
;
3011 IUnknown
*regClassObject
;
3012 HRESULT hres
= E_UNEXPECTED
;
3015 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
3018 return E_INVALIDARG
;
3022 if (!(apt
= apartment_get_current_or_mta()))
3024 ERR("apartment not initialised\n");
3025 return CO_E_NOTINITIALIZED
;
3029 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3030 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3033 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3035 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3037 apartment_release(apt
);
3038 return FTMarshalCF_Create(iid
, ppv
);
3040 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3041 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3044 if (CLSCTX_INPROC
& dwClsContext
)
3046 ACTCTX_SECTION_KEYED_DATA data
;
3048 data
.cbSize
= sizeof(data
);
3049 /* search activation context first */
3050 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3051 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3054 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3056 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3057 clsreg
.u
.actctx
.data
= data
.lpData
;
3058 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3059 clsreg
.hkey
= FALSE
;
3061 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3062 ReleaseActCtx(data
.hActCtx
);
3063 apartment_release(apt
);
3069 * First, try and see if we can't match the class ID with one of the
3070 * registered classes.
3072 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3075 /* Get the required interface from the retrieved pointer. */
3076 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3079 * Since QI got another reference on the pointer, we want to release the
3080 * one we already have. If QI was unsuccessful, this will release the object. This
3081 * is good since we are not returning it in the "out" parameter.
3083 IUnknown_Release(regClassObject
);
3084 apartment_release(apt
);
3088 /* First try in-process server */
3089 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3091 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3094 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3097 if (hres
== REGDB_E_CLASSNOTREG
)
3098 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3099 else if (hres
== REGDB_E_KEYMISSING
)
3101 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3102 hres
= REGDB_E_CLASSNOTREG
;
3106 if (SUCCEEDED(hres
))
3108 clsreg
.u
.hkey
= hkey
;
3111 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3115 /* return if we got a class, otherwise fall through to one of the
3117 if (SUCCEEDED(hres
))
3119 apartment_release(apt
);
3124 /* Next try in-process handler */
3125 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3127 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3130 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3133 if (hres
== REGDB_E_CLASSNOTREG
)
3134 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3135 else if (hres
== REGDB_E_KEYMISSING
)
3137 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3138 hres
= REGDB_E_CLASSNOTREG
;
3142 if (SUCCEEDED(hres
))
3144 clsreg
.u
.hkey
= hkey
;
3147 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3151 /* return if we got a class, otherwise fall through to one of the
3153 if (SUCCEEDED(hres
))
3155 apartment_release(apt
);
3159 apartment_release(apt
);
3161 /* Next try out of process */
3162 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3164 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3165 if (SUCCEEDED(hres
))
3169 /* Finally try remote: this requires networked DCOM (a lot of work) */
3170 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3172 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3173 hres
= REGDB_E_CLASSNOTREG
;
3177 ERR("no class object %s could be created for context 0x%x\n",
3178 debugstr_guid(rclsid
), dwClsContext
);
3182 /***********************************************************************
3183 * CoResumeClassObjects (OLE32.@)
3185 * Resumes all class objects registered with REGCLS_SUSPENDED.
3189 * Failure: HRESULT code.
3191 HRESULT WINAPI
CoResumeClassObjects(void)
3197 /***********************************************************************
3198 * CoCreateInstance [OLE32.@]
3200 * Creates an instance of the specified class.
3203 * rclsid [I] Class ID to create an instance of.
3204 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3205 * dwClsContext [I] Flags to restrict the location of the created instance.
3206 * iid [I] The ID of the interface of the instance to return.
3207 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3211 * Failure: HRESULT code.
3214 * The dwClsContext parameter can be one or more of the following:
3215 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3216 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3217 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3218 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3220 * Aggregation is the concept of deferring the IUnknown of an object to another
3221 * object. This allows a separate object to behave as though it was part of
3222 * the object and to allow this the pUnkOuter parameter can be set. Note that
3223 * not all objects support having an outer of unknown.
3226 * CoGetClassObject()
3228 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3230 LPUNKNOWN pUnkOuter
,
3235 MULTI_QI multi_qi
= { iid
};
3238 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3239 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3244 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3245 *ppv
= multi_qi
.pItf
;
3249 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3253 for (i
= 0; i
< count
; i
++)
3260 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3262 ULONG index
= 0, fetched
= 0;
3268 index
= fetched
= 1;
3271 for (; index
< count
; index
++)
3273 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3274 if (mqi
[index
].hr
== S_OK
)
3279 IUnknown_Release(unk
);
3282 return E_NOINTERFACE
;
3284 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3287 /***********************************************************************
3288 * CoCreateInstanceEx [OLE32.@]
3290 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3292 LPUNKNOWN pUnkOuter
,
3294 COSERVERINFO
* pServerInfo
,
3298 IUnknown
*unk
= NULL
;
3304 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3306 if (!cmq
|| !pResults
)
3307 return E_INVALIDARG
;
3310 FIXME("() non-NULL pServerInfo not supported!\n");
3312 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3314 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3318 if (!(apt
= apartment_get_current_or_mta()))
3320 ERR("apartment not initialised\n");
3321 return CO_E_NOTINITIALIZED
;
3323 apartment_release(apt
);
3326 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3328 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3330 IGlobalInterfaceTable
*git
= get_std_git();
3331 TRACE("Retrieving GIT\n");
3332 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3335 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3336 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3339 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3343 * Get a class factory to construct the object we want.
3345 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3350 * Create the object and don't forget to release the factory
3352 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3353 IClassFactory_Release(cf
);
3356 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3357 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3359 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3360 debugstr_guid(pResults
[0].pIID
),
3361 debugstr_guid(&clsid
),hres
);
3365 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3368 /***********************************************************************
3369 * CoGetInstanceFromFile [OLE32.@]
3371 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3372 COSERVERINFO
*server_info
,
3382 IPersistFile
*pf
= NULL
;
3383 IUnknown
* unk
= NULL
;
3387 if (count
== 0 || !results
)
3388 return E_INVALIDARG
;
3391 FIXME("() non-NULL server_info not supported\n");
3393 init_multi_qi(count
, results
, E_NOINTERFACE
);
3395 /* optionally get CLSID from a file */
3398 hr
= GetClassFile(filename
, &clsid
);
3401 ERR("failed to get CLSID from a file\n");
3408 hr
= CoCreateInstance(rclsid
,
3416 init_multi_qi(count
, results
, hr
);
3420 /* init from file */
3421 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3424 init_multi_qi(count
, results
, hr
);
3425 IUnknown_Release(unk
);
3429 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3430 IPersistFile_Release(pf
);
3432 return return_multi_qi(unk
, count
, results
, FALSE
);
3435 init_multi_qi(count
, results
, hr
);
3436 IUnknown_Release(unk
);
3441 /***********************************************************************
3442 * CoGetInstanceFromIStorage [OLE32.@]
3444 HRESULT WINAPI
CoGetInstanceFromIStorage(
3445 COSERVERINFO
*server_info
,
3454 IPersistStorage
*ps
= NULL
;
3455 IUnknown
* unk
= NULL
;
3459 if (count
== 0 || !results
|| !storage
)
3460 return E_INVALIDARG
;
3463 FIXME("() non-NULL server_info not supported\n");
3465 init_multi_qi(count
, results
, E_NOINTERFACE
);
3467 /* optionally get CLSID from a file */
3470 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3471 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3474 ERR("failed to get CLSID from a file\n");
3478 rclsid
= &stat
.clsid
;
3481 hr
= CoCreateInstance(rclsid
,
3490 /* init from IStorage */
3491 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3493 ERR("failed to get IPersistStorage\n");
3497 IPersistStorage_Load(ps
, storage
);
3498 IPersistStorage_Release(ps
);
3501 return return_multi_qi(unk
, count
, results
, FALSE
);
3504 /***********************************************************************
3505 * CoLoadLibrary (OLE32.@)
3510 * lpszLibName [I] Path to library.
3511 * bAutoFree [I] Whether the library should automatically be freed.
3514 * Success: Handle to loaded library.
3518 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3520 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3522 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3524 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3527 /***********************************************************************
3528 * CoFreeLibrary [OLE32.@]
3530 * Unloads a library from memory.
3533 * hLibrary [I] Handle to library to unload.
3539 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3541 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3543 FreeLibrary(hLibrary
);
3547 /***********************************************************************
3548 * CoFreeAllLibraries [OLE32.@]
3550 * Function for backwards compatibility only. Does nothing.
3556 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3558 void WINAPI
CoFreeAllLibraries(void)
3563 /***********************************************************************
3564 * CoFreeUnusedLibrariesEx [OLE32.@]
3566 * Frees any previously unused libraries whose delay has expired and marks
3567 * currently unused libraries for unloading. Unused are identified as those that
3568 * return S_OK from their DllCanUnloadNow function.
3571 * dwUnloadDelay [I] Unload delay in milliseconds.
3572 * dwReserved [I] Reserved. Set to 0.
3578 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3580 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3582 struct apartment
*apt
= COM_CurrentApt();
3585 ERR("apartment not initialised\n");
3589 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3592 /***********************************************************************
3593 * CoFreeUnusedLibraries [OLE32.@]
3595 * Frees any unused libraries. Unused are identified as those that return
3596 * S_OK from their DllCanUnloadNow function.
3602 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3604 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3606 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3609 /***********************************************************************
3610 * CoFileTimeNow [OLE32.@]
3612 * Retrieves the current time in FILETIME format.
3615 * lpFileTime [O] The current time.
3620 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3622 GetSystemTimeAsFileTime( lpFileTime
);
3626 /******************************************************************************
3627 * CoLockObjectExternal [OLE32.@]
3629 * Increments or decrements the external reference count of a stub object.
3632 * pUnk [I] Stub object.
3633 * fLock [I] If TRUE then increments the external ref-count,
3634 * otherwise decrements.
3635 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3636 * calling CoDisconnectObject.
3640 * Failure: HRESULT code.
3643 * If fLock is TRUE and an object is passed in that doesn't have a stub
3644 * manager then a new stub manager is created for the object.
3646 HRESULT WINAPI
CoLockObjectExternal(
3649 BOOL fLastUnlockReleases
)
3651 struct stub_manager
*stubmgr
;
3652 struct apartment
*apt
;
3654 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3655 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3657 if (!(apt
= apartment_get_current_or_mta()))
3659 ERR("apartment not initialised\n");
3660 return CO_E_NOTINITIALIZED
;
3663 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3666 WARN("stub object not found %p\n", pUnk
);
3667 /* Note: native is pretty broken here because it just silently
3668 * fails, without returning an appropriate error code, making apps
3669 * think that the object was disconnected, when it actually wasn't */
3670 apartment_release(apt
);
3675 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3677 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3679 stub_manager_int_release(stubmgr
);
3680 apartment_release(apt
);
3684 /***********************************************************************
3685 * CoInitializeWOW (OLE32.@)
3687 * WOW equivalent of CoInitialize?
3696 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3698 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3702 /***********************************************************************
3703 * CoGetState [OLE32.@]
3705 * Retrieves the thread state object previously stored by CoSetState().
3708 * ppv [I] Address where pointer to object will be stored.
3712 * Failure: E_OUTOFMEMORY.
3715 * Crashes on all invalid ppv addresses, including NULL.
3716 * If the function returns a non-NULL object then the caller must release its
3717 * reference on the object when the object is no longer required.
3722 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3724 struct oletls
*info
= COM_CurrentInfo();
3725 if (!info
) return E_OUTOFMEMORY
;
3731 IUnknown_AddRef(info
->state
);
3733 TRACE("apt->state=%p\n", info
->state
);
3739 /***********************************************************************
3740 * CoSetState [OLE32.@]
3742 * Sets the thread state object.
3745 * pv [I] Pointer to state object to be stored.
3748 * The system keeps a reference on the object while the object stored.
3752 * Failure: E_OUTOFMEMORY.
3754 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3756 struct oletls
*info
= COM_CurrentInfo();
3757 if (!info
) return E_OUTOFMEMORY
;
3759 if (pv
) IUnknown_AddRef(pv
);
3763 TRACE("-- release %p now\n", info
->state
);
3764 IUnknown_Release(info
->state
);
3773 /******************************************************************************
3774 * CoTreatAsClass [OLE32.@]
3776 * Sets the TreatAs value of a class.
3779 * clsidOld [I] Class to set TreatAs value on.
3780 * clsidNew [I] The class the clsidOld should be treated as.
3784 * Failure: HRESULT code.
3789 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3791 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3792 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3794 WCHAR szClsidNew
[CHARS_IN_GUID
];
3796 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3797 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3800 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3804 if (IsEqualGUID( clsidOld
, clsidNew
))
3806 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3807 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3809 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3811 res
= REGDB_E_WRITEREGDB
;
3817 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3818 res
= REGDB_E_WRITEREGDB
;
3824 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3825 RegDeleteKeyW(hkey
, wszTreatAs
);
3827 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAY_SIZE(szClsidNew
))){
3828 WARN("StringFromGUID2 failed\n");
3833 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3834 WARN("RegSetValue failed\n");
3835 res
= REGDB_E_WRITEREGDB
;
3842 if (hkey
) RegCloseKey(hkey
);
3846 /******************************************************************************
3847 * CoGetTreatAsClass [OLE32.@]
3849 * Gets the TreatAs value of a class.
3852 * clsidOld [I] Class to get the TreatAs value of.
3853 * clsidNew [I] The class the clsidOld should be treated as.
3857 * Failure: HRESULT code.
3862 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3864 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3866 WCHAR szClsidNew
[CHARS_IN_GUID
];
3868 LONG len
= sizeof(szClsidNew
);
3870 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3872 if (!clsidOld
|| !clsidNew
)
3873 return E_INVALIDARG
;
3875 *clsidNew
= *clsidOld
; /* copy over old value */
3877 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3883 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3888 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3890 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3892 if (hkey
) RegCloseKey(hkey
);
3896 /******************************************************************************
3897 * CoGetCurrentProcess [OLE32.@]
3899 * Gets the current process ID.
3902 * The current process ID.
3905 * Is DWORD really the correct return type for this function?
3907 DWORD WINAPI
CoGetCurrentProcess(void)
3909 return GetCurrentProcessId();
3912 /***********************************************************************
3913 * CoGetCurrentLogicalThreadId [OLE32.@]
3915 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3917 TRACE("(%p)\n", id
);
3920 return E_INVALIDARG
;
3922 *id
= COM_CurrentCausalityId();
3926 /******************************************************************************
3927 * CoRegisterMessageFilter [OLE32.@]
3929 * Registers a message filter.
3932 * lpMessageFilter [I] Pointer to interface.
3933 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3937 * Failure: HRESULT code.
3940 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3941 * lpMessageFilter removes the message filter.
3943 * If lplpMessageFilter is not NULL the previous message filter will be
3944 * returned in the memory pointer to this parameter and the caller is
3945 * responsible for releasing the object.
3947 * The current thread be in an apartment otherwise the function will crash.
3949 HRESULT WINAPI
CoRegisterMessageFilter(
3950 LPMESSAGEFILTER lpMessageFilter
,
3951 LPMESSAGEFILTER
*lplpMessageFilter
)
3953 struct apartment
*apt
;
3954 IMessageFilter
*lpOldMessageFilter
;
3956 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3958 apt
= COM_CurrentApt();
3960 /* can't set a message filter in a multi-threaded apartment */
3961 if (!apt
|| apt
->multi_threaded
)
3963 WARN("can't set message filter in MTA or uninitialized apt\n");
3964 return CO_E_NOT_SUPPORTED
;
3967 if (lpMessageFilter
)
3968 IMessageFilter_AddRef(lpMessageFilter
);
3970 EnterCriticalSection(&apt
->cs
);
3972 lpOldMessageFilter
= apt
->filter
;
3973 apt
->filter
= lpMessageFilter
;
3975 LeaveCriticalSection(&apt
->cs
);
3977 if (lplpMessageFilter
)
3978 *lplpMessageFilter
= lpOldMessageFilter
;
3979 else if (lpOldMessageFilter
)
3980 IMessageFilter_Release(lpOldMessageFilter
);
3985 /***********************************************************************
3986 * CoIsOle1Class [OLE32.@]
3988 * Determines whether the specified class an OLE v1 class.
3991 * clsid [I] Class to test.
3994 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3996 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3998 FIXME("%s\n", debugstr_guid(clsid
));
4002 /***********************************************************************
4003 * IsEqualGUID [OLE32.@]
4005 * Compares two Unique Identifiers.
4008 * rguid1 [I] The first GUID to compare.
4009 * rguid2 [I] The other GUID to compare.
4015 BOOL WINAPI
IsEqualGUID(
4019 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
4022 /***********************************************************************
4023 * CoInitializeSecurity [OLE32.@]
4025 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4026 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4027 void* pReserved1
, DWORD dwAuthnLevel
,
4028 DWORD dwImpLevel
, void* pReserved2
,
4029 DWORD dwCapabilities
, void* pReserved3
)
4031 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4032 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4033 dwCapabilities
, pReserved3
);
4037 /***********************************************************************
4038 * CoSuspendClassObjects [OLE32.@]
4040 * Suspends all registered class objects to prevent further requests coming in
4041 * for those objects.
4045 * Failure: HRESULT code.
4047 HRESULT WINAPI
CoSuspendClassObjects(void)
4053 /***********************************************************************
4054 * CoAddRefServerProcess [OLE32.@]
4056 * Helper function for incrementing the reference count of a local-server
4060 * New reference count.
4063 * CoReleaseServerProcess().
4065 ULONG WINAPI
CoAddRefServerProcess(void)
4071 EnterCriticalSection(&csRegisteredClassList
);
4072 refs
= ++s_COMServerProcessReferences
;
4073 LeaveCriticalSection(&csRegisteredClassList
);
4075 TRACE("refs before: %d\n", refs
- 1);
4080 /***********************************************************************
4081 * CoReleaseServerProcess [OLE32.@]
4083 * Helper function for decrementing the reference count of a local-server
4087 * New reference count.
4090 * When reference count reaches 0, this function suspends all registered
4091 * classes so no new connections are accepted.
4094 * CoAddRefServerProcess(), CoSuspendClassObjects().
4096 ULONG WINAPI
CoReleaseServerProcess(void)
4102 EnterCriticalSection(&csRegisteredClassList
);
4104 refs
= --s_COMServerProcessReferences
;
4105 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4107 LeaveCriticalSection(&csRegisteredClassList
);
4109 TRACE("refs after: %d\n", refs
);
4114 /***********************************************************************
4115 * CoIsHandlerConnected [OLE32.@]
4117 * Determines whether a proxy is connected to a remote stub.
4120 * pUnk [I] Pointer to object that may or may not be connected.
4123 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4126 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4128 FIXME("%p\n", pUnk
);
4133 /***********************************************************************
4134 * CoAllowSetForegroundWindow [OLE32.@]
4137 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4139 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4143 /***********************************************************************
4144 * CoQueryProxyBlanket [OLE32.@]
4146 * Retrieves the security settings being used by a proxy.
4149 * pProxy [I] Pointer to the proxy object.
4150 * pAuthnSvc [O] The type of authentication service.
4151 * pAuthzSvc [O] The type of authorization service.
4152 * ppServerPrincName [O] Optional. The server prinicple name.
4153 * pAuthnLevel [O] The authentication level.
4154 * pImpLevel [O] The impersonation level.
4155 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4156 * pCapabilities [O] Flags affecting the security behaviour.
4160 * Failure: HRESULT code.
4163 * CoCopyProxy, CoSetProxyBlanket.
4165 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4166 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4167 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4169 IClientSecurity
*pCliSec
;
4172 TRACE("%p\n", pProxy
);
4174 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4177 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4178 pAuthzSvc
, ppServerPrincName
,
4179 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4181 IClientSecurity_Release(pCliSec
);
4184 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4188 /***********************************************************************
4189 * CoSetProxyBlanket [OLE32.@]
4191 * Sets the security settings for a proxy.
4194 * pProxy [I] Pointer to the proxy object.
4195 * AuthnSvc [I] The type of authentication service.
4196 * AuthzSvc [I] The type of authorization service.
4197 * pServerPrincName [I] The server prinicple name.
4198 * AuthnLevel [I] The authentication level.
4199 * ImpLevel [I] The impersonation level.
4200 * pAuthInfo [I] Information specific to the authorization/authentication service.
4201 * Capabilities [I] Flags affecting the security behaviour.
4205 * Failure: HRESULT code.
4208 * CoQueryProxyBlanket, CoCopyProxy.
4210 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4211 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4212 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4214 IClientSecurity
*pCliSec
;
4217 TRACE("%p\n", pProxy
);
4219 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4222 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4223 AuthzSvc
, pServerPrincName
,
4224 AuthnLevel
, ImpLevel
, pAuthInfo
,
4226 IClientSecurity_Release(pCliSec
);
4229 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4233 /***********************************************************************
4234 * CoCopyProxy [OLE32.@]
4239 * pProxy [I] Pointer to the proxy object.
4240 * ppCopy [O] Copy of the proxy.
4244 * Failure: HRESULT code.
4247 * CoQueryProxyBlanket, CoSetProxyBlanket.
4249 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4251 IClientSecurity
*pCliSec
;
4254 TRACE("%p\n", pProxy
);
4256 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4259 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4260 IClientSecurity_Release(pCliSec
);
4263 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4268 /***********************************************************************
4269 * CoGetCallContext [OLE32.@]
4271 * Gets the context of the currently executing server call in the current
4275 * riid [I] Context interface to return.
4276 * ppv [O] Pointer to memory that will receive the context on return.
4280 * Failure: HRESULT code.
4282 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4284 struct oletls
*info
= COM_CurrentInfo();
4286 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4289 return E_OUTOFMEMORY
;
4291 if (!info
->call_state
)
4292 return RPC_E_CALL_COMPLETE
;
4294 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4297 /***********************************************************************
4298 * CoSwitchCallContext [OLE32.@]
4300 * Switches the context of the currently executing server call in the current
4304 * pObject [I] Pointer to new context object
4305 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4309 * Failure: HRESULT code.
4311 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4313 struct oletls
*info
= COM_CurrentInfo();
4315 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4318 return E_OUTOFMEMORY
;
4320 *ppOldObject
= info
->call_state
;
4321 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4326 /***********************************************************************
4327 * CoQueryClientBlanket [OLE32.@]
4329 * Retrieves the authentication information about the client of the currently
4330 * executing server call in the current thread.
4333 * pAuthnSvc [O] Optional. The type of authentication service.
4334 * pAuthzSvc [O] Optional. The type of authorization service.
4335 * pServerPrincName [O] Optional. The server prinicple name.
4336 * pAuthnLevel [O] Optional. The authentication level.
4337 * pImpLevel [O] Optional. The impersonation level.
4338 * pPrivs [O] Optional. Information about the privileges of the client.
4339 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4343 * Failure: HRESULT code.
4346 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4348 HRESULT WINAPI
CoQueryClientBlanket(
4351 OLECHAR
**pServerPrincName
,
4354 RPC_AUTHZ_HANDLE
*pPrivs
,
4355 DWORD
*pCapabilities
)
4357 IServerSecurity
*pSrvSec
;
4360 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4361 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4362 pPrivs
, pCapabilities
);
4364 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4367 hr
= IServerSecurity_QueryBlanket(
4368 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4369 pImpLevel
, pPrivs
, pCapabilities
);
4370 IServerSecurity_Release(pSrvSec
);
4376 /***********************************************************************
4377 * CoImpersonateClient [OLE32.@]
4379 * Impersonates the client of the currently executing server call in the
4387 * Failure: HRESULT code.
4390 * If this function fails then the current thread will not be impersonating
4391 * the client and all actions will take place on behalf of the server.
4392 * Therefore, it is important to check the return value from this function.
4395 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4397 HRESULT WINAPI
CoImpersonateClient(void)
4399 IServerSecurity
*pSrvSec
;
4404 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4407 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4408 IServerSecurity_Release(pSrvSec
);
4414 /***********************************************************************
4415 * CoRevertToSelf [OLE32.@]
4417 * Ends the impersonation of the client of the currently executing server
4418 * call in the current thread.
4425 * Failure: HRESULT code.
4428 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4430 HRESULT WINAPI
CoRevertToSelf(void)
4432 IServerSecurity
*pSrvSec
;
4437 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4440 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4441 IServerSecurity_Release(pSrvSec
);
4447 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4449 /* first try to retrieve messages for incoming COM calls to the apartment window */
4450 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4451 /* next retrieve other messages necessary for the app to remain responsive */
4452 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4453 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4456 /***********************************************************************
4457 * CoWaitForMultipleHandles [OLE32.@]
4459 * Waits for one or more handles to become signaled.
4462 * dwFlags [I] Flags. See notes.
4463 * dwTimeout [I] Timeout in milliseconds.
4464 * cHandles [I] Number of handles pointed to by pHandles.
4465 * pHandles [I] Handles to wait for.
4466 * lpdwindex [O] Index of handle that was signaled.
4470 * Failure: RPC_S_CALLPENDING on timeout.
4474 * The dwFlags parameter can be zero or more of the following:
4475 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4476 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4479 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4481 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4482 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4485 DWORD start_time
= GetTickCount();
4486 APARTMENT
*apt
= COM_CurrentApt();
4487 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4488 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4489 BOOL post_quit
= FALSE
;
4492 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4493 pHandles
, lpdwindex
);
4496 return E_INVALIDARG
;
4501 return E_INVALIDARG
;
4504 return RPC_E_NO_SYNC
;
4508 DWORD now
= GetTickCount();
4511 if (now
- start_time
> dwTimeout
)
4513 hr
= RPC_S_CALLPENDING
;
4519 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4520 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4522 TRACE("waiting for rpc completion or window message\n");
4528 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4529 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4533 if (res
== WAIT_TIMEOUT
)
4534 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4535 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4536 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4538 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4543 /* call message filter */
4545 if (COM_CurrentApt()->filter
)
4547 PENDINGTYPE pendingtype
=
4548 COM_CurrentInfo()->pending_call_count_server
?
4549 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4550 DWORD be_handled
= IMessageFilter_MessagePending(
4551 COM_CurrentApt()->filter
, 0 /* FIXME */,
4552 now
- start_time
, pendingtype
);
4553 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4556 case PENDINGMSG_CANCELCALL
:
4557 WARN("call canceled\n");
4558 hr
= RPC_E_CALL_CANCELED
;
4560 case PENDINGMSG_WAITNOPROCESS
:
4561 case PENDINGMSG_WAITDEFPROCESS
:
4563 /* FIXME: MSDN is very vague about the difference
4564 * between WAITNOPROCESS and WAITDEFPROCESS - there
4565 * appears to be none, so it is possibly a left-over
4566 * from the 16-bit world. */
4573 /* If window is NULL on apartment, peek at messages so that it will not trigger
4574 * MsgWaitForMultipleObjects next time. */
4575 PeekMessageW(NULL
, NULL
, 0, 0, PM_QS_POSTMESSAGE
| PM_NOREMOVE
| PM_NOYIELD
);
4577 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4578 * so after processing 100 messages we go back to checking the wait handles */
4579 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4581 if (msg
.message
== WM_QUIT
)
4583 TRACE("received WM_QUIT message\n");
4585 exit_code
= msg
.wParam
;
4589 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4590 TranslateMessage(&msg
);
4591 DispatchMessageW(&msg
);
4599 TRACE("waiting for rpc completion\n");
4601 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4602 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4603 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4609 hr
= RPC_S_CALLPENDING
;
4612 hr
= HRESULT_FROM_WIN32( GetLastError() );
4620 if (post_quit
) PostQuitMessage(exit_code
);
4621 TRACE("-- 0x%08x\n", hr
);
4626 /***********************************************************************
4627 * CoGetObject [OLE32.@]
4629 * Gets the object named by converting the name to a moniker and binding to it.
4632 * pszName [I] String representing the object.
4633 * pBindOptions [I] Parameters affecting the binding to the named object.
4634 * riid [I] Interface to bind to on the objecct.
4635 * ppv [O] On output, the interface riid of the object represented
4640 * Failure: HRESULT code.
4643 * MkParseDisplayName.
4645 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4646 REFIID riid
, void **ppv
)
4653 hr
= CreateBindCtx(0, &pbc
);
4657 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4664 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4667 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4668 IMoniker_Release(pmk
);
4672 IBindCtx_Release(pbc
);
4677 /***********************************************************************
4678 * CoRegisterChannelHook [OLE32.@]
4680 * Registers a process-wide hook that is called during ORPC calls.
4683 * guidExtension [I] GUID of the channel hook to register.
4684 * pChannelHook [I] Channel hook object to register.
4688 * Failure: HRESULT code.
4690 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4692 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4694 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4697 typedef struct Context
4699 IComThreadingInfo IComThreadingInfo_iface
;
4700 IContextCallback IContextCallback_iface
;
4701 IObjContext IObjContext_iface
;
4705 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4707 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4710 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4712 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4715 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4717 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4720 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4724 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4725 IsEqualIID(riid
, &IID_IUnknown
))
4727 *ppv
= &iface
->IComThreadingInfo_iface
;
4729 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4731 *ppv
= &iface
->IContextCallback_iface
;
4733 else if (IsEqualIID(riid
, &IID_IObjContext
))
4735 *ppv
= &iface
->IObjContext_iface
;
4740 IUnknown_AddRef((IUnknown
*)*ppv
);
4744 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4745 return E_NOINTERFACE
;
4748 static ULONG
Context_AddRef(Context
*This
)
4750 return InterlockedIncrement(&This
->refs
);
4753 static ULONG
Context_Release(Context
*This
)
4755 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4756 releasing context while refcount is at 0 destroys it. */
4759 HeapFree(GetProcessHeap(), 0, This
);
4763 return InterlockedDecrement(&This
->refs
);
4766 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4768 Context
*This
= impl_from_IComThreadingInfo(iface
);
4769 return Context_QueryInterface(This
, riid
, ppv
);
4772 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4774 Context
*This
= impl_from_IComThreadingInfo(iface
);
4775 return Context_AddRef(This
);
4778 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4780 Context
*This
= impl_from_IComThreadingInfo(iface
);
4781 return Context_Release(This
);
4784 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4786 APTTYPEQUALIFIER qualifier
;
4788 TRACE("(%p)\n", apttype
);
4790 return CoGetApartmentType(apttype
, &qualifier
);
4793 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4795 APTTYPEQUALIFIER qualifier
;
4799 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4803 TRACE("(%p)\n", thdtype
);
4808 case APTTYPE_MAINSTA
:
4809 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4812 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4818 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4820 TRACE("(%p)\n", logical_thread_id
);
4821 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4824 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4826 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4830 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4832 Context_CTI_QueryInterface
,
4834 Context_CTI_Release
,
4835 Context_CTI_GetCurrentApartmentType
,
4836 Context_CTI_GetCurrentThreadType
,
4837 Context_CTI_GetCurrentLogicalThreadId
,
4838 Context_CTI_SetCurrentLogicalThreadId
4841 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4843 Context
*This
= impl_from_IContextCallback(iface
);
4844 return Context_QueryInterface(This
, riid
, ppv
);
4847 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4849 Context
*This
= impl_from_IContextCallback(iface
);
4850 return Context_AddRef(This
);
4853 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4855 Context
*This
= impl_from_IContextCallback(iface
);
4856 return Context_Release(This
);
4859 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4860 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4862 Context
*This
= impl_from_IContextCallback(iface
);
4864 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4868 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4870 Context_CC_QueryInterface
,
4873 Context_CC_ContextCallback
4876 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4878 Context
*This
= impl_from_IObjContext(iface
);
4879 return Context_QueryInterface(This
, riid
, ppv
);
4882 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4884 Context
*This
= impl_from_IObjContext(iface
);
4885 return Context_AddRef(This
);
4888 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4890 Context
*This
= impl_from_IObjContext(iface
);
4891 return Context_Release(This
);
4894 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4896 Context
*This
= impl_from_IObjContext(iface
);
4898 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4902 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4904 Context
*This
= impl_from_IObjContext(iface
);
4906 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4910 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4912 Context
*This
= impl_from_IObjContext(iface
);
4914 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4918 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4920 Context
*This
= impl_from_IObjContext(iface
);
4922 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4926 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4928 Context
*This
= impl_from_IObjContext(iface
);
4929 FIXME("(%p/%p)\n", This
, iface
);
4932 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4934 Context
*This
= impl_from_IObjContext(iface
);
4935 FIXME("(%p/%p)\n", This
, iface
);
4938 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4940 Context
*This
= impl_from_IObjContext(iface
);
4941 FIXME("(%p/%p)\n", This
, iface
);
4944 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4946 Context
*This
= impl_from_IObjContext(iface
);
4947 FIXME("(%p/%p)\n", This
, iface
);
4950 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4952 Context
*This
= impl_from_IObjContext(iface
);
4953 FIXME("(%p/%p)\n", This
, iface
);
4956 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4958 Context
*This
= impl_from_IObjContext(iface
);
4959 FIXME("(%p/%p)\n", This
, iface
);
4962 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4964 Context
*This
= impl_from_IObjContext(iface
);
4965 FIXME("(%p/%p)\n", This
, iface
);
4968 static const IObjContextVtbl Context_Object_Vtbl
=
4970 Context_OC_QueryInterface
,
4973 Context_OC_SetProperty
,
4974 Context_OC_RemoveProperty
,
4975 Context_OC_GetProperty
,
4976 Context_OC_EnumContextProps
,
4977 Context_OC_Reserved1
,
4978 Context_OC_Reserved2
,
4979 Context_OC_Reserved3
,
4980 Context_OC_Reserved4
,
4981 Context_OC_Reserved5
,
4982 Context_OC_Reserved6
,
4983 Context_OC_Reserved7
4986 /***********************************************************************
4987 * CoGetObjectContext [OLE32.@]
4989 * Retrieves an object associated with the current context (i.e. apartment).
4992 * riid [I] ID of the interface of the object to retrieve.
4993 * ppv [O] Address where object will be stored on return.
4997 * Failure: HRESULT code.
4999 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
5001 IObjContext
*context
;
5004 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
5007 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
5011 return IObjContext_QueryInterface(context
, riid
, ppv
);
5014 /***********************************************************************
5015 * CoGetContextToken [OLE32.@]
5017 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
5019 struct oletls
*info
= COM_CurrentInfo();
5022 TRACE("(%p)\n", token
);
5025 return E_OUTOFMEMORY
;
5027 if (!(apt
= apartment_get_current_or_mta()))
5029 ERR("apartment not initialised\n");
5030 return CO_E_NOTINITIALIZED
;
5032 apartment_release(apt
);
5037 if (!info
->context_token
)
5041 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5043 return E_OUTOFMEMORY
;
5045 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5046 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5047 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5048 /* Context token does not take a reference, it's always zero until the
5049 interface is explicitly requested with CoGetObjectContext(). */
5052 info
->context_token
= &context
->IObjContext_iface
;
5055 *token
= (ULONG_PTR
)info
->context_token
;
5056 TRACE("context_token=%p\n", info
->context_token
);
5061 /***********************************************************************
5062 * CoGetDefaultContext [OLE32.@]
5064 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5066 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5067 return E_NOINTERFACE
;
5070 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5072 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5076 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5077 if (SUCCEEDED(hres
))
5079 struct class_reg_data regdata
;
5080 WCHAR dllpath
[MAX_PATH
+1];
5082 regdata
.u
.hkey
= hkey
;
5083 regdata
.hkey
= TRUE
;
5085 if (get_object_dll_path(®data
, dllpath
, ARRAY_SIZE(dllpath
)))
5087 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5088 if (!strcmpiW(dllpath
, wszOle32
))
5091 return HandlerCF_Create(rclsid
, riid
, ppv
);
5095 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5099 return CLASS_E_CLASSNOTAVAILABLE
;
5102 /***********************************************************************
5103 * CoGetApartmentType [OLE32.@]
5105 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5107 struct oletls
*info
= COM_CurrentInfo();
5110 TRACE("(%p, %p)\n", type
, qualifier
);
5112 if (!type
|| !qualifier
)
5113 return E_INVALIDARG
;
5116 return E_OUTOFMEMORY
;
5119 *type
= APTTYPE_CURRENT
;
5120 else if (info
->apt
->multi_threaded
)
5121 *type
= APTTYPE_MTA
;
5122 else if (info
->apt
->main
)
5123 *type
= APTTYPE_MAINSTA
;
5125 *type
= APTTYPE_STA
;
5127 *qualifier
= APTTYPEQUALIFIER_NONE
;
5129 if (!info
->apt
&& (apt
= apartment_find_mta()))
5131 apartment_release(apt
);
5132 *type
= APTTYPE_MTA
;
5133 *qualifier
= APTTYPEQUALIFIER_IMPLICIT_MTA
;
5136 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5139 /***********************************************************************
5140 * CoRegisterSurrogate [OLE32.@]
5142 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5144 FIXME("(%p): stub\n", surrogate
);
5149 /***********************************************************************
5150 * CoRegisterSurrogateEx [OLE32.@]
5152 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5154 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5160 IGlobalOptions IGlobalOptions_iface
;
5164 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5166 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5169 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5171 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5173 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5175 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5182 return E_NOINTERFACE
;
5185 IUnknown_AddRef((IUnknown
*)*ppv
);
5189 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5191 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5192 LONG ref
= InterlockedIncrement(&This
->ref
);
5194 TRACE("(%p) ref=%d\n", This
, ref
);
5199 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5201 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5202 LONG ref
= InterlockedDecrement(&This
->ref
);
5204 TRACE("(%p) ref=%d\n", This
, ref
);
5212 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5214 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5215 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5219 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5221 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5222 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5226 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5227 GlobalOptions_QueryInterface
,
5228 GlobalOptions_AddRef
,
5229 GlobalOptions_Release
,
5234 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5236 GlobalOptions
*global_options
;
5239 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5242 return E_INVALIDARG
;
5244 global_options
= heap_alloc(sizeof(*global_options
));
5245 if (!global_options
)
5246 return E_OUTOFMEMORY
;
5247 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5248 global_options
->ref
= 1;
5250 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5251 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5255 /***********************************************************************
5258 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5260 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5263 case DLL_PROCESS_ATTACH
:
5264 hProxyDll
= hinstDLL
;
5267 case DLL_PROCESS_DETACH
:
5268 if (reserved
) break;
5271 UnregisterClassW( (const WCHAR
*)MAKEINTATOM(apt_win_class
), hProxyDll
);
5272 RPC_UnregisterAllChannelHooks();
5273 COMPOBJ_DllList_Free();
5274 DeleteCriticalSection(&csRegisteredClassList
);
5275 DeleteCriticalSection(&csApartment
);
5278 case DLL_THREAD_DETACH
:
5285 /***********************************************************************
5286 * DllRegisterServer (OLE32.@)
5288 HRESULT WINAPI
DllRegisterServer(void)
5290 return OLE32_DllRegisterServer();
5293 /***********************************************************************
5294 * DllUnregisterServer (OLE32.@)
5296 HRESULT WINAPI
DllUnregisterServer(void)
5298 return OLE32_DllUnregisterServer();