ReactOS 0.4.16-dev-122-g325d74c
compobj.c
Go to the documentation of this file.
1/*
2 * COMPOBJ library
3 *
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)
11 *
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.
16 *
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.
21 *
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
25 *
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
29 *
30 * TODO list: (items bunched together depend on each other)
31 *
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
36 *
37 */
38
39#include <stdarg.h>
40#include <stdio.h>
41#include <string.h>
42#include <assert.h>
43
44#define COBJMACROS
45#define NONAMELESSUNION
46
47#include "ntstatus.h"
48#define WIN32_NO_STATUS
49#include "windef.h"
50#include "winbase.h"
51#include "winerror.h"
52#include "winreg.h"
53#include "winuser.h"
54#define USE_COM_CONTEXT_DEF
55#include "objbase.h"
56#include "ole2.h"
57#include "ole2ver.h"
58#include "ctxtcall.h"
59#include "dde.h"
60#include "servprov.h"
61
62#ifndef __REACTOS__
63#include "initguid.h"
64#endif
65#include "compobj_private.h"
66#include "moniker.h"
67
68#include "wine/debug.h"
69
71
72/****************************************************************************
73 * This section defines variables internal to the COM module.
74 */
75
76static APARTMENT *MTA; /* protected by csApartment */
77static APARTMENT *MainApartment; /* the first STA apartment */
78static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
79
82{
83 0, 0, &csApartment,
85 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
86};
87static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
88
90{
96};
97
99{
106
108{
129};
130
132{
141};
142
144{
148};
149
151{
152 union
153 {
154 struct
155 {
157 void *section;
161 } u;
163};
164
166{
167 struct list entry;
170};
171
173
176{
179 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
180};
182
183/*
184 * This is a marshallable object exposing registered local servers.
185 * IServiceProvider is used only because it happens meet requirements
186 * and already has proxy/stub code. If more functionality is needed,
187 * a custom interface may be used instead.
188 */
190{
195};
196
197/*
198 * This lock count counts the number of times CoInitialize is called. It is
199 * decreased every time CoUninitialize is called. When it hits 0, the COM
200 * libraries are freed
201 */
203/* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
205
206/*
207 * This linked list contains the list of registered class objects. These
208 * are mostly used to register the factories for out-of-proc servers of OLE
209 * objects.
210 *
211 * TODO: Make this data structure aware of inter-process communication. This
212 * means that parts of this will be exported to rpcss.
213 */
214typedef struct tagRegisteredClass
215{
216 struct list entry;
225
227
230{
233 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
234};
235static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
236
238{
239 switch (aspect)
240 {
241 case DVASPECT_CONTENT:
242 return MiscStatusContent;
243 case DVASPECT_THUMBNAIL:
244 return MiscStatusThumbnail;
245 case DVASPECT_ICON:
246 return MiscStatusIcon;
247 case DVASPECT_DOCPRINT:
248 return MiscStatusDocPrint;
249 default:
250 return MiscStatus;
251 };
252}
253
255{
256 ACTCTX_SECTION_KEYED_DATA data;
257
258 data.cbSize = sizeof(data);
259 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
260 clsid, &data))
261 {
262 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
264
265 if (!(comclass->miscmask & misc))
266 {
267 if (!(comclass->miscmask & MiscStatus))
268 {
269 *status = 0;
270 return TRUE;
271 }
272 misc = MiscStatus;
273 }
274
275 switch (misc)
276 {
277 case MiscStatus:
278 *status = comclass->miscstatus;
279 break;
280 case MiscStatusIcon:
281 *status = comclass->miscstatusicon;
282 break;
284 *status = comclass->miscstatuscontent;
285 break;
287 *status = comclass->miscstatusthumbnail;
288 break;
290 *status = comclass->miscstatusdocprint;
291 break;
292 default:
293 ;
294 };
295
296 return TRUE;
297 }
298 else
299 return FALSE;
300}
301
302/* wrapper for NtCreateKey that creates the key recursively if necessary */
304{
305 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
306
308 {
309 HANDLE subkey, root = attr->RootDirectory;
310 WCHAR *buffer = attr->ObjectName->Buffer;
311 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
313
314 while (i < len && buffer[i] != '\\') i++;
315 if (i == len) return status;
316
317 attrs = attr->Attributes;
318 attr->ObjectName = &str;
319
320 while (i < len)
321 {
322 str.Buffer = buffer + pos;
323 str.Length = (i - pos) * sizeof(WCHAR);
324 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
325 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
326 if (status) return status;
327 attr->RootDirectory = subkey;
328 while (i < len && buffer[i] == '\\') i++;
329 pos = i;
330 while (i < len && buffer[i] != '\\') i++;
331 }
332 str.Buffer = buffer + pos;
333 str.Length = (i - pos) * sizeof(WCHAR);
334 attr->Attributes = attrs;
335 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
336 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
337 }
338 return status;
339}
340
341#ifdef __REACTOS__
342static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
343#else
344static 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};
347#endif
348
350
351/* create the special HKEY_CLASSES_ROOT key */
353{
354 HKEY hkey, ret = 0;
357
358 attr.Length = sizeof(attr);
359 attr.RootDirectory = 0;
360 attr.ObjectName = &name;
361 attr.Attributes = 0;
362 attr.SecurityDescriptor = NULL;
363 attr.SecurityQualityOfService = NULL;
365 if (create_key( &hkey, access, &attr )) return 0;
366 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
367
368 if (!(access & KEY_WOW64_64KEY))
369 {
370 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
371 ret = hkey;
372 else
373 NtClose( hkey ); /* somebody beat us to it */
374 }
375 else
376 ret = hkey;
377 return ret;
378}
379
380/* map the hkey from special root to normal key if necessary */
382{
383 HKEY ret = hkey;
384 const BOOL is_win64 = sizeof(void*) > sizeof(int);
385 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
386
387 if (hkey == HKEY_CLASSES_ROOT &&
390 if (force_wow32 && ret && ret == classes_root_hkey)
391 {
392 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
393 access &= ~KEY_WOW64_32KEY;
394 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
395 return 0;
396 ret = hkey;
397 }
398
399 return ret;
400}
401
403{
406
407 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
408
409 attr.Length = sizeof(attr);
410 attr.RootDirectory = hkey;
411 attr.ObjectName = &nameW;
412 attr.Attributes = 0;
413 attr.SecurityDescriptor = NULL;
414 attr.SecurityQualityOfService = NULL;
416
417 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
418}
419
421{
424
425 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
426
427 attr.Length = sizeof(attr);
428 attr.RootDirectory = hkey;
429 attr.ObjectName = &nameW;
430 attr.Attributes = 0;
431 attr.SecurityDescriptor = NULL;
432 attr.SecurityQualityOfService = NULL;
434
435 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
436}
437
438/*****************************************************************************
439 * This section contains OpenDllList definitions
440 *
441 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
442 * other functions that do LoadLibrary _without_ giving back a HMODULE.
443 * Without this list these handles would never be freed.
444 *
445 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
446 * next unload-call but not before 600 sec.
447 */
448
451
452typedef struct tagOpenDll
453{
459 struct list entry;
461
463
466{
467 0, 0, &csOpenDllList,
469 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
470};
471static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
472
474{
475 struct list entry;
479};
480
481static 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
484
485/*****************************************************************************
486 * This section contains OpenDllList implementation
487 */
488
490{
491 OpenDll *ptr;
492 OpenDll *ret = NULL;
495 {
496 if (!wcsicmp(library_name, ptr->library_name) &&
497 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
498 {
499 ret = ptr;
500 break;
501 }
502 }
504 return ret;
505}
506
507/* caller must ensure that library_name is not already in the open dll list */
509{
510 OpenDll *entry;
511 int len;
512 HRESULT hr = S_OK;
516
517 TRACE("%s\n", debugstr_w(library_name));
518
519 *ret = COMPOBJ_DllList_Get(library_name);
520 if (*ret) return S_OK;
521
522 /* do this outside the csOpenDllList to avoid creating a lock dependency on
523 * the loader lock */
525 if (!hLibrary)
526 {
527 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
528 /* failure: DLL could not be loaded */
529 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
530 }
531
532 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
533 /* Note: failing to find DllCanUnloadNow is not a failure */
534 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
536 {
537 /* failure: the dll did not export DllGetClassObject */
538 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
540 return CO_E_DLLNOTFOUND;
541 }
542
544
545 *ret = COMPOBJ_DllList_Get(library_name);
546 if (*ret)
547 {
548 /* another caller to this function already added the dll while we
549 * weren't in the critical section */
551 }
552 else
553 {
554 len = lstrlenW(library_name);
555 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
556 if (entry)
557 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
558 if (entry && entry->library_name)
559 {
560 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
561 entry->library = hLibrary;
562 entry->refs = 1;
563 entry->DllCanUnloadNow = DllCanUnloadNow;
564 entry->DllGetClassObject = DllGetClassObject;
566 *ret = entry;
567 }
568 else
569 {
573 }
574 }
575
577
578 return hr;
579}
580
581/* pass FALSE for free_entry to release a reference without destroying the
582 * entry if it reaches zero or TRUE otherwise */
584{
585 if (!InterlockedDecrement(&entry->refs) && free_entry)
586 {
588 list_remove(&entry->entry);
590
591 TRACE("freeing %p\n", entry->library);
592 FreeLibrary(entry->library);
593
594 HeapFree(GetProcessHeap(), 0, entry->library_name);
596 }
597}
598
599/* frees memory associated with active dll list */
600static void COMPOBJ_DllList_Free(void)
601{
602 OpenDll *entry, *cursor2;
605 {
606 list_remove(&entry->entry);
607
608 HeapFree(GetProcessHeap(), 0, entry->library_name);
610 }
613}
614
615/******************************************************************************
616 * Manage apartments.
617 */
618
620{
621 DWORD refs = InterlockedIncrement(&apt->refs);
622 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
623 return refs;
624}
625
626/* allocates memory and fills in the necessary fields for a new apartment
627 * object. must be called inside apartment cs */
629{
630 APARTMENT *apt;
631
632 TRACE("creating new apartment, model=%d\n", model);
633
634 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
635 apt->tid = GetCurrentThreadId();
636
637 list_init(&apt->proxies);
638 list_init(&apt->stubmgrs);
639 list_init(&apt->loaded_dlls);
640 apt->ipidc = 0;
641 apt->refs = 1;
642 apt->remunk_exported = FALSE;
643 apt->oidc = 1;
645 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
646
648
649 if (apt->multi_threaded)
650 {
651 /* FIXME: should be randomly generated by in an RPC call to rpcss */
652 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
653 }
654 else
655 {
656 /* FIXME: should be randomly generated by in an RPC call to rpcss */
657 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
658 }
659
660 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
661
662 list_add_head(&apts, &apt->entry);
663
664 return apt;
665}
666
667/* gets and existing apartment if one exists or otherwise creates an apartment
668 * structure which stores OLE apartment-local information and stores a pointer
669 * to it in the thread-local storage */
671{
672 APARTMENT *apt = COM_CurrentApt();
673
674 if (!apt)
675 {
676 if (model & COINIT_APARTMENTTHREADED)
677 {
679
680 apt = apartment_construct(model);
681 if (!MainApartment)
682 {
683 MainApartment = apt;
684 apt->main = TRUE;
685 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
686 }
687
689
690 if (apt->main)
692 }
693 else
694 {
696
697 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
698 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
699 * in a process */
700 if (MTA)
701 {
702 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
704 }
705 else
706 MTA = apartment_construct(model);
707
708 apt = MTA;
709
711 }
712 COM_CurrentInfo()->apt = apt;
713 }
714
715 return apt;
716}
717
718static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
719{
720 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
721}
722
723/* gets the multi-threaded apartment if it exists. The caller must
724 * release the reference from the apartment as soon as the apartment pointer
725 * is no longer required. */
727{
728 APARTMENT *apt;
729
731
732 if ((apt = MTA))
733 apartment_addref(apt);
734
736
737 return apt;
738}
739
740/* Return the current apartment if it exists, or, failing that, the MTA. Caller
741 * must free the returned apartment in either case. */
743{
744 APARTMENT *apt = COM_CurrentApt();
745 if (apt)
746 {
747 apartment_addref(apt);
748 return apt;
749 }
750 return apartment_find_mta();
751}
752
754{
755 list_remove(&curClass->entry);
756
757 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
759
760 IUnknown_Release(curClass->classObject);
761 HeapFree(GetProcessHeap(), 0, curClass);
762}
763
764static void COM_RevokeAllClasses(const struct apartment *apt)
765{
766 RegisteredClass *curClass, *cursor;
767
769
771 {
772 if (curClass->apartment_id == apt->oxid)
774 }
775
777}
778
780{
781 struct registered_psclsid *psclsid, *psclsid2;
782
784
786 {
787 list_remove(&psclsid->entry);
788 HeapFree(GetProcessHeap(), 0, psclsid);
789 }
790
792}
793
794/******************************************************************************
795 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
796 */
797
798typedef struct ManualResetEvent {
804
806{
807 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
808}
809
811{
813
814 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
815
816 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
817 *ppv = &This->ISynchronize_iface;
818 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
819 *ppv = &This->ISynchronizeHandle_iface;
820 }else {
821 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
822 *ppv = NULL;
823 return E_NOINTERFACE;
824 }
825
826 IUnknown_AddRef((IUnknown*)*ppv);
827 return S_OK;
828}
829
831{
834 TRACE("%p - ref %d\n", This, ref);
835
836 return ref;
837}
838
840{
843 TRACE("%p - ref %d\n", This, ref);
844
845 if(!ref)
846 {
847 CloseHandle(This->event);
849 }
850
851 return ref;
852}
853
855{
857 UINT index;
858 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
859 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
860}
861
863{
865 TRACE("%p\n", This);
866 SetEvent(This->event);
867 return S_OK;
868}
869
871{
873 TRACE("%p\n", This);
874 ResetEvent(This->event);
875 return S_OK;
876}
877
878static ISynchronizeVtbl vt_ISynchronize = {
885};
886
888{
889 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
890}
891
893{
895 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
896}
897
899{
901 return ISynchronize_AddRef(&This->ISynchronize_iface);
902}
903
905{
907 return ISynchronize_Release(&This->ISynchronize_iface);
908}
909
911{
913
914 *ph = This->event;
915 return S_OK;
916}
917
918static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
923};
924
925static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
926{
928 HRESULT hr;
929
930 if(punkouter)
931 FIXME("Aggregation not implemented.\n");
932
933 This->ref = 1;
934 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
935 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
936 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
937
938 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
939 ISynchronize_Release(&This->ISynchronize_iface);
940 return hr;
941}
942
944{
945 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
946}
947
949{
951
952 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
953
954 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
955 *ppv = &This->IServiceProvider_iface;
956 }else {
957 *ppv = NULL;
958 return E_NOINTERFACE;
959 }
960
961 IUnknown_AddRef((IUnknown*)*ppv);
962 return S_OK;
963}
964
966{
969
970 TRACE("(%p) ref=%d\n", This, ref);
971
972 return ref;
973}
974
976{
979
980 TRACE("(%p) ref=%d\n", This, ref);
981
982 if(!ref) {
983 assert(!This->apt);
985 }
986
987 return ref;
988}
989
991{
993 APARTMENT *apt = COM_CurrentApt();
994 RegisteredClass *iter;
996
997 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
998
999 if(!This->apt)
1000 return E_UNEXPECTED;
1001
1003
1005 if(iter->apartment_id == apt->oxid
1006 && (iter->runContext & CLSCTX_LOCAL_SERVER)
1007 && IsEqualGUID(&iter->classIdentifier, guid)) {
1008 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1009 break;
1010 }
1011 }
1012
1014
1015 return hres;
1016}
1017
1018static const IServiceProviderVtbl LocalServerVtbl = {
1023};
1024
1026{
1027 HRESULT hres = S_OK;
1028
1029 EnterCriticalSection(&apt->cs);
1030
1031 if(!apt->local_server) {
1033
1034 obj = heap_alloc(sizeof(*obj));
1035 if(obj) {
1036 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1037 obj->ref = 1;
1038 obj->apt = apt;
1039
1040 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1041 if(SUCCEEDED(hres)) {
1042 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1043 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1044 if(FAILED(hres))
1045 IStream_Release(obj->marshal_stream);
1046 }
1047
1048 if(SUCCEEDED(hres))
1049 apt->local_server = obj;
1050 else
1051 heap_free(obj);
1052 }else {
1054 }
1055 }
1056
1057 if(SUCCEEDED(hres))
1058 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1059
1060 LeaveCriticalSection(&apt->cs);
1061
1062 if(FAILED(hres))
1063 ERR("Failed: %08x\n", hres);
1064 return hres;
1065}
1066
1067/***********************************************************************
1068 * CoRevokeClassObject [OLE32.@]
1069 *
1070 * Removes a class object from the class registry.
1071 *
1072 * PARAMS
1073 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1074 *
1075 * RETURNS
1076 * Success: S_OK.
1077 * Failure: HRESULT code.
1078 *
1079 * NOTES
1080 * Must be called from the same apartment that called CoRegisterClassObject(),
1081 * otherwise it will fail with RPC_E_WRONG_THREAD.
1082 *
1083 * SEE ALSO
1084 * CoRegisterClassObject
1085 */
1087 DWORD dwRegister)
1088{
1090 RegisteredClass *curClass;
1091 APARTMENT *apt;
1092
1093 TRACE("(%08x)\n",dwRegister);
1094
1095 if (!(apt = apartment_get_current_or_mta()))
1096 {
1097 ERR("COM was not initialized\n");
1098 return CO_E_NOTINITIALIZED;
1099 }
1100
1102
1104 {
1105 /*
1106 * Check if we have a match on the cookie.
1107 */
1108 if (curClass->dwCookie == dwRegister)
1109 {
1110 if (curClass->apartment_id == apt->oxid)
1111 {
1113 hr = S_OK;
1114 }
1115 else
1116 {
1117 ERR("called from wrong apartment, should be called from %s\n",
1120 }
1121 break;
1122 }
1123 }
1124
1126 apartment_release(apt);
1127 return hr;
1128}
1129
1130/* frees unused libraries loaded by apartment_getclassobject by calling the
1131 * DLL's DllCanUnloadNow entry point */
1132static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1133{
1135 EnterCriticalSection(&apt->cs);
1137 {
1138 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1139 {
1140 DWORD real_delay = delay;
1141
1142 if (real_delay == INFINITE)
1143 {
1144 /* DLLs that return multi-threaded objects aren't unloaded
1145 * straight away to cope for programs that have races between
1146 * last object destruction and threads in the DLLs that haven't
1147 * finished, despite DllCanUnloadNow returning S_OK */
1148 if (entry->multi_threaded)
1149 real_delay = 10 * 60 * 1000; /* 10 minutes */
1150 else
1151 real_delay = 0;
1152 }
1153
1154 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1155 {
1156 list_remove(&entry->entry);
1159 }
1160 else
1161 {
1162 entry->unload_time = GetTickCount() + real_delay;
1163 if (!entry->unload_time) entry->unload_time = 1;
1164 }
1165 }
1166 else if (entry->unload_time)
1167 entry->unload_time = 0;
1168 }
1169 LeaveCriticalSection(&apt->cs);
1170}
1171
1173{
1174 DWORD ret;
1175
1177
1178 ret = InterlockedDecrement(&apt->refs);
1179 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1180
1181 if (apt->being_destroyed)
1182 {
1184 return ret;
1185 }
1186
1187 /* destruction stuff that needs to happen under csApartment CS */
1188 if (ret == 0)
1189 {
1190 apt->being_destroyed = TRUE;
1191 if (apt == MTA) MTA = NULL;
1192 else if (apt == MainApartment) MainApartment = NULL;
1193 list_remove(&apt->entry);
1194 }
1195
1197
1198 if (ret == 0)
1199 {
1200 struct list *cursor, *cursor2;
1201
1202 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1203
1204 if(apt->local_server) {
1207
1208 memset(&zero, 0, sizeof(zero));
1209 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1210 CoReleaseMarshalData(local_server->marshal_stream);
1211 IStream_Release(local_server->marshal_stream);
1212 local_server->marshal_stream = NULL;
1213
1214 apt->local_server = NULL;
1215 local_server->apt = NULL;
1216 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1217 }
1218
1219 /* Release the references to the registered class objects */
1221
1222 /* no locking is needed for this apartment, because no other thread
1223 * can access it at this point */
1224
1226
1227 if (apt->win) DestroyWindow(apt->win);
1228 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1229
1230 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1231 {
1232 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1233 /* release the implicit reference given by the fact that the
1234 * stub has external references (it must do since it is in the
1235 * stub manager list in the apartment and all non-apartment users
1236 * must have a ref on the apartment and so it cannot be destroyed).
1237 */
1238 stub_manager_int_release(stubmgr);
1239 }
1240
1241 /* if this assert fires, then another thread took a reference to a
1242 * stub manager without taking a reference to the containing
1243 * apartment, which it must do. */
1245
1246 if (apt->filter) IMessageFilter_Release(apt->filter);
1247
1248 /* free as many unused libraries as possible... */
1250
1251 /* ... and free the memory for the apartment loaded dll entry and
1252 * release the dll list reference without freeing the library for the
1253 * rest */
1254 while ((cursor = list_head(&apt->loaded_dlls)))
1255 {
1260 }
1261
1264
1265 HeapFree(GetProcessHeap(), 0, apt);
1266 }
1267
1268 return ret;
1269}
1270
1271/* The given OXID must be local to this process:
1272 *
1273 * The ref parameter is here mostly to ensure people remember that
1274 * they get one, you should normally take a ref for thread safety.
1275 */
1277{
1279 struct list *cursor;
1280
1283 {
1284 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1285 if (apt->oxid == oxid)
1286 {
1287 result = apt;
1289 break;
1290 }
1291 }
1293
1294 return result;
1295}
1296
1297/* gets the apartment which has a given creator thread ID. The caller must
1298 * release the reference from the apartment as soon as the apartment pointer
1299 * is no longer required. */
1301{
1303 struct list *cursor;
1304
1307 {
1308 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1309 if (apt->tid == tid)
1310 {
1311 result = apt;
1313 break;
1314 }
1315 }
1317
1318 return result;
1319}
1320
1321/* gets the main apartment if it exists. The caller must
1322 * release the reference from the apartment as soon as the apartment pointer
1323 * is no longer required. */
1325{
1327
1329
1332
1334
1335 return result;
1336}
1337
1338/* gets the specified class object by loading the appropriate DLL, if
1339 * necessary and calls the DllGetClassObject function for the DLL */
1341 BOOL apartment_threaded,
1342 REFCLSID rclsid, REFIID riid, void **ppv)
1343{
1344 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1345 HRESULT hr = S_OK;
1346 BOOL found = FALSE;
1348
1349 if (!wcsicmp(dllpath, wszOle32))
1350 {
1351 /* we don't need to control the lifetime of this dll, so use the local
1352 * implementation of DllGetClassObject directly */
1353 TRACE("calling ole32!DllGetClassObject\n");
1354 hr = DllGetClassObject(rclsid, riid, ppv);
1355
1356 if (hr != S_OK)
1357 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1358
1359 return hr;
1360 }
1361
1362 EnterCriticalSection(&apt->cs);
1363
1366 {
1367 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1368 found = TRUE;
1369 break;
1370 }
1371
1372 if (!found)
1373 {
1376 hr = E_OUTOFMEMORY;
1377 if (SUCCEEDED(hr))
1378 {
1382 if (FAILED(hr))
1384 }
1385 if (SUCCEEDED(hr))
1386 {
1387 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1389 }
1390 }
1391
1392 LeaveCriticalSection(&apt->cs);
1393
1394 if (SUCCEEDED(hr))
1395 {
1396 /* one component being multi-threaded overrides any number of
1397 * apartment-threaded components */
1398 if (!apartment_threaded)
1400
1401 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1402 /* OK: get the ClassObject */
1404
1405 if (hr != S_OK)
1406 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1407 }
1408
1409 return hr;
1410}
1411
1412/* Returns expanded dll path from the registry or activation context. */
1414{
1415 DWORD ret;
1416
1417 if (regdata->hkey)
1418 {
1419 DWORD keytype;
1421 DWORD dwLength = dstlen * sizeof(WCHAR);
1422
1423 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1424 if (keytype == REG_EXPAND_SZ) {
1426 } else {
1427 const WCHAR *quote_start;
1428 quote_start = wcschr(src, '\"');
1429 if (quote_start) {
1430 const WCHAR *quote_end = wcschr(quote_start + 1, '\"');
1431 if (quote_end) {
1432 memmove(src, quote_start + 1,
1433 (quote_end - quote_start - 1) * sizeof(WCHAR));
1434 src[quote_end - quote_start - 1] = '\0';
1435 }
1436 }
1438 }
1439 }
1440 return !ret;
1441 }
1442 else
1443 {
1444 static const WCHAR dllW[] = {'.','d','l','l',0};
1446 WCHAR *nameW;
1447
1448 *dst = 0;
1449 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1450 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1453 return *dst != 0;
1454 }
1455}
1456
1458{
1460 CLSID clsid; /* clsid of object to marshal */
1461 IID iid; /* interface to marshal */
1462 HANDLE event; /* event signalling when ready for multi-threaded case */
1463 HRESULT hr; /* result for multi-threaded case */
1464 IStream *stream; /* stream that the object will be marshaled into */
1465 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1466};
1467
1469 const struct host_object_params *params)
1470{
1472 HRESULT hr;
1473 static const LARGE_INTEGER llZero;
1475
1476 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1477
1479 {
1480 /* failure: CLSID is not found in registry */
1481 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1482 return REGDB_E_CLASSNOTREG;
1483 }
1484
1485 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1486 &params->clsid, &params->iid, (void **)&object);
1487 if (FAILED(hr))
1488 return hr;
1489
1490 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1491 if (FAILED(hr))
1492 IUnknown_Release(object);
1493 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1494
1495 return hr;
1496}
1497
1499{
1500 switch (msg)
1501 {
1502 case DM_EXECUTERPC:
1504 return 0;
1505 case DM_HOSTOBJECT:
1507 default:
1508 return DefWindowProcW(hWnd, msg, wParam, lParam);
1509 }
1510}
1511
1513{
1517};
1518
1519/* thread for hosting an object to allow an object to appear to be created in
1520 * an apartment with an incompatible threading model */
1522{
1523 struct host_thread_params *params = p;
1524 MSG msg;
1525 HRESULT hr;
1526 struct apartment *apt;
1527
1528 TRACE("\n");
1529
1530 hr = CoInitializeEx(NULL, params->threading_model);
1531 if (FAILED(hr)) return hr;
1532
1533 apt = COM_CurrentApt();
1534 if (params->threading_model == COINIT_APARTMENTTHREADED)
1535 {
1537 params->apartment_hwnd = apartment_getwindow(apt);
1538 }
1539 else
1540 params->apartment_hwnd = NULL;
1541
1542 /* force the message queue to be created before signaling parent thread */
1544
1545 SetEvent(params->ready_event);
1546 params = NULL; /* can't touch params after here as it may be invalid */
1547
1548 while (GetMessageW(&msg, NULL, 0, 0))
1549 {
1550 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1551 {
1552 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1553 obj_params->hr = apartment_hostobject(apt, obj_params);
1554 SetEvent(obj_params->event);
1555 }
1556 else
1557 {
1560 }
1561 }
1562
1563 TRACE("exiting\n");
1564
1566
1567 return S_OK;
1568}
1569
1570/* finds or creates a host apartment, creates the object inside it and returns
1571 * a proxy to it so that the object can be used in the apartment of the
1572 * caller of this function */
1574 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1575 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1576{
1578 HWND apartment_hwnd = NULL;
1579 DWORD apartment_tid = 0;
1580 HRESULT hr;
1581
1582 if (!multi_threaded && main_apartment)
1583 {
1584 APARTMENT *host_apt = apartment_findmain();
1585 if (host_apt)
1586 {
1587 apartment_hwnd = apartment_getwindow(host_apt);
1588 apartment_release(host_apt);
1589 }
1590 }
1591
1592 if (!apartment_hwnd)
1593 {
1594 EnterCriticalSection(&apt->cs);
1595
1596 if (!apt->host_apt_tid)
1597 {
1598 struct host_thread_params thread_params;
1599 HANDLE handles[2];
1600 DWORD wait_value;
1601
1602 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1603 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1604 thread_params.apartment_hwnd = NULL;
1605 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1606 if (!handles[1])
1607 {
1608 CloseHandle(handles[0]);
1609 LeaveCriticalSection(&apt->cs);
1610 return E_OUTOFMEMORY;
1611 }
1612 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1613 CloseHandle(handles[0]);
1614 CloseHandle(handles[1]);
1615 if (wait_value == WAIT_OBJECT_0)
1616 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1617 else
1618 {
1619 LeaveCriticalSection(&apt->cs);
1620 return E_OUTOFMEMORY;
1621 }
1622 }
1623
1624 if (multi_threaded || !main_apartment)
1625 {
1627 apartment_tid = apt->host_apt_tid;
1628 }
1629
1630 LeaveCriticalSection(&apt->cs);
1631 }
1632
1633 /* another thread may have become the main apartment in the time it took
1634 * us to create the thread for the host apartment */
1635 if (!apartment_hwnd && !multi_threaded && main_apartment)
1636 {
1637 APARTMENT *host_apt = apartment_findmain();
1638 if (host_apt)
1639 {
1641 apartment_release(host_apt);
1642 }
1643 }
1644
1645 params.regdata = *regdata;
1646 params.clsid = *rclsid;
1647 params.iid = *riid;
1649 if (FAILED(hr))
1650 return hr;
1651 params.apartment_threaded = !multi_threaded;
1652 if (multi_threaded)
1653 {
1654 params.hr = S_OK;
1655 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1656 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1657 hr = E_OUTOFMEMORY;
1658 else
1659 {
1661 hr = params.hr;
1662 }
1663 CloseHandle(params.event);
1664 }
1665 else
1666 {
1667 if (!apartment_hwnd)
1668 {
1669 ERR("host apartment didn't create window\n");
1670 hr = E_OUTOFMEMORY;
1671 }
1672 else
1674 }
1675 if (SUCCEEDED(hr))
1677 IStream_Release(params.stream);
1678 return hr;
1679}
1680
1681static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1682{
1683 WNDCLASSW wclass;
1684
1685 /* Dispatching to the correct thread in an apartment is done through
1686 * window messages rather than RPC transports. When an interface is
1687 * marshalled into another apartment in the same process, a window of the
1688 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1689 * application) is responsible for pumping the message loop in that thread.
1690 * The WM_USER messages which point to the RPCs are then dispatched to
1691 * apartment_wndproc by the user's code from the apartment in which the
1692 * interface was unmarshalled.
1693 */
1694 memset(&wclass, 0, sizeof(wclass));
1696 wclass.hInstance = hProxyDll;
1698 apt_win_class = RegisterClassW(&wclass);
1699 return TRUE;
1700}
1701
1702/* create a window for the apartment or return the current one if one has
1703 * already been created */
1705{
1706 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1707
1708 if (apt->multi_threaded)
1709 return S_OK;
1710
1711 if (!apt->win)
1712 {
1713 HWND hwnd;
1714
1715 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1716
1717 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1718 HWND_MESSAGE, 0, hProxyDll, NULL);
1719 if (!hwnd)
1720 {
1721 ERR("CreateWindow failed with error %d\n", GetLastError());
1723 }
1725 /* someone beat us to it */
1727 }
1728
1729 return S_OK;
1730}
1731
1732/* retrieves the window for the main- or apartment-threaded apartment */
1734{
1735 assert(!apt->multi_threaded);
1736 return apt->win;
1737}
1738
1739static void COM_TlsDestroy(void)
1740{
1741 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1742 if (info)
1743 {
1744 struct init_spy *cursor, *cursor2;
1745
1746 if (info->apt) apartment_release(info->apt);
1747 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1748 if (info->state) IUnknown_Release(info->state);
1749
1750 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
1751 {
1752 list_remove(&cursor->entry);
1753 if (cursor->spy) IInitializeSpy_Release(cursor->spy);
1755 }
1756
1757 if (info->context_token) IObjContext_Release(info->context_token);
1758
1760 NtCurrentTeb()->ReservedForOle = NULL;
1761 }
1762}
1763
1764/******************************************************************************
1765 * CoBuildVersion [OLE32.@]
1766 *
1767 * Gets the build version of the DLL.
1768 *
1769 * PARAMS
1770 *
1771 * RETURNS
1772 * Current build version, hiword is majornumber, loword is minornumber
1773 */
1775{
1776 TRACE("Returning version %d, build %d.\n", rmm, rup);
1777 return (rmm<<16)+rup;
1778}
1779
1780static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
1781{
1782 struct init_spy *spy;
1783
1784 LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
1785 {
1786 if (id == spy->id && spy->spy)
1787 return spy;
1788 }
1789
1790 return NULL;
1791}
1792
1793/*
1794 * When locked, don't modify list (unless we add a new head), so that it's
1795 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1796 */
1797static inline void lock_init_spies(struct oletls *info)
1798{
1799 info->spies_lock++;
1800}
1801
1802static void unlock_init_spies(struct oletls *info)
1803{
1804 struct init_spy *spy, *next;
1805
1806 if (--info->spies_lock) return;
1807
1809 {
1810 if (spy->spy) continue;
1811 list_remove(&spy->entry);
1812 heap_free(spy);
1813 }
1814}
1815
1816/******************************************************************************
1817 * CoRegisterInitializeSpy [OLE32.@]
1818 *
1819 * Add a Spy that watches CoInitializeEx calls
1820 *
1821 * PARAMS
1822 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1823 * cookie [II] cookie receiver
1824 *
1825 * RETURNS
1826 * Success: S_OK if not already initialized, S_FALSE otherwise.
1827 * Failure: HRESULT code.
1828 *
1829 * SEE ALSO
1830 * CoInitializeEx
1831 */
1833{
1834 struct oletls *info = COM_CurrentInfo();
1835 struct init_spy *entry;
1836 unsigned int id;
1837 HRESULT hr;
1838
1839 TRACE("(%p, %p)\n", spy, cookie);
1840
1841 if (!spy || !cookie || !info)
1842 {
1843 if (!info)
1844 WARN("Could not allocate tls\n");
1845 return E_INVALIDARG;
1846 }
1847
1848 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1849 if (FAILED(hr))
1850 return hr;
1851
1852 entry = heap_alloc(sizeof(*entry));
1853 if (!entry)
1854 {
1855 IInitializeSpy_Release(spy);
1856 return E_OUTOFMEMORY;
1857 }
1858
1859 entry->spy = spy;
1860
1861 id = 0;
1862 while (get_spy_entry(info, id) != NULL)
1863 {
1864 id++;
1865 }
1866
1867 entry->id = id;
1868 list_add_head(&info->spies, &entry->entry);
1869
1870 cookie->s.HighPart = GetCurrentThreadId();
1871 cookie->s.LowPart = entry->id;
1872
1873 return S_OK;
1874}
1875
1876/******************************************************************************
1877 * CoRevokeInitializeSpy [OLE32.@]
1878 *
1879 * Remove a spy that previously watched CoInitializeEx calls
1880 *
1881 * PARAMS
1882 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1883 *
1884 * RETURNS
1885 * Success: S_OK if a spy is removed
1886 * Failure: E_INVALIDARG
1887 *
1888 * SEE ALSO
1889 * CoInitializeEx
1890 */
1892{
1893 struct oletls *info = COM_CurrentInfo();
1894 struct init_spy *spy;
1895
1896 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1897
1898 if (!info || cookie.s.HighPart != GetCurrentThreadId())
1899 return E_INVALIDARG;
1900
1901 if (!(spy = get_spy_entry(info, cookie.s.LowPart))) return E_INVALIDARG;
1902
1903 IInitializeSpy_Release(spy->spy);
1904 spy->spy = NULL;
1905 if (!info->spies_lock)
1906 {
1907 list_remove(&spy->entry);
1908 heap_free(spy);
1909 }
1910 return S_OK;
1911}
1912
1914{
1915 HRESULT hr = S_OK;
1916
1917 if (!info->apt)
1918 {
1919 if (!apartment_get_or_create( model ))
1920 return E_OUTOFMEMORY;
1921 }
1922 else if (!apartment_is_model( info->apt, model ))
1923 {
1924 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1925 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1926 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1927 return RPC_E_CHANGED_MODE;
1928 }
1929 else
1930 hr = S_FALSE;
1931
1932 info->inits++;
1933
1934 return hr;
1935}
1936
1938{
1939 if (!--info->inits)
1940 {
1941 if (info->ole_inits)
1942 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1943 apartment_release( info->apt );
1944 info->apt = NULL;
1945 }
1946}
1947
1948/******************************************************************************
1949 * CoInitialize [OLE32.@]
1950 *
1951 * Initializes the COM libraries by calling CoInitializeEx with
1952 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1953 *
1954 * PARAMS
1955 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1956 *
1957 * RETURNS
1958 * Success: S_OK if not already initialized, S_FALSE otherwise.
1959 * Failure: HRESULT code.
1960 *
1961 * SEE ALSO
1962 * CoInitializeEx
1963 */
1965{
1966 /*
1967 * Just delegate to the newer method.
1968 */
1969 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1970}
1971
1972/******************************************************************************
1973 * CoInitializeEx [OLE32.@]
1974 *
1975 * Initializes the COM libraries.
1976 *
1977 * PARAMS
1978 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1979 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1980 *
1981 * RETURNS
1982 * S_OK if successful,
1983 * S_FALSE if this function was called already.
1984 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1985 * threading model.
1986 *
1987 * NOTES
1988 *
1989 * The behavior used to set the IMalloc used for memory management is
1990 * obsolete.
1991 * The dwCoInit parameter must specify one of the following apartment
1992 * threading models:
1993 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1994 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1995 * The parameter may also specify zero or more of the following flags:
1996 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1997 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1998 *
1999 * SEE ALSO
2000 * CoUninitialize
2001 */
2003{
2004 struct oletls *info = COM_CurrentInfo();
2005 struct init_spy *cursor;
2006 HRESULT hr;
2007
2008 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
2009
2010 if (lpReserved!=NULL)
2011 {
2012 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
2013 }
2014
2015 /*
2016 * Check the lock count. If this is the first time going through the initialize
2017 * process, we have to initialize the libraries.
2018 *
2019 * And crank-up that lock count.
2020 */
2022 {
2023 /*
2024 * Initialize the various COM libraries and data structures.
2025 */
2026 TRACE("() - Initializing the COM libraries\n");
2027
2028 /* we may need to defer this until after apartment initialisation */
2030 }
2031
2033 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2034 {
2035 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
2036 }
2038
2040
2042 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2043 {
2044 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
2045 }
2047
2048 return hr;
2049}
2050
2051/***********************************************************************
2052 * CoUninitialize [OLE32.@]
2053 *
2054 * This method will decrement the refcount on the current apartment, freeing
2055 * the resources associated with it if it is the last thread in the apartment.
2056 * If the last apartment is freed, the function will additionally release
2057 * any COM resources associated with the process.
2058 *
2059 * PARAMS
2060 *
2061 * RETURNS
2062 * Nothing.
2063 *
2064 * SEE ALSO
2065 * CoInitializeEx
2066 */
2068{
2069 struct oletls * info = COM_CurrentInfo();
2070 struct init_spy *cursor, *next;
2071 LONG lCOMRefCnt;
2072
2073 TRACE("()\n");
2074
2075 /* will only happen on OOM */
2076 if (!info) return;
2077
2080 {
2081 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2082 }
2084
2085 /* sanity check */
2086 if (!info->inits)
2087 {
2088 ERR("Mismatched CoUninitialize\n");
2089
2092 {
2093 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2094 }
2096
2097 return;
2098 }
2099
2101
2102 /*
2103 * Decrease the reference count.
2104 * If we are back to 0 locks on the COM library, make sure we free
2105 * all the associated data structures.
2106 */
2107 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2108 if (lCOMRefCnt==1)
2109 {
2110 TRACE("() - Releasing the COM libraries\n");
2111
2114 }
2115 else if (lCOMRefCnt<1) {
2116 ERR( "CoUninitialize() - not CoInitialized.\n" );
2117 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2118 }
2119
2121 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2122 {
2123 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2124 }
2126}
2127
2128/******************************************************************************
2129 * CoDisconnectObject [OLE32.@]
2130 *
2131 * Disconnects all connections to this object from remote processes. Dispatches
2132 * pending RPCs while blocking new RPCs from occurring, and then calls
2133 * IMarshal::DisconnectObject on the given object.
2134 *
2135 * Typically called when the object server is forced to shut down, for instance by
2136 * the user.
2137 *
2138 * PARAMS
2139 * lpUnk [I] The object whose stub should be disconnected.
2140 * reserved [I] Reserved. Should be set to 0.
2141 *
2142 * RETURNS
2143 * Success: S_OK.
2144 * Failure: HRESULT code.
2145 *
2146 * SEE ALSO
2147 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2148 */
2150{
2151 struct stub_manager *manager;
2152 HRESULT hr;
2153 IMarshal *marshal;
2154 APARTMENT *apt;
2155
2156 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2157
2158 if (!lpUnk) return E_INVALIDARG;
2159
2160 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2161 if (hr == S_OK)
2162 {
2163 hr = IMarshal_DisconnectObject(marshal, reserved);
2164 IMarshal_Release(marshal);
2165 return hr;
2166 }
2167
2169 {
2170 ERR("apartment not initialised\n");
2171 return CO_E_NOTINITIALIZED;
2172 }
2173
2174 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2175 if (manager) {
2176 stub_manager_disconnect(manager);
2177 /* Release stub manager twice, to remove the apartment reference. */
2178 stub_manager_int_release(manager);
2179 stub_manager_int_release(manager);
2180 }
2181
2182 /* Note: native is pretty broken here because it just silently
2183 * fails, without returning an appropriate error code if the object was
2184 * not found, making apps think that the object was disconnected, when
2185 * it actually wasn't */
2186
2188 return S_OK;
2189}
2190
2191/******************************************************************************
2192 * CoCreateGuid [OLE32.@]
2193 *
2194 * Simply forwards to UuidCreate in RPCRT4.
2195 *
2196 * PARAMS
2197 * pguid [O] Points to the GUID to initialize.
2198 *
2199 * RETURNS
2200 * Success: S_OK.
2201 * Failure: HRESULT code.
2202 *
2203 * SEE ALSO
2204 * UuidCreate
2205 */
2207{
2208 DWORD status;
2209
2210 if(!pguid) return E_INVALIDARG;
2211
2212 status = UuidCreate(pguid);
2213 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2214 return HRESULT_FROM_WIN32( status );
2215}
2216
2217static inline BOOL is_valid_hex(WCHAR c)
2218{
2219 if (!(((c >= '0') && (c <= '9')) ||
2220 ((c >= 'a') && (c <= 'f')) ||
2221 ((c >= 'A') && (c <= 'F'))))
2222 return FALSE;
2223 return TRUE;
2224}
2225
2226static const BYTE guid_conv_table[256] =
2227{
2228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2231 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2232 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2234 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2235};
2236
2237/* conversion helper for CLSIDFromString/IIDFromString */
2239{
2240 int i;
2241
2242 if (!s || s[0]!='{') {
2243 memset( id, 0, sizeof (CLSID) );
2244 if(!s) return TRUE;
2245 return FALSE;
2246 }
2247
2248 TRACE("%s -> %p\n", debugstr_w(s), id);
2249
2250 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2251
2252 id->Data1 = 0;
2253 for (i = 1; i < 9; i++) {
2254 if (!is_valid_hex(s[i])) return FALSE;
2255 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2256 }
2257 if (s[9]!='-') return FALSE;
2258
2259 id->Data2 = 0;
2260 for (i = 10; i < 14; i++) {
2261 if (!is_valid_hex(s[i])) return FALSE;
2262 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2263 }
2264 if (s[14]!='-') return FALSE;
2265
2266 id->Data3 = 0;
2267 for (i = 15; i < 19; i++) {
2268 if (!is_valid_hex(s[i])) return FALSE;
2269 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2270 }
2271 if (s[19]!='-') return FALSE;
2272
2273 for (i = 20; i < 37; i+=2) {
2274 if (i == 24) {
2275 if (s[i]!='-') return FALSE;
2276 i++;
2277 }
2278 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2279 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2280 }
2281
2282 if (s[37] == '}' && s[38] == '\0')
2283 return TRUE;
2284
2285 return FALSE;
2286}
2287
2288/*****************************************************************************/
2289
2291{
2292 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2293 WCHAR buf2[CHARS_IN_GUID];
2294 LONG buf2len = sizeof(buf2);
2295 HKEY xhkey;
2296 WCHAR *buf;
2297
2298 memset(clsid, 0, sizeof(*clsid));
2299 buf = HeapAlloc( GetProcessHeap(),0,(lstrlenW(progid)+8) * sizeof(WCHAR) );
2300 if (!buf) return E_OUTOFMEMORY;
2301 lstrcpyW( buf, progid );
2302 lstrcatW( buf, clsidW );
2304 {
2306 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2307 return CO_E_CLASSSTRING;
2308 }
2310
2311 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2312 {
2313 RegCloseKey(xhkey);
2314 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2315 return CO_E_CLASSSTRING;
2316 }
2317 RegCloseKey(xhkey);
2318 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2319}
2320
2321/******************************************************************************
2322 * CLSIDFromString [OLE32.@]
2323 *
2324 * Converts a unique identifier from its string representation into
2325 * the GUID struct.
2326 *
2327 * PARAMS
2328 * idstr [I] The string representation of the GUID.
2329 * id [O] GUID converted from the string.
2330 *
2331 * RETURNS
2332 * S_OK on success
2333 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2334 *
2335 * SEE ALSO
2336 * StringFromCLSID
2337 */
2339{
2341 CLSID tmp_id;
2342
2343 if (!id)
2344 return E_INVALIDARG;
2345
2346 if (guid_from_string(idstr, id))
2347 return S_OK;
2348
2349 /* It appears a ProgID is also valid */
2350 ret = clsid_from_string_reg(idstr, &tmp_id);
2351 if(SUCCEEDED(ret))
2352 *id = tmp_id;
2353
2354 return ret;
2355}
2356
2357/******************************************************************************
2358 * IIDFromString [OLE32.@]
2359 *
2360 * Converts an interface identifier from its string representation to
2361 * the IID struct.
2362 *
2363 * PARAMS
2364 * idstr [I] The string representation of the GUID.
2365 * id [O] IID converted from the string.
2366 *
2367 * RETURNS
2368 * S_OK on success
2369 * CO_E_IIDSTRING if idstr is not a valid IID
2370 *
2371 * SEE ALSO
2372 * StringFromIID
2373 */
2375{
2376 TRACE("%s -> %p\n", debugstr_w(s), iid);
2377
2378 if (!s)
2379 {
2380 memset(iid, 0, sizeof(*iid));
2381 return S_OK;
2382 }
2383
2384 /* length mismatch is a special case */
2385 if (lstrlenW(s) + 1 != CHARS_IN_GUID)
2386 return E_INVALIDARG;
2387
2388 if (s[0] != '{')
2389 return CO_E_IIDSTRING;
2390
2391 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2392}
2393
2394/******************************************************************************
2395 * StringFromCLSID [OLE32.@]
2396 * StringFromIID [OLE32.@]
2397 *
2398 * Converts a GUID into the respective string representation.
2399 * The target string is allocated using the OLE IMalloc.
2400 *
2401 * PARAMS
2402 * id [I] the GUID to be converted.
2403 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2404 *
2405 * RETURNS
2406 * S_OK
2407 * E_FAIL
2408 *
2409 * SEE ALSO
2410 * StringFromGUID2, CLSIDFromString
2411 */
2413{
2414 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2415 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2416 return S_OK;
2417}
2418
2419/******************************************************************************
2420 * StringFromGUID2 [OLE32.@]
2421 *
2422 * Modified version of StringFromCLSID that allows you to specify max
2423 * buffer size.
2424 *
2425 * PARAMS
2426 * id [I] GUID to convert to string.
2427 * str [O] Buffer where the result will be stored.
2428 * cmax [I] Size of the buffer in characters.
2429 *
2430 * RETURNS
2431 * Success: The length of the resulting string in characters.
2432 * Failure: 0.
2433 */
2435{
2436 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2437 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2438 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2439 '%','0','2','X','%','0','2','X','}',0 };
2440 if (!id || cmax < CHARS_IN_GUID) return 0;
2441 swprintf( str, formatW, id->Data1, id->Data2, id->Data3,
2442 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2443 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2444 return CHARS_IN_GUID;
2445}
2446
2447/* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2449{
2450 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2451 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2452 LONG res;
2453 HKEY key;
2454
2455 lstrcpyW(path, wszCLSIDSlash);
2456 StringFromGUID2(clsid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
2459 return REGDB_E_CLASSNOTREG;
2460 else if (res != ERROR_SUCCESS)
2461 return REGDB_E_READREGDB;
2462
2463 if (!keyname)
2464 {
2465 *subkey = key;
2466 return S_OK;
2467 }
2468
2469 res = open_classes_key(key, keyname, access, subkey);
2472 return REGDB_E_KEYMISSING;
2473 else if (res != ERROR_SUCCESS)
2474 return REGDB_E_READREGDB;
2475
2476 return S_OK;
2477}
2478
2479/* open HKCR\\AppId\\{string form of appid clsid} key */
2481{
2482 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2483 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2484 DWORD res;
2486 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2487 DWORD size;
2488 HKEY hkey;
2489 DWORD type;
2490 HRESULT hr;
2491
2492 /* read the AppID value under the class's key */
2494 if (FAILED(hr))
2495 return hr;
2496
2497 size = sizeof(buf);
2498 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2499 RegCloseKey(hkey);
2501 return REGDB_E_KEYMISSING;
2502 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2503 return REGDB_E_READREGDB;
2504
2505 lstrcpyW(keyname, szAppIdKey);
2506 lstrcatW(keyname, buf);
2507 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2509 return REGDB_E_KEYMISSING;
2510 else if (res != ERROR_SUCCESS)
2511 return REGDB_E_READREGDB;
2512
2513 return S_OK;
2514}
2515
2516/******************************************************************************
2517 * ProgIDFromCLSID [OLE32.@]
2518 *
2519 * Converts a class id into the respective program ID.
2520 *
2521 * PARAMS
2522 * clsid [I] Class ID, as found in registry.
2523 * ppszProgID [O] Associated ProgID.
2524 *
2525 * RETURNS
2526 * S_OK
2527 * E_OUTOFMEMORY
2528 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2529 */
2531{
2532 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2533 ACTCTX_SECTION_KEYED_DATA data;
2534 HKEY hkey;
2535 HRESULT ret;
2536 LONG progidlen = 0;
2537
2538 if (!ppszProgID)
2539 return E_INVALIDARG;
2540
2541 *ppszProgID = NULL;
2542
2543 data.cbSize = sizeof(data);
2544 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2545 clsid, &data))
2546 {
2547 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2548 if (comclass->progid_len)
2549 {
2550 WCHAR *ptrW;
2551
2552 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2553 if (!*ppszProgID) return E_OUTOFMEMORY;
2554
2555 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2556 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2557 return S_OK;
2558 }
2559 else
2560 return REGDB_E_CLASSNOTREG;
2561 }
2562
2563 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2564 if (FAILED(ret))
2565 return ret;
2566
2567 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2569
2570 if (ret == S_OK)
2571 {
2572 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2573 if (*ppszProgID)
2574 {
2575 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2577 CoTaskMemFree(*ppszProgID);
2578 *ppszProgID = NULL;
2579 }
2580 }
2581 else
2583 }
2584
2585 RegCloseKey(hkey);
2586 return ret;
2587}
2588
2589/******************************************************************************
2590 * CLSIDFromProgID [OLE32.@]
2591 *
2592 * Converts a program id into the respective GUID.
2593 *
2594 * PARAMS
2595 * progid [I] Unicode program ID, as found in registry.
2596 * clsid [O] Associated CLSID.
2597 *
2598 * RETURNS
2599 * Success: S_OK
2600 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2601 */
2603{
2604 ACTCTX_SECTION_KEYED_DATA data;
2605
2606 if (!progid || !clsid)
2607 return E_INVALIDARG;
2608
2609 data.cbSize = sizeof(data);
2610 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2611 progid, &data))
2612 {
2613 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2614 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2615 *clsid = *alias;
2616 return S_OK;
2617 }
2618
2620}
2621
2622/******************************************************************************
2623 * CLSIDFromProgIDEx [OLE32.@]
2624 */
2626{
2627 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2628
2629 return CLSIDFromProgID(progid, clsid);
2630}
2631
2633{
2634 HKEY hkey;
2636 DWORD len;
2637
2638 access |= KEY_READ;
2639
2641 return REGDB_E_IIDNOTREG;
2642
2643 len = sizeof(value);
2644 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2645 return REGDB_E_IIDNOTREG;
2646 RegCloseKey(hkey);
2647
2648 if (CLSIDFromString(value, pclsid) != NOERROR)
2649 return REGDB_E_IIDNOTREG;
2650
2651 return S_OK;
2652}
2653
2654/*****************************************************************************
2655 * CoGetPSClsid [OLE32.@]
2656 *
2657 * Retrieves the CLSID of the proxy/stub factory that implements
2658 * IPSFactoryBuffer for the specified interface.
2659 *
2660 * PARAMS
2661 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2662 * pclsid [O] Where to store returned proxy/stub CLSID.
2663 *
2664 * RETURNS
2665 * S_OK
2666 * E_OUTOFMEMORY
2667 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2668 *
2669 * NOTES
2670 *
2671 * The standard marshaller activates the object with the CLSID
2672 * returned and uses the CreateProxy and CreateStub methods on its
2673 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2674 * given object.
2675 *
2676 * CoGetPSClsid determines this CLSID by searching the
2677 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2678 * in the registry and any interface id registered by
2679 * CoRegisterPSClsid within the current process.
2680 *
2681 * BUGS
2682 *
2683 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2684 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2685 * considered a bug in native unless an application depends on this (unlikely).
2686 *
2687 * SEE ALSO
2688 * CoRegisterPSClsid.
2689 */
2691{
2692 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2693 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2694 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2695 APARTMENT *apt;
2697 ACTCTX_SECTION_KEYED_DATA data;
2698 HRESULT hr;
2699 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2700 BOOL is_wow64;
2701
2702 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2703
2704 if (!(apt = apartment_get_current_or_mta()))
2705 {
2706 ERR("apartment not initialised\n");
2707 return CO_E_NOTINITIALIZED;
2708 }
2709 apartment_release(apt);
2710
2711 if (!pclsid)
2712 return E_INVALIDARG;
2713
2715
2718 {
2719 *pclsid = registered_psclsid->clsid;
2721 return S_OK;
2722 }
2723
2725
2726 data.cbSize = sizeof(data);
2727 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2728 riid, &data))
2729 {
2730 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2731 *pclsid = ifaceps->iid;
2732 return S_OK;
2733 }
2734
2735 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2736 lstrcpyW(path, wszInterface);
2737 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2738 lstrcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2739
2740 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2741 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2743 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2744
2745 if (hr == S_OK)
2746 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2747 else
2748 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2749
2750 return hr;
2751}
2752
2753/*****************************************************************************
2754 * CoRegisterPSClsid [OLE32.@]
2755 *
2756 * Register a proxy/stub CLSID for the given interface in the current process
2757 * only.
2758 *
2759 * PARAMS
2760 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2761 * rclsid [I] CLSID of the proxy/stub.
2762 *
2763 * RETURNS
2764 * Success: S_OK
2765 * Failure: E_OUTOFMEMORY
2766 *
2767 * NOTES
2768 *
2769 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2770 * will be returned from other apartments in the same process.
2771 *
2772 * This function does not add anything to the registry and the effects are
2773 * limited to the lifetime of the current process.
2774 *
2775 * SEE ALSO
2776 * CoGetPSClsid.
2777 */
2779{
2780 APARTMENT *apt;
2782
2783 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2784
2785 if (!(apt = apartment_get_current_or_mta()))
2786 {
2787 ERR("apartment not initialised\n");
2788 return CO_E_NOTINITIALIZED;
2789 }
2790 apartment_release(apt);
2791
2793
2796 {
2797 registered_psclsid->clsid = *rclsid;
2799 return S_OK;
2800 }
2801
2803 if (!registered_psclsid)
2804 {
2806 return E_OUTOFMEMORY;
2807 }
2808
2810 registered_psclsid->clsid = *rclsid;
2812
2814
2815 return S_OK;
2816}
2817
2818
2819/***
2820 * COM_GetRegisteredClassObject
2821 *
2822 * This internal method is used to scan the registered class list to
2823 * find a class object.
2824 *
2825 * Params:
2826 * rclsid Class ID of the class to find.
2827 * dwClsContext Class context to match.
2828 * ppv [out] returns a pointer to the class object. Complying
2829 * to normal COM usage, this method will increase the
2830 * reference count on this object.
2831 */
2833 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2834{
2835 HRESULT hr = S_FALSE;
2836 RegisteredClass *curClass;
2837
2839
2841 {
2842 /*
2843 * Check if we have a match on the class ID and context.
2844 */
2845 if ((apt->oxid == curClass->apartment_id) &&
2846 (dwClsContext & curClass->runContext) &&
2847 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2848 {
2849 /*
2850 * We have a match, return the pointer to the class object.
2851 */
2852 *ppUnk = curClass->classObject;
2853
2854 IUnknown_AddRef(curClass->classObject);
2855
2856 hr = S_OK;
2857 break;
2858 }
2859 }
2860
2862
2863 return hr;
2864}
2865
2866/******************************************************************************
2867 * CoRegisterClassObject [OLE32.@]
2868 *
2869 * Registers the class object for a given class ID. Servers housed in EXE
2870 * files use this method instead of exporting DllGetClassObject to allow
2871 * other code to connect to their objects.
2872 *
2873 * PARAMS
2874 * rclsid [I] CLSID of the object to register.
2875 * pUnk [I] IUnknown of the object.
2876 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2877 * flags [I] REGCLS flags indicating how connections are made.
2878 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2879 *
2880 * RETURNS
2881 * S_OK on success,
2882 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2883 * CO_E_OBJISREG if the object is already registered. We should not return this.
2884 *
2885 * SEE ALSO
2886 * CoRevokeClassObject, CoGetClassObject
2887 *
2888 * NOTES
2889 * In-process objects are only registered for the current apartment.
2890 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2891 * in other apartments.
2892 *
2893 * BUGS
2894 * MSDN claims that multiple interface registrations are legal, but we
2895 * can't do that with our current implementation.
2896 */
2898 REFCLSID rclsid,
2900 DWORD dwClsContext,
2901 DWORD flags,
2902 LPDWORD lpdwRegister)
2903{
2904 static LONG next_cookie;
2905 RegisteredClass* newClass;
2906 LPUNKNOWN foundObject;
2907 HRESULT hr;
2908 APARTMENT *apt;
2909
2910 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2911 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2912
2913 if ( (lpdwRegister==0) || (pUnk==0) )
2914 return E_INVALIDARG;
2915
2916 if (!(apt = apartment_get_current_or_mta()))
2917 {
2918 ERR("COM was not initialized\n");
2919 return CO_E_NOTINITIALIZED;
2920 }
2921
2922 *lpdwRegister = 0;
2923
2924 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2925 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2927 dwClsContext |= CLSCTX_INPROC_SERVER;
2928
2929 /*
2930 * First, check if the class is already registered.
2931 * If it is, this should cause an error.
2932 */
2933 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2934 if (hr == S_OK) {
2935 if (flags & REGCLS_MULTIPLEUSE) {
2936 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2937 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2938 IUnknown_Release(foundObject);
2939 apartment_release(apt);
2940 return hr;
2941 }
2942 IUnknown_Release(foundObject);
2943 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2944 apartment_release(apt);
2945 return CO_E_OBJISREG;
2946 }
2947
2948 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2949 if ( newClass == NULL )
2950 {
2951 apartment_release(apt);
2952 return E_OUTOFMEMORY;
2953 }
2954
2955 newClass->classIdentifier = *rclsid;
2956 newClass->apartment_id = apt->oxid;
2957 newClass->runContext = dwClsContext;
2958 newClass->connectFlags = flags;
2959 newClass->RpcRegistration = NULL;
2960
2961 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2962 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2963
2964 /*
2965 * Since we're making a copy of the object pointer, we have to increase its
2966 * reference count.
2967 */
2968 newClass->classObject = pUnk;
2969 IUnknown_AddRef(newClass->classObject);
2970
2974
2975 *lpdwRegister = newClass->dwCookie;
2976
2977 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2978 IStream *marshal_stream;
2979
2980 hr = get_local_server_stream(apt, &marshal_stream);
2981 if(FAILED(hr))
2982 {
2983 apartment_release(apt);
2984 return hr;
2985 }
2986
2988 marshal_stream,
2990 &newClass->RpcRegistration);
2991 IStream_Release(marshal_stream);
2992 }
2993 apartment_release(apt);
2994 return S_OK;
2995}
2996
2998{
2999 if (data->hkey)
3000 {
3001 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
3002 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
3003 static const WCHAR wszFree[] = {'F','r','e','e',0};
3004 static const WCHAR wszBoth[] = {'B','o','t','h',0};
3005 WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */];
3006 DWORD dwLength = sizeof(threading_model);
3007 DWORD keytype;
3008 DWORD ret;
3009
3010 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
3011 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
3012 threading_model[0] = '\0';
3013
3014 if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment;
3015 if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free;
3016 if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both;
3017
3018 /* there's not specific handling for this case */
3019 if (threading_model[0]) return ThreadingModel_Neutral;
3020 return ThreadingModel_No;
3021 }
3022 else
3023 return data->u.actctx.data->model;
3024}
3025
3026static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
3027 REFCLSID rclsid, REFIID riid,
3028 BOOL hostifnecessary, void **ppv)
3029{
3031 BOOL apartment_threaded;
3032
3033 if (hostifnecessary)
3034 {
3035 enum comclass_threadingmodel model = get_threading_model(regdata);
3036
3037 if (model == ThreadingModel_Apartment)
3038 {
3039 apartment_threaded = TRUE;
3040 if (apt->multi_threaded)
3041 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
3042 }
3043 else if (model == ThreadingModel_Free)
3044 {
3045 apartment_threaded = FALSE;
3046 if (!apt->multi_threaded)
3047 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
3048 }
3049 /* everything except "Apartment", "Free" and "Both" */
3050 else if (model != ThreadingModel_Both)
3051 {
3052 apartment_threaded = TRUE;
3053 /* everything else is main-threaded */
3054 if (model != ThreadingModel_No)
3055 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
3056
3057 if (apt->multi_threaded || !apt->main)
3058 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
3059 }
3060 else
3061 apartment_threaded = FALSE;
3062 }
3063 else
3064 apartment_threaded = !apt->multi_threaded;
3065
3067 {
3068 /* failure: CLSID is not found in registry */
3069 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
3070 return REGDB_E_CLASSNOTREG;
3071 }
3072
3073 return apartment_getclassobject(apt, dllpath, apartment_threaded,
3074 rclsid, riid, ppv);
3075}
3076
3077/***********************************************************************
3078 * CoGetClassObject [OLE32.@]
3079 *
3080 * Creates an object of the specified class.
3081 *
3082 * PARAMS
3083 * rclsid [I] Class ID to create an instance of.
3084 * dwClsContext [I] Flags to restrict the location of the created instance.
3085 * pServerInfo [I] Optional. Details for connecting to a remote server.
3086 * iid [I] The ID of the interface of the instance to return.
3087 * ppv [O] On returns, contains a pointer to the specified interface of the object.
3088 *
3089 * RETURNS
3090 * Success: S_OK
3091 * Failure: HRESULT code.
3092 *
3093 * NOTES
3094 * The dwClsContext parameter can be one or more of the following:
3095 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3096 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3097 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3098 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3099 *
3100 * SEE ALSO
3101 * CoCreateInstance()
3102 */
3104 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3105 REFIID iid, LPVOID *ppv)
3106{
3107 struct class_reg_data clsreg;
3108 IUnknown *regClassObject;
3110 APARTMENT *apt;
3111
3112 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3113
3114 if (!ppv)
3115 return E_INVALIDARG;
3116
3117 *ppv = NULL;
3118
3119 if (!(apt = apartment_get_current_or_mta()))
3120 {
3121 ERR("apartment not initialised\n");
3122 return CO_E_NOTINITIALIZED;
3123 }
3124
3125 if (pServerInfo) {
3126 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3127 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3128 }
3129
3130 if (CLSCTX_INPROC_SERVER & dwClsContext)
3131 {
3133 {
3134 apartment_release(apt);
3135 return FTMarshalCF_Create(iid, ppv);
3136 }
3137 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3138 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3139 }
3140
3141 if (CLSCTX_INPROC & dwClsContext)
3142 {
3143 ACTCTX_SECTION_KEYED_DATA data;
3144
3145 data.cbSize = sizeof(data);
3146 /* search activation context first */
3147 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3148 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3149 rclsid, &data))
3150 {
3151 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3152
3153 clsreg.u.actctx.hactctx = data.hActCtx;
3154 clsreg.u.actctx.data = data.lpData;
3155 clsreg.u.actctx.section = data.lpSectionBase;
3156 clsreg.hkey = FALSE;
3157
3158 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3159 ReleaseActCtx(data.hActCtx);
3160 apartment_release(apt);
3161 return hres;
3162 }
3163 }
3164
3165 /*
3166 * First, try and see if we can't match the class ID with one of the
3167 * registered classes.
3168 */
3169 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3170 &regClassObject))
3171 {
3172 /* Get the required interface from the retrieved pointer. */
3173 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3174
3175 /*
3176 * Since QI got another reference on the pointer, we want to release the
3177 * one we already have. If QI was unsuccessful, this will release the object. This
3178 * is good since we are not returning it in the "out" parameter.
3179 */
3180 IUnknown_Release(regClassObject);
3181 apartment_release(apt);
3182 return hres;
3183 }
3184
3185 /* First try in-process server */
3186 if (CLSCTX_INPROC_SERVER & dwClsContext)
3187 {
3188 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3189 HKEY hkey;
3190
3191 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3192 if (FAILED(hres))
3193 {
3195 ERR("class %s not registered\n", debugstr_guid(rclsid));
3196 else if (hres == REGDB_E_KEYMISSING)
3197 {
3198 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3200 }
3201 }
3202
3203 if (SUCCEEDED(hres))
3204 {
3205 clsreg.u.hkey = hkey;
3206 clsreg.hkey = TRUE;
3207
3208 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3209 RegCloseKey(hkey);
3210 }
3211
3212 /* return if we got a class, otherwise fall through to one of the
3213 * other types */
3214 if (SUCCEEDED(hres))
3215 {
3216 apartment_release(apt);
3217 return hres;
3218 }
3219 }
3220
3221 /* Next try in-process handler */
3222 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3223 {
3224 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3225 HKEY hkey;
3226
3227 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3228 if (FAILED(hres))
3229 {
3231 ERR("class %s not registered\n", debugstr_guid(rclsid));
3232 else if (hres == REGDB_E_KEYMISSING)
3233 {
3234 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3236 }
3237 }
3238
3239 if (SUCCEEDED(hres))
3240 {
3241 clsreg.u.hkey = hkey;
3242 clsreg.hkey = TRUE;
3243
3244 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3245 RegCloseKey(hkey);
3246 }
3247
3248 /* return if we got a class, otherwise fall through to one of the
3249 * other types */
3250 if (SUCCEEDED(hres))
3251 {
3252 apartment_release(apt);
3253 return hres;
3254 }
3255 }
3256 apartment_release(apt);
3257
3258 /* Next try out of process */
3259 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3260 {
3261 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3262 if (SUCCEEDED(hres))
3263 return hres;
3264 }
3265
3266 /* Finally try remote: this requires networked DCOM (a lot of work) */
3267 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3268 {
3269 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3271 }
3272
3273 if (FAILED(hres))
3274 ERR("no class object %s could be created for context 0x%x\n",
3275 debugstr_guid(rclsid), dwClsContext);
3276 return hres;
3277}
3278
3279/***********************************************************************
3280 * CoResumeClassObjects (OLE32.@)
3281 *
3282 * Resumes all class objects registered with REGCLS_SUSPENDED.
3283 *
3284 * RETURNS
3285 * Success: S_OK.
3286 * Failure: HRESULT code.
3287 */
3289{
3290 FIXME("stub\n");
3291 return S_OK;
3292}
3293
3294/***********************************************************************
3295 * CoCreateInstance [OLE32.@]
3296 *
3297 * Creates an instance of the specified class.
3298 *
3299 * PARAMS
3300 * rclsid [I] Class ID to create an instance of.
3301 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3302 * dwClsContext [I] Flags to restrict the location of the created instance.
3303 * iid [I] The ID of the interface of the instance to return.
3304 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3305 *
3306 * RETURNS
3307 * Success: S_OK
3308 * Failure: HRESULT code.
3309 *
3310 * NOTES
3311 * The dwClsContext parameter can be one or more of the following:
3312 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3313 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3314 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3315 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3316 *
3317 * Aggregation is the concept of deferring the IUnknown of an object to another
3318 * object. This allows a separate object to behave as though it was part of
3319 * the object and to allow this the pUnkOuter parameter can be set. Note that
3320 * not all objects support having an outer of unknown.
3321 *
3322 * SEE ALSO
3323 * CoGetClassObject()
3324 */
3326 REFCLSID rclsid,
3327 LPUNKNOWN pUnkOuter,
3328 DWORD dwClsContext,
3329 REFIID iid,
3330 LPVOID *ppv)
3331{
3332 MULTI_QI multi_qi = { iid };
3333 HRESULT hres;
3334
3335 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3336 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3337
3338 if (ppv==0)
3339 return E_POINTER;
3340
3341 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3342 *ppv = multi_qi.pItf;
3343 return hres;
3344}
3345
3346static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3347{
3348 ULONG i;
3349
3350 for (i = 0; i < count; i++)
3351 {
3352 mqi[i].pItf = NULL;
3353 mqi[i].hr = hr;
3354 }
3355}
3356
3357static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3358{
3359 ULONG index = 0, fetched = 0;
3360
3361 if (include_unk)
3362 {
3363 mqi[0].hr = S_OK;
3364 mqi[0].pItf = unk;
3365 index = fetched = 1;
3366 }
3367
3368 for (; index < count; index++)
3369 {
3370 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3371 if (mqi[index].hr == S_OK)
3372 fetched++;
3373 }
3374
3375 if (!include_unk)
3376 IUnknown_Release(unk);
3377
3378 if (fetched == 0)
3379 return E_NOINTERFACE;
3380
3381 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3382}
3383
3384/***********************************************************************
3385 * CoCreateInstanceEx [OLE32.@]
3386 */
3388 REFCLSID rclsid,
3389 LPUNKNOWN pUnkOuter,
3390 DWORD dwClsContext,
3391 COSERVERINFO* pServerInfo,
3392 ULONG cmq,
3393 MULTI_QI* pResults)
3394{
3395 IUnknown *unk = NULL;
3397 APARTMENT *apt;
3398 CLSID clsid;
3399 HRESULT hres;
3400
3401 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3402
3403 if (!cmq || !pResults)
3404 return E_INVALIDARG;
3405
3406 if (pServerInfo)
3407 FIXME("() non-NULL pServerInfo not supported!\n");
3408
3409 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3410
3411 hres = CoGetTreatAsClass(rclsid, &clsid);
3412 if(FAILED(hres))
3413 clsid = *rclsid;
3414
3415 if (!(apt = apartment_get_current_or_mta()))
3416 {
3417 ERR("apartment not initialised\n");
3418 return CO_E_NOTINITIALIZED;
3419 }
3420 apartment_release(apt);
3421
3422 /*
3423 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3424 */
3426 {
3428 TRACE("Retrieving GIT\n");
3429 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3430 }
3431
3433 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3434 if (FAILED(hres))
3435 return hres;
3436 return return_multi_qi(unk, cmq, pResults, TRUE);
3437 }
3438
3439 /*
3440 * Get a class factory to construct the object we want.
3441 */
3442 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3443 if (FAILED(hres))
3444 return hres;
3445
3446 /*
3447 * Create the object and don't forget to release the factory
3448 */
3449 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3450 IClassFactory_Release(cf);
3451 if (FAILED(hres))
3452 {
3453 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3454 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3455 else
3456 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3457 debugstr_guid(pResults[0].pIID),
3459 return hres;
3460 }
3461
3462 return return_multi_qi(unk, cmq, pResults, TRUE);
3463}
3464
3465/***********************************************************************
3466 * CoGetInstanceFromFile [OLE32.@]
3467 */
3470 CLSID *rclsid,
3471 IUnknown *outer,
3472 DWORD cls_context,
3473 DWORD grfmode,
3475 DWORD count,
3476 MULTI_QI *results
3477)
3478{
3479 IPersistFile *pf = NULL;
3480 IUnknown* unk = NULL;
3481 CLSID clsid;
3482 HRESULT hr;
3483
3484 if (count == 0 || !results)
3485 return E_INVALIDARG;
3486
3487 if (server_info)
3488 FIXME("() non-NULL server_info not supported\n");
3489
3491
3492 /* optionally get CLSID from a file */
3493 if (!rclsid)
3494 {
3496 if (FAILED(hr))
3497 {
3498 ERR("failed to get CLSID from a file\n");
3499 return hr;
3500 }
3501
3502 rclsid = &clsid;
3503 }
3504
3505 hr = CoCreateInstance(rclsid,
3506 outer,
3507 cls_context,
3508 &IID_IUnknown,
3509 (void**)&unk);
3510
3511 if (hr != S_OK)
3512 {
3514 return hr;
3515 }
3516
3517 /* init from file */
3518 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3519 if (FAILED(hr))
3520 {
3522 IUnknown_Release(unk);
3523 return hr;
3524 }
3525
3526 hr = IPersistFile_Load(pf, filename, grfmode);
3527 IPersistFile_Release(pf);
3528 if (SUCCEEDED(hr))
3529 return return_multi_qi(unk, count, results, FALSE);
3530 else
3531 {
3533 IUnknown_Release(unk);
3534 return hr;
3535 }
3536}
3537
3538/***********************************************************************
3539 * CoGetInstanceFromIStorage [OLE32.@]
3540 */
3543 CLSID *rclsid,
3544 IUnknown *outer,
3545 DWORD cls_context,
3547 DWORD count,
3548 MULTI_QI *results
3549)
3550{
3551 IPersistStorage *ps = NULL;
3552 IUnknown* unk = NULL;
3553 STATSTG stat;
3554 HRESULT hr;
3555
3556 if (count == 0 || !results || !storage)
3557 return E_INVALIDARG;
3558
3559 if (server_info)
3560 FIXME("() non-NULL server_info not supported\n");
3561
3563
3564 /* optionally get CLSID from a file */
3565 if (!rclsid)
3566 {
3567 memset(&stat.clsid, 0, sizeof(stat.clsid));
3568 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3569 if (FAILED(hr))
3570 {
3571 ERR("failed to get CLSID from a file\n");
3572 return hr;
3573 }
3574
3575 rclsid = &stat.clsid;
3576 }
3577
3578 hr = CoCreateInstance(rclsid,
3579 outer,
3580 cls_context,
3581 &IID_IUnknown,
3582 (void**)&unk);
3583
3584 if (hr != S_OK)
3585 return hr;
3586
3587 /* init from IStorage */
3588 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3589 if (FAILED(hr))
3590 ERR("failed to get IPersistStorage\n");
3591
3592 if (ps)
3593 {
3594 IPersistStorage_Load(ps, storage);
3595 IPersistStorage_Release(ps);
3596 }
3597
3598 return return_multi_qi(unk, count, results, FALSE);
3599}
3600
3601/***********************************************************************
3602 * CoLoadLibrary (OLE32.@)
3603 *
3604 * Loads a library.
3605 *
3606 * PARAMS
3607 * lpszLibName [I] Path to library.
3608 * bAutoFree [I] Whether the library should automatically be freed.
3609 *
3610 * RETURNS
3611 * Success: Handle to loaded library.
3612 * Failure: NULL.
3613 *
3614 * SEE ALSO
3615 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3616 */
3618{
3619 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3620
3621 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3622}
3623
3624/***********************************************************************
3625 * CoFreeLibrary [OLE32.@]
3626 *
3627 * Unloads a library from memory.
3628 *
3629 * PARAMS
3630 * hLibrary [I] Handle to library to unload.
3631 *
3632 * RETURNS
3633 * Nothing
3634 *
3635 * SEE ALSO
3636 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3637 */
3639{
3641}
3642
3643
3644/***********************************************************************
3645 * CoFreeAllLibraries [OLE32.@]
3646 *
3647 * Function for backwards compatibility only. Does nothing.
3648 *
3649 * RETURNS
3650 * Nothing.
3651 *
3652 * SEE ALSO
3653 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3654 */
3656{
3657 /* NOP */
3658}
3659
3660/***********************************************************************
3661 * CoFreeUnusedLibrariesEx [OLE32.@]
3662 *
3663 * Frees any previously unused libraries whose delay has expired and marks
3664 * currently unused libraries for unloading. Unused are identified as those that
3665 * return S_OK from their DllCanUnloadNow function.
3666 *
3667 * PARAMS
3668 * dwUnloadDelay [I] Unload delay in milliseconds.
3669 * dwReserved [I] Reserved. Set to 0.
3670 *
3671 * RETURNS
3672 * Nothing.
3673 *
3674 * SEE ALSO
3675 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3676 */
3678{
3679 struct apartment *apt = COM_CurrentApt();
3680 if (!apt)
3681 {
3682 ERR("apartment not initialised\n");
3683 return;
3684 }
3685
3686 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3687}
3688
3689/***********************************************************************
3690 * CoFreeUnusedLibraries [OLE32.@]
3691 *
3692 * Frees any unused libraries. Unused are identified as those that return
3693 * S_OK from their DllCanUnloadNow function.
3694 *
3695 * RETURNS
3696 * Nothing.
3697 *
3698 * SEE ALSO
3699 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3700 */
3702{
3704}
3705
3706/***********************************************************************
3707 * CoFileTimeNow [OLE32.@]
3708 *
3709 * Retrieves the current time in FILETIME format.
3710 *
3711 * PARAMS
3712 * lpFileTime [O] The current time.
3713 *
3714 * RETURNS
3715 * S_OK.
3716 */
3718{
3719 GetSystemTimeAsFileTime( lpFileTime );
3720 return S_OK;
3721}
3722
3723/******************************************************************************
3724 * CoLockObjectExternal [OLE32.@]
3725 *
3726 * Increments or decrements the external reference count of a stub object.
3727 *
3728 * PARAMS
3729 * pUnk [I] Stub object.
3730 * fLock [I] If TRUE then increments the external ref-count,
3731 * otherwise decrements.
3732 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3733 * calling CoDisconnectObject.
3734 *
3735 * RETURNS
3736 * Success: S_OK.
3737 * Failure: HRESULT code.
3738 *
3739 * NOTES
3740 * If fLock is TRUE and an object is passed in that doesn't have a stub
3741 * manager then a new stub manager is created for the object.
3742 */
3745 BOOL fLock,
3746 BOOL fLastUnlockReleases)
3747{
3748 struct stub_manager *stubmgr;
3749 struct apartment *apt;
3750
3751 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3752 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3753
3754 if (!(apt = apartment_get_current_or_mta()))
3755 {
3756 ERR("apartment not initialised\n");
3757 return CO_E_NOTINITIALIZED;
3758 }
3759
3760 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3761 if (!stubmgr)
3762 {
3763 WARN("stub object not found %p\n", pUnk);
3764 /* Note: native is pretty broken here because it just silently
3765 * fails, without returning an appropriate error code, making apps
3766 * think that the object was disconnected, when it actually wasn't */
3767 apartment_release(apt);
3768 return S_OK;
3769 }
3770
3771 if (fLock)
3772 stub_manager_ext_addref(stubmgr, 1, FALSE);
3773 else
3774 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3775
3776 stub_manager_int_release(stubmgr);
3777 apartment_release(apt);
3778 return S_OK;
3779}
3780
3781/***********************************************************************
3782 * CoInitializeWOW (OLE32.@)
3783 *
3784 * WOW equivalent of CoInitialize?
3785 *
3786 * PARAMS
3787 * x [I] Unknown.
3788 * y [I] Unknown.
3789 *
3790 * RETURNS
3791 * Unknown.
3792 */
3794{
3795 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3796 return 0;
3797}
3798
3799/***********************************************************************
3800 * CoGetState [OLE32.@]
3801 *
3802 * Retrieves the thread state object previously stored by CoSetState().
3803 *
3804 * PARAMS
3805 * ppv [I] Address where pointer to object will be stored.
3806 *
3807 * RETURNS
3808 * Success: S_OK.
3809 * Failure: E_OUTOFMEMORY.
3810 *
3811 * NOTES
3812 * Crashes on all invalid ppv addresses, including NULL.
3813 * If the function returns a non-NULL object then the caller must release its
3814 * reference on the object when the object is no longer required.
3815 *
3816 * SEE ALSO
3817 * CoSetState().
3818 */
3820{
3821 struct oletls *info = COM_CurrentInfo();
3822 if (!info) return E_OUTOFMEMORY;
3823
3824 *ppv = NULL;
3825
3826 if (info->state)
3827 {
3828 IUnknown_AddRef(info->state);
3829 *ppv = info->state;
3830 TRACE("apt->state=%p\n", info->state);
3831 }
3832
3833 return S_OK;
3834}
3835
3836/***********************************************************************
3837 * CoSetState [OLE32.@]
3838 *
3839 * Sets the thread state object.
3840 *
3841 * PARAMS
3842 * pv [I] Pointer to state object to be stored.
3843 *
3844 * NOTES
3845 * The system keeps a reference on the object while the object stored.
3846 *
3847 * RETURNS
3848 * Success: S_OK.
3849 * Failure: E_OUTOFMEMORY.
3850 */
3852{
3853 struct oletls *info = COM_CurrentInfo();
3854 if (!info) return E_OUTOFMEMORY;
3855
3856 if (pv) IUnknown_AddRef(pv);
3857
3858 if (info->state)
3859 {
3860 TRACE("-- release %p now\n", info->state);
3861 IUnknown_Release(info->state);
3862 }
3863
3864 info->state = pv;
3865
3866 return S_OK;
3867}
3868
3869
3870/******************************************************************************
3871 * CoTreatAsClass [OLE32.@]
3872 *
3873 * Sets the TreatAs value of a class.
3874 *
3875 * PARAMS
3876 * clsidOld [I] Class to set TreatAs value on.
3877 * clsidNew [I] The class the clsidOld should be treated as.
3878 *
3879 * RETURNS
3880 * Success: S_OK.
3881 * Failure: HRESULT code.
3882 *
3883 * SEE ALSO
3884 * CoGetTreatAsClass
3885 */
3887{
3888 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3889 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3890 HKEY hkey = NULL;
3891 WCHAR szClsidNew[CHARS_IN_GUID];
3892 HRESULT res = S_OK;
3893 WCHAR auto_treat_as[CHARS_IN_GUID];
3894 LONG auto_treat_as_size = sizeof(auto_treat_as);
3895 CLSID id;
3896
3897 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3898 if (FAILED(res))
3899 goto done;
3900
3901 if (IsEqualGUID( clsidOld, clsidNew ))
3902 {
3903 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3904 CLSIDFromString(auto_treat_as, &id) == S_OK)
3905 {
3906 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3907 {
3909 goto done;
3910 }
3911 }
3912 else
3913 {
3914 if(RegDeleteKeyW(hkey, wszTreatAs))
3916 goto done;
3917 }
3918 }
3919 else
3920 {
3921 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3922 RegDeleteKeyW(hkey, wszTreatAs);
3923 }else{
3924 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){
3925 WARN("StringFromGUID2 failed\n");
3926 res = E_FAIL;
3927 goto done;
3928 }
3929
3930 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3931 WARN("RegSetValue failed\n");
3933 goto done;
3934 }
3935 }
3936 }
3937
3938done:
3939 if (hkey) RegCloseKey(hkey);
3940 return res;
3941}
3942
3943/******************************************************************************
3944 * CoGetTreatAsClass [OLE32.@]
3945 *
3946 * Gets the TreatAs value of a class.
3947 *
3948 * PARAMS
3949 * clsidOld [I] Class to get the TreatAs value of.
3950 * clsidNew [I] The class the clsidOld should be treated as.
3951 *
3952 * RETURNS
3953 * Success: S_OK.
3954 * Failure: HRESULT code.
3955 *
3956 * SEE ALSO
3957 * CoSetTreatAsClass
3958 */
3960{
3961 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3962 HKEY hkey = NULL;
3963 WCHAR szClsidNew[CHARS_IN_GUID];
3964 HRESULT res = S_OK;
3965 LONG len = sizeof(szClsidNew);
3966
3967 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3968
3969 if (!clsidOld || !clsidNew)
3970 return E_INVALIDARG;
3971
3972 *clsidNew = *clsidOld; /* copy over old value */
3973
3974 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3975 if (FAILED(res))
3976 {
3977 res = S_FALSE;
3978 goto done;
3979 }
3980 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3981 {
3982 res = S_FALSE;
3983 goto done;
3984 }
3985 res = CLSIDFromString(szClsidNew,clsidNew);
3986 if (FAILED(res))
3987 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3988done:
3989 if (hkey) RegCloseKey(hkey);
3990 return res;
3991}
3992
3993/******************************************************************************
3994 * CoGetCurrentProcess [OLE32.@]
3995 *
3996 * Gets the current process ID.
3997 *
3998 * RETURNS
3999 * The current process ID.
4000 *
4001 * NOTES
4002 * Is DWORD really the correct return type for this function?
4003 */
4005{
4006 return GetCurrentProcessId();
4007}
4008
4009/***********************************************************************
4010 * CoGetCurrentLogicalThreadId [OLE32.@]
4011 */
4013{
4014 TRACE("(%p)\n", id);
4015
4016 if (!id)
4017 return E_INVALIDARG;
4018
4019 *id = COM_CurrentCausalityId();
4020 return S_OK;
4021}
4022
4023/******************************************************************************
4024 * CoRegisterMessageFilter [OLE32.@]
4025 *
4026 * Registers a message filter.
4027 *
4028 * PARAMS
4029 * lpMessageFilter [I] Pointer to interface.
4030 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
4031 *
4032 * RETURNS
4033 * Success: S_OK.
4034 * Failure: HRESULT code.
4035 *
4036 * NOTES
4037 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4038 * lpMessageFilter removes the message filter.
4039 *
4040 * If lplpMessageFilter is not NULL the previous message filter will be
4041 * returned in the memory pointer to this parameter and the caller is
4042 * responsible for releasing the object.
4043 *
4044 * The current thread be in an apartment otherwise the function will crash.
4045 */
4047 LPMESSAGEFILTER lpMessageFilter,
4048 LPMESSAGEFILTER *lplpMessageFilter)
4049{
4050 struct apartment *apt;
4051 IMessageFilter *lpOldMessageFilter;
4052
4053 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
4054
4055 apt = COM_CurrentApt();
4056
4057 /* can't set a message filter in a multi-threaded apartment */
4058 if (!apt || apt->multi_threaded)
4059 {
4060 WARN("can't set message filter in MTA or uninitialized apt\n");
4061 return CO_E_NOT_SUPPORTED;
4062 }
4063
4064 if (lpMessageFilter)
4065 IMessageFilter_AddRef(lpMessageFilter);
4066
4067 EnterCriticalSection(&apt->cs);
4068
4069 lpOldMessageFilter = apt->filter;
4070 apt->filter = lpMessageFilter;
4071
4072 LeaveCriticalSection(&apt->cs);
4073
4074 if (lplpMessageFilter)
4075 *lplpMessageFilter = lpOldMessageFilter;
4076 else if (lpOldMessageFilter)
4077 IMessageFilter_Release(lpOldMessageFilter);
4078
4079 return S_OK;
4080}
4081
4082/***********************************************************************
4083 * CoIsOle1Class [OLE32.@]
4084 *
4085 * Determines whether the specified class an OLE v1 class.
4086 *
4087 * PARAMS
4088 * clsid [I] Class to test.
4089 *
4090 * RETURNS
4091 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4092 */
4094{
4095 FIXME("%s\n", debugstr_guid(clsid));
4096 return FALSE;
4097}
4098
4099/***********************************************************************
4100 * IsEqualGUID [OLE32.@]
4101 *
4102 * Compares two Unique Identifiers.
4103 *
4104 * PARAMS
4105 * rguid1 [I] The first GUID to compare.
4106 * rguid2 [I] The other GUID to compare.
4107 *
4108 * RETURNS
4109 * TRUE if equal
4110 */
4111#undef IsEqualGUID
4113 REFGUID rguid1,
4114 REFGUID rguid2)
4115{
4116 return !memcmp(rguid1,rguid2,sizeof(GUID));
4117}
4118
4119/***********************************************************************
4120 * CoInitializeSecurity [OLE32.@]
4121 */
4123 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4124 void* pReserved1, DWORD dwAuthnLevel,
4125 DWORD dwImpLevel, void* pReserved2,
4126 DWORD dwCapabilities, void* pReserved3)
4127{
4128 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4129 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4130 dwCapabilities, pReserved3);
4131 return S_OK;
4132}
4133
4134/***********************************************************************
4135 * CoSuspendClassObjects [OLE32.@]
4136 *
4137 * Suspends all registered class objects to prevent further requests coming in
4138 * for those objects.
4139 *
4140 * RETURNS
4141 * Success: S_OK.
4142 * Failure: HRESULT code.
4143 */
4145{
4146 FIXME("\n");
4147 return S_OK;
4148}
4149
4150/***********************************************************************
4151 * CoAddRefServerProcess [OLE32.@]
4152 *
4153 * Helper function for incrementing the reference count of a local-server
4154 * process.
4155 *
4156 * RETURNS
4157 * New reference count.
4158 *
4159 * SEE ALSO
4160 * CoReleaseServerProcess().
4161 */
4163{
4164 ULONG refs;
4165
4166 TRACE("\n");
4167
4171
4172 TRACE("refs before: %d\n", refs - 1);
4173
4174 return refs;
4175}
4176
4177/***********************************************************************
4178 * CoReleaseServerProcess [OLE32.@]
4179 *
4180 * Helper function for decrementing the reference count of a local-server
4181 * process.
4182 *
4183 * RETURNS
4184 * New reference count.
4185 *
4186 * NOTES
4187 * When reference count reaches 0, this function suspends all registered
4188 * classes so no new connections are accepted.
4189 *
4190 * SEE ALSO
4191 * CoAddRefServerProcess(), CoSuspendClassObjects().
4192 */
4194{
4195 ULONG refs;
4196
4197 TRACE("\n");
4198
4200
4202 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4203
4205
4206 TRACE("refs after: %d\n", refs);
4207
4208 return refs;
4209}
4210
4211/***********************************************************************
4212 * CoIsHandlerConnected [OLE32.@]
4213 *
4214 * Determines whether a proxy is connected to a remote stub.
4215 *
4216 * PARAMS
4217 * pUnk [I] Pointer to object that may or may not be connected.
4218 *
4219 * RETURNS
4220 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4221 * FALSE otherwise.
4222 */
4224{
4225 FIXME("%p\n", pUnk);
4226
4227 return TRUE;
4228}
4229
4230/***********************************************************************
4231 * CoAllowSetForegroundWindow [OLE32.@]
4232 *
4233 */
4235{
4236 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4237 return S_OK;
4238}
4239
4240/***********************************************************************
4241 * CoQueryProxyBlanket [OLE32.@]
4242 *
4243 * Retrieves the security settings being used by a proxy.
4244 *
4245 * PARAMS
4246 * pProxy [I] Pointer to the proxy object.
4247 * pAuthnSvc [O] The type of authentication service.
4248 * pAuthzSvc [O] The type of authorization service.
4249 * ppServerPrincName [O] Optional. The server prinicple name.
4250 * pAuthnLevel [O] The authentication level.
4251 * pImpLevel [O] The impersonation level.
4252 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4253 * pCapabilities [O] Flags affecting the security behaviour.
4254 *
4255 * RETURNS
4256 * Success: S_OK.
4257 * Failure: HRESULT code.
4258 *
4259 * SEE ALSO
4260 * CoCopyProxy, CoSetProxyBlanket.
4261 */
4263 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4264 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4265{
4266 IClientSecurity *pCliSec;
4267 HRESULT hr;
4268
4269 TRACE("%p\n", pProxy);
4270
4271 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4272 if (SUCCEEDED(hr))
4273 {
4274 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4275 pAuthzSvc, ppServerPrincName,
4276 pAuthnLevel, pImpLevel, ppAuthInfo,
4277 pCapabilities);
4278 IClientSecurity_Release(pCliSec);
4279 }
4280
4281 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4282 return hr;
4283}
4284
4285/***********************************************************************
4286 * CoSetProxyBlanket [OLE32.@]
4287 *
4288 * Sets