xref: /reactos/dll/win32/ole32/compobj.c (revision 0f5d91b7)
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 
70 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71 
72 /****************************************************************************
73  * This section defines variables internal to the COM module.
74  */
75 
76 static APARTMENT *MTA; /* protected by csApartment */
77 static APARTMENT *MainApartment; /* the first STA apartment */
78 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
79 
80 static CRITICAL_SECTION csApartment;
81 static CRITICAL_SECTION_DEBUG critsect_debug =
82 {
83     0, 0, &csApartment,
84     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
85       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
86 };
87 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
88 
89 enum comclass_threadingmodel
90 {
91     ThreadingModel_Apartment = 1,
92     ThreadingModel_Free      = 2,
93     ThreadingModel_No        = 3,
94     ThreadingModel_Both      = 4,
95     ThreadingModel_Neutral   = 5
96 };
97 
98 enum comclass_miscfields
99 {
100     MiscStatus          = 1,
101     MiscStatusIcon      = 2,
102     MiscStatusContent   = 4,
103     MiscStatusThumbnail = 8,
104     MiscStatusDocPrint  = 16
105 };
106 
107 struct comclassredirect_data
108 {
109     ULONG size;
110     BYTE  res;
111     BYTE  miscmask;
112     BYTE  res1[2];
113     DWORD model;
114     GUID  clsid;
115     GUID  alias;
116     GUID  clsid2;
117     GUID  tlbid;
118     ULONG name_len;
119     ULONG name_offset;
120     ULONG progid_len;
121     ULONG progid_offset;
122     ULONG clrdata_len;
123     ULONG clrdata_offset;
124     DWORD miscstatus;
125     DWORD miscstatuscontent;
126     DWORD miscstatusthumbnail;
127     DWORD miscstatusicon;
128     DWORD miscstatusdocprint;
129 };
130 
131 struct ifacepsredirect_data
132 {
133     ULONG size;
134     DWORD mask;
135     GUID  iid;
136     ULONG nummethods;
137     GUID  tlbid;
138     GUID  base;
139     ULONG name_len;
140     ULONG name_offset;
141 };
142 
143 struct progidredirect_data
144 {
145     ULONG size;
146     DWORD reserved;
147     ULONG clsid_offset;
148 };
149 
150 struct class_reg_data
151 {
152     union
153     {
154         struct
155         {
156             struct comclassredirect_data *data;
157             void *section;
158             HANDLE hactctx;
159         } actctx;
160         HKEY hkey;
161     } u;
162     BOOL hkey;
163 };
164 
165 struct registered_psclsid
166 {
167     struct list entry;
168     IID iid;
169     CLSID clsid;
170 };
171 
172 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
173 
174 static CRITICAL_SECTION cs_registered_psclsid_list;
175 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
176 {
177     0, 0, &cs_registered_psclsid_list,
178     { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
179       0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
180 };
181 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
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  */
189 struct LocalServer
190 {
191     IServiceProvider IServiceProvider_iface;
192     LONG ref;
193     APARTMENT *apt;
194     IStream *marshal_stream;
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  */
202 static LONG s_COMLockCount = 0;
203 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
204 static LONG s_COMServerProcessReferences = 0;
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  */
214 typedef struct tagRegisteredClass
215 {
216   struct list entry;
217   CLSID     classIdentifier;
218   OXID      apartment_id;
219   LPUNKNOWN classObject;
220   DWORD     runContext;
221   DWORD     connectFlags;
222   DWORD     dwCookie;
223   void     *RpcRegistration;
224 } RegisteredClass;
225 
226 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
227 
228 static CRITICAL_SECTION csRegisteredClassList;
229 static CRITICAL_SECTION_DEBUG class_cs_debug =
230 {
231     0, 0, &csRegisteredClassList,
232     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
233       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
234 };
235 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
236 
dvaspect_to_miscfields(DWORD aspect)237 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
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 
actctx_get_miscstatus(const CLSID * clsid,DWORD aspect,DWORD * status)254 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
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;
263         enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
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;
283         case MiscStatusContent:
284             *status = comclass->miscstatuscontent;
285             break;
286         case MiscStatusThumbnail:
287             *status = comclass->miscstatusthumbnail;
288             break;
289         case MiscStatusDocPrint:
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 */
create_key(HKEY * retkey,ACCESS_MASK access,OBJECT_ATTRIBUTES * attr)303 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
304 {
305     NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
306 
307     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
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);
312         UNICODE_STRING str;
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__
342 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
343 #else
344 static const WCHAR classes_rootW[] =
345     {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346      '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
347 #endif
348 
349 static HKEY classes_root_hkey;
350 
351 /* create the special HKEY_CLASSES_ROOT key */
create_classes_root_hkey(DWORD access)352 static HKEY create_classes_root_hkey(DWORD access)
353 {
354     HKEY hkey, ret = 0;
355     OBJECT_ATTRIBUTES attr;
356     UNICODE_STRING name;
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;
364     RtlInitUnicodeString( &name, classes_rootW );
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 */
get_classes_root_hkey(HKEY hkey,REGSAM access)381 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
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 &&
388         ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
389         ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
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 
create_classes_key(HKEY hkey,const WCHAR * name,REGSAM access,HKEY * retkey)402 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
403 {
404     OBJECT_ATTRIBUTES attr;
405     UNICODE_STRING nameW;
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;
415     RtlInitUnicodeString( &nameW, name );
416 
417     return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
418 }
419 
open_classes_key(HKEY hkey,const WCHAR * name,REGSAM access,HKEY * retkey)420 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
421 {
422     OBJECT_ATTRIBUTES attr;
423     UNICODE_STRING nameW;
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;
433     RtlInitUnicodeString( &nameW, name );
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 
449 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
450 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
451 
452 typedef struct tagOpenDll
453 {
454   LONG refs;
455   LPWSTR library_name;
456   HANDLE library;
457   DllGetClassObjectFunc DllGetClassObject;
458   DllCanUnloadNowFunc DllCanUnloadNow;
459   struct list entry;
460 } OpenDll;
461 
462 static struct list openDllList = LIST_INIT(openDllList);
463 
464 static CRITICAL_SECTION csOpenDllList;
465 static CRITICAL_SECTION_DEBUG dll_cs_debug =
466 {
467     0, 0, &csOpenDllList,
468     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
469       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
470 };
471 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
472 
473 struct apartment_loaded_dll
474 {
475     struct list entry;
476     OpenDll *dll;
477     DWORD unload_time;
478     BOOL multi_threaded;
479 };
480 
481 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0};
482 
483 static ATOM apt_win_class;
484 
485 /*****************************************************************************
486  * This section contains OpenDllList implementation
487  */
488 
COMPOBJ_DllList_Get(LPCWSTR library_name)489 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
490 {
491     OpenDll *ptr;
492     OpenDll *ret = NULL;
493     EnterCriticalSection(&csOpenDllList);
494     LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
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     }
503     LeaveCriticalSection(&csOpenDllList);
504     return ret;
505 }
506 
507 /* caller must ensure that library_name is not already in the open dll list */
COMPOBJ_DllList_Add(LPCWSTR library_name,OpenDll ** ret)508 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
509 {
510     OpenDll *entry;
511     int len;
512     HRESULT hr = S_OK;
513     HANDLE hLibrary;
514     DllCanUnloadNowFunc DllCanUnloadNow;
515     DllGetClassObjectFunc DllGetClassObject;
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 */
524     hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
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");
535     if (!DllGetClassObject)
536     {
537         /* failure: the dll did not export DllGetClassObject */
538         ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
539         FreeLibrary(hLibrary);
540         return CO_E_DLLNOTFOUND;
541     }
542 
543     EnterCriticalSection( &csOpenDllList );
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 */
550         FreeLibrary(hLibrary);
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;
565             list_add_tail(&openDllList, &entry->entry);
566             *ret = entry;
567         }
568         else
569         {
570             HeapFree(GetProcessHeap(), 0, entry);
571             hr = E_OUTOFMEMORY;
572             FreeLibrary(hLibrary);
573         }
574     }
575 
576     LeaveCriticalSection( &csOpenDllList );
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 */
COMPOBJ_DllList_ReleaseRef(OpenDll * entry,BOOL free_entry)583 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
584 {
585     if (!InterlockedDecrement(&entry->refs) && free_entry)
586     {
587         EnterCriticalSection(&csOpenDllList);
588         list_remove(&entry->entry);
589         LeaveCriticalSection(&csOpenDllList);
590 
591         TRACE("freeing %p\n", entry->library);
592         FreeLibrary(entry->library);
593 
594         HeapFree(GetProcessHeap(), 0, entry->library_name);
595         HeapFree(GetProcessHeap(), 0, entry);
596     }
597 }
598 
599 /* frees memory associated with active dll list */
COMPOBJ_DllList_Free(void)600 static void COMPOBJ_DllList_Free(void)
601 {
602     OpenDll *entry, *cursor2;
603     EnterCriticalSection(&csOpenDllList);
604     LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
605     {
606         list_remove(&entry->entry);
607 
608         HeapFree(GetProcessHeap(), 0, entry->library_name);
609         HeapFree(GetProcessHeap(), 0, entry);
610     }
611     LeaveCriticalSection(&csOpenDllList);
612     DeleteCriticalSection(&csOpenDllList);
613 }
614 
615 /******************************************************************************
616  * Manage apartments.
617  */
618 
apartment_addref(struct apartment * apt)619 static DWORD apartment_addref(struct apartment *apt)
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 */
apartment_construct(DWORD model)628 static APARTMENT *apartment_construct(DWORD model)
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;
644     InitializeCriticalSection(&apt->cs);
645     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
646 
647     apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
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 */
apartment_get_or_create(DWORD model)670 static APARTMENT *apartment_get_or_create(DWORD model)
671 {
672     APARTMENT *apt = COM_CurrentApt();
673 
674     if (!apt)
675     {
676         if (model & COINIT_APARTMENTTHREADED)
677         {
678             EnterCriticalSection(&csApartment);
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 
688             LeaveCriticalSection(&csApartment);
689 
690             if (apt->main)
691                 apartment_createwindowifneeded(apt);
692         }
693         else
694         {
695             EnterCriticalSection(&csApartment);
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));
703                 apartment_addref(MTA);
704             }
705             else
706                 MTA = apartment_construct(model);
707 
708             apt = MTA;
709 
710             LeaveCriticalSection(&csApartment);
711         }
712         COM_CurrentInfo()->apt = apt;
713     }
714 
715     return apt;
716 }
717 
apartment_is_model(const APARTMENT * apt,DWORD model)718 static 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. */
apartment_find_mta(void)726 static APARTMENT *apartment_find_mta(void)
727 {
728     APARTMENT *apt;
729 
730     EnterCriticalSection(&csApartment);
731 
732     if ((apt = MTA))
733         apartment_addref(apt);
734 
735     LeaveCriticalSection(&csApartment);
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. */
apartment_get_current_or_mta(void)742 APARTMENT *apartment_get_current_or_mta(void)
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 
COM_RevokeRegisteredClassObject(RegisteredClass * curClass)753 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
754 {
755     list_remove(&curClass->entry);
756 
757     if (curClass->runContext & CLSCTX_LOCAL_SERVER)
758         RPC_StopLocalServer(curClass->RpcRegistration);
759 
760     IUnknown_Release(curClass->classObject);
761     HeapFree(GetProcessHeap(), 0, curClass);
762 }
763 
COM_RevokeAllClasses(const struct apartment * apt)764 static void COM_RevokeAllClasses(const struct apartment *apt)
765 {
766   RegisteredClass *curClass, *cursor;
767 
768   EnterCriticalSection( &csRegisteredClassList );
769 
770   LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
771   {
772     if (curClass->apartment_id == apt->oxid)
773       COM_RevokeRegisteredClassObject(curClass);
774   }
775 
776   LeaveCriticalSection( &csRegisteredClassList );
777 }
778 
revoke_registered_psclsids(void)779 static void revoke_registered_psclsids(void)
780 {
781     struct registered_psclsid *psclsid, *psclsid2;
782 
783     EnterCriticalSection( &cs_registered_psclsid_list );
784 
785     LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
786     {
787         list_remove(&psclsid->entry);
788         HeapFree(GetProcessHeap(), 0, psclsid);
789     }
790 
791     LeaveCriticalSection( &cs_registered_psclsid_list );
792 }
793 
794 /******************************************************************************
795  * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
796  */
797 
798 typedef struct ManualResetEvent {
799     ISynchronize        ISynchronize_iface;
800     ISynchronizeHandle  ISynchronizeHandle_iface;
801     LONG ref;
802     HANDLE event;
803 } MREImpl;
804 
impl_from_ISynchronize(ISynchronize * iface)805 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
806 {
807     return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
808 }
809 
ISynchronize_fnQueryInterface(ISynchronize * iface,REFIID riid,void ** ppv)810 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
811 {
812     MREImpl *This = impl_from_ISynchronize(iface);
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 
ISynchronize_fnAddRef(ISynchronize * iface)830 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
831 {
832     MREImpl *This = impl_from_ISynchronize(iface);
833     LONG ref = InterlockedIncrement(&This->ref);
834     TRACE("%p - ref %d\n", This, ref);
835 
836     return ref;
837 }
838 
ISynchronize_fnRelease(ISynchronize * iface)839 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
840 {
841     MREImpl *This = impl_from_ISynchronize(iface);
842     LONG ref = InterlockedDecrement(&This->ref);
843     TRACE("%p - ref %d\n", This, ref);
844 
845     if(!ref)
846     {
847         CloseHandle(This->event);
848         HeapFree(GetProcessHeap(), 0, This);
849     }
850 
851     return ref;
852 }
853 
ISynchronize_fnWait(ISynchronize * iface,DWORD dwFlags,DWORD dwMilliseconds)854 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
855 {
856     MREImpl *This = impl_from_ISynchronize(iface);
857     UINT index;
858     TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
859     return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
860 }
861 
ISynchronize_fnSignal(ISynchronize * iface)862 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
863 {
864     MREImpl *This = impl_from_ISynchronize(iface);
865     TRACE("%p\n", This);
866     SetEvent(This->event);
867     return S_OK;
868 }
869 
ISynchronize_fnReset(ISynchronize * iface)870 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
871 {
872     MREImpl *This = impl_from_ISynchronize(iface);
873     TRACE("%p\n", This);
874     ResetEvent(This->event);
875     return S_OK;
876 }
877 
878 static ISynchronizeVtbl vt_ISynchronize = {
879     ISynchronize_fnQueryInterface,
880     ISynchronize_fnAddRef,
881     ISynchronize_fnRelease,
882     ISynchronize_fnWait,
883     ISynchronize_fnSignal,
884     ISynchronize_fnReset
885 };
886 
impl_from_ISynchronizeHandle(ISynchronizeHandle * iface)887 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
888 {
889     return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
890 }
891 
SynchronizeHandle_QueryInterface(ISynchronizeHandle * iface,REFIID riid,void ** ppv)892 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
893 {
894     MREImpl *This = impl_from_ISynchronizeHandle(iface);
895     return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
896 }
897 
SynchronizeHandle_AddRef(ISynchronizeHandle * iface)898 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
899 {
900     MREImpl *This = impl_from_ISynchronizeHandle(iface);
901     return ISynchronize_AddRef(&This->ISynchronize_iface);
902 }
903 
SynchronizeHandle_Release(ISynchronizeHandle * iface)904 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
905 {
906     MREImpl *This = impl_from_ISynchronizeHandle(iface);
907     return ISynchronize_Release(&This->ISynchronize_iface);
908 }
909 
SynchronizeHandle_GetHandle(ISynchronizeHandle * iface,HANDLE * ph)910 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
911 {
912     MREImpl *This = impl_from_ISynchronizeHandle(iface);
913 
914     *ph = This->event;
915     return S_OK;
916 }
917 
918 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
919     SynchronizeHandle_QueryInterface,
920     SynchronizeHandle_AddRef,
921     SynchronizeHandle_Release,
922     SynchronizeHandle_GetHandle
923 };
924 
ManualResetEvent_Construct(IUnknown * punkouter,REFIID iid,void ** ppv)925 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
926 {
927     MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
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 
impl_from_IServiceProvider(IServiceProvider * iface)943 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
944 {
945     return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
946 }
947 
LocalServer_QueryInterface(IServiceProvider * iface,REFIID riid,void ** ppv)948 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
949 {
950     LocalServer *This = impl_from_IServiceProvider(iface);
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 
LocalServer_AddRef(IServiceProvider * iface)965 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
966 {
967     LocalServer *This = impl_from_IServiceProvider(iface);
968     LONG ref = InterlockedIncrement(&This->ref);
969 
970     TRACE("(%p) ref=%d\n", This, ref);
971 
972     return ref;
973 }
974 
LocalServer_Release(IServiceProvider * iface)975 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
976 {
977     LocalServer *This = impl_from_IServiceProvider(iface);
978     LONG ref = InterlockedDecrement(&This->ref);
979 
980     TRACE("(%p) ref=%d\n", This, ref);
981 
982     if(!ref) {
983         assert(!This->apt);
984         HeapFree(GetProcessHeap(), 0, This);
985     }
986 
987     return ref;
988 }
989 
LocalServer_QueryService(IServiceProvider * iface,REFGUID guid,REFIID riid,void ** ppv)990 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
991 {
992     LocalServer *This = impl_from_IServiceProvider(iface);
993     APARTMENT *apt = COM_CurrentApt();
994     RegisteredClass *iter;
995     HRESULT hres = E_FAIL;
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 
1002     EnterCriticalSection(&csRegisteredClassList);
1003 
1004     LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
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 
1013     LeaveCriticalSection( &csRegisteredClassList );
1014 
1015     return hres;
1016 }
1017 
1018 static const IServiceProviderVtbl LocalServerVtbl = {
1019     LocalServer_QueryInterface,
1020     LocalServer_AddRef,
1021     LocalServer_Release,
1022     LocalServer_QueryService
1023 };
1024 
get_local_server_stream(APARTMENT * apt,IStream ** ret)1025 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
1026 {
1027     HRESULT hres = S_OK;
1028 
1029     EnterCriticalSection(&apt->cs);
1030 
1031     if(!apt->local_server) {
1032         LocalServer *obj;
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 {
1053             hres = E_OUTOFMEMORY;
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  */
CoRevokeClassObject(DWORD dwRegister)1086 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1087         DWORD dwRegister)
1088 {
1089   HRESULT hr = E_INVALIDARG;
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 
1101   EnterCriticalSection( &csRegisteredClassList );
1102 
1103   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
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       {
1112           COM_RevokeRegisteredClassObject(curClass);
1113           hr = S_OK;
1114       }
1115       else
1116       {
1117           ERR("called from wrong apartment, should be called from %s\n",
1118               wine_dbgstr_longlong(curClass->apartment_id));
1119           hr = RPC_E_WRONG_THREAD;
1120       }
1121       break;
1122     }
1123   }
1124 
1125   LeaveCriticalSection( &csRegisteredClassList );
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 */
apartment_freeunusedlibraries(struct apartment * apt,DWORD delay)1132 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1133 {
1134     struct apartment_loaded_dll *entry, *next;
1135     EnterCriticalSection(&apt->cs);
1136     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
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);
1157                 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1158                 HeapFree(GetProcessHeap(), 0, 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 
apartment_release(struct apartment * apt)1172 DWORD apartment_release(struct apartment *apt)
1173 {
1174     DWORD ret;
1175 
1176     EnterCriticalSection(&csApartment);
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     {
1183         LeaveCriticalSection(&csApartment);
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 
1196     LeaveCriticalSection(&csApartment);
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) {
1205             LocalServer *local_server = apt->local_server;
1206             LARGE_INTEGER zero;
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 */
1220         COM_RevokeAllClasses(apt);
1221 
1222         /* no locking is needed for this apartment, because no other thread
1223          * can access it at this point */
1224 
1225         apartment_disconnectproxies(apt);
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. */
1244         assert(list_empty(&apt->stubmgrs));
1245 
1246         if (apt->filter) IMessageFilter_Release(apt->filter);
1247 
1248         /* free as many unused libraries as possible... */
1249         apartment_freeunusedlibraries(apt, 0);
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         {
1256             struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1257             COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1258             list_remove(cursor);
1259             HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1260         }
1261 
1262         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1263         DeleteCriticalSection(&apt->cs);
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  */
apartment_findfromoxid(OXID oxid,BOOL ref)1276 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1277 {
1278     APARTMENT *result = NULL;
1279     struct list *cursor;
1280 
1281     EnterCriticalSection(&csApartment);
1282     LIST_FOR_EACH( cursor, &apts )
1283     {
1284         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1285         if (apt->oxid == oxid)
1286         {
1287             result = apt;
1288             if (ref) apartment_addref(result);
1289             break;
1290         }
1291     }
1292     LeaveCriticalSection(&csApartment);
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. */
apartment_findfromtid(DWORD tid)1300 APARTMENT *apartment_findfromtid(DWORD tid)
1301 {
1302     APARTMENT *result = NULL;
1303     struct list *cursor;
1304 
1305     EnterCriticalSection(&csApartment);
1306     LIST_FOR_EACH( cursor, &apts )
1307     {
1308         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1309         if (apt->tid == tid)
1310         {
1311             result = apt;
1312             apartment_addref(result);
1313             break;
1314         }
1315     }
1316     LeaveCriticalSection(&csApartment);
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. */
apartment_findmain(void)1324 static APARTMENT *apartment_findmain(void)
1325 {
1326     APARTMENT *result;
1327 
1328     EnterCriticalSection(&csApartment);
1329 
1330     result = MainApartment;
1331     if (result) apartment_addref(result);
1332 
1333     LeaveCriticalSection(&csApartment);
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 */
apartment_getclassobject(struct apartment * apt,LPCWSTR dllpath,BOOL apartment_threaded,REFCLSID rclsid,REFIID riid,void ** ppv)1340 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
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;
1347     struct apartment_loaded_dll *apartment_loaded_dll;
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 
1364     LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1365         if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name))
1366         {
1367             TRACE("found %s already loaded\n", debugstr_w(dllpath));
1368             found = TRUE;
1369             break;
1370         }
1371 
1372     if (!found)
1373     {
1374         apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1375         if (!apartment_loaded_dll)
1376             hr = E_OUTOFMEMORY;
1377         if (SUCCEEDED(hr))
1378         {
1379             apartment_loaded_dll->unload_time = 0;
1380             apartment_loaded_dll->multi_threaded = FALSE;
1381             hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1382             if (FAILED(hr))
1383                 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1384         }
1385         if (SUCCEEDED(hr))
1386         {
1387             TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1388             list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
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)
1399             apartment_loaded_dll->multi_threaded = TRUE;
1400 
1401         TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1402         /* OK: get the ClassObject */
1403         hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
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. */
get_object_dll_path(const struct class_reg_data * regdata,WCHAR * dst,DWORD dstlen)1413 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1414 {
1415     DWORD ret;
1416 
1417     if (regdata->hkey)
1418     {
1419 	DWORD keytype;
1420 	WCHAR src[MAX_PATH];
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) {
1425               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
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               }
1437               lstrcpynW(dst, src, dstlen);
1438             }
1439         }
1440         return !ret;
1441     }
1442     else
1443     {
1444         static const WCHAR dllW[] = {'.','d','l','l',0};
1445         ULONG_PTR cookie;
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);
1451         ret = SearchPathW(NULL, nameW, dllW, dstlen, dst, NULL);
1452         DeactivateActCtx(0, cookie);
1453         return *dst != 0;
1454     }
1455 }
1456 
1457 struct host_object_params
1458 {
1459     struct class_reg_data regdata;
1460     CLSID clsid; /* clsid of object to marshal */
1461     IID iid; /* interface to marshal */
1462     HANDLE event; /* event signalling when ready for multi-threaded case */
1463     HRESULT hr; /* result for multi-threaded case */
1464     IStream *stream; /* stream that the object will be marshaled into */
1465     BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1466 };
1467 
apartment_hostobject(struct apartment * apt,const struct host_object_params * params)1468 static HRESULT apartment_hostobject(struct apartment *apt,
1469                                     const struct host_object_params *params)
1470 {
1471     IUnknown *object;
1472     HRESULT hr;
1473     static const LARGE_INTEGER llZero;
1474     WCHAR dllpath[MAX_PATH+1];
1475 
1476     TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1477 
1478     if (!get_object_dll_path(&params->regdata, dllpath, ARRAY_SIZE(dllpath)))
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 
apartment_wndproc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)1498 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1499 {
1500     switch (msg)
1501     {
1502     case DM_EXECUTERPC:
1503         RPC_ExecuteCall((struct dispatch_params *)lParam);
1504         return 0;
1505     case DM_HOSTOBJECT:
1506         return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1507     default:
1508         return DefWindowProcW(hWnd, msg, wParam, lParam);
1509     }
1510 }
1511 
1512 struct host_thread_params
1513 {
1514     COINIT threading_model;
1515     HANDLE ready_event;
1516     HWND apartment_hwnd;
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 */
apartment_hostobject_thread(LPVOID p)1521 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
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     {
1536         apartment_createwindowifneeded(apt);
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 */
1543     PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
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         {
1558             TranslateMessage(&msg);
1559             DispatchMessageW(&msg);
1560         }
1561     }
1562 
1563     TRACE("exiting\n");
1564 
1565     CoUninitialize();
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 */
apartment_hostobject_in_hostapt(struct apartment * apt,BOOL multi_threaded,BOOL main_apartment,const struct class_reg_data * regdata,REFCLSID rclsid,REFIID riid,void ** ppv)1573 static HRESULT apartment_hostobject_in_hostapt(
1574     struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1575     const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1576 {
1577     struct host_object_params params;
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         {
1626             apartment_hwnd = apt->host_apt_hwnd;
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         {
1640             apartment_hwnd = apartment_getwindow(host_apt);
1641             apartment_release(host_apt);
1642         }
1643     }
1644 
1645     params.regdata = *regdata;
1646     params.clsid = *rclsid;
1647     params.iid = *riid;
1648     hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
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         {
1660             WaitForSingleObject(params.event, INFINITE);
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
1673             hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1674     }
1675     if (SUCCEEDED(hr))
1676         hr = CoUnmarshalInterface(params.stream, riid, ppv);
1677     IStream_Release(params.stream);
1678     return hr;
1679 }
1680 
register_class(INIT_ONCE * once,void * param,void ** context)1681 static 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));
1695     wclass.lpfnWndProc = apartment_wndproc;
1696     wclass.hInstance = hProxyDll;
1697     wclass.lpszClassName = wszAptWinClass;
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 */
apartment_createwindowifneeded(struct apartment * apt)1704 HRESULT apartment_createwindowifneeded(struct apartment *apt)
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());
1722             return HRESULT_FROM_WIN32(GetLastError());
1723         }
1724         if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1725             /* someone beat us to it */
1726             DestroyWindow(hwnd);
1727     }
1728 
1729     return S_OK;
1730 }
1731 
1732 /* retrieves the window for the main- or apartment-threaded apartment */
apartment_getwindow(const struct apartment * apt)1733 HWND apartment_getwindow(const struct apartment *apt)
1734 {
1735     assert(!apt->multi_threaded);
1736     return apt->win;
1737 }
1738 
COM_TlsDestroy(void)1739 static 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);
1754             heap_free(cursor);
1755         }
1756 
1757         if (info->context_token) IObjContext_Release(info->context_token);
1758 
1759         HeapFree(GetProcessHeap(), 0, info);
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  */
CoBuildVersion(void)1774 DWORD WINAPI CoBuildVersion(void)
1775 {
1776     TRACE("Returning version %d, build %d.\n", rmm, rup);
1777     return (rmm<<16)+rup;
1778 }
1779 
get_spy_entry(struct oletls * info,unsigned int id)1780 static 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  */
lock_init_spies(struct oletls * info)1797 static inline void lock_init_spies(struct oletls *info)
1798 {
1799     info->spies_lock++;
1800 }
1801 
unlock_init_spies(struct oletls * info)1802 static void unlock_init_spies(struct oletls *info)
1803 {
1804     struct init_spy *spy, *next;
1805 
1806     if (--info->spies_lock) return;
1807 
1808     LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry)
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  */
CoRegisterInitializeSpy(IInitializeSpy * spy,ULARGE_INTEGER * cookie)1832 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
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  */
CoRevokeInitializeSpy(ULARGE_INTEGER cookie)1891 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
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 
enter_apartment(struct oletls * info,DWORD model)1913 HRESULT enter_apartment( struct oletls *info, DWORD model )
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 
leave_apartment(struct oletls * info)1937 void leave_apartment( struct oletls *info )
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  */
CoInitialize(LPVOID lpReserved)1964 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
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  */
CoInitializeEx(LPVOID lpReserved,DWORD dwCoInit)2002 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
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    */
2021   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
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 */
2029     RunningObjectTableImpl_Initialize();
2030   }
2031 
2032   lock_init_spies(info);
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   }
2037   unlock_init_spies(info);
2038 
2039   hr = enter_apartment( info, dwCoInit );
2040 
2041   lock_init_spies(info);
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   }
2046   unlock_init_spies(info);
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  */
CoUninitialize(void)2067 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
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 
2078   lock_init_spies(info);
2079   LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2080   {
2081       if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2082   }
2083   unlock_init_spies(info);
2084 
2085   /* sanity check */
2086   if (!info->inits)
2087   {
2088       ERR("Mismatched CoUninitialize\n");
2089 
2090       lock_init_spies(info);
2091       LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2092       {
2093           if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2094       }
2095       unlock_init_spies(info);
2096 
2097       return;
2098   }
2099 
2100   leave_apartment( info );
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 
2112     revoke_registered_psclsids();
2113     RunningObjectTableImpl_UnInitialize();
2114   }
2115   else if (lCOMRefCnt<1) {
2116     ERR( "CoUninitialize() - not CoInitialized.\n" );
2117     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2118   }
2119 
2120   lock_init_spies(info);
2121   LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2122   {
2123       if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2124   }
2125   unlock_init_spies(info);
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  */
CoDisconnectObject(LPUNKNOWN lpUnk,DWORD reserved)2149 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
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 
2168     if (!(apt = apartment_get_current_or_mta()))
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 
2187     apartment_release(apt);
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  */
CoCreateGuid(GUID * pguid)2206 HRESULT WINAPI CoCreateGuid(GUID *pguid)
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 
is_valid_hex(WCHAR c)2217 static 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 
2226 static 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 */
guid_from_string(LPCWSTR s,GUID * id)2238 static BOOL guid_from_string(LPCWSTR s, GUID *id)
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 
clsid_from_string_reg(LPCOLESTR progid,CLSID * clsid)2290 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
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 );
2303     if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2304     {
2305         HeapFree(GetProcessHeap(),0,buf);
2306         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2307         return CO_E_CLASSSTRING;
2308     }
2309     HeapFree(GetProcessHeap(),0,buf);
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  */
CLSIDFromString(LPCOLESTR idstr,LPCLSID id)2338 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2339 {
2340     HRESULT ret = CO_E_CLASSSTRING;
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  */
IIDFromString(LPCOLESTR s,IID * iid)2374 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
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  */
StringFromCLSID(REFCLSID id,LPOLESTR * idstr)2412 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
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  */
StringFromGUID2(REFGUID id,LPOLESTR str,INT cmax)2434 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
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 */
COM_OpenKeyForCLSID(REFCLSID clsid,LPCWSTR keyname,REGSAM access,HKEY * subkey)2448 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
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);
2457     res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2458     if (res == ERROR_FILE_NOT_FOUND)
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);
2470     RegCloseKey(key);
2471     if (res == ERROR_FILE_NOT_FOUND)
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 */
COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid,REGSAM access,HKEY * subkey)2480 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
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;
2485     WCHAR buf[CHARS_IN_GUID];
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 */
2493     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
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);
2500     if (res == ERROR_FILE_NOT_FOUND)
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);
2508     if (res == ERROR_FILE_NOT_FOUND)
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  */
ProgIDFromCLSID(REFCLSID clsid,LPOLESTR * ppszProgID)2530 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
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))
2568       ret = REGDB_E_CLASSNOTREG;
2569 
2570     if (ret == S_OK)
2571     {
2572       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2573       if (*ppszProgID)
2574       {
2575         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2576           ret = REGDB_E_CLASSNOTREG;
2577           CoTaskMemFree(*ppszProgID);
2578           *ppszProgID = NULL;
2579         }
2580       }
2581       else
2582         ret = E_OUTOFMEMORY;
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  */
CLSIDFromProgID(LPCOLESTR progid,LPCLSID clsid)2602 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
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 
2619     return clsid_from_string_reg(progid, clsid);
2620 }
2621 
2622 /******************************************************************************
2623  *              CLSIDFromProgIDEx [OLE32.@]
2624  */
CLSIDFromProgIDEx(LPCOLESTR progid,LPCLSID clsid)2625 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2626 {
2627     FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2628 
2629     return CLSIDFromProgID(progid, clsid);
2630 }
2631 
get_ps_clsid_from_registry(const WCHAR * path,REGSAM access,CLSID * pclsid)2632 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2633 {
2634     HKEY hkey;
2635     WCHAR value[CHARS_IN_GUID];
2636     DWORD len;
2637 
2638     access |= KEY_READ;
2639 
2640     if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
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  */
CoGetPSClsid(REFIID riid,CLSID * pclsid)2690 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
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;
2696     struct registered_psclsid *registered_psclsid;
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 
2714     EnterCriticalSection(&cs_registered_psclsid_list);
2715 
2716     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2717         if (IsEqualIID(&registered_psclsid->iid, riid))
2718         {
2719             *pclsid = registered_psclsid->clsid;
2720             LeaveCriticalSection(&cs_registered_psclsid_list);
2721             return S_OK;
2722         }
2723 
2724     LeaveCriticalSection(&cs_registered_psclsid_list);
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 ||
2742                        (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
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  */
CoRegisterPSClsid(REFIID riid,REFCLSID rclsid)2778 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2779 {
2780     APARTMENT *apt;
2781     struct registered_psclsid *registered_psclsid;
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 
2792     EnterCriticalSection(&cs_registered_psclsid_list);
2793 
2794     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2795         if (IsEqualIID(&registered_psclsid->iid, riid))
2796         {
2797             registered_psclsid->clsid = *rclsid;
2798             LeaveCriticalSection(&cs_registered_psclsid_list);
2799             return S_OK;
2800         }
2801 
2802     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2803     if (!registered_psclsid)
2804     {
2805         LeaveCriticalSection(&cs_registered_psclsid_list);
2806         return E_OUTOFMEMORY;
2807     }
2808 
2809     registered_psclsid->iid = *riid;
2810     registered_psclsid->clsid = *rclsid;
2811     list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2812 
2813     LeaveCriticalSection(&cs_registered_psclsid_list);
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  */
COM_GetRegisteredClassObject(const struct apartment * apt,REFCLSID rclsid,DWORD dwClsContext,LPUNKNOWN * ppUnk)2832 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2833                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
2834 {
2835   HRESULT hr = S_FALSE;
2836   RegisteredClass *curClass;
2837 
2838   EnterCriticalSection( &csRegisteredClassList );
2839 
2840   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
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 
2861   LeaveCriticalSection( &csRegisteredClassList );
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  */
CoRegisterClassObject(REFCLSID rclsid,LPUNKNOWN pUnk,DWORD dwClsContext,DWORD flags,LPDWORD lpdwRegister)2897 HRESULT WINAPI CoRegisterClassObject(
2898     REFCLSID rclsid,
2899     LPUNKNOWN pUnk,
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. */
2926   if (flags & REGCLS_MULTIPLEUSE)
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 
2971   EnterCriticalSection( &csRegisteredClassList );
2972   list_add_tail(&RegisteredClassList, &newClass->entry);
2973   LeaveCriticalSection( &csRegisteredClassList );
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 
2987       hr = RPC_StartLocalServer(&newClass->classIdentifier,
2988                                 marshal_stream,
2989                                 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2990                                 &newClass->RpcRegistration);
2991       IStream_Release(marshal_stream);
2992   }
2993   apartment_release(apt);
2994   return S_OK;
2995 }
2996 
get_threading_model(const struct class_reg_data * data)2997 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
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 
get_inproc_class_object(APARTMENT * apt,const struct class_reg_data * regdata,REFCLSID rclsid,REFIID riid,BOOL hostifnecessary,void ** ppv)3026 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
3027                                        REFCLSID rclsid, REFIID riid,
3028                                        BOOL hostifnecessary, void **ppv)
3029 {
3030     WCHAR dllpath[MAX_PATH+1];
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 
3066     if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
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  */
CoGetClassObject(REFCLSID rclsid,DWORD dwClsContext,COSERVERINFO * pServerInfo,REFIID iid,LPVOID * ppv)3103 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
3104     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3105     REFIID iid, LPVOID *ppv)
3106 {
3107     struct class_reg_data clsreg;
3108     IUnknown *regClassObject;
3109     HRESULT	hres = E_UNEXPECTED;
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     {
3132         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
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         {
3194             if (hres == REGDB_E_CLASSNOTREG)
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));
3199                 hres = REGDB_E_CLASSNOTREG;
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         {
3230             if (hres == REGDB_E_CLASSNOTREG)
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));
3235                 hres = REGDB_E_CLASSNOTREG;
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");
3270         hres = REGDB_E_CLASSNOTREG;
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  */
CoResumeClassObjects(void)3288 HRESULT WINAPI CoResumeClassObjects(void)
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  */
CoCreateInstance(REFCLSID rclsid,LPUNKNOWN pUnkOuter,DWORD dwClsContext,REFIID iid,LPVOID * ppv)3325 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
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 
init_multi_qi(DWORD count,MULTI_QI * mqi,HRESULT hr)3346 static 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 
return_multi_qi(IUnknown * unk,DWORD count,MULTI_QI * mqi,BOOL include_unk)3357 static 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  */
CoCreateInstanceEx(REFCLSID rclsid,LPUNKNOWN pUnkOuter,DWORD dwClsContext,COSERVERINFO * pServerInfo,ULONG cmq,MULTI_QI * pResults)3387 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3388   REFCLSID      rclsid,
3389   LPUNKNOWN     pUnkOuter,
3390   DWORD         dwClsContext,
3391   COSERVERINFO* pServerInfo,
3392   ULONG         cmq,
3393   MULTI_QI*     pResults)
3394 {
3395     IUnknown *unk = NULL;
3396     IClassFactory *cf;
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      */
3425     if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3426     {
3427         IGlobalInterfaceTable *git = get_std_git();
3428         TRACE("Retrieving GIT\n");
3429         return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3430     }
3431 
3432     if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
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),
3458                   debugstr_guid(&clsid),hres);
3459         return hres;
3460     }
3461 
3462     return return_multi_qi(unk, cmq, pResults, TRUE);
3463 }
3464 
3465 /***********************************************************************
3466  *           CoGetInstanceFromFile [OLE32.@]
3467  */
CoGetInstanceFromFile(COSERVERINFO * server_info,CLSID * rclsid,IUnknown * outer,DWORD cls_context,DWORD grfmode,OLECHAR * filename,DWORD count,MULTI_QI * results)3468 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3469   COSERVERINFO *server_info,
3470   CLSID        *rclsid,
3471   IUnknown     *outer,
3472   DWORD         cls_context,
3473   DWORD         grfmode,
3474   OLECHAR      *filename,
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 
3490   init_multi_qi(count, results, E_NOINTERFACE);
3491 
3492   /* optionally get CLSID from a file */
3493   if (!rclsid)
3494   {
3495     hr = GetClassFile(filename, &clsid);
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   {
3513       init_multi_qi(count, results, hr);
3514       return hr;
3515   }
3516 
3517   /* init from file */
3518   hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3519   if (FAILED(hr))
3520   {
3521       init_multi_qi(count, results, hr);
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   {
3532       init_multi_qi(count, results, hr);
3533       IUnknown_Release(unk);
3534       return hr;
3535   }
3536 }
3537 
3538 /***********************************************************************
3539  *           CoGetInstanceFromIStorage [OLE32.@]
3540  */
CoGetInstanceFromIStorage(COSERVERINFO * server_info,CLSID * rclsid,IUnknown * outer,DWORD cls_context,IStorage * storage,DWORD count,MULTI_QI * results)3541 HRESULT WINAPI CoGetInstanceFromIStorage(
3542   COSERVERINFO *server_info,
3543   CLSID        *rclsid,
3544   IUnknown     *outer,
3545   DWORD         cls_context,
3546   IStorage     *storage,
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 
3562   init_multi_qi(count, results, E_NOINTERFACE);
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  */
CoLoadLibrary(LPOLESTR lpszLibName,BOOL bAutoFree)3617 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
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  */
CoFreeLibrary(HINSTANCE hLibrary)3638 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3639 {
3640     FreeLibrary(hLibrary);
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  */
CoFreeAllLibraries(void)3655 void WINAPI CoFreeAllLibraries(void)
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  */
CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay,DWORD dwReserved)3677 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
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  */
CoFreeUnusedLibraries(void)3701 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3702 {
3703     CoFreeUnusedLibrariesEx(INFINITE, 0);
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  */
CoFileTimeNow(FILETIME * lpFileTime)3717 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
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  */
CoLockObjectExternal(LPUNKNOWN pUnk,BOOL fLock,BOOL fLastUnlockReleases)3743 HRESULT WINAPI CoLockObjectExternal(
3744     LPUNKNOWN pUnk,
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  */
CoInitializeWOW(DWORD x,DWORD y)3793 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
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  */
CoGetState(IUnknown ** ppv)3819 HRESULT WINAPI CoGetState(IUnknown ** ppv)
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  */
CoSetState(IUnknown * pv)3851 HRESULT WINAPI CoSetState(IUnknown * pv)
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  */
CoTreatAsClass(REFCLSID clsidOld,REFCLSID clsidNew)3886 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
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            {
3908                res = REGDB_E_WRITEREGDB;
3909                goto done;
3910            }
3911        }
3912        else
3913        {
3914            if(RegDeleteKeyW(hkey, wszTreatAs))
3915                res = REGDB_E_WRITEREGDB;
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");
3932                 res = REGDB_E_WRITEREGDB;
3933                 goto done;
3934             }
3935         }
3936     }
3937 
3938 done:
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  */
CoGetTreatAsClass(REFCLSID clsidOld,LPCLSID clsidNew)3959 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
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);
3988 done:
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  */
CoGetCurrentProcess(void)4004 DWORD WINAPI CoGetCurrentProcess(void)
4005 {
4006 	return GetCurrentProcessId();
4007 }
4008 
4009 /***********************************************************************
4010  *              CoGetCurrentLogicalThreadId        [OLE32.@]
4011  */
CoGetCurrentLogicalThreadId(GUID * id)4012 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
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  */
CoRegisterMessageFilter(LPMESSAGEFILTER lpMessageFilter,LPMESSAGEFILTER * lplpMessageFilter)4046 HRESULT WINAPI CoRegisterMessageFilter(
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  */
CoIsOle1Class(REFCLSID clsid)4093 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
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
IsEqualGUID(REFGUID rguid1,REFGUID rguid2)4112 BOOL WINAPI IsEqualGUID(
4113      REFGUID rguid1,
4114      REFGUID rguid2)
4115 {
4116     return !memcmp(rguid1,rguid2,sizeof(GUID));
4117 }
4118 
4119 /***********************************************************************
4120  *           CoInitializeSecurity [OLE32.@]
4121  */
CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc,LONG cAuthSvc,SOLE_AUTHENTICATION_SERVICE * asAuthSvc,void * pReserved1,DWORD dwAuthnLevel,DWORD dwImpLevel,void * pReserved2,DWORD dwCapabilities,void * pReserved3)4122 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
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  */
CoSuspendClassObjects(void)4144 HRESULT WINAPI CoSuspendClassObjects(void)
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  */
CoAddRefServerProcess(void)4162 ULONG WINAPI CoAddRefServerProcess(void)
4163 {
4164     ULONG refs;
4165 
4166     TRACE("\n");
4167 
4168     EnterCriticalSection(&csRegisteredClassList);
4169     refs = ++s_COMServerProcessReferences;
4170     LeaveCriticalSection(&csRegisteredClassList);
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  */
CoReleaseServerProcess(void)4193 ULONG WINAPI CoReleaseServerProcess(void)
4194 {
4195     ULONG refs;
4196 
4197     TRACE("\n");
4198 
4199     EnterCriticalSection(&csRegisteredClassList);
4200 
4201     refs = --s_COMServerProcessReferences;
4202     /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4203 
4204     LeaveCriticalSection(&csRegisteredClassList);
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  */
CoIsHandlerConnected(IUnknown * pUnk)4223 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4224 {
4225     FIXME("%p\n", pUnk);
4226 
4227     return TRUE;
4228 }
4229 
4230 /***********************************************************************
4231  *           CoAllowSetForegroundWindow [OLE32.@]
4232  *
4233  */
CoAllowSetForegroundWindow(IUnknown * pUnk,void * pvReserved)4234 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
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  */
CoQueryProxyBlanket(IUnknown * pProxy,DWORD * pAuthnSvc,DWORD * pAuthzSvc,OLECHAR ** ppServerPrincName,DWORD * pAuthnLevel,DWORD * pImpLevel,void ** ppAuthInfo,DWORD * pCapabilities)4262 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
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 the security settings for a proxy.
4289  *
4290  * PARAMS
4291  *  pProxy       [I] Pointer to the proxy object.
4292  *  AuthnSvc     [I] The type of authentication service.
4293  *  AuthzSvc     [I] The type of authorization service.
4294  *  pServerPrincName [I] The server prinicple name.
4295  *  AuthnLevel   [I] The authentication level.
4296  *  ImpLevel     [I] The impersonation level.
4297  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
4298  *  Capabilities [I] Flags affecting the security behaviour.
4299  *
4300  * RETURNS
4301  *  Success: S_OK.
4302  *  Failure: HRESULT code.
4303  *
4304  * SEE ALSO
4305  *  CoQueryProxyBlanket, CoCopyProxy.
4306  */
CoSetProxyBlanket(IUnknown * pProxy,DWORD AuthnSvc,DWORD AuthzSvc,OLECHAR * pServerPrincName,DWORD AuthnLevel,DWORD ImpLevel,void * pAuthInfo,DWORD Capabilities)4307 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4308     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4309     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4310 {
4311     IClientSecurity *pCliSec;
4312     HRESULT hr;
4313 
4314     TRACE("%p\n", pProxy);
4315 
4316     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4317     if (SUCCEEDED(hr))
4318     {
4319         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4320                                         AuthzSvc, pServerPrincName,
4321                                         AuthnLevel, ImpLevel, pAuthInfo,
4322                                         Capabilities);
4323         IClientSecurity_Release(pCliSec);
4324     }
4325 
4326     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4327     return hr;
4328 }
4329 
4330 /***********************************************************************
4331  *           CoCopyProxy [OLE32.@]
4332  *
4333  * Copies a proxy.
4334  *
4335  * PARAMS
4336  *  pProxy [I] Pointer to the proxy object.
4337  *  ppCopy [O] Copy of the proxy.
4338  *
4339  * RETURNS
4340  *  Success: S_OK.
4341  *  Failure: HRESULT code.
4342  *
4343  * SEE ALSO
4344  *  CoQueryProxyBlanket, CoSetProxyBlanket.
4345  */
CoCopyProxy(IUnknown * pProxy,IUnknown ** ppCopy)4346 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4347 {
4348     IClientSecurity *pCliSec;
4349     HRESULT hr;
4350 
4351     TRACE("%p\n", pProxy);
4352 
4353     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4354     if (SUCCEEDED(hr))
4355     {
4356         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4357         IClientSecurity_Release(pCliSec);
4358     }
4359 
4360     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4361     return hr;
4362 }
4363 
4364 
4365 /***********************************************************************
4366  *           CoGetCallContext [OLE32.@]
4367  *
4368  * Gets the context of the currently executing server call in the current
4369  * thread.
4370  *
4371  * PARAMS
4372  *  riid [I] Context interface to return.
4373  *  ppv  [O] Pointer to memory that will receive the context on return.
4374  *
4375  * RETURNS
4376  *  Success: S_OK.
4377  *  Failure: HRESULT code.
4378  */
CoGetCallContext(REFIID riid,void ** ppv)4379 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4380 {
4381     struct oletls *info = COM_CurrentInfo();
4382 
4383     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4384 
4385     if (!info)
4386         return E_OUTOFMEMORY;
4387 
4388     if (!info->call_state)
4389         return RPC_E_CALL_COMPLETE;
4390 
4391     return IUnknown_QueryInterface(info->call_state, riid, ppv);
4392 }
4393 
4394 /***********************************************************************
4395  *           CoSwitchCallContext [OLE32.@]
4396  *
4397  * Switches the context of the currently executing server call in the current
4398  * thread.
4399  *
4400  * PARAMS
4401  *  pObject     [I] Pointer to new context object
4402  *  ppOldObject [O] Pointer to memory that will receive old context object pointer
4403  *
4404  * RETURNS
4405  *  Success: S_OK.
4406  *  Failure: HRESULT code.
4407  */
CoSwitchCallContext(IUnknown * pObject,IUnknown ** ppOldObject)4408 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4409 {
4410     struct oletls *info = COM_CurrentInfo();
4411 
4412     TRACE("(%p, %p)\n", pObject, ppOldObject);
4413 
4414     if (!info)
4415         return E_OUTOFMEMORY;
4416 
4417     *ppOldObject = info->call_state;
4418     info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4419 
4420     return S_OK;
4421 }
4422 
4423 /***********************************************************************
4424  *           CoQueryClientBlanket [OLE32.@]
4425  *
4426  * Retrieves the authentication information about the client of the currently
4427  * executing server call in the current thread.
4428  *
4429  * PARAMS
4430  *  pAuthnSvc     [O] Optional. The type of authentication service.
4431  *  pAuthzSvc     [O] Optional. The type of authorization service.
4432  *  pServerPrincName [O] Optional. The server prinicple name.
4433  *  pAuthnLevel   [O] Optional. The authentication level.
4434  *  pImpLevel     [O] Optional. The impersonation level.
4435  *  pPrivs        [O] Optional. Information about the privileges of the client.
4436  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
4437  *
4438  * RETURNS
4439  *  Success: S_OK.
4440  *  Failure: HRESULT code.
4441  *
4442  * SEE ALSO
4443  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4444  */
CoQueryClientBlanket(DWORD * pAuthnSvc,DWORD * pAuthzSvc,OLECHAR ** pServerPrincName,DWORD * pAuthnLevel,DWORD * pImpLevel,RPC_AUTHZ_HANDLE * pPrivs,DWORD * pCapabilities)4445 HRESULT WINAPI CoQueryClientBlanket(
4446     DWORD *pAuthnSvc,
4447     DWORD *pAuthzSvc,
4448     OLECHAR **pServerPrincName,
4449     DWORD *pAuthnLevel,
4450     DWORD *pImpLevel,
4451     RPC_AUTHZ_HANDLE *pPrivs,
4452     DWORD *pCapabilities)
4453 {
4454     IServerSecurity *pSrvSec;
4455     HRESULT hr;
4456 
4457     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4458         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4459         pPrivs, pCapabilities);
4460 
4461     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4462     if (SUCCEEDED(hr))
4463     {
4464         hr = IServerSecurity_QueryBlanket(
4465             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4466             pImpLevel, pPrivs, pCapabilities);
4467         IServerSecurity_Release(pSrvSec);
4468     }
4469 
4470     return hr;
4471 }
4472 
4473 /***********************************************************************
4474  *           CoImpersonateClient [OLE32.@]
4475  *
4476  * Impersonates the client of the currently executing server call in the
4477  * current thread.
4478  *
4479  * PARAMS
4480  *  None.
4481  *
4482  * RETURNS
4483  *  Success: S_OK.
4484  *  Failure: HRESULT code.
4485  *
4486  * NOTES
4487  *  If this function fails then the current thread will not be impersonating
4488  *  the client and all actions will take place on behalf of the server.
4489  *  Therefore, it is important to check the return value from this function.
4490  *
4491  * SEE ALSO
4492  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4493  */
CoImpersonateClient(void)4494 HRESULT WINAPI CoImpersonateClient(void)
4495 {
4496     IServerSecurity *pSrvSec;
4497     HRESULT hr;
4498 
4499     TRACE("\n");
4500 
4501     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4502     if (SUCCEEDED(hr))
4503     {
4504         hr = IServerSecurity_ImpersonateClient(pSrvSec);
4505         IServerSecurity_Release(pSrvSec);
4506     }
4507 
4508     return hr;
4509 }
4510 
4511 /***********************************************************************
4512  *           CoRevertToSelf [OLE32.@]
4513  *
4514  * Ends the impersonation of the client of the currently executing server
4515  * call in the current thread.
4516  *
4517  * PARAMS
4518  *  None.
4519  *
4520  * RETURNS
4521  *  Success: S_OK.
4522  *  Failure: HRESULT code.
4523  *
4524  * SEE ALSO
4525  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4526  */
CoRevertToSelf(void)4527 HRESULT WINAPI CoRevertToSelf(void)
4528 {
4529     IServerSecurity *pSrvSec;
4530     HRESULT hr;
4531 
4532     TRACE("\n");
4533 
4534     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4535     if (SUCCEEDED(hr))
4536     {
4537         hr = IServerSecurity_RevertToSelf(pSrvSec);
4538         IServerSecurity_Release(pSrvSec);
4539     }
4540 
4541     return hr;
4542 }
4543 
COM_PeekMessage(struct apartment * apt,MSG * msg)4544 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4545 {
4546     /* first try to retrieve messages for incoming COM calls to the apartment window */
4547     return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4548            /* next retrieve other messages necessary for the app to remain responsive */
4549            PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4550            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4551 }
4552 
4553 /***********************************************************************
4554  *           CoWaitForMultipleHandles [OLE32.@]
4555  *
4556  * Waits for one or more handles to become signaled.
4557  *
4558  * PARAMS
4559  *  dwFlags   [I] Flags. See notes.
4560  *  dwTimeout [I] Timeout in milliseconds.
4561  *  cHandles  [I] Number of handles pointed to by pHandles.
4562  *  pHandles  [I] Handles to wait for.
4563  *  lpdwindex [O] Index of handle that was signaled.
4564  *
4565  * RETURNS
4566  *  Success: S_OK.
4567  *  Failure: RPC_S_CALLPENDING on timeout.
4568  *
4569  * NOTES
4570  *
4571  * The dwFlags parameter can be zero or more of the following:
4572  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4573  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4574  *
4575  * SEE ALSO
4576  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
4577  */
CoWaitForMultipleHandles(DWORD dwFlags,DWORD dwTimeout,ULONG cHandles,LPHANDLE pHandles,LPDWORD lpdwindex)4578 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4579     ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4580 {
4581     HRESULT hr = S_OK;
4582     DWORD start_time = GetTickCount();
4583     APARTMENT *apt = COM_CurrentApt();
4584     BOOL message_loop = apt && !apt->multi_threaded;
4585     BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4586     BOOL post_quit = FALSE;
4587     UINT exit_code;
4588 
4589     TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4590         pHandles, lpdwindex);
4591 
4592     if (!lpdwindex)
4593         return E_INVALIDARG;
4594 
4595     *lpdwindex = 0;
4596 
4597     if (!pHandles)
4598         return E_INVALIDARG;
4599 
4600     if (!cHandles)
4601         return RPC_E_NO_SYNC;
4602 
4603     while (TRUE)
4604     {
4605         DWORD now = GetTickCount();
4606         DWORD res;
4607 
4608         if (now - start_time > dwTimeout)
4609         {
4610             hr = RPC_S_CALLPENDING;
4611             break;
4612         }
4613 
4614         if (message_loop)
4615         {
4616             DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4617                     ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4618 
4619             TRACE("waiting for rpc completion or window message\n");
4620 
4621             res = WAIT_TIMEOUT;
4622 
4623             if (check_apc)
4624             {
4625                 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4626                     (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4627                 check_apc = FALSE;
4628             }
4629 
4630             if (res == WAIT_TIMEOUT)
4631                 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4632                     (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4633                     QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4634 
4635             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
4636             {
4637                 MSG msg;
4638                 int count = 0;
4639 
4640                 /* call message filter */
4641 
4642                 if (COM_CurrentApt()->filter)
4643                 {
4644                     PENDINGTYPE pendingtype =
4645                         COM_CurrentInfo()->pending_call_count_server ?
4646                             PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4647                     DWORD be_handled = IMessageFilter_MessagePending(
4648                         COM_CurrentApt()->filter, 0 /* FIXME */,
4649                         now - start_time, pendingtype);
4650                     TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4651                     switch (be_handled)
4652                     {
4653                     case PENDINGMSG_CANCELCALL:
4654                         WARN("call canceled\n");
4655                         hr = RPC_E_CALL_CANCELED;
4656                         break;
4657                     case PENDINGMSG_WAITNOPROCESS:
4658                     case PENDINGMSG_WAITDEFPROCESS:
4659                     default:
4660                         /* FIXME: MSDN is very vague about the difference
4661                          * between WAITNOPROCESS and WAITDEFPROCESS - there
4662                          * appears to be none, so it is possibly a left-over
4663                          * from the 16-bit world. */
4664                         break;
4665                     }
4666                 }
4667 
4668                 if (!apt->win)
4669                 {
4670                     /* If window is NULL on apartment, peek at messages so that it will not trigger
4671                      * MsgWaitForMultipleObjects next time. */
4672                     PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
4673                 }
4674                 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4675                  * so after processing 100 messages we go back to checking the wait handles */
4676                 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4677                 {
4678                     if (msg.message == WM_QUIT)
4679                     {
4680                         TRACE("received WM_QUIT message\n");
4681                         post_quit = TRUE;
4682                         exit_code = msg.wParam;
4683                     }
4684                     else
4685                     {
4686                         TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4687                         TranslateMessage(&msg);
4688                         DispatchMessageW(&msg);
4689                     }
4690                 }
4691                 continue;
4692             }
4693         }
4694         else
4695         {
4696             TRACE("waiting for rpc completion\n");
4697 
4698             res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4699                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4700                 (dwFlags & COWAIT_ALERTABLE) != 0);
4701         }
4702 
4703         switch (res)
4704         {
4705         case WAIT_TIMEOUT:
4706             hr = RPC_S_CALLPENDING;
4707             break;
4708         case WAIT_FAILED:
4709             hr = HRESULT_FROM_WIN32( GetLastError() );
4710             break;
4711         default:
4712             *lpdwindex = res;
4713             break;
4714         }
4715         break;
4716     }
4717     if (post_quit) PostQuitMessage(exit_code);
4718     TRACE("-- 0x%08x\n", hr);
4719     return hr;
4720 }
4721 
4722 
4723 /***********************************************************************
4724  *           CoGetObject [OLE32.@]
4725  *
4726  * Gets the object named by converting the name to a moniker and binding to it.
4727  *
4728  * PARAMS
4729  *  pszName      [I] String representing the object.
4730  *  pBindOptions [I] Parameters affecting the binding to the named object.
4731  *  riid         [I] Interface to bind to on the objecct.
4732  *  ppv          [O] On output, the interface riid of the object represented
4733  *                   by pszName.
4734  *
4735  * RETURNS
4736  *  Success: S_OK.
4737  *  Failure: HRESULT code.
4738  *
4739  * SEE ALSO
4740  *  MkParseDisplayName.
4741  */
CoGetObject(LPCWSTR pszName,BIND_OPTS * pBindOptions,REFIID riid,void ** ppv)4742 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4743     REFIID riid, void **ppv)
4744 {
4745     IBindCtx *pbc;
4746     HRESULT hr;
4747 
4748     *ppv = NULL;
4749 
4750     hr = CreateBindCtx(0, &pbc);
4751     if (SUCCEEDED(hr))
4752     {
4753         if (pBindOptions)
4754             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4755 
4756         if (SUCCEEDED(hr))
4757         {
4758             ULONG chEaten;
4759             IMoniker *pmk;
4760 
4761             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4762             if (SUCCEEDED(hr))
4763             {
4764                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4765                 IMoniker_Release(pmk);
4766             }
4767         }
4768 
4769         IBindCtx_Release(pbc);
4770     }
4771     return hr;
4772 }
4773 
4774 /***********************************************************************
4775  *           CoRegisterChannelHook [OLE32.@]
4776  *
4777  * Registers a process-wide hook that is called during ORPC calls.
4778  *
4779  * PARAMS
4780  *  guidExtension [I] GUID of the channel hook to register.
4781  *  pChannelHook  [I] Channel hook object to register.
4782  *
4783  * RETURNS
4784  *  Success: S_OK.
4785  *  Failure: HRESULT code.
4786  */
CoRegisterChannelHook(REFGUID guidExtension,IChannelHook * pChannelHook)4787 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4788 {
4789     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4790 
4791     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4792 }
4793 
4794 typedef struct Context
4795 {
4796     IComThreadingInfo IComThreadingInfo_iface;
4797     IContextCallback IContextCallback_iface;
4798     IObjContext IObjContext_iface;
4799     LONG refs;
4800 } Context;
4801 
impl_from_IComThreadingInfo(IComThreadingInfo * iface)4802 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4803 {
4804         return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4805 }
4806 
impl_from_IContextCallback(IContextCallback * iface)4807 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4808 {
4809         return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4810 }
4811 
impl_from_IObjContext(IObjContext * iface)4812 static inline Context *impl_from_IObjContext( IObjContext *iface )
4813 {
4814         return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4815 }
4816 
Context_QueryInterface(Context * iface,REFIID riid,LPVOID * ppv)4817 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4818 {
4819     *ppv = NULL;
4820 
4821     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4822         IsEqualIID(riid, &IID_IUnknown))
4823     {
4824         *ppv = &iface->IComThreadingInfo_iface;
4825     }
4826     else if (IsEqualIID(riid, &IID_IContextCallback))
4827     {
4828         *ppv = &iface->IContextCallback_iface;
4829     }
4830     else if (IsEqualIID(riid, &IID_IObjContext))
4831     {
4832         *ppv = &iface->IObjContext_iface;
4833     }
4834 
4835     if (*ppv)
4836     {
4837         IUnknown_AddRef((IUnknown*)*ppv);
4838         return S_OK;
4839     }
4840 
4841     FIXME("interface not implemented %s\n", debugstr_guid(riid));
4842     return E_NOINTERFACE;
4843 }
4844 
Context_AddRef(Context * This)4845 static ULONG Context_AddRef(Context *This)
4846 {
4847     return InterlockedIncrement(&This->refs);
4848 }
4849 
Context_Release(Context * This)4850 static ULONG Context_Release(Context *This)
4851 {
4852     /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4853        releasing context while refcount is at 0 destroys it. */
4854     if (!This->refs)
4855     {
4856         HeapFree(GetProcessHeap(), 0, This);
4857         return 0;
4858     }
4859 
4860     return InterlockedDecrement(&This->refs);
4861 }
4862 
Context_CTI_QueryInterface(IComThreadingInfo * iface,REFIID riid,LPVOID * ppv)4863 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4864 {
4865     Context *This = impl_from_IComThreadingInfo(iface);
4866     return Context_QueryInterface(This, riid, ppv);
4867 }
4868 
Context_CTI_AddRef(IComThreadingInfo * iface)4869 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4870 {
4871     Context *This = impl_from_IComThreadingInfo(iface);
4872     return Context_AddRef(This);
4873 }
4874 
Context_CTI_Release(IComThreadingInfo * iface)4875 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4876 {
4877     Context *This = impl_from_IComThreadingInfo(iface);
4878     return Context_Release(This);
4879 }
4880 
Context_CTI_GetCurrentApartmentType(IComThreadingInfo * iface,APTTYPE * apttype)4881 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4882 {
4883     APTTYPEQUALIFIER qualifier;
4884 
4885     TRACE("(%p)\n", apttype);
4886 
4887     return CoGetApartmentType(apttype, &qualifier);
4888 }
4889 
Context_CTI_GetCurrentThreadType(IComThreadingInfo * iface,THDTYPE * thdtype)4890 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4891 {
4892     APTTYPEQUALIFIER qualifier;
4893     APTTYPE apttype;
4894     HRESULT hr;
4895 
4896     hr = CoGetApartmentType(&apttype, &qualifier);
4897     if (FAILED(hr))
4898         return hr;
4899 
4900     TRACE("(%p)\n", thdtype);
4901 
4902     switch (apttype)
4903     {
4904     case APTTYPE_STA:
4905     case APTTYPE_MAINSTA:
4906         *thdtype = THDTYPE_PROCESSMESSAGES;
4907         break;
4908     default:
4909         *thdtype = THDTYPE_BLOCKMESSAGES;
4910         break;
4911     }
4912     return S_OK;
4913 }
4914 
Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo * iface,GUID * logical_thread_id)4915 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4916 {
4917     TRACE("(%p)\n", logical_thread_id);
4918     return CoGetCurrentLogicalThreadId(logical_thread_id);
4919 }
4920 
Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo * iface,REFGUID logical_thread_id)4921 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4922 {
4923     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4924     return E_NOTIMPL;
4925 }
4926 
4927 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4928 {
4929     Context_CTI_QueryInterface,
4930     Context_CTI_AddRef,
4931     Context_CTI_Release,
4932     Context_CTI_GetCurrentApartmentType,
4933     Context_CTI_GetCurrentThreadType,
4934     Context_CTI_GetCurrentLogicalThreadId,
4935     Context_CTI_SetCurrentLogicalThreadId
4936 };
4937 
Context_CC_QueryInterface(IContextCallback * iface,REFIID riid,LPVOID * ppv)4938 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4939 {
4940     Context *This = impl_from_IContextCallback(iface);
4941     return Context_QueryInterface(This, riid, ppv);
4942 }
4943 
Context_CC_AddRef(IContextCallback * iface)4944 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4945 {
4946     Context *This = impl_from_IContextCallback(iface);
4947     return Context_AddRef(This);
4948 }
4949 
Context_CC_Release(IContextCallback * iface)4950 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4951 {
4952     Context *This = impl_from_IContextCallback(iface);
4953     return Context_Release(This);
4954 }
4955 
Context_CC_ContextCallback(IContextCallback * iface,PFNCONTEXTCALL pCallback,ComCallData * param,REFIID riid,int method,IUnknown * punk)4956 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4957                             ComCallData *param, REFIID riid, int method, IUnknown *punk)
4958 {
4959     Context *This = impl_from_IContextCallback(iface);
4960 
4961     FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4962     return E_NOTIMPL;
4963 }
4964 
4965 static const IContextCallbackVtbl Context_Callback_Vtbl =
4966 {
4967     Context_CC_QueryInterface,
4968     Context_CC_AddRef,
4969     Context_CC_Release,
4970     Context_CC_ContextCallback
4971 };
4972 
Context_OC_QueryInterface(IObjContext * iface,REFIID riid,LPVOID * ppv)4973 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4974 {
4975     Context *This = impl_from_IObjContext(iface);
4976     return Context_QueryInterface(This, riid, ppv);
4977 }
4978 
Context_OC_AddRef(IObjContext * iface)4979 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4980 {
4981     Context *This = impl_from_IObjContext(iface);
4982     return Context_AddRef(This);
4983 }
4984 
Context_OC_Release(IObjContext * iface)4985 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4986 {
4987     Context *This = impl_from_IObjContext(iface);
4988     return Context_Release(This);
4989 }
4990 
Context_OC_SetProperty(IObjContext * iface,REFGUID propid,CPFLAGS flags,IUnknown * punk)4991 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4992 {
4993     Context *This = impl_from_IObjContext(iface);
4994 
4995     FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4996     return E_NOTIMPL;
4997 }
4998 
Context_OC_RemoveProperty(IObjContext * iface,REFGUID propid)4999 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
5000 {
5001     Context *This = impl_from_IObjContext(iface);
5002 
5003     FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
5004     return E_NOTIMPL;
5005 }
5006 
Context_OC_GetProperty(IObjContext * iface,REFGUID propid,CPFLAGS * flags,IUnknown ** punk)5007 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
5008 {
5009     Context *This = impl_from_IObjContext(iface);
5010 
5011     FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
5012     return E_NOTIMPL;
5013 }
5014 
Context_OC_EnumContextProps(IObjContext * iface,IEnumContextProps ** props)5015 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
5016 {
5017     Context *This = impl_from_IObjContext(iface);
5018 
5019     FIXME("(%p/%p)->(%p)\n", This, iface, props);
5020     return E_NOTIMPL;
5021 }
5022 
Context_OC_Reserved1(IObjContext * iface)5023 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
5024 {
5025     Context *This = impl_from_IObjContext(iface);
5026     FIXME("(%p/%p)\n", This, iface);
5027 }
5028 
Context_OC_Reserved2(IObjContext * iface)5029 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
5030 {
5031     Context *This = impl_from_IObjContext(iface);
5032     FIXME("(%p/%p)\n", This, iface);
5033 }
5034 
Context_OC_Reserved3(IObjContext * iface)5035 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
5036 {
5037     Context *This = impl_from_IObjContext(iface);
5038     FIXME("(%p/%p)\n", This, iface);
5039 }
5040 
Context_OC_Reserved4(IObjContext * iface)5041 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
5042 {
5043     Context *This = impl_from_IObjContext(iface);
5044     FIXME("(%p/%p)\n", This, iface);
5045 }
5046 
Context_OC_Reserved5(IObjContext * iface)5047 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
5048 {
5049     Context *This = impl_from_IObjContext(iface);
5050     FIXME("(%p/%p)\n", This, iface);
5051 }
5052 
Context_OC_Reserved6(IObjContext * iface)5053 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
5054 {
5055     Context *This = impl_from_IObjContext(iface);
5056     FIXME("(%p/%p)\n", This, iface);
5057 }
5058 
Context_OC_Reserved7(IObjContext * iface)5059 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
5060 {
5061     Context *This = impl_from_IObjContext(iface);
5062     FIXME("(%p/%p)\n", This, iface);
5063 }
5064 
5065 static const IObjContextVtbl Context_Object_Vtbl =
5066 {
5067     Context_OC_QueryInterface,
5068     Context_OC_AddRef,
5069     Context_OC_Release,
5070     Context_OC_SetProperty,
5071     Context_OC_RemoveProperty,
5072     Context_OC_GetProperty,
5073     Context_OC_EnumContextProps,
5074     Context_OC_Reserved1,
5075     Context_OC_Reserved2,
5076     Context_OC_Reserved3,
5077     Context_OC_Reserved4,
5078     Context_OC_Reserved5,
5079     Context_OC_Reserved6,
5080     Context_OC_Reserved7
5081 };
5082 
5083 /***********************************************************************
5084  *           CoGetObjectContext [OLE32.@]
5085  *
5086  * Retrieves an object associated with the current context (i.e. apartment).
5087  *
5088  * PARAMS
5089  *  riid [I] ID of the interface of the object to retrieve.
5090  *  ppv  [O] Address where object will be stored on return.
5091  *
5092  * RETURNS
5093  *  Success: S_OK.
5094  *  Failure: HRESULT code.
5095  */
CoGetObjectContext(REFIID riid,void ** ppv)5096 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
5097 {
5098     IObjContext *context;
5099     HRESULT hr;
5100 
5101     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
5102 
5103     *ppv = NULL;
5104     hr = CoGetContextToken((ULONG_PTR*)&context);
5105     if (FAILED(hr))
5106         return hr;
5107 
5108     return IObjContext_QueryInterface(context, riid, ppv);
5109 }
5110 
5111 /***********************************************************************
5112  *           CoGetContextToken [OLE32.@]
5113  */
CoGetContextToken(ULONG_PTR * token)5114 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
5115 {
5116     struct oletls *info = COM_CurrentInfo();
5117     APARTMENT *apt;
5118 
5119     TRACE("(%p)\n", token);
5120 
5121     if (!info)
5122         return E_OUTOFMEMORY;
5123 
5124     if (!(apt = apartment_get_current_or_mta()))
5125     {
5126         ERR("apartment not initialised\n");
5127         return CO_E_NOTINITIALIZED;
5128     }
5129     apartment_release(apt);
5130 
5131     if (!token)
5132         return E_POINTER;
5133 
5134     if (!info->context_token)
5135     {
5136         Context *context;
5137 
5138         context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5139         if (!context)
5140             return E_OUTOFMEMORY;
5141 
5142         context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5143         context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5144         context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5145         /* Context token does not take a reference, it's always zero until the
5146            interface is explicitly requested with CoGetObjectContext(). */
5147         context->refs = 0;
5148 
5149         info->context_token = &context->IObjContext_iface;
5150     }
5151 
5152     *token = (ULONG_PTR)info->context_token;
5153     TRACE("context_token=%p\n", info->context_token);
5154 
5155     return S_OK;
5156 }
5157 
5158 /***********************************************************************
5159  *           CoGetDefaultContext [OLE32.@]
5160  */
CoGetDefaultContext(APTTYPE type,REFIID riid,LPVOID * ppv)5161 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5162 {
5163     FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5164     return E_NOINTERFACE;
5165 }
5166 
Handler_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID * ppv)5167 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5168 {
5169     static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5170     HKEY hkey;
5171     HRESULT hres;
5172 
5173     hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5174     if (SUCCEEDED(hres))
5175     {
5176         struct class_reg_data regdata;
5177         WCHAR dllpath[MAX_PATH+1];
5178 
5179         regdata.u.hkey = hkey;
5180         regdata.hkey = TRUE;
5181 
5182         if (get_object_dll_path(&regdata, dllpath, ARRAY_SIZE(dllpath)))
5183         {
5184             static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5185             if (!wcsicmp(dllpath, wszOle32))
5186             {
5187                 RegCloseKey(hkey);
5188                 return HandlerCF_Create(rclsid, riid, ppv);
5189             }
5190         }
5191         else
5192             WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5193         RegCloseKey(hkey);
5194     }
5195 
5196     return CLASS_E_CLASSNOTAVAILABLE;
5197 }
5198 
5199 /***********************************************************************
5200  *           CoGetApartmentType [OLE32.@]
5201  */
CoGetApartmentType(APTTYPE * type,APTTYPEQUALIFIER * qualifier)5202 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5203 {
5204     struct oletls *info = COM_CurrentInfo();
5205     APARTMENT *apt;
5206 
5207     TRACE("(%p, %p)\n", type, qualifier);
5208 
5209     if (!type || !qualifier)
5210         return E_INVALIDARG;
5211 
5212     if (!info)
5213         return E_OUTOFMEMORY;
5214 
5215     if (!info->apt)
5216         *type = APTTYPE_CURRENT;
5217     else if (info->apt->multi_threaded)
5218         *type = APTTYPE_MTA;
5219     else if (info->apt->main)
5220         *type = APTTYPE_MAINSTA;
5221     else
5222         *type = APTTYPE_STA;
5223 
5224     *qualifier = APTTYPEQUALIFIER_NONE;
5225 
5226     if (!info->apt && (apt = apartment_find_mta()))
5227     {
5228         apartment_release(apt);
5229         *type = APTTYPE_MTA;
5230         *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
5231     }
5232 
5233     return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5234 }
5235 
5236 /***********************************************************************
5237  *           CoDisableCallCancellation [OLE32.@]
5238  */
CoDisableCallCancellation(void * reserved)5239 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
5240 {
5241     FIXME("(%p): stub\n", reserved);
5242 
5243     return E_NOTIMPL;
5244 }
5245 
5246 /***********************************************************************
5247  *           CoEnableCallCancellation [OLE32.@]
5248  */
CoEnableCallCancellation(void * reserved)5249 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
5250 {
5251     FIXME("(%p): stub\n", reserved);
5252 
5253     return E_NOTIMPL;
5254 }
5255 
5256 /***********************************************************************
5257  *           CoRegisterSurrogate [OLE32.@]
5258  */
CoRegisterSurrogate(ISurrogate * surrogate)5259 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5260 {
5261     FIXME("(%p): stub\n", surrogate);
5262 
5263     return E_NOTIMPL;
5264 }
5265 
5266 /***********************************************************************
5267  *           CoRegisterSurrogateEx [OLE32.@]
5268  */
CoRegisterSurrogateEx(REFGUID guid,void * reserved)5269 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5270 {
5271     FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5272 
5273     return E_NOTIMPL;
5274 }
5275 
5276 typedef struct {
5277     IGlobalOptions IGlobalOptions_iface;
5278     LONG ref;
5279 } GlobalOptions;
5280 
impl_from_IGlobalOptions(IGlobalOptions * iface)5281 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5282 {
5283     return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5284 }
5285 
GlobalOptions_QueryInterface(IGlobalOptions * iface,REFIID riid,void ** ppv)5286 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5287 {
5288     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5289 
5290     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5291 
5292     if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5293     {
5294         *ppv = iface;
5295     }
5296     else
5297     {
5298         *ppv = NULL;
5299         return E_NOINTERFACE;
5300     }
5301 
5302     IUnknown_AddRef((IUnknown*)*ppv);
5303     return S_OK;
5304 }
5305 
GlobalOptions_AddRef(IGlobalOptions * iface)5306 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5307 {
5308     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5309     LONG ref = InterlockedIncrement(&This->ref);
5310 
5311     TRACE("(%p) ref=%d\n", This, ref);
5312 
5313     return ref;
5314 }
5315 
GlobalOptions_Release(IGlobalOptions * iface)5316 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5317 {
5318     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5319     LONG ref = InterlockedDecrement(&This->ref);
5320 
5321     TRACE("(%p) ref=%d\n", This, ref);
5322 
5323     if (!ref)
5324         heap_free(This);
5325 
5326     return ref;
5327 }
5328 
GlobalOptions_Set(IGlobalOptions * iface,GLOBALOPT_PROPERTIES property,ULONG_PTR value)5329 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5330 {
5331     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5332     FIXME("(%p)->(%u %lx)\n", This, property, value);
5333     return S_OK;
5334 }
5335 
GlobalOptions_Query(IGlobalOptions * iface,GLOBALOPT_PROPERTIES property,ULONG_PTR * value)5336 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5337 {
5338     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5339     FIXME("(%p)->(%u %p)\n", This, property, value);
5340     return E_NOTIMPL;
5341 }
5342 
5343 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5344     GlobalOptions_QueryInterface,
5345     GlobalOptions_AddRef,
5346     GlobalOptions_Release,
5347     GlobalOptions_Set,
5348     GlobalOptions_Query
5349 };
5350 
GlobalOptions_CreateInstance(IClassFactory * iface,IUnknown * outer,REFIID riid,void ** ppv)5351 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5352 {
5353     GlobalOptions *global_options;
5354     HRESULT hres;
5355 
5356     TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5357 
5358     if (outer)
5359         return E_INVALIDARG;
5360 
5361     global_options = heap_alloc(sizeof(*global_options));
5362     if (!global_options)
5363         return E_OUTOFMEMORY;
5364     global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5365     global_options->ref = 1;
5366 
5367     hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5368     IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5369     return hres;
5370 }
5371 
5372 /***********************************************************************
5373  *		DllMain (OLE32.@)
5374  */
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID reserved)5375 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5376 {
5377     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5378 
5379     switch(fdwReason) {
5380     case DLL_PROCESS_ATTACH:
5381         hProxyDll = hinstDLL;
5382 	break;
5383 
5384     case DLL_PROCESS_DETACH:
5385         if (reserved) break;
5386         release_std_git();
5387         if(apt_win_class)
5388             UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll );
5389         RPC_UnregisterAllChannelHooks();
5390         COMPOBJ_DllList_Free();
5391         DeleteCriticalSection(&csRegisteredClassList);
5392         DeleteCriticalSection(&csApartment);
5393 	break;
5394 
5395     case DLL_THREAD_DETACH:
5396         COM_TlsDestroy();
5397         break;
5398     }
5399     return TRUE;
5400 }
5401 
5402 /***********************************************************************
5403  *		DllRegisterServer (OLE32.@)
5404  */
DllRegisterServer(void)5405 HRESULT WINAPI DllRegisterServer(void)
5406 {
5407     return OLE32_DllRegisterServer();
5408 }
5409 
5410 /***********************************************************************
5411  *		DllUnregisterServer (OLE32.@)
5412  */
DllUnregisterServer(void)5413 HRESULT WINAPI DllUnregisterServer(void)
5414 {
5415     return OLE32_DllUnregisterServer();
5416 }
5417