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 static void COM_RevokeRegisteredClassObject(RegisteredClass
*curClass
)
722 list_remove(&curClass
->entry
);
724 if (curClass
->runContext
& CLSCTX_LOCAL_SERVER
)
725 RPC_StopLocalServer(curClass
->RpcRegistration
);
727 IUnknown_Release(curClass
->classObject
);
728 HeapFree(GetProcessHeap(), 0, curClass
);
731 static void COM_RevokeAllClasses(const struct apartment
*apt
)
733 RegisteredClass
*curClass
, *cursor
;
735 EnterCriticalSection( &csRegisteredClassList
);
737 LIST_FOR_EACH_ENTRY_SAFE(curClass
, cursor
, &RegisteredClassList
, RegisteredClass
, entry
)
739 if (curClass
->apartment_id
== apt
->oxid
)
740 COM_RevokeRegisteredClassObject(curClass
);
743 LeaveCriticalSection( &csRegisteredClassList
);
746 static void revoke_registered_psclsids(void)
748 struct registered_psclsid
*psclsid
, *psclsid2
;
750 EnterCriticalSection( &cs_registered_psclsid_list
);
752 LIST_FOR_EACH_ENTRY_SAFE(psclsid
, psclsid2
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
754 list_remove(&psclsid
->entry
);
755 HeapFree(GetProcessHeap(), 0, psclsid
);
758 LeaveCriticalSection( &cs_registered_psclsid_list
);
761 /******************************************************************************
762 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
765 typedef struct ManualResetEvent
{
766 ISynchronize ISynchronize_iface
;
767 ISynchronizeHandle ISynchronizeHandle_iface
;
772 static inline MREImpl
*impl_from_ISynchronize(ISynchronize
*iface
)
774 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronize_iface
);
777 static HRESULT WINAPI
ISynchronize_fnQueryInterface(ISynchronize
*iface
, REFIID riid
, void **ppv
)
779 MREImpl
*This
= impl_from_ISynchronize(iface
);
781 TRACE("%p (%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
783 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ISynchronize
)) {
784 *ppv
= &This
->ISynchronize_iface
;
785 }else if(IsEqualGUID(riid
, &IID_ISynchronizeHandle
)) {
786 *ppv
= &This
->ISynchronizeHandle_iface
;
788 ERR("Unknown interface %s requested.\n", debugstr_guid(riid
));
790 return E_NOINTERFACE
;
793 IUnknown_AddRef((IUnknown
*)*ppv
);
797 static ULONG WINAPI
ISynchronize_fnAddRef(ISynchronize
*iface
)
799 MREImpl
*This
= impl_from_ISynchronize(iface
);
800 LONG ref
= InterlockedIncrement(&This
->ref
);
801 TRACE("%p - ref %d\n", This
, ref
);
806 static ULONG WINAPI
ISynchronize_fnRelease(ISynchronize
*iface
)
808 MREImpl
*This
= impl_from_ISynchronize(iface
);
809 LONG ref
= InterlockedDecrement(&This
->ref
);
810 TRACE("%p - ref %d\n", This
, ref
);
814 CloseHandle(This
->event
);
815 HeapFree(GetProcessHeap(), 0, This
);
821 static HRESULT WINAPI
ISynchronize_fnWait(ISynchronize
*iface
, DWORD dwFlags
, DWORD dwMilliseconds
)
823 MREImpl
*This
= impl_from_ISynchronize(iface
);
825 TRACE("%p (%08x, %08x)\n", This
, dwFlags
, dwMilliseconds
);
826 return CoWaitForMultipleHandles(dwFlags
, dwMilliseconds
, 1, &This
->event
, &index
);
829 static HRESULT WINAPI
ISynchronize_fnSignal(ISynchronize
*iface
)
831 MREImpl
*This
= impl_from_ISynchronize(iface
);
833 SetEvent(This
->event
);
837 static HRESULT WINAPI
ISynchronize_fnReset(ISynchronize
*iface
)
839 MREImpl
*This
= impl_from_ISynchronize(iface
);
841 ResetEvent(This
->event
);
845 static ISynchronizeVtbl vt_ISynchronize
= {
846 ISynchronize_fnQueryInterface
,
847 ISynchronize_fnAddRef
,
848 ISynchronize_fnRelease
,
850 ISynchronize_fnSignal
,
854 static inline MREImpl
*impl_from_ISynchronizeHandle(ISynchronizeHandle
*iface
)
856 return CONTAINING_RECORD(iface
, MREImpl
, ISynchronizeHandle_iface
);
859 static HRESULT WINAPI
SynchronizeHandle_QueryInterface(ISynchronizeHandle
*iface
, REFIID riid
, void **ppv
)
861 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
862 return ISynchronize_QueryInterface(&This
->ISynchronize_iface
, riid
, ppv
);
865 static ULONG WINAPI
SynchronizeHandle_AddRef(ISynchronizeHandle
*iface
)
867 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
868 return ISynchronize_AddRef(&This
->ISynchronize_iface
);
871 static ULONG WINAPI
SynchronizeHandle_Release(ISynchronizeHandle
*iface
)
873 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
874 return ISynchronize_Release(&This
->ISynchronize_iface
);
877 static HRESULT WINAPI
SynchronizeHandle_GetHandle(ISynchronizeHandle
*iface
, HANDLE
*ph
)
879 MREImpl
*This
= impl_from_ISynchronizeHandle(iface
);
885 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl
= {
886 SynchronizeHandle_QueryInterface
,
887 SynchronizeHandle_AddRef
,
888 SynchronizeHandle_Release
,
889 SynchronizeHandle_GetHandle
892 static HRESULT
ManualResetEvent_Construct(IUnknown
*punkouter
, REFIID iid
, void **ppv
)
894 MREImpl
*This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MREImpl
));
898 FIXME("Aggregation not implemented.\n");
901 This
->ISynchronize_iface
.lpVtbl
= &vt_ISynchronize
;
902 This
->ISynchronizeHandle_iface
.lpVtbl
= &SynchronizeHandleVtbl
;
903 This
->event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
905 hr
= ISynchronize_QueryInterface(&This
->ISynchronize_iface
, iid
, ppv
);
906 ISynchronize_Release(&This
->ISynchronize_iface
);
910 static inline LocalServer
*impl_from_IServiceProvider(IServiceProvider
*iface
)
912 return CONTAINING_RECORD(iface
, LocalServer
, IServiceProvider_iface
);
915 static HRESULT WINAPI
LocalServer_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
917 LocalServer
*This
= impl_from_IServiceProvider(iface
);
919 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
921 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IServiceProvider
)) {
922 *ppv
= &This
->IServiceProvider_iface
;
925 return E_NOINTERFACE
;
928 IUnknown_AddRef((IUnknown
*)*ppv
);
932 static ULONG WINAPI
LocalServer_AddRef(IServiceProvider
*iface
)
934 LocalServer
*This
= impl_from_IServiceProvider(iface
);
935 LONG ref
= InterlockedIncrement(&This
->ref
);
937 TRACE("(%p) ref=%d\n", This
, ref
);
942 static ULONG WINAPI
LocalServer_Release(IServiceProvider
*iface
)
944 LocalServer
*This
= impl_from_IServiceProvider(iface
);
945 LONG ref
= InterlockedDecrement(&This
->ref
);
947 TRACE("(%p) ref=%d\n", This
, ref
);
951 HeapFree(GetProcessHeap(), 0, This
);
957 static HRESULT WINAPI
LocalServer_QueryService(IServiceProvider
*iface
, REFGUID guid
, REFIID riid
, void **ppv
)
959 LocalServer
*This
= impl_from_IServiceProvider(iface
);
960 APARTMENT
*apt
= COM_CurrentApt();
961 RegisteredClass
*iter
;
962 HRESULT hres
= E_FAIL
;
964 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guid
), debugstr_guid(riid
), ppv
);
969 EnterCriticalSection(&csRegisteredClassList
);
971 LIST_FOR_EACH_ENTRY(iter
, &RegisteredClassList
, RegisteredClass
, entry
) {
972 if(iter
->apartment_id
== apt
->oxid
973 && (iter
->runContext
& CLSCTX_LOCAL_SERVER
)
974 && IsEqualGUID(&iter
->classIdentifier
, guid
)) {
975 hres
= IUnknown_QueryInterface(iter
->classObject
, riid
, ppv
);
980 LeaveCriticalSection( &csRegisteredClassList
);
985 static const IServiceProviderVtbl LocalServerVtbl
= {
986 LocalServer_QueryInterface
,
989 LocalServer_QueryService
992 static HRESULT
get_local_server_stream(APARTMENT
*apt
, IStream
**ret
)
996 EnterCriticalSection(&apt
->cs
);
998 if(!apt
->local_server
) {
1001 obj
= heap_alloc(sizeof(*obj
));
1003 obj
->IServiceProvider_iface
.lpVtbl
= &LocalServerVtbl
;
1007 hres
= CreateStreamOnHGlobal(0, TRUE
, &obj
->marshal_stream
);
1008 if(SUCCEEDED(hres
)) {
1009 hres
= CoMarshalInterface(obj
->marshal_stream
, &IID_IServiceProvider
, (IUnknown
*)&obj
->IServiceProvider_iface
,
1010 MSHCTX_LOCAL
, NULL
, MSHLFLAGS_TABLESTRONG
);
1012 IStream_Release(obj
->marshal_stream
);
1016 apt
->local_server
= obj
;
1020 hres
= E_OUTOFMEMORY
;
1025 hres
= IStream_Clone(apt
->local_server
->marshal_stream
, ret
);
1027 LeaveCriticalSection(&apt
->cs
);
1030 ERR("Failed: %08x\n", hres
);
1034 /***********************************************************************
1035 * CoRevokeClassObject [OLE32.@]
1037 * Removes a class object from the class registry.
1040 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1044 * Failure: HRESULT code.
1047 * Must be called from the same apartment that called CoRegisterClassObject(),
1048 * otherwise it will fail with RPC_E_WRONG_THREAD.
1051 * CoRegisterClassObject
1053 HRESULT WINAPI DECLSPEC_HOTPATCH
CoRevokeClassObject(
1056 HRESULT hr
= E_INVALIDARG
;
1057 RegisteredClass
*curClass
;
1060 TRACE("(%08x)\n",dwRegister
);
1062 apt
= COM_CurrentApt();
1065 ERR("COM was not initialized\n");
1066 return CO_E_NOTINITIALIZED
;
1069 EnterCriticalSection( &csRegisteredClassList
);
1071 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
1074 * Check if we have a match on the cookie.
1076 if (curClass
->dwCookie
== dwRegister
)
1078 if (curClass
->apartment_id
== apt
->oxid
)
1080 COM_RevokeRegisteredClassObject(curClass
);
1085 ERR("called from wrong apartment, should be called from %s\n",
1086 wine_dbgstr_longlong(curClass
->apartment_id
));
1087 hr
= RPC_E_WRONG_THREAD
;
1093 LeaveCriticalSection( &csRegisteredClassList
);
1098 /* frees unused libraries loaded by apartment_getclassobject by calling the
1099 * DLL's DllCanUnloadNow entry point */
1100 static void apartment_freeunusedlibraries(struct apartment
*apt
, DWORD delay
)
1102 struct apartment_loaded_dll
*entry
, *next
;
1103 EnterCriticalSection(&apt
->cs
);
1104 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1106 if (entry
->dll
->DllCanUnloadNow
&& (entry
->dll
->DllCanUnloadNow() == S_OK
))
1108 DWORD real_delay
= delay
;
1110 if (real_delay
== INFINITE
)
1112 /* DLLs that return multi-threaded objects aren't unloaded
1113 * straight away to cope for programs that have races between
1114 * last object destruction and threads in the DLLs that haven't
1115 * finished, despite DllCanUnloadNow returning S_OK */
1116 if (entry
->multi_threaded
)
1117 real_delay
= 10 * 60 * 1000; /* 10 minutes */
1122 if (!real_delay
|| (entry
->unload_time
&& ((int)(GetTickCount() - entry
->unload_time
) > 0)))
1124 list_remove(&entry
->entry
);
1125 COMPOBJ_DllList_ReleaseRef(entry
->dll
, TRUE
);
1126 HeapFree(GetProcessHeap(), 0, entry
);
1130 entry
->unload_time
= GetTickCount() + real_delay
;
1131 if (!entry
->unload_time
) entry
->unload_time
= 1;
1134 else if (entry
->unload_time
)
1135 entry
->unload_time
= 0;
1137 LeaveCriticalSection(&apt
->cs
);
1140 DWORD
apartment_release(struct apartment
*apt
)
1144 EnterCriticalSection(&csApartment
);
1146 ret
= InterlockedDecrement(&apt
->refs
);
1147 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt
->oxid
), ret
);
1148 /* destruction stuff that needs to happen under csApartment CS */
1151 if (apt
== MTA
) MTA
= NULL
;
1152 else if (apt
== MainApartment
) MainApartment
= NULL
;
1153 list_remove(&apt
->entry
);
1156 LeaveCriticalSection(&csApartment
);
1160 struct list
*cursor
, *cursor2
;
1162 TRACE("destroying apartment %p, oxid %s\n", apt
, wine_dbgstr_longlong(apt
->oxid
));
1164 if(apt
->local_server
) {
1165 LocalServer
*local_server
= apt
->local_server
;
1168 memset(&zero
, 0, sizeof(zero
));
1169 IStream_Seek(local_server
->marshal_stream
, zero
, STREAM_SEEK_SET
, NULL
);
1170 CoReleaseMarshalData(local_server
->marshal_stream
);
1171 IStream_Release(local_server
->marshal_stream
);
1172 local_server
->marshal_stream
= NULL
;
1174 apt
->local_server
= NULL
;
1175 local_server
->apt
= NULL
;
1176 IServiceProvider_Release(&local_server
->IServiceProvider_iface
);
1179 /* Release the references to the registered class objects */
1180 COM_RevokeAllClasses(apt
);
1182 /* no locking is needed for this apartment, because no other thread
1183 * can access it at this point */
1185 apartment_disconnectproxies(apt
);
1187 if (apt
->win
) DestroyWindow(apt
->win
);
1188 if (apt
->host_apt_tid
) PostThreadMessageW(apt
->host_apt_tid
, WM_QUIT
, 0, 0);
1190 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &apt
->stubmgrs
)
1192 struct stub_manager
*stubmgr
= LIST_ENTRY(cursor
, struct stub_manager
, entry
);
1193 /* release the implicit reference given by the fact that the
1194 * stub has external references (it must do since it is in the
1195 * stub manager list in the apartment and all non-apartment users
1196 * must have a ref on the apartment and so it cannot be destroyed).
1198 stub_manager_int_release(stubmgr
);
1201 /* if this assert fires, then another thread took a reference to a
1202 * stub manager without taking a reference to the containing
1203 * apartment, which it must do. */
1204 assert(list_empty(&apt
->stubmgrs
));
1206 if (apt
->filter
) IMessageFilter_Release(apt
->filter
);
1208 /* free as many unused libraries as possible... */
1209 apartment_freeunusedlibraries(apt
, 0);
1211 /* ... and free the memory for the apartment loaded dll entry and
1212 * release the dll list reference without freeing the library for the
1214 while ((cursor
= list_head(&apt
->loaded_dlls
)))
1216 struct apartment_loaded_dll
*apartment_loaded_dll
= LIST_ENTRY(cursor
, struct apartment_loaded_dll
, entry
);
1217 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll
->dll
, FALSE
);
1218 list_remove(cursor
);
1219 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1222 DEBUG_CLEAR_CRITSEC_NAME(&apt
->cs
);
1223 DeleteCriticalSection(&apt
->cs
);
1225 HeapFree(GetProcessHeap(), 0, apt
);
1231 /* The given OXID must be local to this process:
1233 * The ref parameter is here mostly to ensure people remember that
1234 * they get one, you should normally take a ref for thread safety.
1236 APARTMENT
*apartment_findfromoxid(OXID oxid
, BOOL ref
)
1238 APARTMENT
*result
= NULL
;
1239 struct list
*cursor
;
1241 EnterCriticalSection(&csApartment
);
1242 LIST_FOR_EACH( cursor
, &apts
)
1244 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1245 if (apt
->oxid
== oxid
)
1248 if (ref
) apartment_addref(result
);
1252 LeaveCriticalSection(&csApartment
);
1257 /* gets the apartment which has a given creator thread ID. The caller must
1258 * release the reference from the apartment as soon as the apartment pointer
1259 * is no longer required. */
1260 APARTMENT
*apartment_findfromtid(DWORD tid
)
1262 APARTMENT
*result
= NULL
;
1263 struct list
*cursor
;
1265 EnterCriticalSection(&csApartment
);
1266 LIST_FOR_EACH( cursor
, &apts
)
1268 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1269 if (apt
->tid
== tid
)
1272 apartment_addref(result
);
1276 LeaveCriticalSection(&csApartment
);
1281 /* gets the main apartment if it exists. The caller must
1282 * release the reference from the apartment as soon as the apartment pointer
1283 * is no longer required. */
1284 static APARTMENT
*apartment_findmain(void)
1288 EnterCriticalSection(&csApartment
);
1290 result
= MainApartment
;
1291 if (result
) apartment_addref(result
);
1293 LeaveCriticalSection(&csApartment
);
1298 /* gets the multi-threaded apartment if it exists. The caller must
1299 * release the reference from the apartment as soon as the apartment pointer
1300 * is no longer required. */
1301 static APARTMENT
*apartment_find_multi_threaded(void)
1303 APARTMENT
*result
= NULL
;
1304 struct list
*cursor
;
1306 EnterCriticalSection(&csApartment
);
1308 LIST_FOR_EACH( cursor
, &apts
)
1310 struct apartment
*apt
= LIST_ENTRY( cursor
, struct apartment
, entry
);
1311 if (apt
->multi_threaded
)
1314 apartment_addref(result
);
1319 LeaveCriticalSection(&csApartment
);
1323 /* gets the specified class object by loading the appropriate DLL, if
1324 * necessary and calls the DllGetClassObject function for the DLL */
1325 static HRESULT
apartment_getclassobject(struct apartment
*apt
, LPCWSTR dllpath
,
1326 BOOL apartment_threaded
,
1327 REFCLSID rclsid
, REFIID riid
, void **ppv
)
1329 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
1332 struct apartment_loaded_dll
*apartment_loaded_dll
;
1334 if (!strcmpiW(dllpath
, wszOle32
))
1336 /* we don't need to control the lifetime of this dll, so use the local
1337 * implementation of DllGetClassObject directly */
1338 TRACE("calling ole32!DllGetClassObject\n");
1339 hr
= DllGetClassObject(rclsid
, riid
, ppv
);
1342 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1347 EnterCriticalSection(&apt
->cs
);
1349 LIST_FOR_EACH_ENTRY(apartment_loaded_dll
, &apt
->loaded_dlls
, struct apartment_loaded_dll
, entry
)
1350 if (!strcmpiW(dllpath
, apartment_loaded_dll
->dll
->library_name
))
1352 TRACE("found %s already loaded\n", debugstr_w(dllpath
));
1359 apartment_loaded_dll
= HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll
));
1360 if (!apartment_loaded_dll
)
1364 apartment_loaded_dll
->unload_time
= 0;
1365 apartment_loaded_dll
->multi_threaded
= FALSE
;
1366 hr
= COMPOBJ_DllList_Add( dllpath
, &apartment_loaded_dll
->dll
);
1368 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll
);
1372 TRACE("added new loaded dll %s\n", debugstr_w(dllpath
));
1373 list_add_tail(&apt
->loaded_dlls
, &apartment_loaded_dll
->entry
);
1377 LeaveCriticalSection(&apt
->cs
);
1381 /* one component being multi-threaded overrides any number of
1382 * apartment-threaded components */
1383 if (!apartment_threaded
)
1384 apartment_loaded_dll
->multi_threaded
= TRUE
;
1386 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll
->dll
->DllGetClassObject
);
1387 /* OK: get the ClassObject */
1388 hr
= apartment_loaded_dll
->dll
->DllGetClassObject(rclsid
, riid
, ppv
);
1391 ERR("DllGetClassObject returned error 0x%08x\n", hr
);
1397 /***********************************************************************
1398 * COM_RegReadPath [internal]
1400 * Reads a registry value and expands it when necessary
1402 static DWORD
COM_RegReadPath(const struct class_reg_data
*regdata
, WCHAR
*dst
, DWORD dstlen
)
1409 WCHAR src
[MAX_PATH
];
1410 DWORD dwLength
= dstlen
* sizeof(WCHAR
);
1412 if( (ret
= RegQueryValueExW(regdata
->u
.hkey
, NULL
, NULL
, &keytype
, (BYTE
*)src
, &dwLength
)) == ERROR_SUCCESS
) {
1413 if (keytype
== REG_EXPAND_SZ
) {
1414 if (dstlen
<= ExpandEnvironmentStringsW(src
, dst
, dstlen
)) ret
= ERROR_MORE_DATA
;
1416 const WCHAR
*quote_start
;
1417 quote_start
= strchrW(src
, '\"');
1419 const WCHAR
*quote_end
= strchrW(quote_start
+ 1, '\"');
1421 memmove(src
, quote_start
+ 1,
1422 (quote_end
- quote_start
- 1) * sizeof(WCHAR
));
1423 src
[quote_end
- quote_start
- 1] = '\0';
1426 lstrcpynW(dst
, src
, dstlen
);
1437 nameW
= (WCHAR
*)((BYTE
*)regdata
->u
.actctx
.section
+ regdata
->u
.actctx
.data
->name_offset
);
1438 ActivateActCtx(regdata
->u
.actctx
.hactctx
, &cookie
);
1439 ret
= SearchPathW(NULL
, nameW
, NULL
, dstlen
, dst
, NULL
);
1440 DeactivateActCtx(0, cookie
);
1445 struct host_object_params
1447 struct class_reg_data regdata
;
1448 CLSID clsid
; /* clsid of object to marshal */
1449 IID iid
; /* interface to marshal */
1450 HANDLE event
; /* event signalling when ready for multi-threaded case */
1451 HRESULT hr
; /* result for multi-threaded case */
1452 IStream
*stream
; /* stream that the object will be marshaled into */
1453 BOOL apartment_threaded
; /* is the component purely apartment-threaded? */
1456 static HRESULT
apartment_hostobject(struct apartment
*apt
,
1457 const struct host_object_params
*params
)
1461 static const LARGE_INTEGER llZero
;
1462 WCHAR dllpath
[MAX_PATH
+1];
1464 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms
->clsid
), debugstr_guid(¶ms
->iid
));
1466 if (COM_RegReadPath(¶ms
->regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
1468 /* failure: CLSID is not found in registry */
1469 WARN("class %s not registered inproc\n", debugstr_guid(¶ms
->clsid
));
1470 return REGDB_E_CLASSNOTREG
;
1473 hr
= apartment_getclassobject(apt
, dllpath
, params
->apartment_threaded
,
1474 ¶ms
->clsid
, ¶ms
->iid
, (void **)&object
);
1478 hr
= CoMarshalInterface(params
->stream
, ¶ms
->iid
, object
, MSHCTX_INPROC
, NULL
, MSHLFLAGS_NORMAL
);
1480 IUnknown_Release(object
);
1481 IStream_Seek(params
->stream
, llZero
, STREAM_SEEK_SET
, NULL
);
1486 static LRESULT CALLBACK
apartment_wndproc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1491 RPC_ExecuteCall((struct dispatch_params
*)lParam
);
1494 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params
*)lParam
);
1496 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1500 struct host_thread_params
1502 COINIT threading_model
;
1504 HWND apartment_hwnd
;
1507 /* thread for hosting an object to allow an object to appear to be created in
1508 * an apartment with an incompatible threading model */
1509 static DWORD CALLBACK
apartment_hostobject_thread(LPVOID p
)
1511 struct host_thread_params
*params
= p
;
1514 struct apartment
*apt
;
1518 hr
= CoInitializeEx(NULL
, params
->threading_model
);
1519 if (FAILED(hr
)) return hr
;
1521 apt
= COM_CurrentApt();
1522 if (params
->threading_model
== COINIT_APARTMENTTHREADED
)
1524 apartment_createwindowifneeded(apt
);
1525 params
->apartment_hwnd
= apartment_getwindow(apt
);
1528 params
->apartment_hwnd
= NULL
;
1530 /* force the message queue to be created before signaling parent thread */
1531 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1533 SetEvent(params
->ready_event
);
1534 params
= NULL
; /* can't touch params after here as it may be invalid */
1536 while (GetMessageW(&msg
, NULL
, 0, 0))
1538 if (!msg
.hwnd
&& (msg
.message
== DM_HOSTOBJECT
))
1540 struct host_object_params
*obj_params
= (struct host_object_params
*)msg
.lParam
;
1541 obj_params
->hr
= apartment_hostobject(apt
, obj_params
);
1542 SetEvent(obj_params
->event
);
1546 TranslateMessage(&msg
);
1547 DispatchMessageW(&msg
);
1558 /* finds or creates a host apartment, creates the object inside it and returns
1559 * a proxy to it so that the object can be used in the apartment of the
1560 * caller of this function */
1561 static HRESULT
apartment_hostobject_in_hostapt(
1562 struct apartment
*apt
, BOOL multi_threaded
, BOOL main_apartment
,
1563 const struct class_reg_data
*regdata
, REFCLSID rclsid
, REFIID riid
, void **ppv
)
1565 struct host_object_params params
;
1566 HWND apartment_hwnd
= NULL
;
1567 DWORD apartment_tid
= 0;
1570 if (!multi_threaded
&& main_apartment
)
1572 APARTMENT
*host_apt
= apartment_findmain();
1575 apartment_hwnd
= apartment_getwindow(host_apt
);
1576 apartment_release(host_apt
);
1580 if (!apartment_hwnd
)
1582 EnterCriticalSection(&apt
->cs
);
1584 if (!apt
->host_apt_tid
)
1586 struct host_thread_params thread_params
;
1590 thread_params
.threading_model
= multi_threaded
? COINIT_MULTITHREADED
: COINIT_APARTMENTTHREADED
;
1591 handles
[0] = thread_params
.ready_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1592 thread_params
.apartment_hwnd
= NULL
;
1593 handles
[1] = CreateThread(NULL
, 0, apartment_hostobject_thread
, &thread_params
, 0, &apt
->host_apt_tid
);
1596 CloseHandle(handles
[0]);
1597 LeaveCriticalSection(&apt
->cs
);
1598 return E_OUTOFMEMORY
;
1600 wait_value
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1601 CloseHandle(handles
[0]);
1602 CloseHandle(handles
[1]);
1603 if (wait_value
== WAIT_OBJECT_0
)
1604 apt
->host_apt_hwnd
= thread_params
.apartment_hwnd
;
1607 LeaveCriticalSection(&apt
->cs
);
1608 return E_OUTOFMEMORY
;
1612 if (multi_threaded
|| !main_apartment
)
1614 apartment_hwnd
= apt
->host_apt_hwnd
;
1615 apartment_tid
= apt
->host_apt_tid
;
1618 LeaveCriticalSection(&apt
->cs
);
1621 /* another thread may have become the main apartment in the time it took
1622 * us to create the thread for the host apartment */
1623 if (!apartment_hwnd
&& !multi_threaded
&& main_apartment
)
1625 APARTMENT
*host_apt
= apartment_findmain();
1628 apartment_hwnd
= apartment_getwindow(host_apt
);
1629 apartment_release(host_apt
);
1633 params
.regdata
= *regdata
;
1634 params
.clsid
= *rclsid
;
1636 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, ¶ms
.stream
);
1639 params
.apartment_threaded
= !multi_threaded
;
1643 params
.event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1644 if (!PostThreadMessageW(apartment_tid
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
))
1648 WaitForSingleObject(params
.event
, INFINITE
);
1651 CloseHandle(params
.event
);
1655 if (!apartment_hwnd
)
1657 ERR("host apartment didn't create window\n");
1661 hr
= SendMessageW(apartment_hwnd
, DM_HOSTOBJECT
, 0, (LPARAM
)¶ms
);
1664 hr
= CoUnmarshalInterface(params
.stream
, riid
, ppv
);
1665 IStream_Release(params
.stream
);
1669 static BOOL WINAPI
register_class( INIT_ONCE
*once
, void *param
, void **context
)
1673 /* Dispatching to the correct thread in an apartment is done through
1674 * window messages rather than RPC transports. When an interface is
1675 * marshalled into another apartment in the same process, a window of the
1676 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1677 * application) is responsible for pumping the message loop in that thread.
1678 * The WM_USER messages which point to the RPCs are then dispatched to
1679 * apartment_wndproc by the user's code from the apartment in which the
1680 * interface was unmarshalled.
1682 memset(&wclass
, 0, sizeof(wclass
));
1683 wclass
.lpfnWndProc
= apartment_wndproc
;
1684 wclass
.hInstance
= hProxyDll
;
1685 wclass
.lpszClassName
= wszAptWinClass
;
1686 RegisterClassW(&wclass
);
1690 /* create a window for the apartment or return the current one if one has
1691 * already been created */
1692 HRESULT
apartment_createwindowifneeded(struct apartment
*apt
)
1694 static INIT_ONCE class_init_once
= INIT_ONCE_STATIC_INIT
;
1696 if (apt
->multi_threaded
)
1703 InitOnceExecuteOnce( &class_init_once
, register_class
, NULL
, NULL
);
1705 hwnd
= CreateWindowW(wszAptWinClass
, NULL
, 0, 0, 0, 0, 0,
1706 HWND_MESSAGE
, 0, hProxyDll
, NULL
);
1709 ERR("CreateWindow failed with error %d\n", GetLastError());
1710 return HRESULT_FROM_WIN32(GetLastError());
1712 if (InterlockedCompareExchangePointer((PVOID
*)&apt
->win
, hwnd
, NULL
))
1713 /* someone beat us to it */
1714 DestroyWindow(hwnd
);
1720 /* retrieves the window for the main- or apartment-threaded apartment */
1721 HWND
apartment_getwindow(const struct apartment
*apt
)
1723 assert(!apt
->multi_threaded
);
1727 static void COM_TlsDestroy(void)
1729 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1732 if (info
->apt
) apartment_release(info
->apt
);
1733 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1734 if (info
->state
) IUnknown_Release(info
->state
);
1735 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1736 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1737 HeapFree(GetProcessHeap(), 0, info
);
1738 NtCurrentTeb()->ReservedForOle
= NULL
;
1742 /******************************************************************************
1743 * CoBuildVersion [OLE32.@]
1745 * Gets the build version of the DLL.
1750 * Current build version, hiword is majornumber, loword is minornumber
1752 DWORD WINAPI
CoBuildVersion(void)
1754 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1755 return (rmm
<<16)+rup
;
1758 /******************************************************************************
1759 * CoRegisterInitializeSpy [OLE32.@]
1761 * Add a Spy that watches CoInitializeEx calls
1764 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1765 * cookie [II] cookie receiver
1768 * Success: S_OK if not already initialized, S_FALSE otherwise.
1769 * Failure: HRESULT code.
1774 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1776 struct oletls
*info
= COM_CurrentInfo();
1779 TRACE("(%p, %p)\n", spy
, cookie
);
1781 if (!spy
|| !cookie
|| !info
)
1784 WARN("Could not allocate tls\n");
1785 return E_INVALIDARG
;
1790 FIXME("Already registered?\n");
1791 return E_UNEXPECTED
;
1794 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1797 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1803 /******************************************************************************
1804 * CoRevokeInitializeSpy [OLE32.@]
1806 * Remove a spy that previously watched CoInitializeEx calls
1809 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1812 * Success: S_OK if a spy is removed
1813 * Failure: E_INVALIDARG
1818 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1820 struct oletls
*info
= COM_CurrentInfo();
1821 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1823 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1824 return E_INVALIDARG
;
1826 IInitializeSpy_Release(info
->spy
);
1831 HRESULT
enter_apartment( struct oletls
*info
, DWORD model
)
1837 if (!apartment_get_or_create( model
))
1838 return E_OUTOFMEMORY
;
1840 else if (!apartment_is_model( info
->apt
, model
))
1842 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1843 info
->apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1844 model
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded" );
1845 return RPC_E_CHANGED_MODE
;
1855 void leave_apartment( struct oletls
*info
)
1859 if (info
->ole_inits
)
1860 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1861 apartment_release( info
->apt
);
1866 /******************************************************************************
1867 * CoInitialize [OLE32.@]
1869 * Initializes the COM libraries by calling CoInitializeEx with
1870 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1873 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1876 * Success: S_OK if not already initialized, S_FALSE otherwise.
1877 * Failure: HRESULT code.
1882 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1885 * Just delegate to the newer method.
1887 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1890 /******************************************************************************
1891 * CoInitializeEx [OLE32.@]
1893 * Initializes the COM libraries.
1896 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1897 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1900 * S_OK if successful,
1901 * S_FALSE if this function was called already.
1902 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1907 * The behavior used to set the IMalloc used for memory management is
1909 * The dwCoInit parameter must specify one of the following apartment
1911 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1912 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1913 * The parameter may also specify zero or more of the following flags:
1914 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1915 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1920 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1922 struct oletls
*info
= COM_CurrentInfo();
1925 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1927 if (lpReserved
!=NULL
)
1929 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1933 * Check the lock count. If this is the first time going through the initialize
1934 * process, we have to initialize the libraries.
1936 * And crank-up that lock count.
1938 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1941 * Initialize the various COM libraries and data structures.
1943 TRACE("() - Initializing the COM libraries\n");
1945 /* we may need to defer this until after apartment initialisation */
1946 RunningObjectTableImpl_Initialize();
1950 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1952 hr
= enter_apartment( info
, dwCoInit
);
1955 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1960 /***********************************************************************
1961 * CoUninitialize [OLE32.@]
1963 * This method will decrement the refcount on the current apartment, freeing
1964 * the resources associated with it if it is the last thread in the apartment.
1965 * If the last apartment is freed, the function will additionally release
1966 * any COM resources associated with the process.
1976 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1978 struct oletls
* info
= COM_CurrentInfo();
1983 /* will only happen on OOM */
1987 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1992 ERR("Mismatched CoUninitialize\n");
1995 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1999 leave_apartment( info
);
2002 * Decrease the reference count.
2003 * If we are back to 0 locks on the COM library, make sure we free
2004 * all the associated data structures.
2006 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2009 TRACE("() - Releasing the COM libraries\n");
2011 revoke_registered_psclsids();
2012 RunningObjectTableImpl_UnInitialize();
2014 else if (lCOMRefCnt
<1) {
2015 ERR( "CoUninitialize() - not CoInitialized.\n" );
2016 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2019 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2022 /******************************************************************************
2023 * CoDisconnectObject [OLE32.@]
2025 * Disconnects all connections to this object from remote processes. Dispatches
2026 * pending RPCs while blocking new RPCs from occurring, and then calls
2027 * IMarshal::DisconnectObject on the given object.
2029 * Typically called when the object server is forced to shut down, for instance by
2033 * lpUnk [I] The object whose stub should be disconnected.
2034 * reserved [I] Reserved. Should be set to 0.
2038 * Failure: HRESULT code.
2041 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2043 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2045 struct stub_manager
*manager
;
2050 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2052 if (!lpUnk
) return E_INVALIDARG
;
2054 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2057 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2058 IMarshal_Release(marshal
);
2062 apt
= COM_CurrentApt();
2064 return CO_E_NOTINITIALIZED
;
2066 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2068 stub_manager_disconnect(manager
);
2069 /* Release stub manager twice, to remove the apartment reference. */
2070 stub_manager_int_release(manager
);
2071 stub_manager_int_release(manager
);
2074 /* Note: native is pretty broken here because it just silently
2075 * fails, without returning an appropriate error code if the object was
2076 * not found, making apps think that the object was disconnected, when
2077 * it actually wasn't */
2082 /******************************************************************************
2083 * CoCreateGuid [OLE32.@]
2085 * Simply forwards to UuidCreate in RPCRT4.
2088 * pguid [O] Points to the GUID to initialize.
2092 * Failure: HRESULT code.
2097 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2101 if(!pguid
) return E_INVALIDARG
;
2103 status
= UuidCreate(pguid
);
2104 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2105 return HRESULT_FROM_WIN32( status
);
2108 static inline BOOL
is_valid_hex(WCHAR c
)
2110 if (!(((c
>= '0') && (c
<= '9')) ||
2111 ((c
>= 'a') && (c
<= 'f')) ||
2112 ((c
>= 'A') && (c
<= 'F'))))
2117 static const BYTE guid_conv_table
[256] =
2119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2122 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2123 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2124 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2125 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2128 /* conversion helper for CLSIDFromString/IIDFromString */
2129 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2133 if (!s
|| s
[0]!='{') {
2134 memset( id
, 0, sizeof (CLSID
) );
2139 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2141 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2144 for (i
= 1; i
< 9; i
++) {
2145 if (!is_valid_hex(s
[i
])) return FALSE
;
2146 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2148 if (s
[9]!='-') return FALSE
;
2151 for (i
= 10; i
< 14; i
++) {
2152 if (!is_valid_hex(s
[i
])) return FALSE
;
2153 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2155 if (s
[14]!='-') return FALSE
;
2158 for (i
= 15; i
< 19; i
++) {
2159 if (!is_valid_hex(s
[i
])) return FALSE
;
2160 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2162 if (s
[19]!='-') return FALSE
;
2164 for (i
= 20; i
< 37; i
+=2) {
2166 if (s
[i
]!='-') return FALSE
;
2169 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2170 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2173 if (s
[37] == '}' && s
[38] == '\0')
2179 /*****************************************************************************/
2181 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2183 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2184 WCHAR buf2
[CHARS_IN_GUID
];
2185 LONG buf2len
= sizeof(buf2
);
2189 memset(clsid
, 0, sizeof(*clsid
));
2190 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2191 if (!buf
) return E_OUTOFMEMORY
;
2192 strcpyW( buf
, progid
);
2193 strcatW( buf
, clsidW
);
2194 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2196 HeapFree(GetProcessHeap(),0,buf
);
2197 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2198 return CO_E_CLASSSTRING
;
2200 HeapFree(GetProcessHeap(),0,buf
);
2202 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2205 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2206 return CO_E_CLASSSTRING
;
2209 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2212 /******************************************************************************
2213 * CLSIDFromString [OLE32.@]
2215 * Converts a unique identifier from its string representation into
2219 * idstr [I] The string representation of the GUID.
2220 * id [O] GUID converted from the string.
2224 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2229 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2231 HRESULT ret
= CO_E_CLASSSTRING
;
2235 return E_INVALIDARG
;
2237 if (guid_from_string(idstr
, id
))
2240 /* It appears a ProgID is also valid */
2241 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2248 /******************************************************************************
2249 * IIDFromString [OLE32.@]
2251 * Converts an interface identifier from its string representation to
2255 * idstr [I] The string representation of the GUID.
2256 * id [O] IID converted from the string.
2260 * CO_E_IIDSTRING if idstr is not a valid IID
2265 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2267 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2271 memset(iid
, 0, sizeof(*iid
));
2275 /* length mismatch is a special case */
2276 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2277 return E_INVALIDARG
;
2280 return CO_E_IIDSTRING
;
2282 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2285 /******************************************************************************
2286 * StringFromCLSID [OLE32.@]
2287 * StringFromIID [OLE32.@]
2289 * Converts a GUID into the respective string representation.
2290 * The target string is allocated using the OLE IMalloc.
2293 * id [I] the GUID to be converted.
2294 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2301 * StringFromGUID2, CLSIDFromString
2303 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2305 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2306 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2310 /******************************************************************************
2311 * StringFromGUID2 [OLE32.@]
2313 * Modified version of StringFromCLSID that allows you to specify max
2317 * id [I] GUID to convert to string.
2318 * str [O] Buffer where the result will be stored.
2319 * cmax [I] Size of the buffer in characters.
2322 * Success: The length of the resulting string in characters.
2325 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2327 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2328 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2329 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2330 '%','0','2','X','%','0','2','X','}',0 };
2331 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2332 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2333 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2334 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2335 return CHARS_IN_GUID
;
2338 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2339 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2341 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2342 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2346 strcpyW(path
, wszCLSIDSlash
);
2347 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2348 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2349 if (res
== ERROR_FILE_NOT_FOUND
)
2350 return REGDB_E_CLASSNOTREG
;
2351 else if (res
!= ERROR_SUCCESS
)
2352 return REGDB_E_READREGDB
;
2360 res
= open_classes_key(key
, keyname
, access
, subkey
);
2362 if (res
== ERROR_FILE_NOT_FOUND
)
2363 return REGDB_E_KEYMISSING
;
2364 else if (res
!= ERROR_SUCCESS
)
2365 return REGDB_E_READREGDB
;
2370 /* open HKCR\\AppId\\{string form of appid clsid} key */
2371 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2373 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2374 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2376 WCHAR buf
[CHARS_IN_GUID
];
2377 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2383 /* read the AppID value under the class's key */
2384 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2389 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2391 if (res
== ERROR_FILE_NOT_FOUND
)
2392 return REGDB_E_KEYMISSING
;
2393 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2394 return REGDB_E_READREGDB
;
2396 strcpyW(keyname
, szAppIdKey
);
2397 strcatW(keyname
, buf
);
2398 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2399 if (res
== ERROR_FILE_NOT_FOUND
)
2400 return REGDB_E_KEYMISSING
;
2401 else if (res
!= ERROR_SUCCESS
)
2402 return REGDB_E_READREGDB
;
2407 /******************************************************************************
2408 * ProgIDFromCLSID [OLE32.@]
2410 * Converts a class id into the respective program ID.
2413 * clsid [I] Class ID, as found in registry.
2414 * ppszProgID [O] Associated ProgID.
2419 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2421 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2423 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2424 ACTCTX_SECTION_KEYED_DATA data
;
2430 return E_INVALIDARG
;
2434 data
.cbSize
= sizeof(data
);
2435 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2438 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2439 if (comclass
->progid_len
)
2443 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2444 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2446 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2447 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2451 return REGDB_E_CLASSNOTREG
;
2454 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2458 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2459 ret
= REGDB_E_CLASSNOTREG
;
2463 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2466 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2467 ret
= REGDB_E_CLASSNOTREG
;
2468 CoTaskMemFree(*ppszProgID
);
2473 ret
= E_OUTOFMEMORY
;
2480 /******************************************************************************
2481 * CLSIDFromProgID [OLE32.@]
2483 * Converts a program id into the respective GUID.
2486 * progid [I] Unicode program ID, as found in registry.
2487 * clsid [O] Associated CLSID.
2491 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2493 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2495 ACTCTX_SECTION_KEYED_DATA data
;
2497 if (!progid
|| !clsid
)
2498 return E_INVALIDARG
;
2500 data
.cbSize
= sizeof(data
);
2501 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2504 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2505 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2510 return clsid_from_string_reg(progid
, clsid
);
2513 /******************************************************************************
2514 * CLSIDFromProgIDEx [OLE32.@]
2516 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2518 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2520 return CLSIDFromProgID(progid
, clsid
);
2523 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2526 WCHAR value
[CHARS_IN_GUID
];
2531 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2532 return REGDB_E_IIDNOTREG
;
2534 len
= sizeof(value
);
2535 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2536 return REGDB_E_IIDNOTREG
;
2539 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2540 return REGDB_E_IIDNOTREG
;
2545 /*****************************************************************************
2546 * CoGetPSClsid [OLE32.@]
2548 * Retrieves the CLSID of the proxy/stub factory that implements
2549 * IPSFactoryBuffer for the specified interface.
2552 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2553 * pclsid [O] Where to store returned proxy/stub CLSID.
2558 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2562 * The standard marshaller activates the object with the CLSID
2563 * returned and uses the CreateProxy and CreateStub methods on its
2564 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2567 * CoGetPSClsid determines this CLSID by searching the
2568 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2569 * in the registry and any interface id registered by
2570 * CoRegisterPSClsid within the current process.
2574 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2575 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2576 * considered a bug in native unless an application depends on this (unlikely).
2579 * CoRegisterPSClsid.
2581 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2583 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2584 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2585 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2586 APARTMENT
*apt
= COM_CurrentApt();
2587 struct registered_psclsid
*registered_psclsid
;
2588 ACTCTX_SECTION_KEYED_DATA data
;
2590 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2593 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2597 ERR("apartment not initialised\n");
2598 return CO_E_NOTINITIALIZED
;
2602 return E_INVALIDARG
;
2604 EnterCriticalSection(&cs_registered_psclsid_list
);
2606 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2607 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2609 *pclsid
= registered_psclsid
->clsid
;
2610 LeaveCriticalSection(&cs_registered_psclsid_list
);
2614 LeaveCriticalSection(&cs_registered_psclsid_list
);
2616 data
.cbSize
= sizeof(data
);
2617 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2620 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2621 *pclsid
= ifaceps
->iid
;
2625 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2626 strcpyW(path
, wszInterface
);
2627 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2628 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2630 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2631 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2632 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2633 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2636 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2638 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2643 /*****************************************************************************
2644 * CoRegisterPSClsid [OLE32.@]
2646 * Register a proxy/stub CLSID for the given interface in the current process
2650 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2651 * rclsid [I] CLSID of the proxy/stub.
2655 * Failure: E_OUTOFMEMORY
2659 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2660 * will be returned from other apartments in the same process.
2662 * This function does not add anything to the registry and the effects are
2663 * limited to the lifetime of the current process.
2668 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2670 APARTMENT
*apt
= COM_CurrentApt();
2671 struct registered_psclsid
*registered_psclsid
;
2673 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2677 ERR("apartment not initialised\n");
2678 return CO_E_NOTINITIALIZED
;
2681 EnterCriticalSection(&cs_registered_psclsid_list
);
2683 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2684 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2686 registered_psclsid
->clsid
= *rclsid
;
2687 LeaveCriticalSection(&cs_registered_psclsid_list
);
2691 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2692 if (!registered_psclsid
)
2694 LeaveCriticalSection(&cs_registered_psclsid_list
);
2695 return E_OUTOFMEMORY
;
2698 registered_psclsid
->iid
= *riid
;
2699 registered_psclsid
->clsid
= *rclsid
;
2700 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2702 LeaveCriticalSection(&cs_registered_psclsid_list
);
2709 * COM_GetRegisteredClassObject
2711 * This internal method is used to scan the registered class list to
2712 * find a class object.
2715 * rclsid Class ID of the class to find.
2716 * dwClsContext Class context to match.
2717 * ppv [out] returns a pointer to the class object. Complying
2718 * to normal COM usage, this method will increase the
2719 * reference count on this object.
2721 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2722 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2724 HRESULT hr
= S_FALSE
;
2725 RegisteredClass
*curClass
;
2727 EnterCriticalSection( &csRegisteredClassList
);
2729 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2732 * Check if we have a match on the class ID and context.
2734 if ((apt
->oxid
== curClass
->apartment_id
) &&
2735 (dwClsContext
& curClass
->runContext
) &&
2736 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2739 * We have a match, return the pointer to the class object.
2741 *ppUnk
= curClass
->classObject
;
2743 IUnknown_AddRef(curClass
->classObject
);
2750 LeaveCriticalSection( &csRegisteredClassList
);
2755 /******************************************************************************
2756 * CoRegisterClassObject [OLE32.@]
2758 * Registers the class object for a given class ID. Servers housed in EXE
2759 * files use this method instead of exporting DllGetClassObject to allow
2760 * other code to connect to their objects.
2763 * rclsid [I] CLSID of the object to register.
2764 * pUnk [I] IUnknown of the object.
2765 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2766 * flags [I] REGCLS flags indicating how connections are made.
2767 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2771 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2772 * CO_E_OBJISREG if the object is already registered. We should not return this.
2775 * CoRevokeClassObject, CoGetClassObject
2778 * In-process objects are only registered for the current apartment.
2779 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2780 * in other apartments.
2783 * MSDN claims that multiple interface registrations are legal, but we
2784 * can't do that with our current implementation.
2786 HRESULT WINAPI
CoRegisterClassObject(
2791 LPDWORD lpdwRegister
)
2793 static LONG next_cookie
;
2794 RegisteredClass
* newClass
;
2795 LPUNKNOWN foundObject
;
2799 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2800 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2802 if ( (lpdwRegister
==0) || (pUnk
==0) )
2803 return E_INVALIDARG
;
2805 apt
= COM_CurrentApt();
2808 ERR("COM was not initialized\n");
2809 return CO_E_NOTINITIALIZED
;
2814 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2815 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2816 if (flags
& REGCLS_MULTIPLEUSE
)
2817 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2820 * First, check if the class is already registered.
2821 * If it is, this should cause an error.
2823 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2825 if (flags
& REGCLS_MULTIPLEUSE
) {
2826 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2827 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2828 IUnknown_Release(foundObject
);
2831 IUnknown_Release(foundObject
);
2832 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2833 return CO_E_OBJISREG
;
2836 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2837 if ( newClass
== NULL
)
2838 return E_OUTOFMEMORY
;
2840 newClass
->classIdentifier
= *rclsid
;
2841 newClass
->apartment_id
= apt
->oxid
;
2842 newClass
->runContext
= dwClsContext
;
2843 newClass
->connectFlags
= flags
;
2844 newClass
->RpcRegistration
= NULL
;
2846 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2847 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2850 * Since we're making a copy of the object pointer, we have to increase its
2853 newClass
->classObject
= pUnk
;
2854 IUnknown_AddRef(newClass
->classObject
);
2856 EnterCriticalSection( &csRegisteredClassList
);
2857 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2858 LeaveCriticalSection( &csRegisteredClassList
);
2860 *lpdwRegister
= newClass
->dwCookie
;
2862 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2863 IStream
*marshal_stream
;
2865 hr
= get_local_server_stream(apt
, &marshal_stream
);
2869 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2871 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2872 &newClass
->RpcRegistration
);
2873 IStream_Release(marshal_stream
);
2878 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2882 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2883 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2884 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2885 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2886 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2887 DWORD dwLength
= sizeof(threading_model
);
2891 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2892 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2893 threading_model
[0] = '\0';
2895 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2896 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2897 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2899 /* there's not specific handling for this case */
2900 if (threading_model
[0]) return ThreadingModel_Neutral
;
2901 return ThreadingModel_No
;
2904 return data
->u
.actctx
.data
->model
;
2907 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2908 REFCLSID rclsid
, REFIID riid
,
2909 BOOL hostifnecessary
, void **ppv
)
2911 WCHAR dllpath
[MAX_PATH
+1];
2912 BOOL apartment_threaded
;
2914 if (hostifnecessary
)
2916 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2918 if (model
== ThreadingModel_Apartment
)
2920 apartment_threaded
= TRUE
;
2921 if (apt
->multi_threaded
)
2922 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2924 else if (model
== ThreadingModel_Free
)
2926 apartment_threaded
= FALSE
;
2927 if (!apt
->multi_threaded
)
2928 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2930 /* everything except "Apartment", "Free" and "Both" */
2931 else if (model
!= ThreadingModel_Both
)
2933 apartment_threaded
= TRUE
;
2934 /* everything else is main-threaded */
2935 if (model
!= ThreadingModel_No
)
2936 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2938 if (apt
->multi_threaded
|| !apt
->main
)
2939 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2942 apartment_threaded
= FALSE
;
2945 apartment_threaded
= !apt
->multi_threaded
;
2947 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2949 /* failure: CLSID is not found in registry */
2950 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2951 return REGDB_E_CLASSNOTREG
;
2954 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2958 /***********************************************************************
2959 * CoGetClassObject [OLE32.@]
2961 * Creates an object of the specified class.
2964 * rclsid [I] Class ID to create an instance of.
2965 * dwClsContext [I] Flags to restrict the location of the created instance.
2966 * pServerInfo [I] Optional. Details for connecting to a remote server.
2967 * iid [I] The ID of the interface of the instance to return.
2968 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2972 * Failure: HRESULT code.
2975 * The dwClsContext parameter can be one or more of the following:
2976 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2977 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2978 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2979 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2982 * CoCreateInstance()
2984 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2985 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2986 REFIID iid
, LPVOID
*ppv
)
2988 struct class_reg_data clsreg
;
2989 IUnknown
*regClassObject
;
2990 HRESULT hres
= E_UNEXPECTED
;
2992 BOOL release_apt
= FALSE
;
2994 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2997 return E_INVALIDARG
;
3001 if (!(apt
= COM_CurrentApt()))
3003 if (!(apt
= apartment_find_multi_threaded()))
3005 ERR("apartment not initialised\n");
3006 return CO_E_NOTINITIALIZED
;
3012 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3013 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3016 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3018 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3020 if (release_apt
) apartment_release(apt
);
3021 return FTMarshalCF_Create(iid
, ppv
);
3023 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3024 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3027 if (CLSCTX_INPROC
& dwClsContext
)
3029 ACTCTX_SECTION_KEYED_DATA data
;
3031 data
.cbSize
= sizeof(data
);
3032 /* search activation context first */
3033 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3034 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3037 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3039 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3040 clsreg
.u
.actctx
.data
= data
.lpData
;
3041 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3042 clsreg
.hkey
= FALSE
;
3044 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3045 ReleaseActCtx(data
.hActCtx
);
3046 if (release_apt
) apartment_release(apt
);
3052 * First, try and see if we can't match the class ID with one of the
3053 * registered classes.
3055 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3058 /* Get the required interface from the retrieved pointer. */
3059 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3062 * Since QI got another reference on the pointer, we want to release the
3063 * one we already have. If QI was unsuccessful, this will release the object. This
3064 * is good since we are not returning it in the "out" parameter.
3066 IUnknown_Release(regClassObject
);
3067 if (release_apt
) apartment_release(apt
);
3071 /* First try in-process server */
3072 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3074 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3077 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3080 if (hres
== REGDB_E_CLASSNOTREG
)
3081 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3082 else if (hres
== REGDB_E_KEYMISSING
)
3084 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3085 hres
= REGDB_E_CLASSNOTREG
;
3089 if (SUCCEEDED(hres
))
3091 clsreg
.u
.hkey
= hkey
;
3094 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3098 /* return if we got a class, otherwise fall through to one of the
3100 if (SUCCEEDED(hres
))
3102 if (release_apt
) apartment_release(apt
);
3107 /* Next try in-process handler */
3108 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3110 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3113 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3116 if (hres
== REGDB_E_CLASSNOTREG
)
3117 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3118 else if (hres
== REGDB_E_KEYMISSING
)
3120 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3121 hres
= REGDB_E_CLASSNOTREG
;
3125 if (SUCCEEDED(hres
))
3127 clsreg
.u
.hkey
= hkey
;
3130 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3134 /* return if we got a class, otherwise fall through to one of the
3136 if (SUCCEEDED(hres
))
3138 if (release_apt
) apartment_release(apt
);
3142 if (release_apt
) apartment_release(apt
);
3144 /* Next try out of process */
3145 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3147 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3148 if (SUCCEEDED(hres
))
3152 /* Finally try remote: this requires networked DCOM (a lot of work) */
3153 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3155 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3156 hres
= REGDB_E_CLASSNOTREG
;
3160 ERR("no class object %s could be created for context 0x%x\n",
3161 debugstr_guid(rclsid
), dwClsContext
);
3165 /***********************************************************************
3166 * CoResumeClassObjects (OLE32.@)
3168 * Resumes all class objects registered with REGCLS_SUSPENDED.
3172 * Failure: HRESULT code.
3174 HRESULT WINAPI
CoResumeClassObjects(void)
3180 /***********************************************************************
3181 * CoCreateInstance [OLE32.@]
3183 * Creates an instance of the specified class.
3186 * rclsid [I] Class ID to create an instance of.
3187 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3188 * dwClsContext [I] Flags to restrict the location of the created instance.
3189 * iid [I] The ID of the interface of the instance to return.
3190 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3194 * Failure: HRESULT code.
3197 * The dwClsContext parameter can be one or more of the following:
3198 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3199 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3200 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3201 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3203 * Aggregation is the concept of deferring the IUnknown of an object to another
3204 * object. This allows a separate object to behave as though it was part of
3205 * the object and to allow this the pUnkOuter parameter can be set. Note that
3206 * not all objects support having an outer of unknown.
3209 * CoGetClassObject()
3211 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3213 LPUNKNOWN pUnkOuter
,
3218 MULTI_QI multi_qi
= { iid
};
3221 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3222 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3227 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3228 *ppv
= multi_qi
.pItf
;
3232 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3236 for (i
= 0; i
< count
; i
++)
3243 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3245 ULONG index
= 0, fetched
= 0;
3251 index
= fetched
= 1;
3254 for (; index
< count
; index
++)
3256 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3257 if (mqi
[index
].hr
== S_OK
)
3262 IUnknown_Release(unk
);
3265 return E_NOINTERFACE
;
3267 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3270 /***********************************************************************
3271 * CoCreateInstanceEx [OLE32.@]
3273 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3275 LPUNKNOWN pUnkOuter
,
3277 COSERVERINFO
* pServerInfo
,
3281 IUnknown
*unk
= NULL
;
3287 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3289 if (!cmq
|| !pResults
)
3290 return E_INVALIDARG
;
3293 FIXME("() non-NULL pServerInfo not supported!\n");
3295 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3297 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3301 if (!(apt
= COM_CurrentApt()))
3303 if (!(apt
= apartment_find_multi_threaded()))
3305 ERR("apartment not initialised\n");
3306 return CO_E_NOTINITIALIZED
;
3308 apartment_release(apt
);
3312 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3314 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3316 IGlobalInterfaceTable
*git
= get_std_git();
3317 TRACE("Retrieving GIT\n");
3318 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3321 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3322 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3325 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3329 * Get a class factory to construct the object we want.
3331 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3336 * Create the object and don't forget to release the factory
3338 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3339 IClassFactory_Release(cf
);
3342 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3343 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3345 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3346 debugstr_guid(pResults
[0].pIID
),
3347 debugstr_guid(&clsid
),hres
);
3351 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3354 /***********************************************************************
3355 * CoGetInstanceFromFile [OLE32.@]
3357 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3358 COSERVERINFO
*server_info
,
3368 IPersistFile
*pf
= NULL
;
3369 IUnknown
* unk
= NULL
;
3373 if (count
== 0 || !results
)
3374 return E_INVALIDARG
;
3377 FIXME("() non-NULL server_info not supported\n");
3379 init_multi_qi(count
, results
, E_NOINTERFACE
);
3381 /* optionally get CLSID from a file */
3384 hr
= GetClassFile(filename
, &clsid
);
3387 ERR("failed to get CLSID from a file\n");
3394 hr
= CoCreateInstance(rclsid
,
3402 init_multi_qi(count
, results
, hr
);
3406 /* init from file */
3407 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3410 init_multi_qi(count
, results
, hr
);
3411 IUnknown_Release(unk
);
3415 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3416 IPersistFile_Release(pf
);
3418 return return_multi_qi(unk
, count
, results
, FALSE
);
3421 init_multi_qi(count
, results
, hr
);
3422 IUnknown_Release(unk
);
3427 /***********************************************************************
3428 * CoGetInstanceFromIStorage [OLE32.@]
3430 HRESULT WINAPI
CoGetInstanceFromIStorage(
3431 COSERVERINFO
*server_info
,
3440 IPersistStorage
*ps
= NULL
;
3441 IUnknown
* unk
= NULL
;
3445 if (count
== 0 || !results
|| !storage
)
3446 return E_INVALIDARG
;
3449 FIXME("() non-NULL server_info not supported\n");
3451 init_multi_qi(count
, results
, E_NOINTERFACE
);
3453 /* optionally get CLSID from a file */
3456 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3457 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3460 ERR("failed to get CLSID from a file\n");
3464 rclsid
= &stat
.clsid
;
3467 hr
= CoCreateInstance(rclsid
,
3476 /* init from IStorage */
3477 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3479 ERR("failed to get IPersistStorage\n");
3483 IPersistStorage_Load(ps
, storage
);
3484 IPersistStorage_Release(ps
);
3487 return return_multi_qi(unk
, count
, results
, FALSE
);
3490 /***********************************************************************
3491 * CoLoadLibrary (OLE32.@)
3496 * lpszLibName [I] Path to library.
3497 * bAutoFree [I] Whether the library should automatically be freed.
3500 * Success: Handle to loaded library.
3504 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3506 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3508 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3510 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3513 /***********************************************************************
3514 * CoFreeLibrary [OLE32.@]
3516 * Unloads a library from memory.
3519 * hLibrary [I] Handle to library to unload.
3525 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3527 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3529 FreeLibrary(hLibrary
);
3533 /***********************************************************************
3534 * CoFreeAllLibraries [OLE32.@]
3536 * Function for backwards compatibility only. Does nothing.
3542 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3544 void WINAPI
CoFreeAllLibraries(void)
3549 /***********************************************************************
3550 * CoFreeUnusedLibrariesEx [OLE32.@]
3552 * Frees any previously unused libraries whose delay has expired and marks
3553 * currently unused libraries for unloading. Unused are identified as those that
3554 * return S_OK from their DllCanUnloadNow function.
3557 * dwUnloadDelay [I] Unload delay in milliseconds.
3558 * dwReserved [I] Reserved. Set to 0.
3564 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3566 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3568 struct apartment
*apt
= COM_CurrentApt();
3571 ERR("apartment not initialised\n");
3575 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3578 /***********************************************************************
3579 * CoFreeUnusedLibraries [OLE32.@]
3581 * Frees any unused libraries. Unused are identified as those that return
3582 * S_OK from their DllCanUnloadNow function.
3588 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3590 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3592 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3595 /***********************************************************************
3596 * CoFileTimeNow [OLE32.@]
3598 * Retrieves the current time in FILETIME format.
3601 * lpFileTime [O] The current time.
3606 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3608 GetSystemTimeAsFileTime( lpFileTime
);
3612 /******************************************************************************
3613 * CoLockObjectExternal [OLE32.@]
3615 * Increments or decrements the external reference count of a stub object.
3618 * pUnk [I] Stub object.
3619 * fLock [I] If TRUE then increments the external ref-count,
3620 * otherwise decrements.
3621 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3622 * calling CoDisconnectObject.
3626 * Failure: HRESULT code.
3629 * If fLock is TRUE and an object is passed in that doesn't have a stub
3630 * manager then a new stub manager is created for the object.
3632 HRESULT WINAPI
CoLockObjectExternal(
3635 BOOL fLastUnlockReleases
)
3637 struct stub_manager
*stubmgr
;
3638 struct apartment
*apt
;
3640 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3641 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3643 apt
= COM_CurrentApt();
3644 if (!apt
) return CO_E_NOTINITIALIZED
;
3646 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3649 WARN("stub object not found %p\n", pUnk
);
3650 /* Note: native is pretty broken here because it just silently
3651 * fails, without returning an appropriate error code, making apps
3652 * think that the object was disconnected, when it actually wasn't */
3657 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3659 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3661 stub_manager_int_release(stubmgr
);
3665 /***********************************************************************
3666 * CoInitializeWOW (OLE32.@)
3668 * WOW equivalent of CoInitialize?
3677 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3679 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3683 /***********************************************************************
3684 * CoGetState [OLE32.@]
3686 * Retrieves the thread state object previously stored by CoSetState().
3689 * ppv [I] Address where pointer to object will be stored.
3693 * Failure: E_OUTOFMEMORY.
3696 * Crashes on all invalid ppv addresses, including NULL.
3697 * If the function returns a non-NULL object then the caller must release its
3698 * reference on the object when the object is no longer required.
3703 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3705 struct oletls
*info
= COM_CurrentInfo();
3706 if (!info
) return E_OUTOFMEMORY
;
3712 IUnknown_AddRef(info
->state
);
3714 TRACE("apt->state=%p\n", info
->state
);
3720 /***********************************************************************
3721 * CoSetState [OLE32.@]
3723 * Sets the thread state object.
3726 * pv [I] Pointer to state object to be stored.
3729 * The system keeps a reference on the object while the object stored.
3733 * Failure: E_OUTOFMEMORY.
3735 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3737 struct oletls
*info
= COM_CurrentInfo();
3738 if (!info
) return E_OUTOFMEMORY
;
3740 if (pv
) IUnknown_AddRef(pv
);
3744 TRACE("-- release %p now\n", info
->state
);
3745 IUnknown_Release(info
->state
);
3754 /******************************************************************************
3755 * CoTreatAsClass [OLE32.@]
3757 * Sets the TreatAs value of a class.
3760 * clsidOld [I] Class to set TreatAs value on.
3761 * clsidNew [I] The class the clsidOld should be treated as.
3765 * Failure: HRESULT code.
3770 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3772 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3773 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3775 WCHAR szClsidNew
[CHARS_IN_GUID
];
3777 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3778 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3781 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3785 if (IsEqualGUID( clsidOld
, clsidNew
))
3787 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3788 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3790 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3792 res
= REGDB_E_WRITEREGDB
;
3798 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3799 res
= REGDB_E_WRITEREGDB
;
3805 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3806 RegDeleteKeyW(hkey
, wszTreatAs
);
3808 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3809 WARN("StringFromGUID2 failed\n");
3814 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3815 WARN("RegSetValue failed\n");
3816 res
= REGDB_E_WRITEREGDB
;
3823 if (hkey
) RegCloseKey(hkey
);
3827 /******************************************************************************
3828 * CoGetTreatAsClass [OLE32.@]
3830 * Gets the TreatAs value of a class.
3833 * clsidOld [I] Class to get the TreatAs value of.
3834 * clsidNew [I] The class the clsidOld should be treated as.
3838 * Failure: HRESULT code.
3843 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3845 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3847 WCHAR szClsidNew
[CHARS_IN_GUID
];
3849 LONG len
= sizeof(szClsidNew
);
3851 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3853 if (!clsidOld
|| !clsidNew
)
3854 return E_INVALIDARG
;
3856 *clsidNew
= *clsidOld
; /* copy over old value */
3858 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3864 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3869 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3871 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3873 if (hkey
) RegCloseKey(hkey
);
3877 /******************************************************************************
3878 * CoGetCurrentProcess [OLE32.@]
3880 * Gets the current process ID.
3883 * The current process ID.
3886 * Is DWORD really the correct return type for this function?
3888 DWORD WINAPI
CoGetCurrentProcess(void)
3890 return GetCurrentProcessId();
3893 /***********************************************************************
3894 * CoGetCurrentLogicalThreadId [OLE32.@]
3896 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3898 TRACE("(%p)\n", id
);
3901 return E_INVALIDARG
;
3903 *id
= COM_CurrentCausalityId();
3907 /******************************************************************************
3908 * CoRegisterMessageFilter [OLE32.@]
3910 * Registers a message filter.
3913 * lpMessageFilter [I] Pointer to interface.
3914 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3918 * Failure: HRESULT code.
3921 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3922 * lpMessageFilter removes the message filter.
3924 * If lplpMessageFilter is not NULL the previous message filter will be
3925 * returned in the memory pointer to this parameter and the caller is
3926 * responsible for releasing the object.
3928 * The current thread be in an apartment otherwise the function will crash.
3930 HRESULT WINAPI
CoRegisterMessageFilter(
3931 LPMESSAGEFILTER lpMessageFilter
,
3932 LPMESSAGEFILTER
*lplpMessageFilter
)
3934 struct apartment
*apt
;
3935 IMessageFilter
*lpOldMessageFilter
;
3937 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3939 apt
= COM_CurrentApt();
3941 /* can't set a message filter in a multi-threaded apartment */
3942 if (!apt
|| apt
->multi_threaded
)
3944 WARN("can't set message filter in MTA or uninitialized apt\n");
3945 return CO_E_NOT_SUPPORTED
;
3948 if (lpMessageFilter
)
3949 IMessageFilter_AddRef(lpMessageFilter
);
3951 EnterCriticalSection(&apt
->cs
);
3953 lpOldMessageFilter
= apt
->filter
;
3954 apt
->filter
= lpMessageFilter
;
3956 LeaveCriticalSection(&apt
->cs
);
3958 if (lplpMessageFilter
)
3959 *lplpMessageFilter
= lpOldMessageFilter
;
3960 else if (lpOldMessageFilter
)
3961 IMessageFilter_Release(lpOldMessageFilter
);
3966 /***********************************************************************
3967 * CoIsOle1Class [OLE32.@]
3969 * Determines whether the specified class an OLE v1 class.
3972 * clsid [I] Class to test.
3975 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3977 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3979 FIXME("%s\n", debugstr_guid(clsid
));
3983 /***********************************************************************
3984 * IsEqualGUID [OLE32.@]
3986 * Compares two Unique Identifiers.
3989 * rguid1 [I] The first GUID to compare.
3990 * rguid2 [I] The other GUID to compare.
3996 BOOL WINAPI
IsEqualGUID(
4000 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
4003 /***********************************************************************
4004 * CoInitializeSecurity [OLE32.@]
4006 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4007 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4008 void* pReserved1
, DWORD dwAuthnLevel
,
4009 DWORD dwImpLevel
, void* pReserved2
,
4010 DWORD dwCapabilities
, void* pReserved3
)
4012 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4013 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4014 dwCapabilities
, pReserved3
);
4018 /***********************************************************************
4019 * CoSuspendClassObjects [OLE32.@]
4021 * Suspends all registered class objects to prevent further requests coming in
4022 * for those objects.
4026 * Failure: HRESULT code.
4028 HRESULT WINAPI
CoSuspendClassObjects(void)
4034 /***********************************************************************
4035 * CoAddRefServerProcess [OLE32.@]
4037 * Helper function for incrementing the reference count of a local-server
4041 * New reference count.
4044 * CoReleaseServerProcess().
4046 ULONG WINAPI
CoAddRefServerProcess(void)
4052 EnterCriticalSection(&csRegisteredClassList
);
4053 refs
= ++s_COMServerProcessReferences
;
4054 LeaveCriticalSection(&csRegisteredClassList
);
4056 TRACE("refs before: %d\n", refs
- 1);
4061 /***********************************************************************
4062 * CoReleaseServerProcess [OLE32.@]
4064 * Helper function for decrementing the reference count of a local-server
4068 * New reference count.
4071 * When reference count reaches 0, this function suspends all registered
4072 * classes so no new connections are accepted.
4075 * CoAddRefServerProcess(), CoSuspendClassObjects().
4077 ULONG WINAPI
CoReleaseServerProcess(void)
4083 EnterCriticalSection(&csRegisteredClassList
);
4085 refs
= --s_COMServerProcessReferences
;
4086 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4088 LeaveCriticalSection(&csRegisteredClassList
);
4090 TRACE("refs after: %d\n", refs
);
4095 /***********************************************************************
4096 * CoIsHandlerConnected [OLE32.@]
4098 * Determines whether a proxy is connected to a remote stub.
4101 * pUnk [I] Pointer to object that may or may not be connected.
4104 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4107 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4109 FIXME("%p\n", pUnk
);
4114 /***********************************************************************
4115 * CoAllowSetForegroundWindow [OLE32.@]
4118 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4120 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4124 /***********************************************************************
4125 * CoQueryProxyBlanket [OLE32.@]
4127 * Retrieves the security settings being used by a proxy.
4130 * pProxy [I] Pointer to the proxy object.
4131 * pAuthnSvc [O] The type of authentication service.
4132 * pAuthzSvc [O] The type of authorization service.
4133 * ppServerPrincName [O] Optional. The server prinicple name.
4134 * pAuthnLevel [O] The authentication level.
4135 * pImpLevel [O] The impersonation level.
4136 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4137 * pCapabilities [O] Flags affecting the security behaviour.
4141 * Failure: HRESULT code.
4144 * CoCopyProxy, CoSetProxyBlanket.
4146 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4147 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4148 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4150 IClientSecurity
*pCliSec
;
4153 TRACE("%p\n", pProxy
);
4155 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4158 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4159 pAuthzSvc
, ppServerPrincName
,
4160 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4162 IClientSecurity_Release(pCliSec
);
4165 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4169 /***********************************************************************
4170 * CoSetProxyBlanket [OLE32.@]
4172 * Sets the security settings for a proxy.
4175 * pProxy [I] Pointer to the proxy object.
4176 * AuthnSvc [I] The type of authentication service.
4177 * AuthzSvc [I] The type of authorization service.
4178 * pServerPrincName [I] The server prinicple name.
4179 * AuthnLevel [I] The authentication level.
4180 * ImpLevel [I] The impersonation level.
4181 * pAuthInfo [I] Information specific to the authorization/authentication service.
4182 * Capabilities [I] Flags affecting the security behaviour.
4186 * Failure: HRESULT code.
4189 * CoQueryProxyBlanket, CoCopyProxy.
4191 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4192 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4193 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4195 IClientSecurity
*pCliSec
;
4198 TRACE("%p\n", pProxy
);
4200 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4203 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4204 AuthzSvc
, pServerPrincName
,
4205 AuthnLevel
, ImpLevel
, pAuthInfo
,
4207 IClientSecurity_Release(pCliSec
);
4210 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4214 /***********************************************************************
4215 * CoCopyProxy [OLE32.@]
4220 * pProxy [I] Pointer to the proxy object.
4221 * ppCopy [O] Copy of the proxy.
4225 * Failure: HRESULT code.
4228 * CoQueryProxyBlanket, CoSetProxyBlanket.
4230 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4232 IClientSecurity
*pCliSec
;
4235 TRACE("%p\n", pProxy
);
4237 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4240 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4241 IClientSecurity_Release(pCliSec
);
4244 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4249 /***********************************************************************
4250 * CoGetCallContext [OLE32.@]
4252 * Gets the context of the currently executing server call in the current
4256 * riid [I] Context interface to return.
4257 * ppv [O] Pointer to memory that will receive the context on return.
4261 * Failure: HRESULT code.
4263 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4265 struct oletls
*info
= COM_CurrentInfo();
4267 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4270 return E_OUTOFMEMORY
;
4272 if (!info
->call_state
)
4273 return RPC_E_CALL_COMPLETE
;
4275 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4278 /***********************************************************************
4279 * CoSwitchCallContext [OLE32.@]
4281 * Switches the context of the currently executing server call in the current
4285 * pObject [I] Pointer to new context object
4286 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4290 * Failure: HRESULT code.
4292 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4294 struct oletls
*info
= COM_CurrentInfo();
4296 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4299 return E_OUTOFMEMORY
;
4301 *ppOldObject
= info
->call_state
;
4302 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4307 /***********************************************************************
4308 * CoQueryClientBlanket [OLE32.@]
4310 * Retrieves the authentication information about the client of the currently
4311 * executing server call in the current thread.
4314 * pAuthnSvc [O] Optional. The type of authentication service.
4315 * pAuthzSvc [O] Optional. The type of authorization service.
4316 * pServerPrincName [O] Optional. The server prinicple name.
4317 * pAuthnLevel [O] Optional. The authentication level.
4318 * pImpLevel [O] Optional. The impersonation level.
4319 * pPrivs [O] Optional. Information about the privileges of the client.
4320 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4324 * Failure: HRESULT code.
4327 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4329 HRESULT WINAPI
CoQueryClientBlanket(
4332 OLECHAR
**pServerPrincName
,
4335 RPC_AUTHZ_HANDLE
*pPrivs
,
4336 DWORD
*pCapabilities
)
4338 IServerSecurity
*pSrvSec
;
4341 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4342 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4343 pPrivs
, pCapabilities
);
4345 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4348 hr
= IServerSecurity_QueryBlanket(
4349 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4350 pImpLevel
, pPrivs
, pCapabilities
);
4351 IServerSecurity_Release(pSrvSec
);
4357 /***********************************************************************
4358 * CoImpersonateClient [OLE32.@]
4360 * Impersonates the client of the currently executing server call in the
4368 * Failure: HRESULT code.
4371 * If this function fails then the current thread will not be impersonating
4372 * the client and all actions will take place on behalf of the server.
4373 * Therefore, it is important to check the return value from this function.
4376 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4378 HRESULT WINAPI
CoImpersonateClient(void)
4380 IServerSecurity
*pSrvSec
;
4385 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4388 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4389 IServerSecurity_Release(pSrvSec
);
4395 /***********************************************************************
4396 * CoRevertToSelf [OLE32.@]
4398 * Ends the impersonation of the client of the currently executing server
4399 * call in the current thread.
4406 * Failure: HRESULT code.
4409 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4411 HRESULT WINAPI
CoRevertToSelf(void)
4413 IServerSecurity
*pSrvSec
;
4418 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4421 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4422 IServerSecurity_Release(pSrvSec
);
4428 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4430 /* first try to retrieve messages for incoming COM calls to the apartment window */
4431 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4432 /* next retrieve other messages necessary for the app to remain responsive */
4433 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4434 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4437 /***********************************************************************
4438 * CoWaitForMultipleHandles [OLE32.@]
4440 * Waits for one or more handles to become signaled.
4443 * dwFlags [I] Flags. See notes.
4444 * dwTimeout [I] Timeout in milliseconds.
4445 * cHandles [I] Number of handles pointed to by pHandles.
4446 * pHandles [I] Handles to wait for.
4447 * lpdwindex [O] Index of handle that was signaled.
4451 * Failure: RPC_S_CALLPENDING on timeout.
4455 * The dwFlags parameter can be zero or more of the following:
4456 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4457 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4460 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4462 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4463 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4466 DWORD start_time
= GetTickCount();
4467 APARTMENT
*apt
= COM_CurrentApt();
4468 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4469 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4471 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4472 pHandles
, lpdwindex
);
4475 return E_INVALIDARG
;
4480 return E_INVALIDARG
;
4483 return RPC_E_NO_SYNC
;
4487 DWORD now
= GetTickCount();
4490 if (now
- start_time
> dwTimeout
)
4492 hr
= RPC_S_CALLPENDING
;
4498 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4499 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4501 TRACE("waiting for rpc completion or window message\n");
4507 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4508 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4512 if (res
== WAIT_TIMEOUT
)
4513 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4514 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4515 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4517 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4522 /* call message filter */
4524 if (COM_CurrentApt()->filter
)
4526 PENDINGTYPE pendingtype
=
4527 COM_CurrentInfo()->pending_call_count_server
?
4528 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4529 DWORD be_handled
= IMessageFilter_MessagePending(
4530 COM_CurrentApt()->filter
, 0 /* FIXME */,
4531 now
- start_time
, pendingtype
);
4532 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4535 case PENDINGMSG_CANCELCALL
:
4536 WARN("call canceled\n");
4537 hr
= RPC_E_CALL_CANCELED
;
4539 case PENDINGMSG_WAITNOPROCESS
:
4540 case PENDINGMSG_WAITDEFPROCESS
:
4542 /* FIXME: MSDN is very vague about the difference
4543 * between WAITNOPROCESS and WAITDEFPROCESS - there
4544 * appears to be none, so it is possibly a left-over
4545 * from the 16-bit world. */
4550 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4551 * so after processing 100 messages we go back to checking the wait handles */
4552 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4554 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4555 TranslateMessage(&msg
);
4556 DispatchMessageW(&msg
);
4557 if (msg
.message
== WM_QUIT
)
4559 TRACE("resending WM_QUIT to outer message loop\n");
4560 PostQuitMessage(msg
.wParam
);
4561 /* no longer need to process messages */
4562 message_loop
= FALSE
;
4571 TRACE("waiting for rpc completion\n");
4573 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4574 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4575 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4581 hr
= RPC_S_CALLPENDING
;
4584 hr
= HRESULT_FROM_WIN32( GetLastError() );
4592 TRACE("-- 0x%08x\n", hr
);
4597 /***********************************************************************
4598 * CoGetObject [OLE32.@]
4600 * Gets the object named by converting the name to a moniker and binding to it.
4603 * pszName [I] String representing the object.
4604 * pBindOptions [I] Parameters affecting the binding to the named object.
4605 * riid [I] Interface to bind to on the objecct.
4606 * ppv [O] On output, the interface riid of the object represented
4611 * Failure: HRESULT code.
4614 * MkParseDisplayName.
4616 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4617 REFIID riid
, void **ppv
)
4624 hr
= CreateBindCtx(0, &pbc
);
4628 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4635 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4638 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4639 IMoniker_Release(pmk
);
4643 IBindCtx_Release(pbc
);
4648 /***********************************************************************
4649 * CoRegisterChannelHook [OLE32.@]
4651 * Registers a process-wide hook that is called during ORPC calls.
4654 * guidExtension [I] GUID of the channel hook to register.
4655 * pChannelHook [I] Channel hook object to register.
4659 * Failure: HRESULT code.
4661 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4663 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4665 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4668 typedef struct Context
4670 IComThreadingInfo IComThreadingInfo_iface
;
4671 IContextCallback IContextCallback_iface
;
4672 IObjContext IObjContext_iface
;
4676 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4678 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4681 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4683 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4686 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4688 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4691 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4695 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4696 IsEqualIID(riid
, &IID_IUnknown
))
4698 *ppv
= &iface
->IComThreadingInfo_iface
;
4700 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4702 *ppv
= &iface
->IContextCallback_iface
;
4704 else if (IsEqualIID(riid
, &IID_IObjContext
))
4706 *ppv
= &iface
->IObjContext_iface
;
4711 IUnknown_AddRef((IUnknown
*)*ppv
);
4715 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4716 return E_NOINTERFACE
;
4719 static ULONG
Context_AddRef(Context
*This
)
4721 return InterlockedIncrement(&This
->refs
);
4724 static ULONG
Context_Release(Context
*This
)
4726 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4727 releasing context while refcount is at 0 destroys it. */
4730 HeapFree(GetProcessHeap(), 0, This
);
4734 return InterlockedDecrement(&This
->refs
);
4737 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4739 Context
*This
= impl_from_IComThreadingInfo(iface
);
4740 return Context_QueryInterface(This
, riid
, ppv
);
4743 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4745 Context
*This
= impl_from_IComThreadingInfo(iface
);
4746 return Context_AddRef(This
);
4749 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4751 Context
*This
= impl_from_IComThreadingInfo(iface
);
4752 return Context_Release(This
);
4755 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4757 APTTYPEQUALIFIER qualifier
;
4759 TRACE("(%p)\n", apttype
);
4761 return CoGetApartmentType(apttype
, &qualifier
);
4764 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4766 APTTYPEQUALIFIER qualifier
;
4770 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4774 TRACE("(%p)\n", thdtype
);
4779 case APTTYPE_MAINSTA
:
4780 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4783 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4789 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4791 TRACE("(%p)\n", logical_thread_id
);
4792 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4795 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4797 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4801 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4803 Context_CTI_QueryInterface
,
4805 Context_CTI_Release
,
4806 Context_CTI_GetCurrentApartmentType
,
4807 Context_CTI_GetCurrentThreadType
,
4808 Context_CTI_GetCurrentLogicalThreadId
,
4809 Context_CTI_SetCurrentLogicalThreadId
4812 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4814 Context
*This
= impl_from_IContextCallback(iface
);
4815 return Context_QueryInterface(This
, riid
, ppv
);
4818 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4820 Context
*This
= impl_from_IContextCallback(iface
);
4821 return Context_AddRef(This
);
4824 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4826 Context
*This
= impl_from_IContextCallback(iface
);
4827 return Context_Release(This
);
4830 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4831 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4833 Context
*This
= impl_from_IContextCallback(iface
);
4835 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4839 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4841 Context_CC_QueryInterface
,
4844 Context_CC_ContextCallback
4847 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4849 Context
*This
= impl_from_IObjContext(iface
);
4850 return Context_QueryInterface(This
, riid
, ppv
);
4853 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4855 Context
*This
= impl_from_IObjContext(iface
);
4856 return Context_AddRef(This
);
4859 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4861 Context
*This
= impl_from_IObjContext(iface
);
4862 return Context_Release(This
);
4865 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4867 Context
*This
= impl_from_IObjContext(iface
);
4869 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4873 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4875 Context
*This
= impl_from_IObjContext(iface
);
4877 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4881 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4883 Context
*This
= impl_from_IObjContext(iface
);
4885 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4889 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4891 Context
*This
= impl_from_IObjContext(iface
);
4893 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4897 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4899 Context
*This
= impl_from_IObjContext(iface
);
4900 FIXME("(%p/%p)\n", This
, iface
);
4903 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4905 Context
*This
= impl_from_IObjContext(iface
);
4906 FIXME("(%p/%p)\n", This
, iface
);
4909 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4911 Context
*This
= impl_from_IObjContext(iface
);
4912 FIXME("(%p/%p)\n", This
, iface
);
4915 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4917 Context
*This
= impl_from_IObjContext(iface
);
4918 FIXME("(%p/%p)\n", This
, iface
);
4921 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4923 Context
*This
= impl_from_IObjContext(iface
);
4924 FIXME("(%p/%p)\n", This
, iface
);
4927 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4929 Context
*This
= impl_from_IObjContext(iface
);
4930 FIXME("(%p/%p)\n", This
, iface
);
4933 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4935 Context
*This
= impl_from_IObjContext(iface
);
4936 FIXME("(%p/%p)\n", This
, iface
);
4939 static const IObjContextVtbl Context_Object_Vtbl
=
4941 Context_OC_QueryInterface
,
4944 Context_OC_SetProperty
,
4945 Context_OC_RemoveProperty
,
4946 Context_OC_GetProperty
,
4947 Context_OC_EnumContextProps
,
4948 Context_OC_Reserved1
,
4949 Context_OC_Reserved2
,
4950 Context_OC_Reserved3
,
4951 Context_OC_Reserved4
,
4952 Context_OC_Reserved5
,
4953 Context_OC_Reserved6
,
4954 Context_OC_Reserved7
4957 /***********************************************************************
4958 * CoGetObjectContext [OLE32.@]
4960 * Retrieves an object associated with the current context (i.e. apartment).
4963 * riid [I] ID of the interface of the object to retrieve.
4964 * ppv [O] Address where object will be stored on return.
4968 * Failure: HRESULT code.
4970 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4972 IObjContext
*context
;
4975 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4978 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
4982 return IObjContext_QueryInterface(context
, riid
, ppv
);
4985 /***********************************************************************
4986 * CoGetContextToken [OLE32.@]
4988 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4990 struct oletls
*info
= COM_CurrentInfo();
4992 TRACE("(%p)\n", token
);
4995 return E_OUTOFMEMORY
;
5000 if (!(apt
= apartment_find_multi_threaded()))
5002 ERR("apartment not initialised\n");
5003 return CO_E_NOTINITIALIZED
;
5005 apartment_release(apt
);
5011 if (!info
->context_token
)
5015 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5017 return E_OUTOFMEMORY
;
5019 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5020 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5021 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5022 /* Context token does not take a reference, it's always zero until the
5023 interface is explicitly requested with CoGetObjectContext(). */
5026 info
->context_token
= &context
->IObjContext_iface
;
5029 *token
= (ULONG_PTR
)info
->context_token
;
5030 TRACE("context_token=%p\n", info
->context_token
);
5035 /***********************************************************************
5036 * CoGetDefaultContext [OLE32.@]
5038 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5040 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5041 return E_NOINTERFACE
;
5044 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5046 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5050 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5051 if (SUCCEEDED(hres
))
5053 struct class_reg_data regdata
;
5054 WCHAR dllpath
[MAX_PATH
+1];
5056 regdata
.u
.hkey
= hkey
;
5057 regdata
.hkey
= TRUE
;
5059 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
5061 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5062 if (!strcmpiW(dllpath
, wszOle32
))
5065 return HandlerCF_Create(rclsid
, riid
, ppv
);
5069 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5073 return CLASS_E_CLASSNOTAVAILABLE
;
5076 /***********************************************************************
5077 * CoGetApartmentType [OLE32.@]
5079 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5081 struct oletls
*info
= COM_CurrentInfo();
5083 FIXME("(%p, %p): semi-stub\n", type
, qualifier
);
5085 if (!type
|| !qualifier
)
5086 return E_INVALIDARG
;
5089 return E_OUTOFMEMORY
;
5092 *type
= APTTYPE_CURRENT
;
5093 else if (info
->apt
->multi_threaded
)
5094 *type
= APTTYPE_MTA
;
5095 else if (info
->apt
->main
)
5096 *type
= APTTYPE_MAINSTA
;
5098 *type
= APTTYPE_STA
;
5100 *qualifier
= APTTYPEQUALIFIER_NONE
;
5102 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5105 /***********************************************************************
5106 * CoRegisterSurrogate [OLE32.@]
5108 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5110 FIXME("(%p): stub\n", surrogate
);
5115 /***********************************************************************
5116 * CoRegisterSurrogateEx [OLE32.@]
5118 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5120 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5126 IGlobalOptions IGlobalOptions_iface
;
5130 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5132 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5135 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5137 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5139 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5141 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5148 return E_NOINTERFACE
;
5151 IUnknown_AddRef((IUnknown
*)*ppv
);
5155 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5157 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5158 LONG ref
= InterlockedIncrement(&This
->ref
);
5160 TRACE("(%p) ref=%d\n", This
, ref
);
5165 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5167 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5168 LONG ref
= InterlockedDecrement(&This
->ref
);
5170 TRACE("(%p) ref=%d\n", This
, ref
);
5178 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5180 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5181 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5185 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5187 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5188 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5192 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5193 GlobalOptions_QueryInterface
,
5194 GlobalOptions_AddRef
,
5195 GlobalOptions_Release
,
5200 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5202 GlobalOptions
*global_options
;
5205 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5208 return E_INVALIDARG
;
5210 global_options
= heap_alloc(sizeof(*global_options
));
5211 if (!global_options
)
5212 return E_OUTOFMEMORY
;
5213 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5214 global_options
->ref
= 1;
5216 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5217 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5221 /***********************************************************************
5224 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5226 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5229 case DLL_PROCESS_ATTACH
:
5230 hProxyDll
= hinstDLL
;
5233 case DLL_PROCESS_DETACH
:
5234 if (reserved
) break;
5236 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5237 RPC_UnregisterAllChannelHooks();
5238 COMPOBJ_DllList_Free();
5239 DeleteCriticalSection(&csRegisteredClassList
);
5240 DeleteCriticalSection(&csApartment
);
5243 case DLL_THREAD_DETACH
:
5250 /***********************************************************************
5251 * DllRegisterServer (OLE32.@)
5253 HRESULT WINAPI
DllRegisterServer(void)
5255 return OLE32_DllRegisterServer();
5258 /***********************************************************************
5259 * DllUnregisterServer (OLE32.@)
5261 HRESULT WINAPI
DllUnregisterServer(void)
5263 return OLE32_DllUnregisterServer();