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 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT
*MTA
; /* protected by csApartment */
80 static APARTMENT
*MainApartment
; /* the first STA apartment */
81 static struct list apts
= LIST_INIT( apts
); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment
;
84 static CRITICAL_SECTION_DEBUG critsect_debug
=
87 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
88 0, 0, { (DWORD_PTR
)(__FILE__
": csApartment") }
90 static CRITICAL_SECTION csApartment
= { &critsect_debug
, -1, 0, 0, 0, 0 };
92 enum comclass_threadingmodel
94 ThreadingModel_Apartment
= 1,
95 ThreadingModel_Free
= 2,
96 ThreadingModel_No
= 3,
97 ThreadingModel_Both
= 4,
98 ThreadingModel_Neutral
= 5
101 enum comclass_miscfields
105 MiscStatusContent
= 4,
106 MiscStatusThumbnail
= 8,
107 MiscStatusDocPrint
= 16
110 struct comclassredirect_data
126 ULONG clrdata_offset
;
128 DWORD miscstatuscontent
;
129 DWORD miscstatusthumbnail
;
130 DWORD miscstatusicon
;
131 DWORD miscstatusdocprint
;
134 struct ifacepsredirect_data
146 struct progidredirect_data
153 struct class_reg_data
159 struct comclassredirect_data
*data
;
168 struct registered_psclsid
175 static struct list registered_psclsid_list
= LIST_INIT(registered_psclsid_list
);
177 static CRITICAL_SECTION cs_registered_psclsid_list
;
178 static CRITICAL_SECTION_DEBUG psclsid_cs_debug
=
180 0, 0, &cs_registered_psclsid_list
,
181 { &psclsid_cs_debug
.ProcessLocksList
, &psclsid_cs_debug
.ProcessLocksList
},
182 0, 0, { (DWORD_PTR
)(__FILE__
": cs_registered_psclsid_list") }
184 static CRITICAL_SECTION cs_registered_psclsid_list
= { &psclsid_cs_debug
, -1, 0, 0, 0, 0 };
187 * This is a marshallable object exposing registered local servers.
188 * IServiceProvider is used only because it happens meet requirements
189 * and already has proxy/stub code. If more functionality is needed,
190 * a custom interface may be used instead.
194 IServiceProvider IServiceProvider_iface
;
197 IStream
*marshal_stream
;
201 * This lock count counts the number of times CoInitialize is called. It is
202 * decreased every time CoUninitialize is called. When it hits 0, the COM
203 * libraries are freed
205 static LONG s_COMLockCount
= 0;
206 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
207 static LONG s_COMServerProcessReferences
= 0;
210 * This linked list contains the list of registered class objects. These
211 * are mostly used to register the factories for out-of-proc servers of OLE
214 * TODO: Make this data structure aware of inter-process communication. This
215 * means that parts of this will be exported to rpcss.
217 typedef struct tagRegisteredClass
220 CLSID classIdentifier
;
222 LPUNKNOWN classObject
;
226 void *RpcRegistration
;
229 static struct list RegisteredClassList
= LIST_INIT(RegisteredClassList
);
231 static CRITICAL_SECTION csRegisteredClassList
;
232 static CRITICAL_SECTION_DEBUG class_cs_debug
=
234 0, 0, &csRegisteredClassList
,
235 { &class_cs_debug
.ProcessLocksList
, &class_cs_debug
.ProcessLocksList
},
236 0, 0, { (DWORD_PTR
)(__FILE__
": csRegisteredClassList") }
238 static CRITICAL_SECTION csRegisteredClassList
= { &class_cs_debug
, -1, 0, 0, 0, 0 };
240 static inline enum comclass_miscfields
dvaspect_to_miscfields(DWORD aspect
)
244 case DVASPECT_CONTENT
:
245 return MiscStatusContent
;
246 case DVASPECT_THUMBNAIL
:
247 return MiscStatusThumbnail
;
249 return MiscStatusIcon
;
250 case DVASPECT_DOCPRINT
:
251 return MiscStatusDocPrint
;
257 BOOL
actctx_get_miscstatus(const CLSID
*clsid
, DWORD aspect
, DWORD
*status
)
259 ACTCTX_SECTION_KEYED_DATA data
;
261 data
.cbSize
= sizeof(data
);
262 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
265 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
266 enum comclass_miscfields misc
= dvaspect_to_miscfields(aspect
);
268 if (!(comclass
->miscmask
& misc
))
270 if (!(comclass
->miscmask
& MiscStatus
))
281 *status
= comclass
->miscstatus
;
284 *status
= comclass
->miscstatusicon
;
286 case MiscStatusContent
:
287 *status
= comclass
->miscstatuscontent
;
289 case MiscStatusThumbnail
:
290 *status
= comclass
->miscstatusthumbnail
;
292 case MiscStatusDocPrint
:
293 *status
= comclass
->miscstatusdocprint
;
305 /* wrapper for NtCreateKey that creates the key recursively if necessary */
306 static NTSTATUS
create_key( HKEY
*retkey
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
308 NTSTATUS status
= NtCreateKey( (HANDLE
*)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
310 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
312 HANDLE subkey
, root
= attr
->RootDirectory
;
313 WCHAR
*buffer
= attr
->ObjectName
->Buffer
;
314 DWORD attrs
, pos
= 0, i
= 0, len
= attr
->ObjectName
->Length
/ sizeof(WCHAR
);
317 while (i
< len
&& buffer
[i
] != '\\') i
++;
318 if (i
== len
) return status
;
320 attrs
= attr
->Attributes
;
321 attr
->ObjectName
= &str
;
325 str
.Buffer
= buffer
+ pos
;
326 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
327 status
= NtCreateKey( &subkey
, access
, attr
, 0, NULL
, 0, NULL
);
328 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
329 if (status
) return status
;
330 attr
->RootDirectory
= subkey
;
331 while (i
< len
&& buffer
[i
] == '\\') i
++;
333 while (i
< len
&& buffer
[i
] != '\\') i
++;
335 str
.Buffer
= buffer
+ pos
;
336 str
.Length
= (i
- pos
) * sizeof(WCHAR
);
337 attr
->Attributes
= attrs
;
338 status
= NtCreateKey( (PHANDLE
)retkey
, access
, attr
, 0, NULL
, 0, NULL
);
339 if (attr
->RootDirectory
!= root
) NtClose( attr
->RootDirectory
);
344 static const WCHAR classes_rootW
[] =
345 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
348 static HKEY classes_root_hkey
;
350 /* create the special HKEY_CLASSES_ROOT key */
351 static HKEY
create_classes_root_hkey(DWORD access
)
354 OBJECT_ATTRIBUTES attr
;
357 attr
.Length
= sizeof(attr
);
358 attr
.RootDirectory
= 0;
359 attr
.ObjectName
= &name
;
361 attr
.SecurityDescriptor
= NULL
;
362 attr
.SecurityQualityOfService
= NULL
;
363 RtlInitUnicodeString( &name
, classes_rootW
);
364 if (create_key( &hkey
, access
, &attr
)) return 0;
365 TRACE( "%s -> %p\n", debugstr_w(attr
.ObjectName
->Buffer
), hkey
);
367 if (!(access
& KEY_WOW64_64KEY
))
369 if (!(ret
= InterlockedCompareExchangePointer( (void **)&classes_root_hkey
, hkey
, 0 )))
372 NtClose( hkey
); /* somebody beat us to it */
379 /* map the hkey from special root to normal key if necessary */
380 static inline HKEY
get_classes_root_hkey( HKEY hkey
, REGSAM access
)
383 const BOOL is_win64
= sizeof(void*) > sizeof(int);
384 const BOOL force_wow32
= is_win64
&& (access
& KEY_WOW64_32KEY
);
386 if (hkey
== HKEY_CLASSES_ROOT
&&
387 ((access
& KEY_WOW64_64KEY
) || !(ret
= classes_root_hkey
)))
388 ret
= create_classes_root_hkey(MAXIMUM_ALLOWED
| (access
& KEY_WOW64_64KEY
));
389 if (force_wow32
&& ret
&& ret
== classes_root_hkey
)
391 static const WCHAR wow6432nodeW
[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
392 access
&= ~KEY_WOW64_32KEY
;
393 if (create_classes_key(classes_root_hkey
, wow6432nodeW
, access
, &hkey
))
401 LSTATUS
create_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
403 OBJECT_ATTRIBUTES attr
;
404 UNICODE_STRING nameW
;
406 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
408 attr
.Length
= sizeof(attr
);
409 attr
.RootDirectory
= hkey
;
410 attr
.ObjectName
= &nameW
;
412 attr
.SecurityDescriptor
= NULL
;
413 attr
.SecurityQualityOfService
= NULL
;
414 RtlInitUnicodeString( &nameW
, name
);
416 return RtlNtStatusToDosError( create_key( retkey
, access
, &attr
) );
419 LSTATUS
open_classes_key( HKEY hkey
, const WCHAR
*name
, REGSAM access
, HKEY
*retkey
)
421 OBJECT_ATTRIBUTES attr
;
422 UNICODE_STRING nameW
;
424 if (!(hkey
= get_classes_root_hkey( hkey
, access
))) return ERROR_INVALID_HANDLE
;
426 attr
.Length
= sizeof(attr
);
427 attr
.RootDirectory
= hkey
;
428 attr
.ObjectName
= &nameW
;
430 attr
.SecurityDescriptor
= NULL
;
431 attr
.SecurityQualityOfService
= NULL
;
432 RtlInitUnicodeString( &nameW
, name
);
434 return RtlNtStatusToDosError( NtOpenKey( (HANDLE
*)retkey
, access
, &attr
) );
437 /*****************************************************************************
438 * This section contains OpenDllList definitions
440 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
441 * other functions that do LoadLibrary _without_ giving back a HMODULE.
442 * Without this list these handles would never be freed.
444 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
445 * next unload-call but not before 600 sec.
448 typedef HRESULT (CALLBACK
*DllGetClassObjectFunc
)(REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
449 typedef HRESULT (WINAPI
*DllCanUnloadNowFunc
)(void);
451 typedef struct tagOpenDll
456 DllGetClassObjectFunc DllGetClassObject
;
457 DllCanUnloadNowFunc DllCanUnloadNow
;
461 static struct list openDllList
= LIST_INIT(openDllList
);
463 static CRITICAL_SECTION csOpenDllList
;
464 static CRITICAL_SECTION_DEBUG dll_cs_debug
=
466 0, 0, &csOpenDllList
,
467 { &dll_cs_debug
.ProcessLocksList
, &dll_cs_debug
.ProcessLocksList
},
468 0, 0, { (DWORD_PTR
)(__FILE__
": csOpenDllList") }
470 static CRITICAL_SECTION csOpenDllList
= { &dll_cs_debug
, -1, 0, 0, 0, 0 };
472 struct apartment_loaded_dll
480 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};
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 static 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 /***********************************************************************
1410 * COM_RegReadPath [internal]
1412 * Reads a registry value and expands it when necessary
1414 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1421 WCHAR src
[MAX_PATH
];
1422 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1424 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1425 if (keytype
== REG_EXPAND_SZ
) {
1426 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1428 const WCHAR
*quote_start
;
1429 quote_start
= strchrW(src
, '\"');
1431 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1433 memmove(src
, quote_start
+ 1,
1434 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1435 src
[quote_end
- quote_start
- 1] = '\0';
1438 lstrcpynW(dst
, src
, dstlen
);
1449 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1450 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1451 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1452 DeactivateActCtx(0, cookie
);
1457 struct host_object_params
1459 struct class_reg_data regdata
;
1460 CLSID clsid
; /* clsid of object to marshal */
1461 IID iid
; /* interface to marshal */
1462 HANDLE event
; /* event signalling when ready for multi-threaded case */
1463 HRESULT hr
; /* result for multi-threaded case */
1464 IStream
*stream
; /* stream that the object will be marshaled into */
1465 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1468 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1469 const struct host_object_params
*params
)
1473 static const LARGE_INTEGER llZero
;
1474 WCHAR dllpath
[MAX_PATH
+1];
1476 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1478 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1480 /* failure: CLSID is not found in registry */
1481 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1482 return REGDB_E_CLASSNOTREG
;
1485 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1486 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1490 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1492 IUnknown_Release(object
);
1493 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1498 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1503 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1506 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1508 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1512 struct host_thread_params
1514 COINIT threading_model
;
1516 HWND apartment_hwnd
;
1519 /* thread for hosting an object to allow an object to appear to be created in
1520 * an apartment with an incompatible threading model */
1521 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1523 struct host_thread_params
*params
= p
;
1526 struct apartment
*apt
;
1530 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1531 if (FAILED(hr
)) return hr
;
1533 apt
= COM_CurrentApt();
1534 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1536 apartment_createwindowifneeded(apt
);
1537 params
->apartment_hwnd
= apartment_getwindow(apt
);
1540 params
->apartment_hwnd
= NULL
;
1542 /* force the message queue to be created before signaling parent thread */
1543 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1545 SetEvent(params
->ready_event
);
1546 params
= NULL
; /* can't touch params after here as it may be invalid */
1548 while (GetMessageW(&msg
, NULL
, 0, 0))
1550 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1552 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1553 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1554 SetEvent(obj_params
->event
);
1558 TranslateMessage(&msg
);
1559 DispatchMessageW(&msg
);
1570 /* finds or creates a host apartment, creates the object inside it and returns
1571 * a proxy to it so that the object can be used in the apartment of the
1572 * caller of this function */
1573 static HRESULT
apartment_hostobject_in_hostapt(
1574 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1575 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1577 struct host_object_params params
;
1578 HWND apartment_hwnd
= NULL
;
1579 DWORD apartment_tid
= 0;
1582 if (!multi_threaded
&& main_apartment
)
1584 APARTMENT
*host_apt
= apartment_findmain();
1587 apartment_hwnd
= apartment_getwindow(host_apt
);
1588 apartment_release(host_apt
);
1592 if (!apartment_hwnd
)
1594 EnterCriticalSection(&apt
->cs
);
1596 if (!apt
->host_apt_tid
)
1598 struct host_thread_params thread_params
;
1602 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1603 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1604 thread_params
.apartment_hwnd
= NULL
;
1605 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1608 CloseHandle(handles
[0]);
1609 LeaveCriticalSection(&apt
->cs
);
1610 return E_OUTOFMEMORY
;
1612 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1613 CloseHandle(handles
[0]);
1614 CloseHandle(handles
[1]);
1615 if (wait_value
== WAIT_OBJECT_0
)
1616 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1619 LeaveCriticalSection(&apt
->cs
);
1620 return E_OUTOFMEMORY
;
1624 if (multi_threaded
|| !main_apartment
)
1626 apartment_hwnd
= apt
->host_apt_hwnd
;
1627 apartment_tid
= apt
->host_apt_tid
;
1630 LeaveCriticalSection(&apt
->cs
);
1633 /* another thread may have become the main apartment in the time it took
1634 * us to create the thread for the host apartment */
1635 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1637 APARTMENT
*host_apt
= apartment_findmain();
1640 apartment_hwnd
= apartment_getwindow(host_apt
);
1641 apartment_release(host_apt
);
1645 params
.regdata
= *regdata
;
1646 params
.clsid
= *rclsid
;
1648 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1651 params
.apartment_threaded
= !multi_threaded
;
1655 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1656 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1660 WaitForSingleObject(params
.event
, INFINITE
);
1663 CloseHandle(params
.event
);
1667 if (!apartment_hwnd
)
1669 ERR("host apartment didn't create window\n");
1673 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1676 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1677 IStream_Release(params
.stream
);
1681 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1685 /* Dispatching to the correct thread in an apartment is done through
1686 * window messages rather than RPC transports. When an interface is
1687 * marshalled into another apartment in the same process, a window of the
1688 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1689 * application) is responsible for pumping the message loop in that thread.
1690 * The WM_USER messages which point to the RPCs are then dispatched to
1691 * apartment_wndproc by the user's code from the apartment in which the
1692 * interface was unmarshalled.
1694 memset(&wclass
, 0, sizeof(wclass
));
1695 wclass
.lpfnWndProc
= apartment_wndproc
;
1696 wclass
.hInstance
= hProxyDll
;
1697 wclass
.lpszClassName
= wszAptWinClass
;
1698 RegisterClassW(&wclass
);
1702 /* create a window for the apartment or return the current one if one has
1703 * already been created */
1704 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1706 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1708 if (apt
->multi_threaded
)
1715 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1717 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1718 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1721 ERR("CreateWindow failed with error %d\n", GetLastError());
1722 return HRESULT_FROM_WIN32(GetLastError());
1724 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1725 /* someone beat us to it */
1726 DestroyWindow(hwnd
);
1732 /* retrieves the window for the main- or apartment-threaded apartment */
1733 HWND
apartment_getwindow(const struct apartment
*apt
)
1735 assert(!apt
->multi_threaded
);
1739 static void COM_TlsDestroy(void)
1741 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1744 if (info
->apt
) apartment_release(info
->apt
);
1745 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1746 if (info
->state
) IUnknown_Release(info
->state
);
1747 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1748 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1749 HeapFree(GetProcessHeap(), 0, info
);
1750 NtCurrentTeb()->ReservedForOle
= NULL
;
1754 /******************************************************************************
1755 * CoBuildVersion [OLE32.@]
1757 * Gets the build version of the DLL.
1762 * Current build version, hiword is majornumber, loword is minornumber
1764 DWORD WINAPI
CoBuildVersion(void)
1766 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1767 return (rmm
<<16)+rup
;
1770 /******************************************************************************
1771 * CoRegisterInitializeSpy [OLE32.@]
1773 * Add a Spy that watches CoInitializeEx calls
1776 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1777 * cookie [II] cookie receiver
1780 * Success: S_OK if not already initialized, S_FALSE otherwise.
1781 * Failure: HRESULT code.
1786 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1788 struct oletls
*info
= COM_CurrentInfo();
1791 TRACE("(%p, %p)\n", spy
, cookie
);
1793 if (!spy
|| !cookie
|| !info
)
1796 WARN("Could not allocate tls\n");
1797 return E_INVALIDARG
;
1802 FIXME("Already registered?\n");
1803 return E_UNEXPECTED
;
1806 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1809 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1815 /******************************************************************************
1816 * CoRevokeInitializeSpy [OLE32.@]
1818 * Remove a spy that previously watched CoInitializeEx calls
1821 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1824 * Success: S_OK if a spy is removed
1825 * Failure: E_INVALIDARG
1830 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1832 struct oletls
*info
= COM_CurrentInfo();
1833 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1835 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1836 return E_INVALIDARG
;
1838 IInitializeSpy_Release(info
->spy
);
1843 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1849 if (!apartment_get_or_create( model
))
1850 return E_OUTOFMEMORY
;
1852 else if (!apartment_is_model( info
->apt
, model
))
1854 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1855 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1856 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1857 return RPC_E_CHANGED_MODE
;
1867 void leave_apartment( struct oletls
*info
)
1871 if (info
->ole_inits
)
1872 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1873 apartment_release( info
->apt
);
1878 /******************************************************************************
1879 * CoInitialize [OLE32.@]
1881 * Initializes the COM libraries by calling CoInitializeEx with
1882 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1885 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1888 * Success: S_OK if not already initialized, S_FALSE otherwise.
1889 * Failure: HRESULT code.
1894 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1897 * Just delegate to the newer method.
1899 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1902 /******************************************************************************
1903 * CoInitializeEx [OLE32.@]
1905 * Initializes the COM libraries.
1908 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1909 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1912 * S_OK if successful,
1913 * S_FALSE if this function was called already.
1914 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1919 * The behavior used to set the IMalloc used for memory management is
1921 * The dwCoInit parameter must specify one of the following apartment
1923 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1924 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1925 * The parameter may also specify zero or more of the following flags:
1926 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1927 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1932 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1934 struct oletls
*info
= COM_CurrentInfo();
1937 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1939 if (lpReserved
!=NULL
)
1941 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1945 * Check the lock count. If this is the first time going through the initialize
1946 * process, we have to initialize the libraries.
1948 * And crank-up that lock count.
1950 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1953 * Initialize the various COM libraries and data structures.
1955 TRACE("() - Initializing the COM libraries\n");
1957 /* we may need to defer this until after apartment initialisation */
1958 RunningObjectTableImpl_Initialize();
1962 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1964 hr
= enter_apartment( info
, dwCoInit
);
1967 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1972 /***********************************************************************
1973 * CoUninitialize [OLE32.@]
1975 * This method will decrement the refcount on the current apartment, freeing
1976 * the resources associated with it if it is the last thread in the apartment.
1977 * If the last apartment is freed, the function will additionally release
1978 * any COM resources associated with the process.
1988 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1990 struct oletls
* info
= COM_CurrentInfo();
1995 /* will only happen on OOM */
1999 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
2004 ERR("Mismatched CoUninitialize\n");
2007 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2011 leave_apartment( info
);
2014 * Decrease the reference count.
2015 * If we are back to 0 locks on the COM library, make sure we free
2016 * all the associated data structures.
2018 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2021 TRACE("() - Releasing the COM libraries\n");
2023 revoke_registered_psclsids();
2024 RunningObjectTableImpl_UnInitialize();
2026 else if (lCOMRefCnt
<1) {
2027 ERR( "CoUninitialize() - not CoInitialized.\n" );
2028 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2031 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2034 /******************************************************************************
2035 * CoDisconnectObject [OLE32.@]
2037 * Disconnects all connections to this object from remote processes. Dispatches
2038 * pending RPCs while blocking new RPCs from occurring, and then calls
2039 * IMarshal::DisconnectObject on the given object.
2041 * Typically called when the object server is forced to shut down, for instance by
2045 * lpUnk [I] The object whose stub should be disconnected.
2046 * reserved [I] Reserved. Should be set to 0.
2050 * Failure: HRESULT code.
2053 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2055 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2057 struct stub_manager
*manager
;
2062 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2064 if (!lpUnk
) return E_INVALIDARG
;
2066 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2069 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2070 IMarshal_Release(marshal
);
2074 if (!(apt
= apartment_get_current_or_mta()))
2076 ERR("apartment not initialised\n");
2077 return CO_E_NOTINITIALIZED
;
2080 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2082 stub_manager_disconnect(manager
);
2083 /* Release stub manager twice, to remove the apartment reference. */
2084 stub_manager_int_release(manager
);
2085 stub_manager_int_release(manager
);
2088 /* Note: native is pretty broken here because it just silently
2089 * fails, without returning an appropriate error code if the object was
2090 * not found, making apps think that the object was disconnected, when
2091 * it actually wasn't */
2093 apartment_release(apt
);
2097 /******************************************************************************
2098 * CoCreateGuid [OLE32.@]
2100 * Simply forwards to UuidCreate in RPCRT4.
2103 * pguid [O] Points to the GUID to initialize.
2107 * Failure: HRESULT code.
2112 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2116 if(!pguid
) return E_INVALIDARG
;
2118 status
= UuidCreate(pguid
);
2119 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2120 return HRESULT_FROM_WIN32( status
);
2123 static inline BOOL
is_valid_hex(WCHAR c
)
2125 if (!(((c
>= '0') && (c
<= '9')) ||
2126 ((c
>= 'a') && (c
<= 'f')) ||
2127 ((c
>= 'A') && (c
<= 'F'))))
2132 static const BYTE guid_conv_table
[256] =
2134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2137 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2138 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2140 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2143 /* conversion helper for CLSIDFromString/IIDFromString */
2144 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2148 if (!s
|| s
[0]!='{') {
2149 memset( id
, 0, sizeof (CLSID
) );
2154 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2156 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2159 for (i
= 1; i
< 9; i
++) {
2160 if (!is_valid_hex(s
[i
])) return FALSE
;
2161 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2163 if (s
[9]!='-') return FALSE
;
2166 for (i
= 10; i
< 14; i
++) {
2167 if (!is_valid_hex(s
[i
])) return FALSE
;
2168 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2170 if (s
[14]!='-') return FALSE
;
2173 for (i
= 15; i
< 19; i
++) {
2174 if (!is_valid_hex(s
[i
])) return FALSE
;
2175 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2177 if (s
[19]!='-') return FALSE
;
2179 for (i
= 20; i
< 37; i
+=2) {
2181 if (s
[i
]!='-') return FALSE
;
2184 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2185 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2188 if (s
[37] == '}' && s
[38] == '\0')
2194 /*****************************************************************************/
2196 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2198 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2199 WCHAR buf2
[CHARS_IN_GUID
];
2200 LONG buf2len
= sizeof(buf2
);
2204 memset(clsid
, 0, sizeof(*clsid
));
2205 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2206 if (!buf
) return E_OUTOFMEMORY
;
2207 strcpyW( buf
, progid
);
2208 strcatW( buf
, clsidW
);
2209 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2211 HeapFree(GetProcessHeap(),0,buf
);
2212 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2213 return CO_E_CLASSSTRING
;
2215 HeapFree(GetProcessHeap(),0,buf
);
2217 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2220 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2221 return CO_E_CLASSSTRING
;
2224 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2227 /******************************************************************************
2228 * CLSIDFromString [OLE32.@]
2230 * Converts a unique identifier from its string representation into
2234 * idstr [I] The string representation of the GUID.
2235 * id [O] GUID converted from the string.
2239 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2244 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2246 HRESULT ret
= CO_E_CLASSSTRING
;
2250 return E_INVALIDARG
;
2252 if (guid_from_string(idstr
, id
))
2255 /* It appears a ProgID is also valid */
2256 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2263 /******************************************************************************
2264 * IIDFromString [OLE32.@]
2266 * Converts an interface identifier from its string representation to
2270 * idstr [I] The string representation of the GUID.
2271 * id [O] IID converted from the string.
2275 * CO_E_IIDSTRING if idstr is not a valid IID
2280 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2282 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2286 memset(iid
, 0, sizeof(*iid
));
2290 /* length mismatch is a special case */
2291 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2292 return E_INVALIDARG
;
2295 return CO_E_IIDSTRING
;
2297 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2300 /******************************************************************************
2301 * StringFromCLSID [OLE32.@]
2302 * StringFromIID [OLE32.@]
2304 * Converts a GUID into the respective string representation.
2305 * The target string is allocated using the OLE IMalloc.
2308 * id [I] the GUID to be converted.
2309 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2316 * StringFromGUID2, CLSIDFromString
2318 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2320 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2321 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2325 /******************************************************************************
2326 * StringFromGUID2 [OLE32.@]
2328 * Modified version of StringFromCLSID that allows you to specify max
2332 * id [I] GUID to convert to string.
2333 * str [O] Buffer where the result will be stored.
2334 * cmax [I] Size of the buffer in characters.
2337 * Success: The length of the resulting string in characters.
2340 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2342 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2343 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2344 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2345 '%','0','2','X','%','0','2','X','}',0 };
2346 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2347 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2348 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2349 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2350 return CHARS_IN_GUID
;
2353 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2354 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2356 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2357 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2361 strcpyW(path
, wszCLSIDSlash
);
2362 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2363 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2364 if (res
== ERROR_FILE_NOT_FOUND
)
2365 return REGDB_E_CLASSNOTREG
;
2366 else if (res
!= ERROR_SUCCESS
)
2367 return REGDB_E_READREGDB
;
2375 res
= open_classes_key(key
, keyname
, access
, subkey
);
2377 if (res
== ERROR_FILE_NOT_FOUND
)
2378 return REGDB_E_KEYMISSING
;
2379 else if (res
!= ERROR_SUCCESS
)
2380 return REGDB_E_READREGDB
;
2385 /* open HKCR\\AppId\\{string form of appid clsid} key */
2386 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2388 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2389 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2391 WCHAR buf
[CHARS_IN_GUID
];
2392 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2398 /* read the AppID value under the class's key */
2399 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2404 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2406 if (res
== ERROR_FILE_NOT_FOUND
)
2407 return REGDB_E_KEYMISSING
;
2408 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2409 return REGDB_E_READREGDB
;
2411 strcpyW(keyname
, szAppIdKey
);
2412 strcatW(keyname
, buf
);
2413 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2414 if (res
== ERROR_FILE_NOT_FOUND
)
2415 return REGDB_E_KEYMISSING
;
2416 else if (res
!= ERROR_SUCCESS
)
2417 return REGDB_E_READREGDB
;
2422 /******************************************************************************
2423 * ProgIDFromCLSID [OLE32.@]
2425 * Converts a class id into the respective program ID.
2428 * clsid [I] Class ID, as found in registry.
2429 * ppszProgID [O] Associated ProgID.
2434 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2436 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2438 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2439 ACTCTX_SECTION_KEYED_DATA data
;
2445 return E_INVALIDARG
;
2449 data
.cbSize
= sizeof(data
);
2450 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2453 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2454 if (comclass
->progid_len
)
2458 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2459 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2461 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2462 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2466 return REGDB_E_CLASSNOTREG
;
2469 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2473 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2474 ret
= REGDB_E_CLASSNOTREG
;
2478 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2481 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2482 ret
= REGDB_E_CLASSNOTREG
;
2483 CoTaskMemFree(*ppszProgID
);
2488 ret
= E_OUTOFMEMORY
;
2495 /******************************************************************************
2496 * CLSIDFromProgID [OLE32.@]
2498 * Converts a program id into the respective GUID.
2501 * progid [I] Unicode program ID, as found in registry.
2502 * clsid [O] Associated CLSID.
2506 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2508 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2510 ACTCTX_SECTION_KEYED_DATA data
;
2512 if (!progid
|| !clsid
)
2513 return E_INVALIDARG
;
2515 data
.cbSize
= sizeof(data
);
2516 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2519 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2520 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2525 return clsid_from_string_reg(progid
, clsid
);
2528 /******************************************************************************
2529 * CLSIDFromProgIDEx [OLE32.@]
2531 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2533 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2535 return CLSIDFromProgID(progid
, clsid
);
2538 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2541 WCHAR value
[CHARS_IN_GUID
];
2546 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2547 return REGDB_E_IIDNOTREG
;
2549 len
= sizeof(value
);
2550 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2551 return REGDB_E_IIDNOTREG
;
2554 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2555 return REGDB_E_IIDNOTREG
;
2560 /*****************************************************************************
2561 * CoGetPSClsid [OLE32.@]
2563 * Retrieves the CLSID of the proxy/stub factory that implements
2564 * IPSFactoryBuffer for the specified interface.
2567 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2568 * pclsid [O] Where to store returned proxy/stub CLSID.
2573 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2577 * The standard marshaller activates the object with the CLSID
2578 * returned and uses the CreateProxy and CreateStub methods on its
2579 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2582 * CoGetPSClsid determines this CLSID by searching the
2583 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2584 * in the registry and any interface id registered by
2585 * CoRegisterPSClsid within the current process.
2589 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2590 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2591 * considered a bug in native unless an application depends on this (unlikely).
2594 * CoRegisterPSClsid.
2596 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2598 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2599 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2600 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2602 struct registered_psclsid
*registered_psclsid
;
2603 ACTCTX_SECTION_KEYED_DATA data
;
2605 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2608 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2610 if (!(apt
= apartment_get_current_or_mta()))
2612 ERR("apartment not initialised\n");
2613 return CO_E_NOTINITIALIZED
;
2615 apartment_release(apt
);
2618 return E_INVALIDARG
;
2620 EnterCriticalSection(&cs_registered_psclsid_list
);
2622 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2623 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2625 *pclsid
= registered_psclsid
->clsid
;
2626 LeaveCriticalSection(&cs_registered_psclsid_list
);
2630 LeaveCriticalSection(&cs_registered_psclsid_list
);
2632 data
.cbSize
= sizeof(data
);
2633 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2636 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2637 *pclsid
= ifaceps
->iid
;
2641 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2642 strcpyW(path
, wszInterface
);
2643 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2644 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2646 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2647 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2648 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2649 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2652 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2654 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2659 /*****************************************************************************
2660 * CoRegisterPSClsid [OLE32.@]
2662 * Register a proxy/stub CLSID for the given interface in the current process
2666 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2667 * rclsid [I] CLSID of the proxy/stub.
2671 * Failure: E_OUTOFMEMORY
2675 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2676 * will be returned from other apartments in the same process.
2678 * This function does not add anything to the registry and the effects are
2679 * limited to the lifetime of the current process.
2684 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2687 struct registered_psclsid
*registered_psclsid
;
2689 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2691 if (!(apt
= apartment_get_current_or_mta()))
2693 ERR("apartment not initialised\n");
2694 return CO_E_NOTINITIALIZED
;
2696 apartment_release(apt
);
2698 EnterCriticalSection(&cs_registered_psclsid_list
);
2700 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2701 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2703 registered_psclsid
->clsid
= *rclsid
;
2704 LeaveCriticalSection(&cs_registered_psclsid_list
);
2708 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2709 if (!registered_psclsid
)
2711 LeaveCriticalSection(&cs_registered_psclsid_list
);
2712 return E_OUTOFMEMORY
;
2715 registered_psclsid
->iid
= *riid
;
2716 registered_psclsid
->clsid
= *rclsid
;
2717 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2719 LeaveCriticalSection(&cs_registered_psclsid_list
);
2726 * COM_GetRegisteredClassObject
2728 * This internal method is used to scan the registered class list to
2729 * find a class object.
2732 * rclsid Class ID of the class to find.
2733 * dwClsContext Class context to match.
2734 * ppv [out] returns a pointer to the class object. Complying
2735 * to normal COM usage, this method will increase the
2736 * reference count on this object.
2738 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2739 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2741 HRESULT hr
= S_FALSE
;
2742 RegisteredClass
*curClass
;
2744 EnterCriticalSection( &csRegisteredClassList
);
2746 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2749 * Check if we have a match on the class ID and context.
2751 if ((apt
->oxid
== curClass
->apartment_id
) &&
2752 (dwClsContext
& curClass
->runContext
) &&
2753 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2756 * We have a match, return the pointer to the class object.
2758 *ppUnk
= curClass
->classObject
;
2760 IUnknown_AddRef(curClass
->classObject
);
2767 LeaveCriticalSection( &csRegisteredClassList
);
2772 /******************************************************************************
2773 * CoRegisterClassObject [OLE32.@]
2775 * Registers the class object for a given class ID. Servers housed in EXE
2776 * files use this method instead of exporting DllGetClassObject to allow
2777 * other code to connect to their objects.
2780 * rclsid [I] CLSID of the object to register.
2781 * pUnk [I] IUnknown of the object.
2782 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2783 * flags [I] REGCLS flags indicating how connections are made.
2784 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2788 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2789 * CO_E_OBJISREG if the object is already registered. We should not return this.
2792 * CoRevokeClassObject, CoGetClassObject
2795 * In-process objects are only registered for the current apartment.
2796 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2797 * in other apartments.
2800 * MSDN claims that multiple interface registrations are legal, but we
2801 * can't do that with our current implementation.
2803 HRESULT WINAPI
CoRegisterClassObject(
2808 LPDWORD lpdwRegister
)
2810 static LONG next_cookie
;
2811 RegisteredClass
* newClass
;
2812 LPUNKNOWN foundObject
;
2816 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2817 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2819 if ( (lpdwRegister
==0) || (pUnk
==0) )
2820 return E_INVALIDARG
;
2822 if (!(apt
= apartment_get_current_or_mta()))
2824 ERR("COM was not initialized\n");
2825 return CO_E_NOTINITIALIZED
;
2830 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2831 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2832 if (flags
& REGCLS_MULTIPLEUSE
)
2833 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2836 * First, check if the class is already registered.
2837 * If it is, this should cause an error.
2839 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2841 if (flags
& REGCLS_MULTIPLEUSE
) {
2842 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2843 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2844 IUnknown_Release(foundObject
);
2845 apartment_release(apt
);
2848 IUnknown_Release(foundObject
);
2849 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2850 apartment_release(apt
);
2851 return CO_E_OBJISREG
;
2854 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2855 if ( newClass
== NULL
)
2857 apartment_release(apt
);
2858 return E_OUTOFMEMORY
;
2861 newClass
->classIdentifier
= *rclsid
;
2862 newClass
->apartment_id
= apt
->oxid
;
2863 newClass
->runContext
= dwClsContext
;
2864 newClass
->connectFlags
= flags
;
2865 newClass
->RpcRegistration
= NULL
;
2867 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2868 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2871 * Since we're making a copy of the object pointer, we have to increase its
2874 newClass
->classObject
= pUnk
;
2875 IUnknown_AddRef(newClass
->classObject
);
2877 EnterCriticalSection( &csRegisteredClassList
);
2878 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2879 LeaveCriticalSection( &csRegisteredClassList
);
2881 *lpdwRegister
= newClass
->dwCookie
;
2883 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2884 IStream
*marshal_stream
;
2886 hr
= get_local_server_stream(apt
, &marshal_stream
);
2889 apartment_release(apt
);
2893 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2895 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2896 &newClass
->RpcRegistration
);
2897 IStream_Release(marshal_stream
);
2899 apartment_release(apt
);
2903 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2907 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2908 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2909 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2910 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2911 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2912 DWORD dwLength
= sizeof(threading_model
);
2916 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2917 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2918 threading_model
[0] = '\0';
2920 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2921 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2922 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2924 /* there's not specific handling for this case */
2925 if (threading_model
[0]) return ThreadingModel_Neutral
;
2926 return ThreadingModel_No
;
2929 return data
->u
.actctx
.data
->model
;
2932 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2933 REFCLSID rclsid
, REFIID riid
,
2934 BOOL hostifnecessary
, void **ppv
)
2936 WCHAR dllpath
[MAX_PATH
+1];
2937 BOOL apartment_threaded
;
2939 if (hostifnecessary
)
2941 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2943 if (model
== ThreadingModel_Apartment
)
2945 apartment_threaded
= TRUE
;
2946 if (apt
->multi_threaded
)
2947 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2949 else if (model
== ThreadingModel_Free
)
2951 apartment_threaded
= FALSE
;
2952 if (!apt
->multi_threaded
)
2953 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2955 /* everything except "Apartment", "Free" and "Both" */
2956 else if (model
!= ThreadingModel_Both
)
2958 apartment_threaded
= TRUE
;
2959 /* everything else is main-threaded */
2960 if (model
!= ThreadingModel_No
)
2961 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2963 if (apt
->multi_threaded
|| !apt
->main
)
2964 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2967 apartment_threaded
= FALSE
;
2970 apartment_threaded
= !apt
->multi_threaded
;
2972 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2974 /* failure: CLSID is not found in registry */
2975 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2976 return REGDB_E_CLASSNOTREG
;
2979 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2983 /***********************************************************************
2984 * CoGetClassObject [OLE32.@]
2986 * Creates an object of the specified class.
2989 * rclsid [I] Class ID to create an instance of.
2990 * dwClsContext [I] Flags to restrict the location of the created instance.
2991 * pServerInfo [I] Optional. Details for connecting to a remote server.
2992 * iid [I] The ID of the interface of the instance to return.
2993 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2997 * Failure: HRESULT code.
3000 * The dwClsContext parameter can be one or more of the following:
3001 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3002 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3003 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3004 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3007 * CoCreateInstance()
3009 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
3010 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
3011 REFIID iid
, LPVOID
*ppv
)
3013 struct class_reg_data clsreg
;
3014 IUnknown
*regClassObject
;
3015 HRESULT hres
= E_UNEXPECTED
;
3018 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
3021 return E_INVALIDARG
;
3025 if (!(apt
= apartment_get_current_or_mta()))
3027 ERR("apartment not initialised\n");
3028 return CO_E_NOTINITIALIZED
;
3032 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3033 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3036 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3038 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3040 apartment_release(apt
);
3041 return FTMarshalCF_Create(iid
, ppv
);
3043 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3044 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3047 if (CLSCTX_INPROC
& dwClsContext
)
3049 ACTCTX_SECTION_KEYED_DATA data
;
3051 data
.cbSize
= sizeof(data
);
3052 /* search activation context first */
3053 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3054 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3057 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3059 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3060 clsreg
.u
.actctx
.data
= data
.lpData
;
3061 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3062 clsreg
.hkey
= FALSE
;
3064 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3065 ReleaseActCtx(data
.hActCtx
);
3066 apartment_release(apt
);
3072 * First, try and see if we can't match the class ID with one of the
3073 * registered classes.
3075 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3078 /* Get the required interface from the retrieved pointer. */
3079 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3082 * Since QI got another reference on the pointer, we want to release the
3083 * one we already have. If QI was unsuccessful, this will release the object. This
3084 * is good since we are not returning it in the "out" parameter.
3086 IUnknown_Release(regClassObject
);
3087 apartment_release(apt
);
3091 /* First try in-process server */
3092 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3094 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3097 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3100 if (hres
== REGDB_E_CLASSNOTREG
)
3101 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3102 else if (hres
== REGDB_E_KEYMISSING
)
3104 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3105 hres
= REGDB_E_CLASSNOTREG
;
3109 if (SUCCEEDED(hres
))
3111 clsreg
.u
.hkey
= hkey
;
3114 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3118 /* return if we got a class, otherwise fall through to one of the
3120 if (SUCCEEDED(hres
))
3122 apartment_release(apt
);
3127 /* Next try in-process handler */
3128 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3130 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3133 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3136 if (hres
== REGDB_E_CLASSNOTREG
)
3137 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3138 else if (hres
== REGDB_E_KEYMISSING
)
3140 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3141 hres
= REGDB_E_CLASSNOTREG
;
3145 if (SUCCEEDED(hres
))
3147 clsreg
.u
.hkey
= hkey
;
3150 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3154 /* return if we got a class, otherwise fall through to one of the
3156 if (SUCCEEDED(hres
))
3158 apartment_release(apt
);
3162 apartment_release(apt
);
3164 /* Next try out of process */
3165 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3167 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3168 if (SUCCEEDED(hres
))
3172 /* Finally try remote: this requires networked DCOM (a lot of work) */
3173 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3175 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3176 hres
= REGDB_E_CLASSNOTREG
;
3180 ERR("no class object %s could be created for context 0x%x\n",
3181 debugstr_guid(rclsid
), dwClsContext
);
3185 /***********************************************************************
3186 * CoResumeClassObjects (OLE32.@)
3188 * Resumes all class objects registered with REGCLS_SUSPENDED.
3192 * Failure: HRESULT code.
3194 HRESULT WINAPI
CoResumeClassObjects(void)
3200 /***********************************************************************
3201 * CoCreateInstance [OLE32.@]
3203 * Creates an instance of the specified class.
3206 * rclsid [I] Class ID to create an instance of.
3207 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3208 * dwClsContext [I] Flags to restrict the location of the created instance.
3209 * iid [I] The ID of the interface of the instance to return.
3210 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3214 * Failure: HRESULT code.
3217 * The dwClsContext parameter can be one or more of the following:
3218 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3219 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3220 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3221 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3223 * Aggregation is the concept of deferring the IUnknown of an object to another
3224 * object. This allows a separate object to behave as though it was part of
3225 * the object and to allow this the pUnkOuter parameter can be set. Note that
3226 * not all objects support having an outer of unknown.
3229 * CoGetClassObject()
3231 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3233 LPUNKNOWN pUnkOuter
,
3238 MULTI_QI multi_qi
= { iid
};
3241 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3242 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3247 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3248 *ppv
= multi_qi
.pItf
;
3252 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3256 for (i
= 0; i
< count
; i
++)
3263 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3265 ULONG index
= 0, fetched
= 0;
3271 index
= fetched
= 1;
3274 for (; index
< count
; index
++)
3276 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3277 if (mqi
[index
].hr
== S_OK
)
3282 IUnknown_Release(unk
);
3285 return E_NOINTERFACE
;
3287 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3290 /***********************************************************************
3291 * CoCreateInstanceEx [OLE32.@]
3293 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3295 LPUNKNOWN pUnkOuter
,
3297 COSERVERINFO
* pServerInfo
,
3301 IUnknown
*unk
= NULL
;
3307 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3309 if (!cmq
|| !pResults
)
3310 return E_INVALIDARG
;
3313 FIXME("() non-NULL pServerInfo not supported!\n");
3315 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3317 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3321 if (!(apt
= apartment_get_current_or_mta()))
3323 ERR("apartment not initialised\n");
3324 return CO_E_NOTINITIALIZED
;
3326 apartment_release(apt
);
3329 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3331 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3333 IGlobalInterfaceTable
*git
= get_std_git();
3334 TRACE("Retrieving GIT\n");
3335 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3338 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3339 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3342 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3346 * Get a class factory to construct the object we want.
3348 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3353 * Create the object and don't forget to release the factory
3355 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3356 IClassFactory_Release(cf
);
3359 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3360 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3362 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3363 debugstr_guid(pResults
[0].pIID
),
3364 debugstr_guid(&clsid
),hres
);
3368 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3371 /***********************************************************************
3372 * CoGetInstanceFromFile [OLE32.@]
3374 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3375 COSERVERINFO
*server_info
,
3385 IPersistFile
*pf
= NULL
;
3386 IUnknown
* unk
= NULL
;
3390 if (count
== 0 || !results
)
3391 return E_INVALIDARG
;
3394 FIXME("() non-NULL server_info not supported\n");
3396 init_multi_qi(count
, results
, E_NOINTERFACE
);
3398 /* optionally get CLSID from a file */
3401 hr
= GetClassFile(filename
, &clsid
);
3404 ERR("failed to get CLSID from a file\n");
3411 hr
= CoCreateInstance(rclsid
,
3419 init_multi_qi(count
, results
, hr
);
3423 /* init from file */
3424 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3427 init_multi_qi(count
, results
, hr
);
3428 IUnknown_Release(unk
);
3432 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3433 IPersistFile_Release(pf
);
3435 return return_multi_qi(unk
, count
, results
, FALSE
);
3438 init_multi_qi(count
, results
, hr
);
3439 IUnknown_Release(unk
);
3444 /***********************************************************************
3445 * CoGetInstanceFromIStorage [OLE32.@]
3447 HRESULT WINAPI
CoGetInstanceFromIStorage(
3448 COSERVERINFO
*server_info
,
3457 IPersistStorage
*ps
= NULL
;
3458 IUnknown
* unk
= NULL
;
3462 if (count
== 0 || !results
|| !storage
)
3463 return E_INVALIDARG
;
3466 FIXME("() non-NULL server_info not supported\n");
3468 init_multi_qi(count
, results
, E_NOINTERFACE
);
3470 /* optionally get CLSID from a file */
3473 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3474 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3477 ERR("failed to get CLSID from a file\n");
3481 rclsid
= &stat
.clsid
;
3484 hr
= CoCreateInstance(rclsid
,
3493 /* init from IStorage */
3494 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3496 ERR("failed to get IPersistStorage\n");
3500 IPersistStorage_Load(ps
, storage
);
3501 IPersistStorage_Release(ps
);
3504 return return_multi_qi(unk
, count
, results
, FALSE
);
3507 /***********************************************************************
3508 * CoLoadLibrary (OLE32.@)
3513 * lpszLibName [I] Path to library.
3514 * bAutoFree [I] Whether the library should automatically be freed.
3517 * Success: Handle to loaded library.
3521 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3523 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3525 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3527 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3530 /***********************************************************************
3531 * CoFreeLibrary [OLE32.@]
3533 * Unloads a library from memory.
3536 * hLibrary [I] Handle to library to unload.
3542 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3544 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3546 FreeLibrary(hLibrary
);
3550 /***********************************************************************
3551 * CoFreeAllLibraries [OLE32.@]
3553 * Function for backwards compatibility only. Does nothing.
3559 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3561 void WINAPI
CoFreeAllLibraries(void)
3566 /***********************************************************************
3567 * CoFreeUnusedLibrariesEx [OLE32.@]
3569 * Frees any previously unused libraries whose delay has expired and marks
3570 * currently unused libraries for unloading. Unused are identified as those that
3571 * return S_OK from their DllCanUnloadNow function.
3574 * dwUnloadDelay [I] Unload delay in milliseconds.
3575 * dwReserved [I] Reserved. Set to 0.
3581 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3583 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3585 struct apartment
*apt
= COM_CurrentApt();
3588 ERR("apartment not initialised\n");
3592 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3595 /***********************************************************************
3596 * CoFreeUnusedLibraries [OLE32.@]
3598 * Frees any unused libraries. Unused are identified as those that return
3599 * S_OK from their DllCanUnloadNow function.
3605 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3607 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3609 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3612 /***********************************************************************
3613 * CoFileTimeNow [OLE32.@]
3615 * Retrieves the current time in FILETIME format.
3618 * lpFileTime [O] The current time.
3623 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3625 GetSystemTimeAsFileTime( lpFileTime
);
3629 /******************************************************************************
3630 * CoLockObjectExternal [OLE32.@]
3632 * Increments or decrements the external reference count of a stub object.
3635 * pUnk [I] Stub object.
3636 * fLock [I] If TRUE then increments the external ref-count,
3637 * otherwise decrements.
3638 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3639 * calling CoDisconnectObject.
3643 * Failure: HRESULT code.
3646 * If fLock is TRUE and an object is passed in that doesn't have a stub
3647 * manager then a new stub manager is created for the object.
3649 HRESULT WINAPI
CoLockObjectExternal(
3652 BOOL fLastUnlockReleases
)
3654 struct stub_manager
*stubmgr
;
3655 struct apartment
*apt
;
3657 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3658 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3660 if (!(apt
= apartment_get_current_or_mta()))
3662 ERR("apartment not initialised\n");
3663 return CO_E_NOTINITIALIZED
;
3666 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3669 WARN("stub object not found %p\n", pUnk
);
3670 /* Note: native is pretty broken here because it just silently
3671 * fails, without returning an appropriate error code, making apps
3672 * think that the object was disconnected, when it actually wasn't */
3673 apartment_release(apt
);
3678 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3680 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3682 stub_manager_int_release(stubmgr
);
3683 apartment_release(apt
);
3687 /***********************************************************************
3688 * CoInitializeWOW (OLE32.@)
3690 * WOW equivalent of CoInitialize?
3699 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3701 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3705 /***********************************************************************
3706 * CoGetState [OLE32.@]
3708 * Retrieves the thread state object previously stored by CoSetState().
3711 * ppv [I] Address where pointer to object will be stored.
3715 * Failure: E_OUTOFMEMORY.
3718 * Crashes on all invalid ppv addresses, including NULL.
3719 * If the function returns a non-NULL object then the caller must release its
3720 * reference on the object when the object is no longer required.
3725 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3727 struct oletls
*info
= COM_CurrentInfo();
3728 if (!info
) return E_OUTOFMEMORY
;
3734 IUnknown_AddRef(info
->state
);
3736 TRACE("apt->state=%p\n", info
->state
);
3742 /***********************************************************************
3743 * CoSetState [OLE32.@]
3745 * Sets the thread state object.
3748 * pv [I] Pointer to state object to be stored.
3751 * The system keeps a reference on the object while the object stored.
3755 * Failure: E_OUTOFMEMORY.
3757 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3759 struct oletls
*info
= COM_CurrentInfo();
3760 if (!info
) return E_OUTOFMEMORY
;
3762 if (pv
) IUnknown_AddRef(pv
);
3766 TRACE("-- release %p now\n", info
->state
);
3767 IUnknown_Release(info
->state
);
3776 /******************************************************************************
3777 * CoTreatAsClass [OLE32.@]
3779 * Sets the TreatAs value of a class.
3782 * clsidOld [I] Class to set TreatAs value on.
3783 * clsidNew [I] The class the clsidOld should be treated as.
3787 * Failure: HRESULT code.
3792 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3794 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3795 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3797 WCHAR szClsidNew
[CHARS_IN_GUID
];
3799 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3800 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3803 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3807 if (IsEqualGUID( clsidOld
, clsidNew
))
3809 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3810 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3812 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3814 res
= REGDB_E_WRITEREGDB
;
3820 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3821 res
= REGDB_E_WRITEREGDB
;
3827 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3828 RegDeleteKeyW(hkey
, wszTreatAs
);
3830 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3831 WARN("StringFromGUID2 failed\n");
3836 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3837 WARN("RegSetValue failed\n");
3838 res
= REGDB_E_WRITEREGDB
;
3845 if (hkey
) RegCloseKey(hkey
);
3849 /******************************************************************************
3850 * CoGetTreatAsClass [OLE32.@]
3852 * Gets the TreatAs value of a class.
3855 * clsidOld [I] Class to get the TreatAs value of.
3856 * clsidNew [I] The class the clsidOld should be treated as.
3860 * Failure: HRESULT code.
3865 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3867 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3869 WCHAR szClsidNew
[CHARS_IN_GUID
];
3871 LONG len
= sizeof(szClsidNew
);
3873 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3875 if (!clsidOld
|| !clsidNew
)
3876 return E_INVALIDARG
;
3878 *clsidNew
= *clsidOld
; /* copy over old value */
3880 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3886 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3891 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3893 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3895 if (hkey
) RegCloseKey(hkey
);
3899 /******************************************************************************
3900 * CoGetCurrentProcess [OLE32.@]
3902 * Gets the current process ID.
3905 * The current process ID.
3908 * Is DWORD really the correct return type for this function?
3910 DWORD WINAPI
CoGetCurrentProcess(void)
3912 return GetCurrentProcessId();
3915 /***********************************************************************
3916 * CoGetCurrentLogicalThreadId [OLE32.@]
3918 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3920 TRACE("(%p)\n", id
);
3923 return E_INVALIDARG
;
3925 *id
= COM_CurrentCausalityId();
3929 /******************************************************************************
3930 * CoRegisterMessageFilter [OLE32.@]
3932 * Registers a message filter.
3935 * lpMessageFilter [I] Pointer to interface.
3936 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3940 * Failure: HRESULT code.
3943 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3944 * lpMessageFilter removes the message filter.
3946 * If lplpMessageFilter is not NULL the previous message filter will be
3947 * returned in the memory pointer to this parameter and the caller is
3948 * responsible for releasing the object.
3950 * The current thread be in an apartment otherwise the function will crash.
3952 HRESULT WINAPI
CoRegisterMessageFilter(
3953 LPMESSAGEFILTER lpMessageFilter
,
3954 LPMESSAGEFILTER
*lplpMessageFilter
)
3956 struct apartment
*apt
;
3957 IMessageFilter
*lpOldMessageFilter
;
3959 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3961 apt
= COM_CurrentApt();
3963 /* can't set a message filter in a multi-threaded apartment */
3964 if (!apt
|| apt
->multi_threaded
)
3966 WARN("can't set message filter in MTA or uninitialized apt\n");
3967 return CO_E_NOT_SUPPORTED
;
3970 if (lpMessageFilter
)
3971 IMessageFilter_AddRef(lpMessageFilter
);
3973 EnterCriticalSection(&apt
->cs
);
3975 lpOldMessageFilter
= apt
->filter
;
3976 apt
->filter
= lpMessageFilter
;
3978 LeaveCriticalSection(&apt
->cs
);
3980 if (lplpMessageFilter
)
3981 *lplpMessageFilter
= lpOldMessageFilter
;
3982 else if (lpOldMessageFilter
)
3983 IMessageFilter_Release(lpOldMessageFilter
);
3988 /***********************************************************************
3989 * CoIsOle1Class [OLE32.@]
3991 * Determines whether the specified class an OLE v1 class.
3994 * clsid [I] Class to test.
3997 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3999 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
4001 FIXME("%s\n", debugstr_guid(clsid
));
4005 /***********************************************************************
4006 * IsEqualGUID [OLE32.@]
4008 * Compares two Unique Identifiers.
4011 * rguid1 [I] The first GUID to compare.
4012 * rguid2 [I] The other GUID to compare.
4018 BOOL WINAPI
IsEqualGUID(
4022 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
4025 /***********************************************************************
4026 * CoInitializeSecurity [OLE32.@]
4028 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4029 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4030 void* pReserved1
, DWORD dwAuthnLevel
,
4031 DWORD dwImpLevel
, void* pReserved2
,
4032 DWORD dwCapabilities
, void* pReserved3
)
4034 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4035 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4036 dwCapabilities
, pReserved3
);
4040 /***********************************************************************
4041 * CoSuspendClassObjects [OLE32.@]
4043 * Suspends all registered class objects to prevent further requests coming in
4044 * for those objects.
4048 * Failure: HRESULT code.
4050 HRESULT WINAPI
CoSuspendClassObjects(void)
4056 /***********************************************************************
4057 * CoAddRefServerProcess [OLE32.@]
4059 * Helper function for incrementing the reference count of a local-server
4063 * New reference count.
4066 * CoReleaseServerProcess().
4068 ULONG WINAPI
CoAddRefServerProcess(void)
4074 EnterCriticalSection(&csRegisteredClassList
);
4075 refs
= ++s_COMServerProcessReferences
;
4076 LeaveCriticalSection(&csRegisteredClassList
);
4078 TRACE("refs before: %d\n", refs
- 1);
4083 /***********************************************************************
4084 * CoReleaseServerProcess [OLE32.@]
4086 * Helper function for decrementing the reference count of a local-server
4090 * New reference count.
4093 * When reference count reaches 0, this function suspends all registered
4094 * classes so no new connections are accepted.
4097 * CoAddRefServerProcess(), CoSuspendClassObjects().
4099 ULONG WINAPI
CoReleaseServerProcess(void)
4105 EnterCriticalSection(&csRegisteredClassList
);
4107 refs
= --s_COMServerProcessReferences
;
4108 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4110 LeaveCriticalSection(&csRegisteredClassList
);
4112 TRACE("refs after: %d\n", refs
);
4117 /***********************************************************************
4118 * CoIsHandlerConnected [OLE32.@]
4120 * Determines whether a proxy is connected to a remote stub.
4123 * pUnk [I] Pointer to object that may or may not be connected.
4126 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4129 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4131 FIXME("%p\n", pUnk
);
4136 /***********************************************************************
4137 * CoAllowSetForegroundWindow [OLE32.@]
4140 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4142 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4146 /***********************************************************************
4147 * CoQueryProxyBlanket [OLE32.@]
4149 * Retrieves the security settings being used by a proxy.
4152 * pProxy [I] Pointer to the proxy object.
4153 * pAuthnSvc [O] The type of authentication service.
4154 * pAuthzSvc [O] The type of authorization service.
4155 * ppServerPrincName [O] Optional. The server prinicple name.
4156 * pAuthnLevel [O] The authentication level.
4157 * pImpLevel [O] The impersonation level.
4158 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4159 * pCapabilities [O] Flags affecting the security behaviour.
4163 * Failure: HRESULT code.
4166 * CoCopyProxy, CoSetProxyBlanket.
4168 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4169 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4170 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4172 IClientSecurity
*pCliSec
;
4175 TRACE("%p\n", pProxy
);
4177 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4180 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4181 pAuthzSvc
, ppServerPrincName
,
4182 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4184 IClientSecurity_Release(pCliSec
);
4187 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4191 /***********************************************************************
4192 * CoSetProxyBlanket [OLE32.@]
4194 * Sets the security settings for a proxy.
4197 * pProxy [I] Pointer to the proxy object.
4198 * AuthnSvc [I] The type of authentication service.
4199 * AuthzSvc [I] The type of authorization service.
4200 * pServerPrincName [I] The server prinicple name.
4201 * AuthnLevel [I] The authentication level.
4202 * ImpLevel [I] The impersonation level.
4203 * pAuthInfo [I] Information specific to the authorization/authentication service.
4204 * Capabilities [I] Flags affecting the security behaviour.
4208 * Failure: HRESULT code.
4211 * CoQueryProxyBlanket, CoCopyProxy.
4213 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4214 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4215 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4217 IClientSecurity
*pCliSec
;
4220 TRACE("%p\n", pProxy
);
4222 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4225 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4226 AuthzSvc
, pServerPrincName
,
4227 AuthnLevel
, ImpLevel
, pAuthInfo
,
4229 IClientSecurity_Release(pCliSec
);
4232 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4236 /***********************************************************************
4237 * CoCopyProxy [OLE32.@]
4242 * pProxy [I] Pointer to the proxy object.
4243 * ppCopy [O] Copy of the proxy.
4247 * Failure: HRESULT code.
4250 * CoQueryProxyBlanket, CoSetProxyBlanket.
4252 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4254 IClientSecurity
*pCliSec
;
4257 TRACE("%p\n", pProxy
);
4259 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4262 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4263 IClientSecurity_Release(pCliSec
);
4266 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4271 /***********************************************************************
4272 * CoGetCallContext [OLE32.@]
4274 * Gets the context of the currently executing server call in the current
4278 * riid [I] Context interface to return.
4279 * ppv [O] Pointer to memory that will receive the context on return.
4283 * Failure: HRESULT code.
4285 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4287 struct oletls
*info
= COM_CurrentInfo();
4289 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4292 return E_OUTOFMEMORY
;
4294 if (!info
->call_state
)
4295 return RPC_E_CALL_COMPLETE
;
4297 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4300 /***********************************************************************
4301 * CoSwitchCallContext [OLE32.@]
4303 * Switches the context of the currently executing server call in the current
4307 * pObject [I] Pointer to new context object
4308 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4312 * Failure: HRESULT code.
4314 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4316 struct oletls
*info
= COM_CurrentInfo();
4318 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4321 return E_OUTOFMEMORY
;
4323 *ppOldObject
= info
->call_state
;
4324 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4329 /***********************************************************************
4330 * CoQueryClientBlanket [OLE32.@]
4332 * Retrieves the authentication information about the client of the currently
4333 * executing server call in the current thread.
4336 * pAuthnSvc [O] Optional. The type of authentication service.
4337 * pAuthzSvc [O] Optional. The type of authorization service.
4338 * pServerPrincName [O] Optional. The server prinicple name.
4339 * pAuthnLevel [O] Optional. The authentication level.
4340 * pImpLevel [O] Optional. The impersonation level.
4341 * pPrivs [O] Optional. Information about the privileges of the client.
4342 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4346 * Failure: HRESULT code.
4349 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4351 HRESULT WINAPI
CoQueryClientBlanket(
4354 OLECHAR
**pServerPrincName
,
4357 RPC_AUTHZ_HANDLE
*pPrivs
,
4358 DWORD
*pCapabilities
)
4360 IServerSecurity
*pSrvSec
;
4363 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4364 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4365 pPrivs
, pCapabilities
);
4367 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4370 hr
= IServerSecurity_QueryBlanket(
4371 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4372 pImpLevel
, pPrivs
, pCapabilities
);
4373 IServerSecurity_Release(pSrvSec
);
4379 /***********************************************************************
4380 * CoImpersonateClient [OLE32.@]
4382 * Impersonates the client of the currently executing server call in the
4390 * Failure: HRESULT code.
4393 * If this function fails then the current thread will not be impersonating
4394 * the client and all actions will take place on behalf of the server.
4395 * Therefore, it is important to check the return value from this function.
4398 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4400 HRESULT WINAPI
CoImpersonateClient(void)
4402 IServerSecurity
*pSrvSec
;
4407 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4410 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4411 IServerSecurity_Release(pSrvSec
);
4417 /***********************************************************************
4418 * CoRevertToSelf [OLE32.@]
4420 * Ends the impersonation of the client of the currently executing server
4421 * call in the current thread.
4428 * Failure: HRESULT code.
4431 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4433 HRESULT WINAPI
CoRevertToSelf(void)
4435 IServerSecurity
*pSrvSec
;
4440 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4443 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4444 IServerSecurity_Release(pSrvSec
);
4450 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4452 /* first try to retrieve messages for incoming COM calls to the apartment window */
4453 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4454 /* next retrieve other messages necessary for the app to remain responsive */
4455 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4456 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4459 /***********************************************************************
4460 * CoWaitForMultipleHandles [OLE32.@]
4462 * Waits for one or more handles to become signaled.
4465 * dwFlags [I] Flags. See notes.
4466 * dwTimeout [I] Timeout in milliseconds.
4467 * cHandles [I] Number of handles pointed to by pHandles.
4468 * pHandles [I] Handles to wait for.
4469 * lpdwindex [O] Index of handle that was signaled.
4473 * Failure: RPC_S_CALLPENDING on timeout.
4477 * The dwFlags parameter can be zero or more of the following:
4478 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4479 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4482 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4484 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4485 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4488 DWORD start_time
= GetTickCount();
4489 APARTMENT
*apt
= COM_CurrentApt();
4490 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4491 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4492 BOOL post_quit
= FALSE
;
4495 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4496 pHandles
, lpdwindex
);
4499 return E_INVALIDARG
;
4504 return E_INVALIDARG
;
4507 return RPC_E_NO_SYNC
;
4511 DWORD now
= GetTickCount();
4514 if (now
- start_time
> dwTimeout
)
4516 hr
= RPC_S_CALLPENDING
;
4522 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4523 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4525 TRACE("waiting for rpc completion or window message\n");
4531 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4532 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4536 if (res
== WAIT_TIMEOUT
)
4537 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4538 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4539 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4541 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4546 /* call message filter */
4548 if (COM_CurrentApt()->filter
)
4550 PENDINGTYPE pendingtype
=
4551 COM_CurrentInfo()->pending_call_count_server
?
4552 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4553 DWORD be_handled
= IMessageFilter_MessagePending(
4554 COM_CurrentApt()->filter
, 0 /* FIXME */,
4555 now
- start_time
, pendingtype
);
4556 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4559 case PENDINGMSG_CANCELCALL
:
4560 WARN("call canceled\n");
4561 hr
= RPC_E_CALL_CANCELED
;
4563 case PENDINGMSG_WAITNOPROCESS
:
4564 case PENDINGMSG_WAITDEFPROCESS
:
4566 /* FIXME: MSDN is very vague about the difference
4567 * between WAITNOPROCESS and WAITDEFPROCESS - there
4568 * appears to be none, so it is possibly a left-over
4569 * from the 16-bit world. */
4576 /* If window is NULL on apartment, peek at messages so that it will not trigger
4577 * MsgWaitForMultipleObjects next time. */
4578 PeekMessageW(NULL
, NULL
, 0, 0, PM_QS_POSTMESSAGE
| PM_NOREMOVE
| PM_NOYIELD
);
4580 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4581 * so after processing 100 messages we go back to checking the wait handles */
4582 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4584 if (msg
.message
== WM_QUIT
)
4586 TRACE("received WM_QUIT message\n");
4588 exit_code
= msg
.wParam
;
4592 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4593 TranslateMessage(&msg
);
4594 DispatchMessageW(&msg
);
4602 TRACE("waiting for rpc completion\n");
4604 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4605 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4606 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4612 hr
= RPC_S_CALLPENDING
;
4615 hr
= HRESULT_FROM_WIN32( GetLastError() );
4623 if (post_quit
) PostQuitMessage(exit_code
);
4624 TRACE("-- 0x%08x\n", hr
);
4629 /***********************************************************************
4630 * CoGetObject [OLE32.@]
4632 * Gets the object named by converting the name to a moniker and binding to it.
4635 * pszName [I] String representing the object.
4636 * pBindOptions [I] Parameters affecting the binding to the named object.
4637 * riid [I] Interface to bind to on the objecct.
4638 * ppv [O] On output, the interface riid of the object represented
4643 * Failure: HRESULT code.
4646 * MkParseDisplayName.
4648 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4649 REFIID riid
, void **ppv
)
4656 hr
= CreateBindCtx(0, &pbc
);
4660 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4667 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4670 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4671 IMoniker_Release(pmk
);
4675 IBindCtx_Release(pbc
);
4680 /***********************************************************************
4681 * CoRegisterChannelHook [OLE32.@]
4683 * Registers a process-wide hook that is called during ORPC calls.
4686 * guidExtension [I] GUID of the channel hook to register.
4687 * pChannelHook [I] Channel hook object to register.
4691 * Failure: HRESULT code.
4693 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4695 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4697 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4700 typedef struct Context
4702 IComThreadingInfo IComThreadingInfo_iface
;
4703 IContextCallback IContextCallback_iface
;
4704 IObjContext IObjContext_iface
;
4708 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4710 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4713 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4715 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4718 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4720 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4723 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4727 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4728 IsEqualIID(riid
, &IID_IUnknown
))
4730 *ppv
= &iface
->IComThreadingInfo_iface
;
4732 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4734 *ppv
= &iface
->IContextCallback_iface
;
4736 else if (IsEqualIID(riid
, &IID_IObjContext
))
4738 *ppv
= &iface
->IObjContext_iface
;
4743 IUnknown_AddRef((IUnknown
*)*ppv
);
4747 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4748 return E_NOINTERFACE
;
4751 static ULONG
Context_AddRef(Context
*This
)
4753 return InterlockedIncrement(&This
->refs
);
4756 static ULONG
Context_Release(Context
*This
)
4758 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4759 releasing context while refcount is at 0 destroys it. */
4762 HeapFree(GetProcessHeap(), 0, This
);
4766 return InterlockedDecrement(&This
->refs
);
4769 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4771 Context
*This
= impl_from_IComThreadingInfo(iface
);
4772 return Context_QueryInterface(This
, riid
, ppv
);
4775 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4777 Context
*This
= impl_from_IComThreadingInfo(iface
);
4778 return Context_AddRef(This
);
4781 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4783 Context
*This
= impl_from_IComThreadingInfo(iface
);
4784 return Context_Release(This
);
4787 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4789 APTTYPEQUALIFIER qualifier
;
4791 TRACE("(%p)\n", apttype
);
4793 return CoGetApartmentType(apttype
, &qualifier
);
4796 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4798 APTTYPEQUALIFIER qualifier
;
4802 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4806 TRACE("(%p)\n", thdtype
);
4811 case APTTYPE_MAINSTA
:
4812 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4815 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4821 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4823 TRACE("(%p)\n", logical_thread_id
);
4824 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4827 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4829 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4833 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4835 Context_CTI_QueryInterface
,
4837 Context_CTI_Release
,
4838 Context_CTI_GetCurrentApartmentType
,
4839 Context_CTI_GetCurrentThreadType
,
4840 Context_CTI_GetCurrentLogicalThreadId
,
4841 Context_CTI_SetCurrentLogicalThreadId
4844 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4846 Context
*This
= impl_from_IContextCallback(iface
);
4847 return Context_QueryInterface(This
, riid
, ppv
);
4850 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4852 Context
*This
= impl_from_IContextCallback(iface
);
4853 return Context_AddRef(This
);
4856 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4858 Context
*This
= impl_from_IContextCallback(iface
);
4859 return Context_Release(This
);
4862 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4863 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4865 Context
*This
= impl_from_IContextCallback(iface
);
4867 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4871 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4873 Context_CC_QueryInterface
,
4876 Context_CC_ContextCallback
4879 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4881 Context
*This
= impl_from_IObjContext(iface
);
4882 return Context_QueryInterface(This
, riid
, ppv
);
4885 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4887 Context
*This
= impl_from_IObjContext(iface
);
4888 return Context_AddRef(This
);
4891 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4893 Context
*This
= impl_from_IObjContext(iface
);
4894 return Context_Release(This
);
4897 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4899 Context
*This
= impl_from_IObjContext(iface
);
4901 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4905 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4907 Context
*This
= impl_from_IObjContext(iface
);
4909 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4913 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4915 Context
*This
= impl_from_IObjContext(iface
);
4917 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4921 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4923 Context
*This
= impl_from_IObjContext(iface
);
4925 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4929 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4931 Context
*This
= impl_from_IObjContext(iface
);
4932 FIXME("(%p/%p)\n", This
, iface
);
4935 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4937 Context
*This
= impl_from_IObjContext(iface
);
4938 FIXME("(%p/%p)\n", This
, iface
);
4941 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4943 Context
*This
= impl_from_IObjContext(iface
);
4944 FIXME("(%p/%p)\n", This
, iface
);
4947 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4949 Context
*This
= impl_from_IObjContext(iface
);
4950 FIXME("(%p/%p)\n", This
, iface
);
4953 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4955 Context
*This
= impl_from_IObjContext(iface
);
4956 FIXME("(%p/%p)\n", This
, iface
);
4959 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4961 Context
*This
= impl_from_IObjContext(iface
);
4962 FIXME("(%p/%p)\n", This
, iface
);
4965 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4967 Context
*This
= impl_from_IObjContext(iface
);
4968 FIXME("(%p/%p)\n", This
, iface
);
4971 static const IObjContextVtbl Context_Object_Vtbl
=
4973 Context_OC_QueryInterface
,
4976 Context_OC_SetProperty
,
4977 Context_OC_RemoveProperty
,
4978 Context_OC_GetProperty
,
4979 Context_OC_EnumContextProps
,
4980 Context_OC_Reserved1
,
4981 Context_OC_Reserved2
,
4982 Context_OC_Reserved3
,
4983 Context_OC_Reserved4
,
4984 Context_OC_Reserved5
,
4985 Context_OC_Reserved6
,
4986 Context_OC_Reserved7
4989 /***********************************************************************
4990 * CoGetObjectContext [OLE32.@]
4992 * Retrieves an object associated with the current context (i.e. apartment).
4995 * riid [I] ID of the interface of the object to retrieve.
4996 * ppv [O] Address where object will be stored on return.
5000 * Failure: HRESULT code.
5002 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
5004 IObjContext
*context
;
5007 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
5010 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
5014 return IObjContext_QueryInterface(context
, riid
, ppv
);
5017 /***********************************************************************
5018 * CoGetContextToken [OLE32.@]
5020 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
5022 struct oletls
*info
= COM_CurrentInfo();
5025 TRACE("(%p)\n", token
);
5028 return E_OUTOFMEMORY
;
5030 if (!(apt
= apartment_get_current_or_mta()))
5032 ERR("apartment not initialised\n");
5033 return CO_E_NOTINITIALIZED
;
5035 apartment_release(apt
);
5040 if (!info
->context_token
)
5044 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5046 return E_OUTOFMEMORY
;
5048 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5049 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5050 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5051 /* Context token does not take a reference, it's always zero until the
5052 interface is explicitly requested with CoGetObjectContext(). */
5055 info
->context_token
= &context
->IObjContext_iface
;
5058 *token
= (ULONG_PTR
)info
->context_token
;
5059 TRACE("context_token=%p\n", info
->context_token
);
5064 /***********************************************************************
5065 * CoGetDefaultContext [OLE32.@]
5067 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5069 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5070 return E_NOINTERFACE
;
5073 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5075 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5079 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5080 if (SUCCEEDED(hres
))
5082 struct class_reg_data regdata
;
5083 WCHAR dllpath
[MAX_PATH
+1];
5085 regdata
.u
.hkey
= hkey
;
5086 regdata
.hkey
= TRUE
;
5088 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
5090 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5091 if (!strcmpiW(dllpath
, wszOle32
))
5094 return HandlerCF_Create(rclsid
, riid
, ppv
);
5098 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5102 return CLASS_E_CLASSNOTAVAILABLE
;
5105 /***********************************************************************
5106 * CoGetApartmentType [OLE32.@]
5108 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5110 struct oletls
*info
= COM_CurrentInfo();
5113 TRACE("(%p, %p)\n", type
, qualifier
);
5115 if (!type
|| !qualifier
)
5116 return E_INVALIDARG
;
5119 return E_OUTOFMEMORY
;
5122 *type
= APTTYPE_CURRENT
;
5123 else if (info
->apt
->multi_threaded
)
5124 *type
= APTTYPE_MTA
;
5125 else if (info
->apt
->main
)
5126 *type
= APTTYPE_MAINSTA
;
5128 *type
= APTTYPE_STA
;
5130 *qualifier
= APTTYPEQUALIFIER_NONE
;
5132 if (!info
->apt
&& (apt
= apartment_find_mta()))
5134 apartment_release(apt
);
5135 *type
= APTTYPE_MTA
;
5136 *qualifier
= APTTYPEQUALIFIER_IMPLICIT_MTA
;
5139 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5142 /***********************************************************************
5143 * CoRegisterSurrogate [OLE32.@]
5145 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5147 FIXME("(%p): stub\n", surrogate
);
5152 /***********************************************************************
5153 * CoRegisterSurrogateEx [OLE32.@]
5155 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5157 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5163 IGlobalOptions IGlobalOptions_iface
;
5167 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5169 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5172 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5174 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5176 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5178 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5185 return E_NOINTERFACE
;
5188 IUnknown_AddRef((IUnknown
*)*ppv
);
5192 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5194 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5195 LONG ref
= InterlockedIncrement(&This
->ref
);
5197 TRACE("(%p) ref=%d\n", This
, ref
);
5202 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5204 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5205 LONG ref
= InterlockedDecrement(&This
->ref
);
5207 TRACE("(%p) ref=%d\n", This
, ref
);
5215 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5217 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5218 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5222 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5224 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5225 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5229 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5230 GlobalOptions_QueryInterface
,
5231 GlobalOptions_AddRef
,
5232 GlobalOptions_Release
,
5237 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5239 GlobalOptions
*global_options
;
5242 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5245 return E_INVALIDARG
;
5247 global_options
= heap_alloc(sizeof(*global_options
));
5248 if (!global_options
)
5249 return E_OUTOFMEMORY
;
5250 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5251 global_options
->ref
= 1;
5253 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5254 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5258 /***********************************************************************
5261 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5263 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5266 case DLL_PROCESS_ATTACH
:
5267 hProxyDll
= hinstDLL
;
5270 case DLL_PROCESS_DETACH
:
5271 if (reserved
) break;
5273 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5274 RPC_UnregisterAllChannelHooks();
5275 COMPOBJ_DllList_Free();
5276 DeleteCriticalSection(&csRegisteredClassList
);
5277 DeleteCriticalSection(&csApartment
);
5280 case DLL_THREAD_DETACH
:
5287 /***********************************************************************
5288 * DllRegisterServer (OLE32.@)
5290 HRESULT WINAPI
DllRegisterServer(void)
5292 return OLE32_DllRegisterServer();
5295 /***********************************************************************
5296 * DllUnregisterServer (OLE32.@)
5298 HRESULT WINAPI
DllUnregisterServer(void)
5300 return OLE32_DllUnregisterServer();