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 void apartment_joinmta(void)
1729 apartment_addref(MTA
);
1730 COM_CurrentInfo()->apt
= MTA
;
1733 static void COM_TlsDestroy(void)
1735 struct oletls
*info
= NtCurrentTeb()->ReservedForOle
;
1738 if (info
->apt
) apartment_release(info
->apt
);
1739 if (info
->errorinfo
) IErrorInfo_Release(info
->errorinfo
);
1740 if (info
->state
) IUnknown_Release(info
->state
);
1741 if (info
->spy
) IInitializeSpy_Release(info
->spy
);
1742 if (info
->context_token
) IObjContext_Release(info
->context_token
);
1743 HeapFree(GetProcessHeap(), 0, info
);
1744 NtCurrentTeb()->ReservedForOle
= NULL
;
1748 /******************************************************************************
1749 * CoBuildVersion [OLE32.@]
1751 * Gets the build version of the DLL.
1756 * Current build version, hiword is majornumber, loword is minornumber
1758 DWORD WINAPI
CoBuildVersion(void)
1760 TRACE("Returning version %d, build %d.\n", rmm
, rup
);
1761 return (rmm
<<16)+rup
;
1764 /******************************************************************************
1765 * CoRegisterInitializeSpy [OLE32.@]
1767 * Add a Spy that watches CoInitializeEx calls
1770 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1771 * cookie [II] cookie receiver
1774 * Success: S_OK if not already initialized, S_FALSE otherwise.
1775 * Failure: HRESULT code.
1780 HRESULT WINAPI
CoRegisterInitializeSpy(IInitializeSpy
*spy
, ULARGE_INTEGER
*cookie
)
1782 struct oletls
*info
= COM_CurrentInfo();
1785 TRACE("(%p, %p)\n", spy
, cookie
);
1787 if (!spy
|| !cookie
|| !info
)
1790 WARN("Could not allocate tls\n");
1791 return E_INVALIDARG
;
1796 FIXME("Already registered?\n");
1797 return E_UNEXPECTED
;
1800 hr
= IInitializeSpy_QueryInterface(spy
, &IID_IInitializeSpy
, (void **) &info
->spy
);
1803 cookie
->QuadPart
= (DWORD_PTR
)spy
;
1809 /******************************************************************************
1810 * CoRevokeInitializeSpy [OLE32.@]
1812 * Remove a spy that previously watched CoInitializeEx calls
1815 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1818 * Success: S_OK if a spy is removed
1819 * Failure: E_INVALIDARG
1824 HRESULT WINAPI
CoRevokeInitializeSpy(ULARGE_INTEGER cookie
)
1826 struct oletls
*info
= COM_CurrentInfo();
1827 TRACE("(%s)\n", wine_dbgstr_longlong(cookie
.QuadPart
));
1829 if (!info
|| !info
->spy
|| cookie
.QuadPart
!= (DWORD_PTR
)info
->spy
)
1830 return E_INVALIDARG
;
1832 IInitializeSpy_Release(info
->spy
);
1838 /******************************************************************************
1839 * CoInitialize [OLE32.@]
1841 * Initializes the COM libraries by calling CoInitializeEx with
1842 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1845 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1848 * Success: S_OK if not already initialized, S_FALSE otherwise.
1849 * Failure: HRESULT code.
1854 HRESULT WINAPI
CoInitialize(LPVOID lpReserved
)
1857 * Just delegate to the newer method.
1859 return CoInitializeEx(lpReserved
, COINIT_APARTMENTTHREADED
);
1862 /******************************************************************************
1863 * CoInitializeEx [OLE32.@]
1865 * Initializes the COM libraries.
1868 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1869 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1872 * S_OK if successful,
1873 * S_FALSE if this function was called already.
1874 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1879 * The behavior used to set the IMalloc used for memory management is
1881 * The dwCoInit parameter must specify one of the following apartment
1883 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1884 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1885 * The parameter may also specify zero or more of the following flags:
1886 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1887 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1892 HRESULT WINAPI DECLSPEC_HOTPATCH
CoInitializeEx(LPVOID lpReserved
, DWORD dwCoInit
)
1894 struct oletls
*info
= COM_CurrentInfo();
1898 TRACE("(%p, %x)\n", lpReserved
, (int)dwCoInit
);
1900 if (lpReserved
!=NULL
)
1902 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved
, (int)dwCoInit
, lpReserved
);
1906 * Check the lock count. If this is the first time going through the initialize
1907 * process, we have to initialize the libraries.
1909 * And crank-up that lock count.
1911 if (InterlockedExchangeAdd(&s_COMLockCount
,1)==0)
1914 * Initialize the various COM libraries and data structures.
1916 TRACE("() - Initializing the COM libraries\n");
1918 /* we may need to defer this until after apartment initialisation */
1919 RunningObjectTableImpl_Initialize();
1923 IInitializeSpy_PreInitialize(info
->spy
, dwCoInit
, info
->inits
);
1925 if (!(apt
= info
->apt
))
1927 apt
= apartment_get_or_create(dwCoInit
);
1928 if (!apt
) return E_OUTOFMEMORY
;
1930 else if (!apartment_is_model(apt
, dwCoInit
))
1932 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1933 code then we are probably using the wrong threading model to implement that API. */
1934 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1935 apt
->multi_threaded
? "multi-threaded" : "apartment threaded",
1936 dwCoInit
& COINIT_APARTMENTTHREADED
? "apartment threaded" : "multi-threaded");
1937 return RPC_E_CHANGED_MODE
;
1945 IInitializeSpy_PostInitialize(info
->spy
, hr
, dwCoInit
, info
->inits
);
1950 /***********************************************************************
1951 * CoUninitialize [OLE32.@]
1953 * This method will decrement the refcount on the current apartment, freeing
1954 * the resources associated with it if it is the last thread in the apartment.
1955 * If the last apartment is freed, the function will additionally release
1956 * any COM resources associated with the process.
1966 void WINAPI DECLSPEC_HOTPATCH
CoUninitialize(void)
1968 struct oletls
* info
= COM_CurrentInfo();
1973 /* will only happen on OOM */
1977 IInitializeSpy_PreUninitialize(info
->spy
, info
->inits
);
1982 ERR("Mismatched CoUninitialize\n");
1985 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
1991 if (info
->ole_inits
)
1992 WARN("uninitializing apartment while Ole is still initialized\n");
1993 apartment_release(info
->apt
);
1998 * Decrease the reference count.
1999 * If we are back to 0 locks on the COM library, make sure we free
2000 * all the associated data structures.
2002 lCOMRefCnt
= InterlockedExchangeAdd(&s_COMLockCount
,-1);
2005 TRACE("() - Releasing the COM libraries\n");
2007 revoke_registered_psclsids();
2008 RunningObjectTableImpl_UnInitialize();
2010 else if (lCOMRefCnt
<1) {
2011 ERR( "CoUninitialize() - not CoInitialized.\n" );
2012 InterlockedExchangeAdd(&s_COMLockCount
,1); /* restore the lock count. */
2015 IInitializeSpy_PostUninitialize(info
->spy
, info
->inits
);
2018 /******************************************************************************
2019 * CoDisconnectObject [OLE32.@]
2021 * Disconnects all connections to this object from remote processes. Dispatches
2022 * pending RPCs while blocking new RPCs from occurring, and then calls
2023 * IMarshal::DisconnectObject on the given object.
2025 * Typically called when the object server is forced to shut down, for instance by
2029 * lpUnk [I] The object whose stub should be disconnected.
2030 * reserved [I] Reserved. Should be set to 0.
2034 * Failure: HRESULT code.
2037 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2039 HRESULT WINAPI
CoDisconnectObject( LPUNKNOWN lpUnk
, DWORD reserved
)
2041 struct stub_manager
*manager
;
2046 TRACE("(%p, 0x%08x)\n", lpUnk
, reserved
);
2048 if (!lpUnk
) return E_INVALIDARG
;
2050 hr
= IUnknown_QueryInterface(lpUnk
, &IID_IMarshal
, (void **)&marshal
);
2053 hr
= IMarshal_DisconnectObject(marshal
, reserved
);
2054 IMarshal_Release(marshal
);
2058 apt
= COM_CurrentApt();
2060 return CO_E_NOTINITIALIZED
;
2062 manager
= get_stub_manager_from_object(apt
, lpUnk
, FALSE
);
2064 stub_manager_disconnect(manager
);
2065 /* Release stub manager twice, to remove the apartment reference. */
2066 stub_manager_int_release(manager
);
2067 stub_manager_int_release(manager
);
2070 /* Note: native is pretty broken here because it just silently
2071 * fails, without returning an appropriate error code if the object was
2072 * not found, making apps think that the object was disconnected, when
2073 * it actually wasn't */
2078 /******************************************************************************
2079 * CoCreateGuid [OLE32.@]
2081 * Simply forwards to UuidCreate in RPCRT4.
2084 * pguid [O] Points to the GUID to initialize.
2088 * Failure: HRESULT code.
2093 HRESULT WINAPI
CoCreateGuid(GUID
*pguid
)
2097 if(!pguid
) return E_INVALIDARG
;
2099 status
= UuidCreate(pguid
);
2100 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
) return S_OK
;
2101 return HRESULT_FROM_WIN32( status
);
2104 static inline BOOL
is_valid_hex(WCHAR c
)
2106 if (!(((c
>= '0') && (c
<= '9')) ||
2107 ((c
>= 'a') && (c
<= 'f')) ||
2108 ((c
>= 'A') && (c
<= 'F'))))
2113 static const BYTE guid_conv_table
[256] =
2115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2118 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2119 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2121 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2124 /* conversion helper for CLSIDFromString/IIDFromString */
2125 static BOOL
guid_from_string(LPCWSTR s
, GUID
*id
)
2129 if (!s
|| s
[0]!='{') {
2130 memset( id
, 0, sizeof (CLSID
) );
2135 TRACE("%s -> %p\n", debugstr_w(s
), id
);
2137 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2140 for (i
= 1; i
< 9; i
++) {
2141 if (!is_valid_hex(s
[i
])) return FALSE
;
2142 id
->Data1
= (id
->Data1
<< 4) | guid_conv_table
[s
[i
]];
2144 if (s
[9]!='-') return FALSE
;
2147 for (i
= 10; i
< 14; i
++) {
2148 if (!is_valid_hex(s
[i
])) return FALSE
;
2149 id
->Data2
= (id
->Data2
<< 4) | guid_conv_table
[s
[i
]];
2151 if (s
[14]!='-') return FALSE
;
2154 for (i
= 15; i
< 19; i
++) {
2155 if (!is_valid_hex(s
[i
])) return FALSE
;
2156 id
->Data3
= (id
->Data3
<< 4) | guid_conv_table
[s
[i
]];
2158 if (s
[19]!='-') return FALSE
;
2160 for (i
= 20; i
< 37; i
+=2) {
2162 if (s
[i
]!='-') return FALSE
;
2165 if (!is_valid_hex(s
[i
]) || !is_valid_hex(s
[i
+1])) return FALSE
;
2166 id
->Data4
[(i
-20)/2] = guid_conv_table
[s
[i
]] << 4 | guid_conv_table
[s
[i
+1]];
2169 if (s
[37] == '}' && s
[38] == '\0')
2175 /*****************************************************************************/
2177 static HRESULT
clsid_from_string_reg(LPCOLESTR progid
, CLSID
*clsid
)
2179 static const WCHAR clsidW
[] = { '\\','C','L','S','I','D',0 };
2180 WCHAR buf2
[CHARS_IN_GUID
];
2181 LONG buf2len
= sizeof(buf2
);
2185 memset(clsid
, 0, sizeof(*clsid
));
2186 buf
= HeapAlloc( GetProcessHeap(),0,(strlenW(progid
)+8) * sizeof(WCHAR
) );
2187 if (!buf
) return E_OUTOFMEMORY
;
2188 strcpyW( buf
, progid
);
2189 strcatW( buf
, clsidW
);
2190 if (open_classes_key(HKEY_CLASSES_ROOT
, buf
, MAXIMUM_ALLOWED
, &xhkey
))
2192 HeapFree(GetProcessHeap(),0,buf
);
2193 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid
));
2194 return CO_E_CLASSSTRING
;
2196 HeapFree(GetProcessHeap(),0,buf
);
2198 if (RegQueryValueW(xhkey
,NULL
,buf2
,&buf2len
))
2201 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid
));
2202 return CO_E_CLASSSTRING
;
2205 return guid_from_string(buf2
, clsid
) ? S_OK
: CO_E_CLASSSTRING
;
2208 /******************************************************************************
2209 * CLSIDFromString [OLE32.@]
2211 * Converts a unique identifier from its string representation into
2215 * idstr [I] The string representation of the GUID.
2216 * id [O] GUID converted from the string.
2220 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2225 HRESULT WINAPI
CLSIDFromString(LPCOLESTR idstr
, LPCLSID id
)
2227 HRESULT ret
= CO_E_CLASSSTRING
;
2231 return E_INVALIDARG
;
2233 if (guid_from_string(idstr
, id
))
2236 /* It appears a ProgID is also valid */
2237 ret
= clsid_from_string_reg(idstr
, &tmp_id
);
2244 /******************************************************************************
2245 * IIDFromString [OLE32.@]
2247 * Converts an interface identifier from its string representation to
2251 * idstr [I] The string representation of the GUID.
2252 * id [O] IID converted from the string.
2256 * CO_E_IIDSTRING if idstr is not a valid IID
2261 HRESULT WINAPI
IIDFromString(LPCOLESTR s
, IID
*iid
)
2263 TRACE("%s -> %p\n", debugstr_w(s
), iid
);
2267 memset(iid
, 0, sizeof(*iid
));
2271 /* length mismatch is a special case */
2272 if (strlenW(s
) + 1 != CHARS_IN_GUID
)
2273 return E_INVALIDARG
;
2276 return CO_E_IIDSTRING
;
2278 return guid_from_string(s
, iid
) ? S_OK
: CO_E_IIDSTRING
;
2281 /******************************************************************************
2282 * StringFromCLSID [OLE32.@]
2283 * StringFromIID [OLE32.@]
2285 * Converts a GUID into the respective string representation.
2286 * The target string is allocated using the OLE IMalloc.
2289 * id [I] the GUID to be converted.
2290 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2297 * StringFromGUID2, CLSIDFromString
2299 HRESULT WINAPI
StringFromCLSID(REFCLSID id
, LPOLESTR
*idstr
)
2301 if (!(*idstr
= CoTaskMemAlloc(CHARS_IN_GUID
* sizeof(WCHAR
)))) return E_OUTOFMEMORY
;
2302 StringFromGUID2( id
, *idstr
, CHARS_IN_GUID
);
2306 /******************************************************************************
2307 * StringFromGUID2 [OLE32.@]
2309 * Modified version of StringFromCLSID that allows you to specify max
2313 * id [I] GUID to convert to string.
2314 * str [O] Buffer where the result will be stored.
2315 * cmax [I] Size of the buffer in characters.
2318 * Success: The length of the resulting string in characters.
2321 INT WINAPI
StringFromGUID2(REFGUID id
, LPOLESTR str
, INT cmax
)
2323 static const WCHAR formatW
[] = { '{','%','0','8','X','-','%','0','4','X','-',
2324 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2325 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2326 '%','0','2','X','%','0','2','X','}',0 };
2327 if (!id
|| cmax
< CHARS_IN_GUID
) return 0;
2328 sprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
2329 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
2330 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
2331 return CHARS_IN_GUID
;
2334 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2335 HRESULT
COM_OpenKeyForCLSID(REFCLSID clsid
, LPCWSTR keyname
, REGSAM access
, HKEY
*subkey
)
2337 static const WCHAR wszCLSIDSlash
[] = {'C','L','S','I','D','\\',0};
2338 WCHAR path
[CHARS_IN_GUID
+ ARRAYSIZE(wszCLSIDSlash
) - 1];
2342 strcpyW(path
, wszCLSIDSlash
);
2343 StringFromGUID2(clsid
, path
+ strlenW(wszCLSIDSlash
), CHARS_IN_GUID
);
2344 res
= open_classes_key(HKEY_CLASSES_ROOT
, path
, keyname
? KEY_READ
: access
, &key
);
2345 if (res
== ERROR_FILE_NOT_FOUND
)
2346 return REGDB_E_CLASSNOTREG
;
2347 else if (res
!= ERROR_SUCCESS
)
2348 return REGDB_E_READREGDB
;
2356 res
= open_classes_key(key
, keyname
, access
, subkey
);
2358 if (res
== ERROR_FILE_NOT_FOUND
)
2359 return REGDB_E_KEYMISSING
;
2360 else if (res
!= ERROR_SUCCESS
)
2361 return REGDB_E_READREGDB
;
2366 /* open HKCR\\AppId\\{string form of appid clsid} key */
2367 HRESULT
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid
, REGSAM access
, HKEY
*subkey
)
2369 static const WCHAR szAppId
[] = { 'A','p','p','I','d',0 };
2370 static const WCHAR szAppIdKey
[] = { 'A','p','p','I','d','\\',0 };
2372 WCHAR buf
[CHARS_IN_GUID
];
2373 WCHAR keyname
[ARRAYSIZE(szAppIdKey
) + CHARS_IN_GUID
];
2379 /* read the AppID value under the class's key */
2380 hr
= COM_OpenKeyForCLSID(clsid
, NULL
, KEY_READ
, &hkey
);
2385 res
= RegQueryValueExW(hkey
, szAppId
, NULL
, &type
, (LPBYTE
)buf
, &size
);
2387 if (res
== ERROR_FILE_NOT_FOUND
)
2388 return REGDB_E_KEYMISSING
;
2389 else if (res
!= ERROR_SUCCESS
|| type
!=REG_SZ
)
2390 return REGDB_E_READREGDB
;
2392 strcpyW(keyname
, szAppIdKey
);
2393 strcatW(keyname
, buf
);
2394 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, access
, subkey
);
2395 if (res
== ERROR_FILE_NOT_FOUND
)
2396 return REGDB_E_KEYMISSING
;
2397 else if (res
!= ERROR_SUCCESS
)
2398 return REGDB_E_READREGDB
;
2403 /******************************************************************************
2404 * ProgIDFromCLSID [OLE32.@]
2406 * Converts a class id into the respective program ID.
2409 * clsid [I] Class ID, as found in registry.
2410 * ppszProgID [O] Associated ProgID.
2415 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2417 HRESULT WINAPI DECLSPEC_HOTPATCH
ProgIDFromCLSID(REFCLSID clsid
, LPOLESTR
*ppszProgID
)
2419 static const WCHAR wszProgID
[] = {'P','r','o','g','I','D',0};
2420 ACTCTX_SECTION_KEYED_DATA data
;
2426 return E_INVALIDARG
;
2430 data
.cbSize
= sizeof(data
);
2431 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
2434 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
2435 if (comclass
->progid_len
)
2439 *ppszProgID
= CoTaskMemAlloc(comclass
->progid_len
+ sizeof(WCHAR
));
2440 if (!*ppszProgID
) return E_OUTOFMEMORY
;
2442 ptrW
= (WCHAR
*)((BYTE
*)comclass
+ comclass
->progid_offset
);
2443 memcpy(*ppszProgID
, ptrW
, comclass
->progid_len
+ sizeof(WCHAR
));
2447 return REGDB_E_CLASSNOTREG
;
2450 ret
= COM_OpenKeyForCLSID(clsid
, wszProgID
, KEY_READ
, &hkey
);
2454 if (RegQueryValueW(hkey
, NULL
, NULL
, &progidlen
))
2455 ret
= REGDB_E_CLASSNOTREG
;
2459 *ppszProgID
= CoTaskMemAlloc(progidlen
* sizeof(WCHAR
));
2462 if (RegQueryValueW(hkey
, NULL
, *ppszProgID
, &progidlen
)) {
2463 ret
= REGDB_E_CLASSNOTREG
;
2464 CoTaskMemFree(*ppszProgID
);
2469 ret
= E_OUTOFMEMORY
;
2476 /******************************************************************************
2477 * CLSIDFromProgID [OLE32.@]
2479 * Converts a program id into the respective GUID.
2482 * progid [I] Unicode program ID, as found in registry.
2483 * clsid [O] Associated CLSID.
2487 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2489 HRESULT WINAPI DECLSPEC_HOTPATCH
CLSIDFromProgID(LPCOLESTR progid
, LPCLSID clsid
)
2491 ACTCTX_SECTION_KEYED_DATA data
;
2493 if (!progid
|| !clsid
)
2494 return E_INVALIDARG
;
2496 data
.cbSize
= sizeof(data
);
2497 if (FindActCtxSectionStringW(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
,
2500 struct progidredirect_data
*progiddata
= (struct progidredirect_data
*)data
.lpData
;
2501 CLSID
*alias
= (CLSID
*)((BYTE
*)data
.lpSectionBase
+ progiddata
->clsid_offset
);
2506 return clsid_from_string_reg(progid
, clsid
);
2509 /******************************************************************************
2510 * CLSIDFromProgIDEx [OLE32.@]
2512 HRESULT WINAPI
CLSIDFromProgIDEx(LPCOLESTR progid
, LPCLSID clsid
)
2514 FIXME("%s,%p: semi-stub\n", debugstr_w(progid
), clsid
);
2516 return CLSIDFromProgID(progid
, clsid
);
2519 static HRESULT
get_ps_clsid_from_registry(const WCHAR
* path
, REGSAM access
, CLSID
*pclsid
)
2522 WCHAR value
[CHARS_IN_GUID
];
2527 if (open_classes_key(HKEY_CLASSES_ROOT
, path
, access
, &hkey
))
2528 return REGDB_E_IIDNOTREG
;
2530 len
= sizeof(value
);
2531 if (ERROR_SUCCESS
!= RegQueryValueExW(hkey
, NULL
, NULL
, NULL
, (BYTE
*)value
, &len
))
2532 return REGDB_E_IIDNOTREG
;
2535 if (CLSIDFromString(value
, pclsid
) != NOERROR
)
2536 return REGDB_E_IIDNOTREG
;
2541 /*****************************************************************************
2542 * CoGetPSClsid [OLE32.@]
2544 * Retrieves the CLSID of the proxy/stub factory that implements
2545 * IPSFactoryBuffer for the specified interface.
2548 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2549 * pclsid [O] Where to store returned proxy/stub CLSID.
2554 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2558 * The standard marshaller activates the object with the CLSID
2559 * returned and uses the CreateProxy and CreateStub methods on its
2560 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2563 * CoGetPSClsid determines this CLSID by searching the
2564 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2565 * in the registry and any interface id registered by
2566 * CoRegisterPSClsid within the current process.
2570 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2571 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2572 * considered a bug in native unless an application depends on this (unlikely).
2575 * CoRegisterPSClsid.
2577 HRESULT WINAPI
CoGetPSClsid(REFIID riid
, CLSID
*pclsid
)
2579 static const WCHAR wszInterface
[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2580 static const WCHAR wszPSC
[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2581 WCHAR path
[ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1 + ARRAYSIZE(wszPSC
)];
2582 APARTMENT
*apt
= COM_CurrentApt();
2583 struct registered_psclsid
*registered_psclsid
;
2584 ACTCTX_SECTION_KEYED_DATA data
;
2586 REGSAM opposite
= (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY
: KEY_WOW64_64KEY
;
2589 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid
), pclsid
);
2593 ERR("apartment not initialised\n");
2594 return CO_E_NOTINITIALIZED
;
2598 return E_INVALIDARG
;
2600 EnterCriticalSection(&cs_registered_psclsid_list
);
2602 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2603 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2605 *pclsid
= registered_psclsid
->clsid
;
2606 LeaveCriticalSection(&cs_registered_psclsid_list
);
2610 LeaveCriticalSection(&cs_registered_psclsid_list
);
2612 data
.cbSize
= sizeof(data
);
2613 if (FindActCtxSectionGuid(0, NULL
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
,
2616 struct ifacepsredirect_data
*ifaceps
= (struct ifacepsredirect_data
*)data
.lpData
;
2617 *pclsid
= ifaceps
->iid
;
2621 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2622 strcpyW(path
, wszInterface
);
2623 StringFromGUID2(riid
, path
+ ARRAYSIZE(wszInterface
) - 1, CHARS_IN_GUID
);
2624 strcpyW(path
+ ARRAYSIZE(wszInterface
) - 1 + CHARS_IN_GUID
- 1, wszPSC
);
2626 hr
= get_ps_clsid_from_registry(path
, 0, pclsid
);
2627 if (FAILED(hr
) && (opposite
== KEY_WOW64_32KEY
||
2628 (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)))
2629 hr
= get_ps_clsid_from_registry(path
, opposite
, pclsid
);
2632 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid
));
2634 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid
));
2639 /*****************************************************************************
2640 * CoRegisterPSClsid [OLE32.@]
2642 * Register a proxy/stub CLSID for the given interface in the current process
2646 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2647 * rclsid [I] CLSID of the proxy/stub.
2651 * Failure: E_OUTOFMEMORY
2655 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2656 * will be returned from other apartments in the same process.
2658 * This function does not add anything to the registry and the effects are
2659 * limited to the lifetime of the current process.
2664 HRESULT WINAPI
CoRegisterPSClsid(REFIID riid
, REFCLSID rclsid
)
2666 APARTMENT
*apt
= COM_CurrentApt();
2667 struct registered_psclsid
*registered_psclsid
;
2669 TRACE("(%s, %s)\n", debugstr_guid(riid
), debugstr_guid(rclsid
));
2673 ERR("apartment not initialised\n");
2674 return CO_E_NOTINITIALIZED
;
2677 EnterCriticalSection(&cs_registered_psclsid_list
);
2679 LIST_FOR_EACH_ENTRY(registered_psclsid
, ®istered_psclsid_list
, struct registered_psclsid
, entry
)
2680 if (IsEqualIID(®istered_psclsid
->iid
, riid
))
2682 registered_psclsid
->clsid
= *rclsid
;
2683 LeaveCriticalSection(&cs_registered_psclsid_list
);
2687 registered_psclsid
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid
));
2688 if (!registered_psclsid
)
2690 LeaveCriticalSection(&cs_registered_psclsid_list
);
2691 return E_OUTOFMEMORY
;
2694 registered_psclsid
->iid
= *riid
;
2695 registered_psclsid
->clsid
= *rclsid
;
2696 list_add_head(®istered_psclsid_list
, ®istered_psclsid
->entry
);
2698 LeaveCriticalSection(&cs_registered_psclsid_list
);
2705 * COM_GetRegisteredClassObject
2707 * This internal method is used to scan the registered class list to
2708 * find a class object.
2711 * rclsid Class ID of the class to find.
2712 * dwClsContext Class context to match.
2713 * ppv [out] returns a pointer to the class object. Complying
2714 * to normal COM usage, this method will increase the
2715 * reference count on this object.
2717 static HRESULT
COM_GetRegisteredClassObject(const struct apartment
*apt
, REFCLSID rclsid
,
2718 DWORD dwClsContext
, LPUNKNOWN
* ppUnk
)
2720 HRESULT hr
= S_FALSE
;
2721 RegisteredClass
*curClass
;
2723 EnterCriticalSection( &csRegisteredClassList
);
2725 LIST_FOR_EACH_ENTRY(curClass
, &RegisteredClassList
, RegisteredClass
, entry
)
2728 * Check if we have a match on the class ID and context.
2730 if ((apt
->oxid
== curClass
->apartment_id
) &&
2731 (dwClsContext
& curClass
->runContext
) &&
2732 IsEqualGUID(&(curClass
->classIdentifier
), rclsid
))
2735 * We have a match, return the pointer to the class object.
2737 *ppUnk
= curClass
->classObject
;
2739 IUnknown_AddRef(curClass
->classObject
);
2746 LeaveCriticalSection( &csRegisteredClassList
);
2751 /******************************************************************************
2752 * CoRegisterClassObject [OLE32.@]
2754 * Registers the class object for a given class ID. Servers housed in EXE
2755 * files use this method instead of exporting DllGetClassObject to allow
2756 * other code to connect to their objects.
2759 * rclsid [I] CLSID of the object to register.
2760 * pUnk [I] IUnknown of the object.
2761 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2762 * flags [I] REGCLS flags indicating how connections are made.
2763 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2767 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2768 * CO_E_OBJISREG if the object is already registered. We should not return this.
2771 * CoRevokeClassObject, CoGetClassObject
2774 * In-process objects are only registered for the current apartment.
2775 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2776 * in other apartments.
2779 * MSDN claims that multiple interface registrations are legal, but we
2780 * can't do that with our current implementation.
2782 HRESULT WINAPI
CoRegisterClassObject(
2787 LPDWORD lpdwRegister
)
2789 static LONG next_cookie
;
2790 RegisteredClass
* newClass
;
2791 LPUNKNOWN foundObject
;
2795 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2796 debugstr_guid(rclsid
),pUnk
,dwClsContext
,flags
,lpdwRegister
);
2798 if ( (lpdwRegister
==0) || (pUnk
==0) )
2799 return E_INVALIDARG
;
2801 apt
= COM_CurrentApt();
2804 ERR("COM was not initialized\n");
2805 return CO_E_NOTINITIALIZED
;
2810 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2811 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2812 if (flags
& REGCLS_MULTIPLEUSE
)
2813 dwClsContext
|= CLSCTX_INPROC_SERVER
;
2816 * First, check if the class is already registered.
2817 * If it is, this should cause an error.
2819 hr
= COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
, &foundObject
);
2821 if (flags
& REGCLS_MULTIPLEUSE
) {
2822 if (dwClsContext
& CLSCTX_LOCAL_SERVER
)
2823 hr
= CoLockObjectExternal(foundObject
, TRUE
, FALSE
);
2824 IUnknown_Release(foundObject
);
2827 IUnknown_Release(foundObject
);
2828 ERR("object already registered for class %s\n", debugstr_guid(rclsid
));
2829 return CO_E_OBJISREG
;
2832 newClass
= HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass
));
2833 if ( newClass
== NULL
)
2834 return E_OUTOFMEMORY
;
2836 newClass
->classIdentifier
= *rclsid
;
2837 newClass
->apartment_id
= apt
->oxid
;
2838 newClass
->runContext
= dwClsContext
;
2839 newClass
->connectFlags
= flags
;
2840 newClass
->RpcRegistration
= NULL
;
2842 if (!(newClass
->dwCookie
= InterlockedIncrement( &next_cookie
)))
2843 newClass
->dwCookie
= InterlockedIncrement( &next_cookie
);
2846 * Since we're making a copy of the object pointer, we have to increase its
2849 newClass
->classObject
= pUnk
;
2850 IUnknown_AddRef(newClass
->classObject
);
2852 EnterCriticalSection( &csRegisteredClassList
);
2853 list_add_tail(&RegisteredClassList
, &newClass
->entry
);
2854 LeaveCriticalSection( &csRegisteredClassList
);
2856 *lpdwRegister
= newClass
->dwCookie
;
2858 if (dwClsContext
& CLSCTX_LOCAL_SERVER
) {
2859 IStream
*marshal_stream
;
2861 hr
= get_local_server_stream(apt
, &marshal_stream
);
2865 hr
= RPC_StartLocalServer(&newClass
->classIdentifier
,
2867 flags
& (REGCLS_MULTIPLEUSE
|REGCLS_MULTI_SEPARATE
),
2868 &newClass
->RpcRegistration
);
2869 IStream_Release(marshal_stream
);
2874 static enum comclass_threadingmodel
get_threading_model(const struct class_reg_data
*data
)
2878 static const WCHAR wszThreadingModel
[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2879 static const WCHAR wszApartment
[] = {'A','p','a','r','t','m','e','n','t',0};
2880 static const WCHAR wszFree
[] = {'F','r','e','e',0};
2881 static const WCHAR wszBoth
[] = {'B','o','t','h',0};
2882 WCHAR threading_model
[10 /* strlenW(L"apartment")+1 */];
2883 DWORD dwLength
= sizeof(threading_model
);
2887 ret
= RegQueryValueExW(data
->u
.hkey
, wszThreadingModel
, NULL
, &keytype
, (BYTE
*)threading_model
, &dwLength
);
2888 if ((ret
!= ERROR_SUCCESS
) || (keytype
!= REG_SZ
))
2889 threading_model
[0] = '\0';
2891 if (!strcmpiW(threading_model
, wszApartment
)) return ThreadingModel_Apartment
;
2892 if (!strcmpiW(threading_model
, wszFree
)) return ThreadingModel_Free
;
2893 if (!strcmpiW(threading_model
, wszBoth
)) return ThreadingModel_Both
;
2895 /* there's not specific handling for this case */
2896 if (threading_model
[0]) return ThreadingModel_Neutral
;
2897 return ThreadingModel_No
;
2900 return data
->u
.actctx
.data
->model
;
2903 static HRESULT
get_inproc_class_object(APARTMENT
*apt
, const struct class_reg_data
*regdata
,
2904 REFCLSID rclsid
, REFIID riid
,
2905 BOOL hostifnecessary
, void **ppv
)
2907 WCHAR dllpath
[MAX_PATH
+1];
2908 BOOL apartment_threaded
;
2910 if (hostifnecessary
)
2912 enum comclass_threadingmodel model
= get_threading_model(regdata
);
2914 if (model
== ThreadingModel_Apartment
)
2916 apartment_threaded
= TRUE
;
2917 if (apt
->multi_threaded
)
2918 return apartment_hostobject_in_hostapt(apt
, FALSE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2920 else if (model
== ThreadingModel_Free
)
2922 apartment_threaded
= FALSE
;
2923 if (!apt
->multi_threaded
)
2924 return apartment_hostobject_in_hostapt(apt
, TRUE
, FALSE
, regdata
, rclsid
, riid
, ppv
);
2926 /* everything except "Apartment", "Free" and "Both" */
2927 else if (model
!= ThreadingModel_Both
)
2929 apartment_threaded
= TRUE
;
2930 /* everything else is main-threaded */
2931 if (model
!= ThreadingModel_No
)
2932 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model
, debugstr_guid(rclsid
));
2934 if (apt
->multi_threaded
|| !apt
->main
)
2935 return apartment_hostobject_in_hostapt(apt
, FALSE
, TRUE
, regdata
, rclsid
, riid
, ppv
);
2938 apartment_threaded
= FALSE
;
2941 apartment_threaded
= !apt
->multi_threaded
;
2943 if (COM_RegReadPath(regdata
, dllpath
, ARRAYSIZE(dllpath
)) != ERROR_SUCCESS
)
2945 /* failure: CLSID is not found in registry */
2946 WARN("class %s not registered inproc\n", debugstr_guid(rclsid
));
2947 return REGDB_E_CLASSNOTREG
;
2950 return apartment_getclassobject(apt
, dllpath
, apartment_threaded
,
2954 /***********************************************************************
2955 * CoGetClassObject [OLE32.@]
2957 * Creates an object of the specified class.
2960 * rclsid [I] Class ID to create an instance of.
2961 * dwClsContext [I] Flags to restrict the location of the created instance.
2962 * pServerInfo [I] Optional. Details for connecting to a remote server.
2963 * iid [I] The ID of the interface of the instance to return.
2964 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2968 * Failure: HRESULT code.
2971 * The dwClsContext parameter can be one or more of the following:
2972 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2973 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2974 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2975 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2978 * CoCreateInstance()
2980 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetClassObject(
2981 REFCLSID rclsid
, DWORD dwClsContext
, COSERVERINFO
*pServerInfo
,
2982 REFIID iid
, LPVOID
*ppv
)
2984 struct class_reg_data clsreg
;
2985 IUnknown
*regClassObject
;
2986 HRESULT hres
= E_UNEXPECTED
;
2988 BOOL release_apt
= FALSE
;
2990 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid
), debugstr_guid(iid
));
2993 return E_INVALIDARG
;
2997 if (!(apt
= COM_CurrentApt()))
2999 if (!(apt
= apartment_find_multi_threaded()))
3001 ERR("apartment not initialised\n");
3002 return CO_E_NOTINITIALIZED
;
3008 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3009 debugstr_w(pServerInfo
->pwszName
), pServerInfo
->pAuthInfo
);
3012 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3014 if (IsEqualCLSID(rclsid
, &CLSID_InProcFreeMarshaler
))
3016 if (release_apt
) apartment_release(apt
);
3017 return FTMarshalCF_Create(iid
, ppv
);
3019 if (IsEqualCLSID(rclsid
, &CLSID_GlobalOptions
))
3020 return IClassFactory_QueryInterface(&GlobalOptionsCF
, iid
, ppv
);
3023 if (CLSCTX_INPROC
& dwClsContext
)
3025 ACTCTX_SECTION_KEYED_DATA data
;
3027 data
.cbSize
= sizeof(data
);
3028 /* search activation context first */
3029 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
, NULL
,
3030 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
,
3033 struct comclassredirect_data
*comclass
= (struct comclassredirect_data
*)data
.lpData
;
3035 clsreg
.u
.actctx
.hactctx
= data
.hActCtx
;
3036 clsreg
.u
.actctx
.data
= data
.lpData
;
3037 clsreg
.u
.actctx
.section
= data
.lpSectionBase
;
3038 clsreg
.hkey
= FALSE
;
3040 hres
= get_inproc_class_object(apt
, &clsreg
, &comclass
->clsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3041 ReleaseActCtx(data
.hActCtx
);
3042 if (release_apt
) apartment_release(apt
);
3048 * First, try and see if we can't match the class ID with one of the
3049 * registered classes.
3051 if (S_OK
== COM_GetRegisteredClassObject(apt
, rclsid
, dwClsContext
,
3054 /* Get the required interface from the retrieved pointer. */
3055 hres
= IUnknown_QueryInterface(regClassObject
, iid
, ppv
);
3058 * Since QI got another reference on the pointer, we want to release the
3059 * one we already have. If QI was unsuccessful, this will release the object. This
3060 * is good since we are not returning it in the "out" parameter.
3062 IUnknown_Release(regClassObject
);
3063 if (release_apt
) apartment_release(apt
);
3067 /* First try in-process server */
3068 if (CLSCTX_INPROC_SERVER
& dwClsContext
)
3070 static const WCHAR wszInprocServer32
[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3073 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocServer32
, KEY_READ
, &hkey
);
3076 if (hres
== REGDB_E_CLASSNOTREG
)
3077 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3078 else if (hres
== REGDB_E_KEYMISSING
)
3080 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid
));
3081 hres
= REGDB_E_CLASSNOTREG
;
3085 if (SUCCEEDED(hres
))
3087 clsreg
.u
.hkey
= hkey
;
3090 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3094 /* return if we got a class, otherwise fall through to one of the
3096 if (SUCCEEDED(hres
))
3098 if (release_apt
) apartment_release(apt
);
3103 /* Next try in-process handler */
3104 if (CLSCTX_INPROC_HANDLER
& dwClsContext
)
3106 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3109 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
3112 if (hres
== REGDB_E_CLASSNOTREG
)
3113 ERR("class %s not registered\n", debugstr_guid(rclsid
));
3114 else if (hres
== REGDB_E_KEYMISSING
)
3116 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid
));
3117 hres
= REGDB_E_CLASSNOTREG
;
3121 if (SUCCEEDED(hres
))
3123 clsreg
.u
.hkey
= hkey
;
3126 hres
= get_inproc_class_object(apt
, &clsreg
, rclsid
, iid
, !(dwClsContext
& WINE_CLSCTX_DONT_HOST
), ppv
);
3130 /* return if we got a class, otherwise fall through to one of the
3132 if (SUCCEEDED(hres
))
3134 if (release_apt
) apartment_release(apt
);
3138 if (release_apt
) apartment_release(apt
);
3140 /* Next try out of process */
3141 if (CLSCTX_LOCAL_SERVER
& dwClsContext
)
3143 hres
= RPC_GetLocalClassObject(rclsid
,iid
,ppv
);
3144 if (SUCCEEDED(hres
))
3148 /* Finally try remote: this requires networked DCOM (a lot of work) */
3149 if (CLSCTX_REMOTE_SERVER
& dwClsContext
)
3151 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3152 hres
= REGDB_E_CLASSNOTREG
;
3156 ERR("no class object %s could be created for context 0x%x\n",
3157 debugstr_guid(rclsid
), dwClsContext
);
3161 /***********************************************************************
3162 * CoResumeClassObjects (OLE32.@)
3164 * Resumes all class objects registered with REGCLS_SUSPENDED.
3168 * Failure: HRESULT code.
3170 HRESULT WINAPI
CoResumeClassObjects(void)
3176 /***********************************************************************
3177 * CoCreateInstance [OLE32.@]
3179 * Creates an instance of the specified class.
3182 * rclsid [I] Class ID to create an instance of.
3183 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3184 * dwClsContext [I] Flags to restrict the location of the created instance.
3185 * iid [I] The ID of the interface of the instance to return.
3186 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3190 * Failure: HRESULT code.
3193 * The dwClsContext parameter can be one or more of the following:
3194 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3195 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3196 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3197 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3199 * Aggregation is the concept of deferring the IUnknown of an object to another
3200 * object. This allows a separate object to behave as though it was part of
3201 * the object and to allow this the pUnkOuter parameter can be set. Note that
3202 * not all objects support having an outer of unknown.
3205 * CoGetClassObject()
3207 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstance(
3209 LPUNKNOWN pUnkOuter
,
3214 MULTI_QI multi_qi
= { iid
};
3217 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid
),
3218 pUnkOuter
, dwClsContext
, debugstr_guid(iid
), ppv
);
3223 hres
= CoCreateInstanceEx(rclsid
, pUnkOuter
, dwClsContext
, NULL
, 1, &multi_qi
);
3224 *ppv
= multi_qi
.pItf
;
3228 static void init_multi_qi(DWORD count
, MULTI_QI
*mqi
, HRESULT hr
)
3232 for (i
= 0; i
< count
; i
++)
3239 static HRESULT
return_multi_qi(IUnknown
*unk
, DWORD count
, MULTI_QI
*mqi
, BOOL include_unk
)
3241 ULONG index
= 0, fetched
= 0;
3247 index
= fetched
= 1;
3250 for (; index
< count
; index
++)
3252 mqi
[index
].hr
= IUnknown_QueryInterface(unk
, mqi
[index
].pIID
, (void**)&mqi
[index
].pItf
);
3253 if (mqi
[index
].hr
== S_OK
)
3258 IUnknown_Release(unk
);
3261 return E_NOINTERFACE
;
3263 return fetched
== count
? S_OK
: CO_S_NOTALLINTERFACES
;
3266 /***********************************************************************
3267 * CoCreateInstanceEx [OLE32.@]
3269 HRESULT WINAPI DECLSPEC_HOTPATCH
CoCreateInstanceEx(
3271 LPUNKNOWN pUnkOuter
,
3273 COSERVERINFO
* pServerInfo
,
3277 IUnknown
*unk
= NULL
;
3283 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid
), pUnkOuter
, dwClsContext
, pServerInfo
, cmq
, pResults
);
3285 if (!cmq
|| !pResults
)
3286 return E_INVALIDARG
;
3289 FIXME("() non-NULL pServerInfo not supported!\n");
3291 init_multi_qi(cmq
, pResults
, E_NOINTERFACE
);
3293 hres
= CoGetTreatAsClass(rclsid
, &clsid
);
3297 if (!(apt
= COM_CurrentApt()))
3299 if (!(apt
= apartment_find_multi_threaded()))
3301 ERR("apartment not initialised\n");
3302 return CO_E_NOTINITIALIZED
;
3304 apartment_release(apt
);
3308 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3310 if (IsEqualIID(&clsid
, &CLSID_StdGlobalInterfaceTable
))
3312 IGlobalInterfaceTable
*git
= get_std_git();
3313 TRACE("Retrieving GIT\n");
3314 return return_multi_qi((IUnknown
*)git
, cmq
, pResults
, FALSE
);
3317 if (IsEqualCLSID(&clsid
, &CLSID_ManualResetEvent
)) {
3318 hres
= ManualResetEvent_Construct(pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3321 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3325 * Get a class factory to construct the object we want.
3327 hres
= CoGetClassObject(&clsid
, dwClsContext
, NULL
, &IID_IClassFactory
, (void**)&cf
);
3332 * Create the object and don't forget to release the factory
3334 hres
= IClassFactory_CreateInstance(cf
, pUnkOuter
, pResults
[0].pIID
, (void**)&unk
);
3335 IClassFactory_Release(cf
);
3338 if (hres
== CLASS_E_NOAGGREGATION
&& pUnkOuter
)
3339 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid
));
3341 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3342 debugstr_guid(pResults
[0].pIID
),
3343 debugstr_guid(&clsid
),hres
);
3347 return return_multi_qi(unk
, cmq
, pResults
, TRUE
);
3350 /***********************************************************************
3351 * CoGetInstanceFromFile [OLE32.@]
3353 HRESULT WINAPI DECLSPEC_HOTPATCH
CoGetInstanceFromFile(
3354 COSERVERINFO
*server_info
,
3364 IPersistFile
*pf
= NULL
;
3365 IUnknown
* unk
= NULL
;
3369 if (count
== 0 || !results
)
3370 return E_INVALIDARG
;
3373 FIXME("() non-NULL server_info not supported\n");
3375 init_multi_qi(count
, results
, E_NOINTERFACE
);
3377 /* optionally get CLSID from a file */
3380 hr
= GetClassFile(filename
, &clsid
);
3383 ERR("failed to get CLSID from a file\n");
3390 hr
= CoCreateInstance(rclsid
,
3398 init_multi_qi(count
, results
, hr
);
3402 /* init from file */
3403 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistFile
, (void**)&pf
);
3406 init_multi_qi(count
, results
, hr
);
3407 IUnknown_Release(unk
);
3411 hr
= IPersistFile_Load(pf
, filename
, grfmode
);
3412 IPersistFile_Release(pf
);
3414 return return_multi_qi(unk
, count
, results
, FALSE
);
3417 init_multi_qi(count
, results
, hr
);
3418 IUnknown_Release(unk
);
3423 /***********************************************************************
3424 * CoGetInstanceFromIStorage [OLE32.@]
3426 HRESULT WINAPI
CoGetInstanceFromIStorage(
3427 COSERVERINFO
*server_info
,
3436 IPersistStorage
*ps
= NULL
;
3437 IUnknown
* unk
= NULL
;
3441 if (count
== 0 || !results
|| !storage
)
3442 return E_INVALIDARG
;
3445 FIXME("() non-NULL server_info not supported\n");
3447 init_multi_qi(count
, results
, E_NOINTERFACE
);
3449 /* optionally get CLSID from a file */
3452 memset(&stat
.clsid
, 0, sizeof(stat
.clsid
));
3453 hr
= IStorage_Stat(storage
, &stat
, STATFLAG_NONAME
);
3456 ERR("failed to get CLSID from a file\n");
3460 rclsid
= &stat
.clsid
;
3463 hr
= CoCreateInstance(rclsid
,
3472 /* init from IStorage */
3473 hr
= IUnknown_QueryInterface(unk
, &IID_IPersistStorage
, (void**)&ps
);
3475 ERR("failed to get IPersistStorage\n");
3479 IPersistStorage_Load(ps
, storage
);
3480 IPersistStorage_Release(ps
);
3483 return return_multi_qi(unk
, count
, results
, FALSE
);
3486 /***********************************************************************
3487 * CoLoadLibrary (OLE32.@)
3492 * lpszLibName [I] Path to library.
3493 * bAutoFree [I] Whether the library should automatically be freed.
3496 * Success: Handle to loaded library.
3500 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3502 HINSTANCE WINAPI
CoLoadLibrary(LPOLESTR lpszLibName
, BOOL bAutoFree
)
3504 TRACE("(%s, %d)\n", debugstr_w(lpszLibName
), bAutoFree
);
3506 return LoadLibraryExW(lpszLibName
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
);
3509 /***********************************************************************
3510 * CoFreeLibrary [OLE32.@]
3512 * Unloads a library from memory.
3515 * hLibrary [I] Handle to library to unload.
3521 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3523 void WINAPI
CoFreeLibrary(HINSTANCE hLibrary
)
3525 FreeLibrary(hLibrary
);
3529 /***********************************************************************
3530 * CoFreeAllLibraries [OLE32.@]
3532 * Function for backwards compatibility only. Does nothing.
3538 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3540 void WINAPI
CoFreeAllLibraries(void)
3545 /***********************************************************************
3546 * CoFreeUnusedLibrariesEx [OLE32.@]
3548 * Frees any previously unused libraries whose delay has expired and marks
3549 * currently unused libraries for unloading. Unused are identified as those that
3550 * return S_OK from their DllCanUnloadNow function.
3553 * dwUnloadDelay [I] Unload delay in milliseconds.
3554 * dwReserved [I] Reserved. Set to 0.
3560 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3562 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay
, DWORD dwReserved
)
3564 struct apartment
*apt
= COM_CurrentApt();
3567 ERR("apartment not initialised\n");
3571 apartment_freeunusedlibraries(apt
, dwUnloadDelay
);
3574 /***********************************************************************
3575 * CoFreeUnusedLibraries [OLE32.@]
3577 * Frees any unused libraries. Unused are identified as those that return
3578 * S_OK from their DllCanUnloadNow function.
3584 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3586 void WINAPI DECLSPEC_HOTPATCH
CoFreeUnusedLibraries(void)
3588 CoFreeUnusedLibrariesEx(INFINITE
, 0);
3591 /***********************************************************************
3592 * CoFileTimeNow [OLE32.@]
3594 * Retrieves the current time in FILETIME format.
3597 * lpFileTime [O] The current time.
3602 HRESULT WINAPI
CoFileTimeNow( FILETIME
*lpFileTime
)
3604 GetSystemTimeAsFileTime( lpFileTime
);
3608 /******************************************************************************
3609 * CoLockObjectExternal [OLE32.@]
3611 * Increments or decrements the external reference count of a stub object.
3614 * pUnk [I] Stub object.
3615 * fLock [I] If TRUE then increments the external ref-count,
3616 * otherwise decrements.
3617 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3618 * calling CoDisconnectObject.
3622 * Failure: HRESULT code.
3625 * If fLock is TRUE and an object is passed in that doesn't have a stub
3626 * manager then a new stub manager is created for the object.
3628 HRESULT WINAPI
CoLockObjectExternal(
3631 BOOL fLastUnlockReleases
)
3633 struct stub_manager
*stubmgr
;
3634 struct apartment
*apt
;
3636 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3637 pUnk
, fLock
? "TRUE" : "FALSE", fLastUnlockReleases
? "TRUE" : "FALSE");
3639 apt
= COM_CurrentApt();
3640 if (!apt
) return CO_E_NOTINITIALIZED
;
3642 stubmgr
= get_stub_manager_from_object(apt
, pUnk
, fLock
);
3645 WARN("stub object not found %p\n", pUnk
);
3646 /* Note: native is pretty broken here because it just silently
3647 * fails, without returning an appropriate error code, making apps
3648 * think that the object was disconnected, when it actually wasn't */
3653 stub_manager_ext_addref(stubmgr
, 1, FALSE
);
3655 stub_manager_ext_release(stubmgr
, 1, FALSE
, fLastUnlockReleases
);
3657 stub_manager_int_release(stubmgr
);
3661 /***********************************************************************
3662 * CoInitializeWOW (OLE32.@)
3664 * WOW equivalent of CoInitialize?
3673 HRESULT WINAPI
CoInitializeWOW(DWORD x
,DWORD y
)
3675 FIXME("(0x%08x,0x%08x),stub!\n",x
,y
);
3679 /***********************************************************************
3680 * CoGetState [OLE32.@]
3682 * Retrieves the thread state object previously stored by CoSetState().
3685 * ppv [I] Address where pointer to object will be stored.
3689 * Failure: E_OUTOFMEMORY.
3692 * Crashes on all invalid ppv addresses, including NULL.
3693 * If the function returns a non-NULL object then the caller must release its
3694 * reference on the object when the object is no longer required.
3699 HRESULT WINAPI
CoGetState(IUnknown
** ppv
)
3701 struct oletls
*info
= COM_CurrentInfo();
3702 if (!info
) return E_OUTOFMEMORY
;
3708 IUnknown_AddRef(info
->state
);
3710 TRACE("apt->state=%p\n", info
->state
);
3716 /***********************************************************************
3717 * CoSetState [OLE32.@]
3719 * Sets the thread state object.
3722 * pv [I] Pointer to state object to be stored.
3725 * The system keeps a reference on the object while the object stored.
3729 * Failure: E_OUTOFMEMORY.
3731 HRESULT WINAPI
CoSetState(IUnknown
* pv
)
3733 struct oletls
*info
= COM_CurrentInfo();
3734 if (!info
) return E_OUTOFMEMORY
;
3736 if (pv
) IUnknown_AddRef(pv
);
3740 TRACE("-- release %p now\n", info
->state
);
3741 IUnknown_Release(info
->state
);
3750 /******************************************************************************
3751 * CoTreatAsClass [OLE32.@]
3753 * Sets the TreatAs value of a class.
3756 * clsidOld [I] Class to set TreatAs value on.
3757 * clsidNew [I] The class the clsidOld should be treated as.
3761 * Failure: HRESULT code.
3766 HRESULT WINAPI
CoTreatAsClass(REFCLSID clsidOld
, REFCLSID clsidNew
)
3768 static const WCHAR wszAutoTreatAs
[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3769 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3771 WCHAR szClsidNew
[CHARS_IN_GUID
];
3773 WCHAR auto_treat_as
[CHARS_IN_GUID
];
3774 LONG auto_treat_as_size
= sizeof(auto_treat_as
);
3777 res
= COM_OpenKeyForCLSID(clsidOld
, NULL
, KEY_READ
| KEY_WRITE
, &hkey
);
3781 if (IsEqualGUID( clsidOld
, clsidNew
))
3783 if (!RegQueryValueW(hkey
, wszAutoTreatAs
, auto_treat_as
, &auto_treat_as_size
) &&
3784 CLSIDFromString(auto_treat_as
, &id
) == S_OK
)
3786 if (RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, auto_treat_as
, sizeof(auto_treat_as
)))
3788 res
= REGDB_E_WRITEREGDB
;
3794 if(RegDeleteKeyW(hkey
, wszTreatAs
))
3795 res
= REGDB_E_WRITEREGDB
;
3801 if(IsEqualGUID(clsidNew
, &CLSID_NULL
)){
3802 RegDeleteKeyW(hkey
, wszTreatAs
);
3804 if(!StringFromGUID2(clsidNew
, szClsidNew
, ARRAYSIZE(szClsidNew
))){
3805 WARN("StringFromGUID2 failed\n");
3810 if(RegSetValueW(hkey
, wszTreatAs
, REG_SZ
, szClsidNew
, sizeof(szClsidNew
)) != ERROR_SUCCESS
){
3811 WARN("RegSetValue failed\n");
3812 res
= REGDB_E_WRITEREGDB
;
3819 if (hkey
) RegCloseKey(hkey
);
3823 /******************************************************************************
3824 * CoGetTreatAsClass [OLE32.@]
3826 * Gets the TreatAs value of a class.
3829 * clsidOld [I] Class to get the TreatAs value of.
3830 * clsidNew [I] The class the clsidOld should be treated as.
3834 * Failure: HRESULT code.
3839 HRESULT WINAPI
CoGetTreatAsClass(REFCLSID clsidOld
, LPCLSID clsidNew
)
3841 static const WCHAR wszTreatAs
[] = {'T','r','e','a','t','A','s',0};
3843 WCHAR szClsidNew
[CHARS_IN_GUID
];
3845 LONG len
= sizeof(szClsidNew
);
3847 TRACE("(%s,%p)\n", debugstr_guid(clsidOld
), clsidNew
);
3849 if (!clsidOld
|| !clsidNew
)
3850 return E_INVALIDARG
;
3852 *clsidNew
= *clsidOld
; /* copy over old value */
3854 res
= COM_OpenKeyForCLSID(clsidOld
, wszTreatAs
, KEY_READ
, &hkey
);
3860 if (RegQueryValueW(hkey
, NULL
, szClsidNew
, &len
))
3865 res
= CLSIDFromString(szClsidNew
,clsidNew
);
3867 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew
), res
);
3869 if (hkey
) RegCloseKey(hkey
);
3873 /******************************************************************************
3874 * CoGetCurrentProcess [OLE32.@]
3876 * Gets the current process ID.
3879 * The current process ID.
3882 * Is DWORD really the correct return type for this function?
3884 DWORD WINAPI
CoGetCurrentProcess(void)
3886 return GetCurrentProcessId();
3889 /***********************************************************************
3890 * CoGetCurrentLogicalThreadId [OLE32.@]
3892 HRESULT WINAPI
CoGetCurrentLogicalThreadId(GUID
*id
)
3894 TRACE("(%p)\n", id
);
3897 return E_INVALIDARG
;
3899 *id
= COM_CurrentCausalityId();
3903 /******************************************************************************
3904 * CoRegisterMessageFilter [OLE32.@]
3906 * Registers a message filter.
3909 * lpMessageFilter [I] Pointer to interface.
3910 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3914 * Failure: HRESULT code.
3917 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3918 * lpMessageFilter removes the message filter.
3920 * If lplpMessageFilter is not NULL the previous message filter will be
3921 * returned in the memory pointer to this parameter and the caller is
3922 * responsible for releasing the object.
3924 * The current thread be in an apartment otherwise the function will crash.
3926 HRESULT WINAPI
CoRegisterMessageFilter(
3927 LPMESSAGEFILTER lpMessageFilter
,
3928 LPMESSAGEFILTER
*lplpMessageFilter
)
3930 struct apartment
*apt
;
3931 IMessageFilter
*lpOldMessageFilter
;
3933 TRACE("(%p, %p)\n", lpMessageFilter
, lplpMessageFilter
);
3935 apt
= COM_CurrentApt();
3937 /* can't set a message filter in a multi-threaded apartment */
3938 if (!apt
|| apt
->multi_threaded
)
3940 WARN("can't set message filter in MTA or uninitialized apt\n");
3941 return CO_E_NOT_SUPPORTED
;
3944 if (lpMessageFilter
)
3945 IMessageFilter_AddRef(lpMessageFilter
);
3947 EnterCriticalSection(&apt
->cs
);
3949 lpOldMessageFilter
= apt
->filter
;
3950 apt
->filter
= lpMessageFilter
;
3952 LeaveCriticalSection(&apt
->cs
);
3954 if (lplpMessageFilter
)
3955 *lplpMessageFilter
= lpOldMessageFilter
;
3956 else if (lpOldMessageFilter
)
3957 IMessageFilter_Release(lpOldMessageFilter
);
3962 /***********************************************************************
3963 * CoIsOle1Class [OLE32.@]
3965 * Determines whether the specified class an OLE v1 class.
3968 * clsid [I] Class to test.
3971 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3973 BOOL WINAPI
CoIsOle1Class(REFCLSID clsid
)
3975 FIXME("%s\n", debugstr_guid(clsid
));
3979 /***********************************************************************
3980 * IsEqualGUID [OLE32.@]
3982 * Compares two Unique Identifiers.
3985 * rguid1 [I] The first GUID to compare.
3986 * rguid2 [I] The other GUID to compare.
3992 BOOL WINAPI
IsEqualGUID(
3996 return !memcmp(rguid1
,rguid2
,sizeof(GUID
));
3999 /***********************************************************************
4000 * CoInitializeSecurity [OLE32.@]
4002 HRESULT WINAPI
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc
, LONG cAuthSvc
,
4003 SOLE_AUTHENTICATION_SERVICE
* asAuthSvc
,
4004 void* pReserved1
, DWORD dwAuthnLevel
,
4005 DWORD dwImpLevel
, void* pReserved2
,
4006 DWORD dwCapabilities
, void* pReserved3
)
4008 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc
, cAuthSvc
,
4009 asAuthSvc
, pReserved1
, dwAuthnLevel
, dwImpLevel
, pReserved2
,
4010 dwCapabilities
, pReserved3
);
4014 /***********************************************************************
4015 * CoSuspendClassObjects [OLE32.@]
4017 * Suspends all registered class objects to prevent further requests coming in
4018 * for those objects.
4022 * Failure: HRESULT code.
4024 HRESULT WINAPI
CoSuspendClassObjects(void)
4030 /***********************************************************************
4031 * CoAddRefServerProcess [OLE32.@]
4033 * Helper function for incrementing the reference count of a local-server
4037 * New reference count.
4040 * CoReleaseServerProcess().
4042 ULONG WINAPI
CoAddRefServerProcess(void)
4048 EnterCriticalSection(&csRegisteredClassList
);
4049 refs
= ++s_COMServerProcessReferences
;
4050 LeaveCriticalSection(&csRegisteredClassList
);
4052 TRACE("refs before: %d\n", refs
- 1);
4057 /***********************************************************************
4058 * CoReleaseServerProcess [OLE32.@]
4060 * Helper function for decrementing the reference count of a local-server
4064 * New reference count.
4067 * When reference count reaches 0, this function suspends all registered
4068 * classes so no new connections are accepted.
4071 * CoAddRefServerProcess(), CoSuspendClassObjects().
4073 ULONG WINAPI
CoReleaseServerProcess(void)
4079 EnterCriticalSection(&csRegisteredClassList
);
4081 refs
= --s_COMServerProcessReferences
;
4082 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4084 LeaveCriticalSection(&csRegisteredClassList
);
4086 TRACE("refs after: %d\n", refs
);
4091 /***********************************************************************
4092 * CoIsHandlerConnected [OLE32.@]
4094 * Determines whether a proxy is connected to a remote stub.
4097 * pUnk [I] Pointer to object that may or may not be connected.
4100 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4103 BOOL WINAPI
CoIsHandlerConnected(IUnknown
*pUnk
)
4105 FIXME("%p\n", pUnk
);
4110 /***********************************************************************
4111 * CoAllowSetForegroundWindow [OLE32.@]
4114 HRESULT WINAPI
CoAllowSetForegroundWindow(IUnknown
*pUnk
, void *pvReserved
)
4116 FIXME("(%p, %p): stub\n", pUnk
, pvReserved
);
4120 /***********************************************************************
4121 * CoQueryProxyBlanket [OLE32.@]
4123 * Retrieves the security settings being used by a proxy.
4126 * pProxy [I] Pointer to the proxy object.
4127 * pAuthnSvc [O] The type of authentication service.
4128 * pAuthzSvc [O] The type of authorization service.
4129 * ppServerPrincName [O] Optional. The server prinicple name.
4130 * pAuthnLevel [O] The authentication level.
4131 * pImpLevel [O] The impersonation level.
4132 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4133 * pCapabilities [O] Flags affecting the security behaviour.
4137 * Failure: HRESULT code.
4140 * CoCopyProxy, CoSetProxyBlanket.
4142 HRESULT WINAPI
CoQueryProxyBlanket(IUnknown
*pProxy
, DWORD
*pAuthnSvc
,
4143 DWORD
*pAuthzSvc
, OLECHAR
**ppServerPrincName
, DWORD
*pAuthnLevel
,
4144 DWORD
*pImpLevel
, void **ppAuthInfo
, DWORD
*pCapabilities
)
4146 IClientSecurity
*pCliSec
;
4149 TRACE("%p\n", pProxy
);
4151 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4154 hr
= IClientSecurity_QueryBlanket(pCliSec
, pProxy
, pAuthnSvc
,
4155 pAuthzSvc
, ppServerPrincName
,
4156 pAuthnLevel
, pImpLevel
, ppAuthInfo
,
4158 IClientSecurity_Release(pCliSec
);
4161 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4165 /***********************************************************************
4166 * CoSetProxyBlanket [OLE32.@]
4168 * Sets the security settings for a proxy.
4171 * pProxy [I] Pointer to the proxy object.
4172 * AuthnSvc [I] The type of authentication service.
4173 * AuthzSvc [I] The type of authorization service.
4174 * pServerPrincName [I] The server prinicple name.
4175 * AuthnLevel [I] The authentication level.
4176 * ImpLevel [I] The impersonation level.
4177 * pAuthInfo [I] Information specific to the authorization/authentication service.
4178 * Capabilities [I] Flags affecting the security behaviour.
4182 * Failure: HRESULT code.
4185 * CoQueryProxyBlanket, CoCopyProxy.
4187 HRESULT WINAPI
CoSetProxyBlanket(IUnknown
*pProxy
, DWORD AuthnSvc
,
4188 DWORD AuthzSvc
, OLECHAR
*pServerPrincName
, DWORD AuthnLevel
,
4189 DWORD ImpLevel
, void *pAuthInfo
, DWORD Capabilities
)
4191 IClientSecurity
*pCliSec
;
4194 TRACE("%p\n", pProxy
);
4196 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4199 hr
= IClientSecurity_SetBlanket(pCliSec
, pProxy
, AuthnSvc
,
4200 AuthzSvc
, pServerPrincName
,
4201 AuthnLevel
, ImpLevel
, pAuthInfo
,
4203 IClientSecurity_Release(pCliSec
);
4206 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4210 /***********************************************************************
4211 * CoCopyProxy [OLE32.@]
4216 * pProxy [I] Pointer to the proxy object.
4217 * ppCopy [O] Copy of the proxy.
4221 * Failure: HRESULT code.
4224 * CoQueryProxyBlanket, CoSetProxyBlanket.
4226 HRESULT WINAPI
CoCopyProxy(IUnknown
*pProxy
, IUnknown
**ppCopy
)
4228 IClientSecurity
*pCliSec
;
4231 TRACE("%p\n", pProxy
);
4233 hr
= IUnknown_QueryInterface(pProxy
, &IID_IClientSecurity
, (void **)&pCliSec
);
4236 hr
= IClientSecurity_CopyProxy(pCliSec
, pProxy
, ppCopy
);
4237 IClientSecurity_Release(pCliSec
);
4240 if (FAILED(hr
)) ERR("-- failed with 0x%08x\n", hr
);
4245 /***********************************************************************
4246 * CoGetCallContext [OLE32.@]
4248 * Gets the context of the currently executing server call in the current
4252 * riid [I] Context interface to return.
4253 * ppv [O] Pointer to memory that will receive the context on return.
4257 * Failure: HRESULT code.
4259 HRESULT WINAPI
CoGetCallContext(REFIID riid
, void **ppv
)
4261 struct oletls
*info
= COM_CurrentInfo();
4263 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4266 return E_OUTOFMEMORY
;
4268 if (!info
->call_state
)
4269 return RPC_E_CALL_COMPLETE
;
4271 return IUnknown_QueryInterface(info
->call_state
, riid
, ppv
);
4274 /***********************************************************************
4275 * CoSwitchCallContext [OLE32.@]
4277 * Switches the context of the currently executing server call in the current
4281 * pObject [I] Pointer to new context object
4282 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4286 * Failure: HRESULT code.
4288 HRESULT WINAPI
CoSwitchCallContext(IUnknown
*pObject
, IUnknown
**ppOldObject
)
4290 struct oletls
*info
= COM_CurrentInfo();
4292 TRACE("(%p, %p)\n", pObject
, ppOldObject
);
4295 return E_OUTOFMEMORY
;
4297 *ppOldObject
= info
->call_state
;
4298 info
->call_state
= pObject
; /* CoSwitchCallContext does not addref nor release objects */
4303 /***********************************************************************
4304 * CoQueryClientBlanket [OLE32.@]
4306 * Retrieves the authentication information about the client of the currently
4307 * executing server call in the current thread.
4310 * pAuthnSvc [O] Optional. The type of authentication service.
4311 * pAuthzSvc [O] Optional. The type of authorization service.
4312 * pServerPrincName [O] Optional. The server prinicple name.
4313 * pAuthnLevel [O] Optional. The authentication level.
4314 * pImpLevel [O] Optional. The impersonation level.
4315 * pPrivs [O] Optional. Information about the privileges of the client.
4316 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4320 * Failure: HRESULT code.
4323 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4325 HRESULT WINAPI
CoQueryClientBlanket(
4328 OLECHAR
**pServerPrincName
,
4331 RPC_AUTHZ_HANDLE
*pPrivs
,
4332 DWORD
*pCapabilities
)
4334 IServerSecurity
*pSrvSec
;
4337 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4338 pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
, pImpLevel
,
4339 pPrivs
, pCapabilities
);
4341 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4344 hr
= IServerSecurity_QueryBlanket(
4345 pSrvSec
, pAuthnSvc
, pAuthzSvc
, pServerPrincName
, pAuthnLevel
,
4346 pImpLevel
, pPrivs
, pCapabilities
);
4347 IServerSecurity_Release(pSrvSec
);
4353 /***********************************************************************
4354 * CoImpersonateClient [OLE32.@]
4356 * Impersonates the client of the currently executing server call in the
4364 * Failure: HRESULT code.
4367 * If this function fails then the current thread will not be impersonating
4368 * the client and all actions will take place on behalf of the server.
4369 * Therefore, it is important to check the return value from this function.
4372 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4374 HRESULT WINAPI
CoImpersonateClient(void)
4376 IServerSecurity
*pSrvSec
;
4381 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4384 hr
= IServerSecurity_ImpersonateClient(pSrvSec
);
4385 IServerSecurity_Release(pSrvSec
);
4391 /***********************************************************************
4392 * CoRevertToSelf [OLE32.@]
4394 * Ends the impersonation of the client of the currently executing server
4395 * call in the current thread.
4402 * Failure: HRESULT code.
4405 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4407 HRESULT WINAPI
CoRevertToSelf(void)
4409 IServerSecurity
*pSrvSec
;
4414 hr
= CoGetCallContext(&IID_IServerSecurity
, (void **)&pSrvSec
);
4417 hr
= IServerSecurity_RevertToSelf(pSrvSec
);
4418 IServerSecurity_Release(pSrvSec
);
4424 static BOOL
COM_PeekMessage(struct apartment
*apt
, MSG
*msg
)
4426 /* first try to retrieve messages for incoming COM calls to the apartment window */
4427 return (apt
->win
&& PeekMessageW(msg
, apt
->win
, 0, 0, PM_REMOVE
|PM_NOYIELD
)) ||
4428 /* next retrieve other messages necessary for the app to remain responsive */
4429 PeekMessageW(msg
, NULL
, WM_DDE_FIRST
, WM_DDE_LAST
, PM_REMOVE
|PM_NOYIELD
) ||
4430 PeekMessageW(msg
, NULL
, 0, 0, PM_QS_PAINT
|PM_QS_SENDMESSAGE
|PM_REMOVE
|PM_NOYIELD
);
4433 /***********************************************************************
4434 * CoWaitForMultipleHandles [OLE32.@]
4436 * Waits for one or more handles to become signaled.
4439 * dwFlags [I] Flags. See notes.
4440 * dwTimeout [I] Timeout in milliseconds.
4441 * cHandles [I] Number of handles pointed to by pHandles.
4442 * pHandles [I] Handles to wait for.
4443 * lpdwindex [O] Index of handle that was signaled.
4447 * Failure: RPC_S_CALLPENDING on timeout.
4451 * The dwFlags parameter can be zero or more of the following:
4452 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4453 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4456 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4458 HRESULT WINAPI
CoWaitForMultipleHandles(DWORD dwFlags
, DWORD dwTimeout
,
4459 ULONG cHandles
, LPHANDLE pHandles
, LPDWORD lpdwindex
)
4462 DWORD start_time
= GetTickCount();
4463 APARTMENT
*apt
= COM_CurrentApt();
4464 BOOL message_loop
= apt
&& !apt
->multi_threaded
;
4465 BOOL check_apc
= (dwFlags
& COWAIT_ALERTABLE
) != 0;
4467 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags
, dwTimeout
, cHandles
,
4468 pHandles
, lpdwindex
);
4471 return E_INVALIDARG
;
4476 return E_INVALIDARG
;
4479 return RPC_E_NO_SYNC
;
4483 DWORD now
= GetTickCount();
4486 if (now
- start_time
> dwTimeout
)
4488 hr
= RPC_S_CALLPENDING
;
4494 DWORD wait_flags
= ((dwFlags
& COWAIT_WAITALL
) ? MWMO_WAITALL
: 0) |
4495 ((dwFlags
& COWAIT_ALERTABLE
) ? MWMO_ALERTABLE
: 0);
4497 TRACE("waiting for rpc completion or window message\n");
4503 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
,
4504 (dwFlags
& COWAIT_WAITALL
) != 0, 0, TRUE
);
4508 if (res
== WAIT_TIMEOUT
)
4509 res
= MsgWaitForMultipleObjectsEx(cHandles
, pHandles
,
4510 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4511 QS_SENDMESSAGE
| QS_ALLPOSTMESSAGE
| QS_PAINT
, wait_flags
);
4513 if (res
== WAIT_OBJECT_0
+ cHandles
) /* messages available */
4518 /* call message filter */
4520 if (COM_CurrentApt()->filter
)
4522 PENDINGTYPE pendingtype
=
4523 COM_CurrentInfo()->pending_call_count_server
?
4524 PENDINGTYPE_NESTED
: PENDINGTYPE_TOPLEVEL
;
4525 DWORD be_handled
= IMessageFilter_MessagePending(
4526 COM_CurrentApt()->filter
, 0 /* FIXME */,
4527 now
- start_time
, pendingtype
);
4528 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled
);
4531 case PENDINGMSG_CANCELCALL
:
4532 WARN("call canceled\n");
4533 hr
= RPC_E_CALL_CANCELED
;
4535 case PENDINGMSG_WAITNOPROCESS
:
4536 case PENDINGMSG_WAITDEFPROCESS
:
4538 /* FIXME: MSDN is very vague about the difference
4539 * between WAITNOPROCESS and WAITDEFPROCESS - there
4540 * appears to be none, so it is possibly a left-over
4541 * from the 16-bit world. */
4546 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4547 * so after processing 100 messages we go back to checking the wait handles */
4548 while (count
++ < 100 && COM_PeekMessage(apt
, &msg
))
4550 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg
.message
);
4551 TranslateMessage(&msg
);
4552 DispatchMessageW(&msg
);
4553 if (msg
.message
== WM_QUIT
)
4555 TRACE("resending WM_QUIT to outer message loop\n");
4556 PostQuitMessage(msg
.wParam
);
4557 /* no longer need to process messages */
4558 message_loop
= FALSE
;
4567 TRACE("waiting for rpc completion\n");
4569 res
= WaitForMultipleObjectsEx(cHandles
, pHandles
, (dwFlags
& COWAIT_WAITALL
) != 0,
4570 (dwTimeout
== INFINITE
) ? INFINITE
: start_time
+ dwTimeout
- now
,
4571 (dwFlags
& COWAIT_ALERTABLE
) != 0);
4577 hr
= RPC_S_CALLPENDING
;
4580 hr
= HRESULT_FROM_WIN32( GetLastError() );
4588 TRACE("-- 0x%08x\n", hr
);
4593 /***********************************************************************
4594 * CoGetObject [OLE32.@]
4596 * Gets the object named by converting the name to a moniker and binding to it.
4599 * pszName [I] String representing the object.
4600 * pBindOptions [I] Parameters affecting the binding to the named object.
4601 * riid [I] Interface to bind to on the objecct.
4602 * ppv [O] On output, the interface riid of the object represented
4607 * Failure: HRESULT code.
4610 * MkParseDisplayName.
4612 HRESULT WINAPI
CoGetObject(LPCWSTR pszName
, BIND_OPTS
*pBindOptions
,
4613 REFIID riid
, void **ppv
)
4620 hr
= CreateBindCtx(0, &pbc
);
4624 hr
= IBindCtx_SetBindOptions(pbc
, pBindOptions
);
4631 hr
= MkParseDisplayName(pbc
, pszName
, &chEaten
, &pmk
);
4634 hr
= IMoniker_BindToObject(pmk
, pbc
, NULL
, riid
, ppv
);
4635 IMoniker_Release(pmk
);
4639 IBindCtx_Release(pbc
);
4644 /***********************************************************************
4645 * CoRegisterChannelHook [OLE32.@]
4647 * Registers a process-wide hook that is called during ORPC calls.
4650 * guidExtension [I] GUID of the channel hook to register.
4651 * pChannelHook [I] Channel hook object to register.
4655 * Failure: HRESULT code.
4657 HRESULT WINAPI
CoRegisterChannelHook(REFGUID guidExtension
, IChannelHook
*pChannelHook
)
4659 TRACE("(%s, %p)\n", debugstr_guid(guidExtension
), pChannelHook
);
4661 return RPC_RegisterChannelHook(guidExtension
, pChannelHook
);
4664 typedef struct Context
4666 IComThreadingInfo IComThreadingInfo_iface
;
4667 IContextCallback IContextCallback_iface
;
4668 IObjContext IObjContext_iface
;
4672 static inline Context
*impl_from_IComThreadingInfo( IComThreadingInfo
*iface
)
4674 return CONTAINING_RECORD(iface
, Context
, IComThreadingInfo_iface
);
4677 static inline Context
*impl_from_IContextCallback( IContextCallback
*iface
)
4679 return CONTAINING_RECORD(iface
, Context
, IContextCallback_iface
);
4682 static inline Context
*impl_from_IObjContext( IObjContext
*iface
)
4684 return CONTAINING_RECORD(iface
, Context
, IObjContext_iface
);
4687 static HRESULT
Context_QueryInterface(Context
*iface
, REFIID riid
, LPVOID
*ppv
)
4691 if (IsEqualIID(riid
, &IID_IComThreadingInfo
) ||
4692 IsEqualIID(riid
, &IID_IUnknown
))
4694 *ppv
= &iface
->IComThreadingInfo_iface
;
4696 else if (IsEqualIID(riid
, &IID_IContextCallback
))
4698 *ppv
= &iface
->IContextCallback_iface
;
4700 else if (IsEqualIID(riid
, &IID_IObjContext
))
4702 *ppv
= &iface
->IObjContext_iface
;
4707 IUnknown_AddRef((IUnknown
*)*ppv
);
4711 FIXME("interface not implemented %s\n", debugstr_guid(riid
));
4712 return E_NOINTERFACE
;
4715 static ULONG
Context_AddRef(Context
*This
)
4717 return InterlockedIncrement(&This
->refs
);
4720 static ULONG
Context_Release(Context
*This
)
4722 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4723 releasing context while refcount is at 0 destroys it. */
4726 HeapFree(GetProcessHeap(), 0, This
);
4730 return InterlockedDecrement(&This
->refs
);
4733 static HRESULT WINAPI
Context_CTI_QueryInterface(IComThreadingInfo
*iface
, REFIID riid
, LPVOID
*ppv
)
4735 Context
*This
= impl_from_IComThreadingInfo(iface
);
4736 return Context_QueryInterface(This
, riid
, ppv
);
4739 static ULONG WINAPI
Context_CTI_AddRef(IComThreadingInfo
*iface
)
4741 Context
*This
= impl_from_IComThreadingInfo(iface
);
4742 return Context_AddRef(This
);
4745 static ULONG WINAPI
Context_CTI_Release(IComThreadingInfo
*iface
)
4747 Context
*This
= impl_from_IComThreadingInfo(iface
);
4748 return Context_Release(This
);
4751 static HRESULT WINAPI
Context_CTI_GetCurrentApartmentType(IComThreadingInfo
*iface
, APTTYPE
*apttype
)
4753 APTTYPEQUALIFIER qualifier
;
4755 TRACE("(%p)\n", apttype
);
4757 return CoGetApartmentType(apttype
, &qualifier
);
4760 static HRESULT WINAPI
Context_CTI_GetCurrentThreadType(IComThreadingInfo
*iface
, THDTYPE
*thdtype
)
4762 APTTYPEQUALIFIER qualifier
;
4766 hr
= CoGetApartmentType(&apttype
, &qualifier
);
4770 TRACE("(%p)\n", thdtype
);
4775 case APTTYPE_MAINSTA
:
4776 *thdtype
= THDTYPE_PROCESSMESSAGES
;
4779 *thdtype
= THDTYPE_BLOCKMESSAGES
;
4785 static HRESULT WINAPI
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo
*iface
, GUID
*logical_thread_id
)
4787 TRACE("(%p)\n", logical_thread_id
);
4788 return CoGetCurrentLogicalThreadId(logical_thread_id
);
4791 static HRESULT WINAPI
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo
*iface
, REFGUID logical_thread_id
)
4793 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id
));
4797 static const IComThreadingInfoVtbl Context_Threading_Vtbl
=
4799 Context_CTI_QueryInterface
,
4801 Context_CTI_Release
,
4802 Context_CTI_GetCurrentApartmentType
,
4803 Context_CTI_GetCurrentThreadType
,
4804 Context_CTI_GetCurrentLogicalThreadId
,
4805 Context_CTI_SetCurrentLogicalThreadId
4808 static HRESULT WINAPI
Context_CC_QueryInterface(IContextCallback
*iface
, REFIID riid
, LPVOID
*ppv
)
4810 Context
*This
= impl_from_IContextCallback(iface
);
4811 return Context_QueryInterface(This
, riid
, ppv
);
4814 static ULONG WINAPI
Context_CC_AddRef(IContextCallback
*iface
)
4816 Context
*This
= impl_from_IContextCallback(iface
);
4817 return Context_AddRef(This
);
4820 static ULONG WINAPI
Context_CC_Release(IContextCallback
*iface
)
4822 Context
*This
= impl_from_IContextCallback(iface
);
4823 return Context_Release(This
);
4826 static HRESULT WINAPI
Context_CC_ContextCallback(IContextCallback
*iface
, PFNCONTEXTCALL pCallback
,
4827 ComCallData
*param
, REFIID riid
, int method
, IUnknown
*punk
)
4829 Context
*This
= impl_from_IContextCallback(iface
);
4831 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This
, iface
, pCallback
, param
, debugstr_guid(riid
), method
, punk
);
4835 static const IContextCallbackVtbl Context_Callback_Vtbl
=
4837 Context_CC_QueryInterface
,
4840 Context_CC_ContextCallback
4843 static HRESULT WINAPI
Context_OC_QueryInterface(IObjContext
*iface
, REFIID riid
, LPVOID
*ppv
)
4845 Context
*This
= impl_from_IObjContext(iface
);
4846 return Context_QueryInterface(This
, riid
, ppv
);
4849 static ULONG WINAPI
Context_OC_AddRef(IObjContext
*iface
)
4851 Context
*This
= impl_from_IObjContext(iface
);
4852 return Context_AddRef(This
);
4855 static ULONG WINAPI
Context_OC_Release(IObjContext
*iface
)
4857 Context
*This
= impl_from_IObjContext(iface
);
4858 return Context_Release(This
);
4861 static HRESULT WINAPI
Context_OC_SetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS flags
, IUnknown
*punk
)
4863 Context
*This
= impl_from_IObjContext(iface
);
4865 FIXME("(%p/%p)->(%s, %x, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4869 static HRESULT WINAPI
Context_OC_RemoveProperty(IObjContext
*iface
, REFGUID propid
)
4871 Context
*This
= impl_from_IObjContext(iface
);
4873 FIXME("(%p/%p)->(%s)\n", This
, iface
, debugstr_guid(propid
));
4877 static HRESULT WINAPI
Context_OC_GetProperty(IObjContext
*iface
, REFGUID propid
, CPFLAGS
*flags
, IUnknown
**punk
)
4879 Context
*This
= impl_from_IObjContext(iface
);
4881 FIXME("(%p/%p)->(%s, %p, %p)\n", This
, iface
, debugstr_guid(propid
), flags
, punk
);
4885 static HRESULT WINAPI
Context_OC_EnumContextProps(IObjContext
*iface
, IEnumContextProps
**props
)
4887 Context
*This
= impl_from_IObjContext(iface
);
4889 FIXME("(%p/%p)->(%p)\n", This
, iface
, props
);
4893 static void WINAPI
Context_OC_Reserved1(IObjContext
*iface
)
4895 Context
*This
= impl_from_IObjContext(iface
);
4896 FIXME("(%p/%p)\n", This
, iface
);
4899 static void WINAPI
Context_OC_Reserved2(IObjContext
*iface
)
4901 Context
*This
= impl_from_IObjContext(iface
);
4902 FIXME("(%p/%p)\n", This
, iface
);
4905 static void WINAPI
Context_OC_Reserved3(IObjContext
*iface
)
4907 Context
*This
= impl_from_IObjContext(iface
);
4908 FIXME("(%p/%p)\n", This
, iface
);
4911 static void WINAPI
Context_OC_Reserved4(IObjContext
*iface
)
4913 Context
*This
= impl_from_IObjContext(iface
);
4914 FIXME("(%p/%p)\n", This
, iface
);
4917 static void WINAPI
Context_OC_Reserved5(IObjContext
*iface
)
4919 Context
*This
= impl_from_IObjContext(iface
);
4920 FIXME("(%p/%p)\n", This
, iface
);
4923 static void WINAPI
Context_OC_Reserved6(IObjContext
*iface
)
4925 Context
*This
= impl_from_IObjContext(iface
);
4926 FIXME("(%p/%p)\n", This
, iface
);
4929 static void WINAPI
Context_OC_Reserved7(IObjContext
*iface
)
4931 Context
*This
= impl_from_IObjContext(iface
);
4932 FIXME("(%p/%p)\n", This
, iface
);
4935 static const IObjContextVtbl Context_Object_Vtbl
=
4937 Context_OC_QueryInterface
,
4940 Context_OC_SetProperty
,
4941 Context_OC_RemoveProperty
,
4942 Context_OC_GetProperty
,
4943 Context_OC_EnumContextProps
,
4944 Context_OC_Reserved1
,
4945 Context_OC_Reserved2
,
4946 Context_OC_Reserved3
,
4947 Context_OC_Reserved4
,
4948 Context_OC_Reserved5
,
4949 Context_OC_Reserved6
,
4950 Context_OC_Reserved7
4953 /***********************************************************************
4954 * CoGetObjectContext [OLE32.@]
4956 * Retrieves an object associated with the current context (i.e. apartment).
4959 * riid [I] ID of the interface of the object to retrieve.
4960 * ppv [O] Address where object will be stored on return.
4964 * Failure: HRESULT code.
4966 HRESULT WINAPI
CoGetObjectContext(REFIID riid
, void **ppv
)
4968 IObjContext
*context
;
4971 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
4974 hr
= CoGetContextToken((ULONG_PTR
*)&context
);
4978 return IObjContext_QueryInterface(context
, riid
, ppv
);
4981 /***********************************************************************
4982 * CoGetContextToken [OLE32.@]
4984 HRESULT WINAPI
CoGetContextToken( ULONG_PTR
*token
)
4986 struct oletls
*info
= COM_CurrentInfo();
4988 TRACE("(%p)\n", token
);
4991 return E_OUTOFMEMORY
;
4996 if (!(apt
= apartment_find_multi_threaded()))
4998 ERR("apartment not initialised\n");
4999 return CO_E_NOTINITIALIZED
;
5001 apartment_release(apt
);
5007 if (!info
->context_token
)
5011 context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*context
));
5013 return E_OUTOFMEMORY
;
5015 context
->IComThreadingInfo_iface
.lpVtbl
= &Context_Threading_Vtbl
;
5016 context
->IContextCallback_iface
.lpVtbl
= &Context_Callback_Vtbl
;
5017 context
->IObjContext_iface
.lpVtbl
= &Context_Object_Vtbl
;
5018 /* Context token does not take a reference, it's always zero until the
5019 interface is explicitly requested with CoGetObjectContext(). */
5022 info
->context_token
= &context
->IObjContext_iface
;
5025 *token
= (ULONG_PTR
)info
->context_token
;
5026 TRACE("context_token=%p\n", info
->context_token
);
5031 /***********************************************************************
5032 * CoGetDefaultContext [OLE32.@]
5034 HRESULT WINAPI
CoGetDefaultContext(APTTYPE type
, REFIID riid
, LPVOID
*ppv
)
5036 FIXME("%d %s %p stub\n", type
, debugstr_guid(riid
), ppv
);
5037 return E_NOINTERFACE
;
5040 HRESULT
Handler_DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
5042 static const WCHAR wszInprocHandler32
[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5046 hres
= COM_OpenKeyForCLSID(rclsid
, wszInprocHandler32
, KEY_READ
, &hkey
);
5047 if (SUCCEEDED(hres
))
5049 struct class_reg_data regdata
;
5050 WCHAR dllpath
[MAX_PATH
+1];
5052 regdata
.u
.hkey
= hkey
;
5053 regdata
.hkey
= TRUE
;
5055 if (COM_RegReadPath(®data
, dllpath
, ARRAYSIZE(dllpath
)) == ERROR_SUCCESS
)
5057 static const WCHAR wszOle32
[] = {'o','l','e','3','2','.','d','l','l',0};
5058 if (!strcmpiW(dllpath
, wszOle32
))
5061 return HandlerCF_Create(rclsid
, riid
, ppv
);
5065 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath
));
5069 return CLASS_E_CLASSNOTAVAILABLE
;
5072 /***********************************************************************
5073 * CoGetApartmentType [OLE32.@]
5075 HRESULT WINAPI
CoGetApartmentType(APTTYPE
*type
, APTTYPEQUALIFIER
*qualifier
)
5077 struct oletls
*info
= COM_CurrentInfo();
5079 FIXME("(%p, %p): semi-stub\n", type
, qualifier
);
5081 if (!type
|| !qualifier
)
5082 return E_INVALIDARG
;
5085 return E_OUTOFMEMORY
;
5088 *type
= APTTYPE_CURRENT
;
5089 else if (info
->apt
->multi_threaded
)
5090 *type
= APTTYPE_MTA
;
5091 else if (info
->apt
->main
)
5092 *type
= APTTYPE_MAINSTA
;
5094 *type
= APTTYPE_STA
;
5096 *qualifier
= APTTYPEQUALIFIER_NONE
;
5098 return info
->apt
? S_OK
: CO_E_NOTINITIALIZED
;
5101 /***********************************************************************
5102 * CoRegisterSurrogate [OLE32.@]
5104 HRESULT WINAPI
CoRegisterSurrogate(ISurrogate
*surrogate
)
5106 FIXME("(%p): stub\n", surrogate
);
5111 /***********************************************************************
5112 * CoRegisterSurrogateEx [OLE32.@]
5114 HRESULT WINAPI
CoRegisterSurrogateEx(REFGUID guid
, void *reserved
)
5116 FIXME("(%s %p): stub\n", debugstr_guid(guid
), reserved
);
5122 IGlobalOptions IGlobalOptions_iface
;
5126 static inline GlobalOptions
*impl_from_IGlobalOptions(IGlobalOptions
*iface
)
5128 return CONTAINING_RECORD(iface
, GlobalOptions
, IGlobalOptions_iface
);
5131 static HRESULT WINAPI
GlobalOptions_QueryInterface(IGlobalOptions
*iface
, REFIID riid
, void **ppv
)
5133 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5135 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
5137 if (IsEqualGUID(&IID_IGlobalOptions
, riid
) || IsEqualGUID(&IID_IUnknown
, riid
))
5144 return E_NOINTERFACE
;
5147 IUnknown_AddRef((IUnknown
*)*ppv
);
5151 static ULONG WINAPI
GlobalOptions_AddRef(IGlobalOptions
*iface
)
5153 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5154 LONG ref
= InterlockedIncrement(&This
->ref
);
5156 TRACE("(%p) ref=%d\n", This
, ref
);
5161 static ULONG WINAPI
GlobalOptions_Release(IGlobalOptions
*iface
)
5163 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5164 LONG ref
= InterlockedDecrement(&This
->ref
);
5166 TRACE("(%p) ref=%d\n", This
, ref
);
5174 static HRESULT WINAPI
GlobalOptions_Set(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR value
)
5176 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5177 FIXME("(%p)->(%u %lx)\n", This
, property
, value
);
5181 static HRESULT WINAPI
GlobalOptions_Query(IGlobalOptions
*iface
, GLOBALOPT_PROPERTIES property
, ULONG_PTR
*value
)
5183 GlobalOptions
*This
= impl_from_IGlobalOptions(iface
);
5184 FIXME("(%p)->(%u %p)\n", This
, property
, value
);
5188 static const IGlobalOptionsVtbl GlobalOptionsVtbl
= {
5189 GlobalOptions_QueryInterface
,
5190 GlobalOptions_AddRef
,
5191 GlobalOptions_Release
,
5196 HRESULT WINAPI
GlobalOptions_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **ppv
)
5198 GlobalOptions
*global_options
;
5201 TRACE("(%p %s %p)\n", outer
, debugstr_guid(riid
), ppv
);
5204 return E_INVALIDARG
;
5206 global_options
= heap_alloc(sizeof(*global_options
));
5207 if (!global_options
)
5208 return E_OUTOFMEMORY
;
5209 global_options
->IGlobalOptions_iface
.lpVtbl
= &GlobalOptionsVtbl
;
5210 global_options
->ref
= 1;
5212 hres
= IGlobalOptions_QueryInterface(&global_options
->IGlobalOptions_iface
, riid
, ppv
);
5213 IGlobalOptions_Release(&global_options
->IGlobalOptions_iface
);
5217 /***********************************************************************
5220 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID reserved
)
5222 TRACE("%p 0x%x %p\n", hinstDLL
, fdwReason
, reserved
);
5225 case DLL_PROCESS_ATTACH
:
5226 hProxyDll
= hinstDLL
;
5229 case DLL_PROCESS_DETACH
:
5230 if (reserved
) break;
5232 UnregisterClassW( wszAptWinClass
, hProxyDll
);
5233 RPC_UnregisterAllChannelHooks();
5234 COMPOBJ_DllList_Free();
5235 DeleteCriticalSection(&csRegisteredClassList
);
5236 DeleteCriticalSection(&csApartment
);
5239 case DLL_THREAD_DETACH
:
5246 /***********************************************************************
5247 * DllRegisterServer (OLE32.@)
5249 HRESULT WINAPI
DllRegisterServer(void)
5251 return OLE32_DllRegisterServer();
5254 /***********************************************************************
5255 * DllUnregisterServer (OLE32.@)
5257 HRESULT WINAPI
DllUnregisterServer(void)
5259 return OLE32_DllUnregisterServer();