4cb8f4be6462dae5d21ef594956ff597400f559f
[reactos.git] / dll / win32 / ole32 / compobj.c
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 "config.h"
40
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45
46 #define COBJMACROS
47 #define NONAMELESSUNION
48
49 #include "ntstatus.h"
50 #define WIN32_NO_STATUS
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winuser.h"
56 #define USE_COM_CONTEXT_DEF
57 #include "objbase.h"
58 #include "ole2.h"
59 #include "ole2ver.h"
60 #include "ctxtcall.h"
61 #include "dde.h"
62 #include "servprov.h"
63 #ifndef __REACTOS__
64 #include "initguid.h"
65 #endif
66 #include "compobj_private.h"
67 #include "moniker.h"
68
69 #include "wine/unicode.h"
70 #include "wine/debug.h"
71
72 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73
74 #undef ARRAYSIZE
75 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76
77 /****************************************************************************
78 * This section defines variables internal to the COM module.
79 */
80
81 static APARTMENT *MTA; /* protected by csApartment */
82 static APARTMENT *MainApartment; /* the first STA apartment */
83 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
84
85 static CRITICAL_SECTION csApartment;
86 static CRITICAL_SECTION_DEBUG critsect_debug =
87 {
88 0, 0, &csApartment,
89 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
90 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
91 };
92 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
93
94 enum comclass_threadingmodel
95 {
96 ThreadingModel_Apartment = 1,
97 ThreadingModel_Free = 2,
98 ThreadingModel_No = 3,
99 ThreadingModel_Both = 4,
100 ThreadingModel_Neutral = 5
101 };
102
103 enum comclass_miscfields
104 {
105 MiscStatus = 1,
106 MiscStatusIcon = 2,
107 MiscStatusContent = 4,
108 MiscStatusThumbnail = 8,
109 MiscStatusDocPrint = 16
110 };
111
112 struct comclassredirect_data
113 {
114 ULONG size;
115 BYTE res;
116 BYTE miscmask;
117 BYTE res1[2];
118 DWORD model;
119 GUID clsid;
120 GUID alias;
121 GUID clsid2;
122 GUID tlbid;
123 ULONG name_len;
124 ULONG name_offset;
125 ULONG progid_len;
126 ULONG progid_offset;
127 ULONG clrdata_len;
128 ULONG clrdata_offset;
129 DWORD miscstatus;
130 DWORD miscstatuscontent;
131 DWORD miscstatusthumbnail;
132 DWORD miscstatusicon;
133 DWORD miscstatusdocprint;
134 };
135
136 struct ifacepsredirect_data
137 {
138 ULONG size;
139 DWORD mask;
140 GUID iid;
141 ULONG nummethods;
142 GUID tlbid;
143 GUID base;
144 ULONG name_len;
145 ULONG name_offset;
146 };
147
148 struct progidredirect_data
149 {
150 ULONG size;
151 DWORD reserved;
152 ULONG clsid_offset;
153 };
154
155 struct class_reg_data
156 {
157 union
158 {
159 struct
160 {
161 struct comclassredirect_data *data;
162 void *section;
163 HANDLE hactctx;
164 } actctx;
165 HKEY hkey;
166 } u;
167 BOOL hkey;
168 };
169
170 struct registered_psclsid
171 {
172 struct list entry;
173 IID iid;
174 CLSID clsid;
175 };
176
177 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
178
179 static CRITICAL_SECTION cs_registered_psclsid_list;
180 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
181 {
182 0, 0, &cs_registered_psclsid_list,
183 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
184 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
185 };
186 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
187
188 /*
189 * This is a marshallable object exposing registered local servers.
190 * IServiceProvider is used only because it happens meet requirements
191 * and already has proxy/stub code. If more functionality is needed,
192 * a custom interface may be used instead.
193 */
194 struct LocalServer
195 {
196 IServiceProvider IServiceProvider_iface;
197 LONG ref;
198 APARTMENT *apt;
199 IStream *marshal_stream;
200 };
201
202 /*
203 * This lock count counts the number of times CoInitialize is called. It is
204 * decreased every time CoUninitialize is called. When it hits 0, the COM
205 * libraries are freed
206 */
207 static LONG s_COMLockCount = 0;
208 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
209 static LONG s_COMServerProcessReferences = 0;
210
211 /*
212 * This linked list contains the list of registered class objects. These
213 * are mostly used to register the factories for out-of-proc servers of OLE
214 * objects.
215 *
216 * TODO: Make this data structure aware of inter-process communication. This
217 * means that parts of this will be exported to rpcss.
218 */
219 typedef struct tagRegisteredClass
220 {
221 struct list entry;
222 CLSID classIdentifier;
223 OXID apartment_id;
224 LPUNKNOWN classObject;
225 DWORD runContext;
226 DWORD connectFlags;
227 DWORD dwCookie;
228 void *RpcRegistration;
229 } RegisteredClass;
230
231 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
232
233 static CRITICAL_SECTION csRegisteredClassList;
234 static CRITICAL_SECTION_DEBUG class_cs_debug =
235 {
236 0, 0, &csRegisteredClassList,
237 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
238 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
239 };
240 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
241
242 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
243 {
244 switch (aspect)
245 {
246 case DVASPECT_CONTENT:
247 return MiscStatusContent;
248 case DVASPECT_THUMBNAIL:
249 return MiscStatusThumbnail;
250 case DVASPECT_ICON:
251 return MiscStatusIcon;
252 case DVASPECT_DOCPRINT:
253 return MiscStatusDocPrint;
254 default:
255 return MiscStatus;
256 };
257 }
258
259 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
260 {
261 ACTCTX_SECTION_KEYED_DATA data;
262
263 data.cbSize = sizeof(data);
264 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
265 clsid, &data))
266 {
267 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
268 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
269
270 if (!(comclass->miscmask & misc))
271 {
272 if (!(comclass->miscmask & MiscStatus))
273 {
274 *status = 0;
275 return TRUE;
276 }
277 misc = MiscStatus;
278 }
279
280 switch (misc)
281 {
282 case MiscStatus:
283 *status = comclass->miscstatus;
284 break;
285 case MiscStatusIcon:
286 *status = comclass->miscstatusicon;
287 break;
288 case MiscStatusContent:
289 *status = comclass->miscstatuscontent;
290 break;
291 case MiscStatusThumbnail:
292 *status = comclass->miscstatusthumbnail;
293 break;
294 case MiscStatusDocPrint:
295 *status = comclass->miscstatusdocprint;
296 break;
297 default:
298 ;
299 };
300
301 return TRUE;
302 }
303 else
304 return FALSE;
305 }
306
307 /* wrapper for NtCreateKey that creates the key recursively if necessary */
308 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
309 {
310 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
311
312 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
313 {
314 HANDLE subkey, root = attr->RootDirectory;
315 WCHAR *buffer = attr->ObjectName->Buffer;
316 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
317 UNICODE_STRING str;
318
319 while (i < len && buffer[i] != '\\') i++;
320 if (i == len) return status;
321
322 attrs = attr->Attributes;
323 attr->ObjectName = &str;
324
325 while (i < len)
326 {
327 str.Buffer = buffer + pos;
328 str.Length = (i - pos) * sizeof(WCHAR);
329 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
330 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
331 if (status) return status;
332 attr->RootDirectory = subkey;
333 while (i < len && buffer[i] == '\\') i++;
334 pos = i;
335 while (i < len && buffer[i] != '\\') i++;
336 }
337 str.Buffer = buffer + pos;
338 str.Length = (i - pos) * sizeof(WCHAR);
339 attr->Attributes = attrs;
340 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
341 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
342 }
343 return status;
344 }
345
346 #ifdef __REACTOS__
347 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
348 #else
349 static const WCHAR classes_rootW[] =
350 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
351 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
352 #endif
353
354 static HKEY classes_root_hkey;
355
356 /* create the special HKEY_CLASSES_ROOT key */
357 static HKEY create_classes_root_hkey(DWORD access)
358 {
359 HKEY hkey, ret = 0;
360 OBJECT_ATTRIBUTES attr;
361 UNICODE_STRING name;
362
363 attr.Length = sizeof(attr);
364 attr.RootDirectory = 0;
365 attr.ObjectName = &name;
366 attr.Attributes = 0;
367 attr.SecurityDescriptor = NULL;
368 attr.SecurityQualityOfService = NULL;
369 RtlInitUnicodeString( &name, classes_rootW );
370 if (create_key( &hkey, access, &attr )) return 0;
371 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
372
373 if (!(access & KEY_WOW64_64KEY))
374 {
375 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
376 ret = hkey;
377 else
378 NtClose( hkey ); /* somebody beat us to it */
379 }
380 else
381 ret = hkey;
382 return ret;
383 }
384
385 /* map the hkey from special root to normal key if necessary */
386 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
387 {
388 HKEY ret = hkey;
389 const BOOL is_win64 = sizeof(void*) > sizeof(int);
390 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
391
392 if (hkey == HKEY_CLASSES_ROOT &&
393 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
394 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
395 if (force_wow32 && ret && ret == classes_root_hkey)
396 {
397 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
398 access &= ~KEY_WOW64_32KEY;
399 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
400 return 0;
401 ret = hkey;
402 }
403
404 return ret;
405 }
406
407 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
408 {
409 OBJECT_ATTRIBUTES attr;
410 UNICODE_STRING nameW;
411
412 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
413
414 attr.Length = sizeof(attr);
415 attr.RootDirectory = hkey;
416 attr.ObjectName = &nameW;
417 attr.Attributes = 0;
418 attr.SecurityDescriptor = NULL;
419 attr.SecurityQualityOfService = NULL;
420 RtlInitUnicodeString( &nameW, name );
421
422 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
423 }
424
425 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
426 {
427 OBJECT_ATTRIBUTES attr;
428 UNICODE_STRING nameW;
429
430 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
431
432 attr.Length = sizeof(attr);
433 attr.RootDirectory = hkey;
434 attr.ObjectName = &nameW;
435 attr.Attributes = 0;
436 attr.SecurityDescriptor = NULL;
437 attr.SecurityQualityOfService = NULL;
438 RtlInitUnicodeString( &nameW, name );
439
440 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
441 }
442
443 /*****************************************************************************
444 * This section contains OpenDllList definitions
445 *
446 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
447 * other functions that do LoadLibrary _without_ giving back a HMODULE.
448 * Without this list these handles would never be freed.
449 *
450 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
451 * next unload-call but not before 600 sec.
452 */
453
454 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
455 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
456
457 typedef struct tagOpenDll
458 {
459 LONG refs;
460 LPWSTR library_name;
461 HANDLE library;
462 DllGetClassObjectFunc DllGetClassObject;
463 DllCanUnloadNowFunc DllCanUnloadNow;
464 struct list entry;
465 } OpenDll;
466
467 static struct list openDllList = LIST_INIT(openDllList);
468
469 static CRITICAL_SECTION csOpenDllList;
470 static CRITICAL_SECTION_DEBUG dll_cs_debug =
471 {
472 0, 0, &csOpenDllList,
473 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
474 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
475 };
476 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
477
478 struct apartment_loaded_dll
479 {
480 struct list entry;
481 OpenDll *dll;
482 DWORD unload_time;
483 BOOL multi_threaded;
484 };
485
486 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};
487
488 /*****************************************************************************
489 * This section contains OpenDllList implementation
490 */
491
492 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
493 {
494 OpenDll *ptr;
495 OpenDll *ret = NULL;
496 EnterCriticalSection(&csOpenDllList);
497 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
498 {
499 if (!strcmpiW(library_name, ptr->library_name) &&
500 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
501 {
502 ret = ptr;
503 break;
504 }
505 }
506 LeaveCriticalSection(&csOpenDllList);
507 return ret;
508 }
509
510 /* caller must ensure that library_name is not already in the open dll list */
511 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
512 {
513 OpenDll *entry;
514 int len;
515 HRESULT hr = S_OK;
516 HANDLE hLibrary;
517 DllCanUnloadNowFunc DllCanUnloadNow;
518 DllGetClassObjectFunc DllGetClassObject;
519
520 TRACE("%s\n", debugstr_w(library_name));
521
522 *ret = COMPOBJ_DllList_Get(library_name);
523 if (*ret) return S_OK;
524
525 /* do this outside the csOpenDllList to avoid creating a lock dependency on
526 * the loader lock */
527 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
528 if (!hLibrary)
529 {
530 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
531 /* failure: DLL could not be loaded */
532 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
533 }
534
535 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
536 /* Note: failing to find DllCanUnloadNow is not a failure */
537 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
538 if (!DllGetClassObject)
539 {
540 /* failure: the dll did not export DllGetClassObject */
541 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
542 FreeLibrary(hLibrary);
543 return CO_E_DLLNOTFOUND;
544 }
545
546 EnterCriticalSection( &csOpenDllList );
547
548 *ret = COMPOBJ_DllList_Get(library_name);
549 if (*ret)
550 {
551 /* another caller to this function already added the dll while we
552 * weren't in the critical section */
553 FreeLibrary(hLibrary);
554 }
555 else
556 {
557 len = strlenW(library_name);
558 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
559 if (entry)
560 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
561 if (entry && entry->library_name)
562 {
563 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
564 entry->library = hLibrary;
565 entry->refs = 1;
566 entry->DllCanUnloadNow = DllCanUnloadNow;
567 entry->DllGetClassObject = DllGetClassObject;
568 list_add_tail(&openDllList, &entry->entry);
569 *ret = entry;
570 }
571 else
572 {
573 HeapFree(GetProcessHeap(), 0, entry);
574 hr = E_OUTOFMEMORY;
575 FreeLibrary(hLibrary);
576 }
577 }
578
579 LeaveCriticalSection( &csOpenDllList );
580
581 return hr;
582 }
583
584 /* pass FALSE for free_entry to release a reference without destroying the
585 * entry if it reaches zero or TRUE otherwise */
586 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
587 {
588 if (!InterlockedDecrement(&entry->refs) && free_entry)
589 {
590 EnterCriticalSection(&csOpenDllList);
591 list_remove(&entry->entry);
592 LeaveCriticalSection(&csOpenDllList);
593
594 TRACE("freeing %p\n", entry->library);
595 FreeLibrary(entry->library);
596
597 HeapFree(GetProcessHeap(), 0, entry->library_name);
598 HeapFree(GetProcessHeap(), 0, entry);
599 }
600 }
601
602 /* frees memory associated with active dll list */
603 static void COMPOBJ_DllList_Free(void)
604 {
605 OpenDll *entry, *cursor2;
606 EnterCriticalSection(&csOpenDllList);
607 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
608 {
609 list_remove(&entry->entry);
610
611 HeapFree(GetProcessHeap(), 0, entry->library_name);
612 HeapFree(GetProcessHeap(), 0, entry);
613 }
614 LeaveCriticalSection(&csOpenDllList);
615 DeleteCriticalSection(&csOpenDllList);
616 }
617
618 /******************************************************************************
619 * Manage apartments.
620 */
621
622 static DWORD apartment_addref(struct apartment *apt)
623 {
624 DWORD refs = InterlockedIncrement(&apt->refs);
625 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
626 return refs;
627 }
628
629 /* allocates memory and fills in the necessary fields for a new apartment
630 * object. must be called inside apartment cs */
631 static APARTMENT *apartment_construct(DWORD model)
632 {
633 APARTMENT *apt;
634
635 TRACE("creating new apartment, model=%d\n", model);
636
637 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
638 apt->tid = GetCurrentThreadId();
639
640 list_init(&apt->proxies);
641 list_init(&apt->stubmgrs);
642 list_init(&apt->loaded_dlls);
643 apt->ipidc = 0;
644 apt->refs = 1;
645 apt->remunk_exported = FALSE;
646 apt->oidc = 1;
647 InitializeCriticalSection(&apt->cs);
648 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
649
650 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
651
652 if (apt->multi_threaded)
653 {
654 /* FIXME: should be randomly generated by in an RPC call to rpcss */
655 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
656 }
657 else
658 {
659 /* FIXME: should be randomly generated by in an RPC call to rpcss */
660 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
661 }
662
663 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
664
665 list_add_head(&apts, &apt->entry);
666
667 return apt;
668 }
669
670 /* gets and existing apartment if one exists or otherwise creates an apartment
671 * structure which stores OLE apartment-local information and stores a pointer
672 * to it in the thread-local storage */
673 static APARTMENT *apartment_get_or_create(DWORD model)
674 {
675 APARTMENT *apt = COM_CurrentApt();
676
677 if (!apt)
678 {
679 if (model & COINIT_APARTMENTTHREADED)
680 {
681 EnterCriticalSection(&csApartment);
682
683 apt = apartment_construct(model);
684 if (!MainApartment)
685 {
686 MainApartment = apt;
687 apt->main = TRUE;
688 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
689 }
690
691 LeaveCriticalSection(&csApartment);
692
693 if (apt->main)
694 apartment_createwindowifneeded(apt);
695 }
696 else
697 {
698 EnterCriticalSection(&csApartment);
699
700 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
701 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
702 * in a process */
703 if (MTA)
704 {
705 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
706 apartment_addref(MTA);
707 }
708 else
709 MTA = apartment_construct(model);
710
711 apt = MTA;
712
713 LeaveCriticalSection(&csApartment);
714 }
715 COM_CurrentInfo()->apt = apt;
716 }
717
718 return apt;
719 }
720
721 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
722 {
723 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
724 }
725
726 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
727 {
728 list_remove(&curClass->entry);
729
730 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
731 RPC_StopLocalServer(curClass->RpcRegistration);
732
733 IUnknown_Release(curClass->classObject);
734 HeapFree(GetProcessHeap(), 0, curClass);
735 }
736
737 static void COM_RevokeAllClasses(const struct apartment *apt)
738 {
739 RegisteredClass *curClass, *cursor;
740
741 EnterCriticalSection( &csRegisteredClassList );
742
743 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
744 {
745 if (curClass->apartment_id == apt->oxid)
746 COM_RevokeRegisteredClassObject(curClass);
747 }
748
749 LeaveCriticalSection( &csRegisteredClassList );
750 }
751
752 static void revoke_registered_psclsids(void)
753 {
754 struct registered_psclsid *psclsid, *psclsid2;
755
756 EnterCriticalSection( &cs_registered_psclsid_list );
757
758 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
759 {
760 list_remove(&psclsid->entry);
761 HeapFree(GetProcessHeap(), 0, psclsid);
762 }
763
764 LeaveCriticalSection( &cs_registered_psclsid_list );
765 }
766
767 /******************************************************************************
768 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
769 */
770
771 typedef struct ManualResetEvent {
772 ISynchronize ISynchronize_iface;
773 ISynchronizeHandle ISynchronizeHandle_iface;
774 LONG ref;
775 HANDLE event;
776 } MREImpl;
777
778 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
779 {
780 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
781 }
782
783 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
784 {
785 MREImpl *This = impl_from_ISynchronize(iface);
786
787 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
788
789 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
790 *ppv = &This->ISynchronize_iface;
791 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
792 *ppv = &This->ISynchronizeHandle_iface;
793 }else {
794 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
795 *ppv = NULL;
796 return E_NOINTERFACE;
797 }
798
799 IUnknown_AddRef((IUnknown*)*ppv);
800 return S_OK;
801 }
802
803 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
804 {
805 MREImpl *This = impl_from_ISynchronize(iface);
806 LONG ref = InterlockedIncrement(&This->ref);
807 TRACE("%p - ref %d\n", This, ref);
808
809 return ref;
810 }
811
812 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
813 {
814 MREImpl *This = impl_from_ISynchronize(iface);
815 LONG ref = InterlockedDecrement(&This->ref);
816 TRACE("%p - ref %d\n", This, ref);
817
818 if(!ref)
819 {
820 CloseHandle(This->event);
821 HeapFree(GetProcessHeap(), 0, This);
822 }
823
824 return ref;
825 }
826
827 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
828 {
829 MREImpl *This = impl_from_ISynchronize(iface);
830 UINT index;
831 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
832 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
833 }
834
835 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
836 {
837 MREImpl *This = impl_from_ISynchronize(iface);
838 TRACE("%p\n", This);
839 SetEvent(This->event);
840 return S_OK;
841 }
842
843 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
844 {
845 MREImpl *This = impl_from_ISynchronize(iface);
846 TRACE("%p\n", This);
847 ResetEvent(This->event);
848 return S_OK;
849 }
850
851 static ISynchronizeVtbl vt_ISynchronize = {
852 ISynchronize_fnQueryInterface,
853 ISynchronize_fnAddRef,
854 ISynchronize_fnRelease,
855 ISynchronize_fnWait,
856 ISynchronize_fnSignal,
857 ISynchronize_fnReset
858 };
859
860 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
861 {
862 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
863 }
864
865 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
866 {
867 MREImpl *This = impl_from_ISynchronizeHandle(iface);
868 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
869 }
870
871 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
872 {
873 MREImpl *This = impl_from_ISynchronizeHandle(iface);
874 return ISynchronize_AddRef(&This->ISynchronize_iface);
875 }
876
877 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
878 {
879 MREImpl *This = impl_from_ISynchronizeHandle(iface);
880 return ISynchronize_Release(&This->ISynchronize_iface);
881 }
882
883 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
884 {
885 MREImpl *This = impl_from_ISynchronizeHandle(iface);
886
887 *ph = This->event;
888 return S_OK;
889 }
890
891 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
892 SynchronizeHandle_QueryInterface,
893 SynchronizeHandle_AddRef,
894 SynchronizeHandle_Release,
895 SynchronizeHandle_GetHandle
896 };
897
898 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
899 {
900 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
901 HRESULT hr;
902
903 if(punkouter)
904 FIXME("Aggregation not implemented.\n");
905
906 This->ref = 1;
907 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
908 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
909 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
910
911 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
912 ISynchronize_Release(&This->ISynchronize_iface);
913 return hr;
914 }
915
916 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
917 {
918 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
919 }
920
921 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
922 {
923 LocalServer *This = impl_from_IServiceProvider(iface);
924
925 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
926
927 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
928 *ppv = &This->IServiceProvider_iface;
929 }else {
930 *ppv = NULL;
931 return E_NOINTERFACE;
932 }
933
934 IUnknown_AddRef((IUnknown*)*ppv);
935 return S_OK;
936 }
937
938 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
939 {
940 LocalServer *This = impl_from_IServiceProvider(iface);
941 LONG ref = InterlockedIncrement(&This->ref);
942
943 TRACE("(%p) ref=%d\n", This, ref);
944
945 return ref;
946 }
947
948 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
949 {
950 LocalServer *This = impl_from_IServiceProvider(iface);
951 LONG ref = InterlockedDecrement(&This->ref);
952
953 TRACE("(%p) ref=%d\n", This, ref);
954
955 if(!ref) {
956 assert(!This->apt);
957 HeapFree(GetProcessHeap(), 0, This);
958 }
959
960 return ref;
961 }
962
963 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
964 {
965 LocalServer *This = impl_from_IServiceProvider(iface);
966 APARTMENT *apt = COM_CurrentApt();
967 RegisteredClass *iter;
968 HRESULT hres = E_FAIL;
969
970 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
971
972 if(!This->apt)
973 return E_UNEXPECTED;
974
975 EnterCriticalSection(&csRegisteredClassList);
976
977 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
978 if(iter->apartment_id == apt->oxid
979 && (iter->runContext & CLSCTX_LOCAL_SERVER)
980 && IsEqualGUID(&iter->classIdentifier, guid)) {
981 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
982 break;
983 }
984 }
985
986 LeaveCriticalSection( &csRegisteredClassList );
987
988 return hres;
989 }
990
991 static const IServiceProviderVtbl LocalServerVtbl = {
992 LocalServer_QueryInterface,
993 LocalServer_AddRef,
994 LocalServer_Release,
995 LocalServer_QueryService
996 };
997
998 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
999 {
1000 HRESULT hres = S_OK;
1001
1002 EnterCriticalSection(&apt->cs);
1003
1004 if(!apt->local_server) {
1005 LocalServer *obj;
1006
1007 obj = heap_alloc(sizeof(*obj));
1008 if(obj) {
1009 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1010 obj->ref = 1;
1011 obj->apt = apt;
1012
1013 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1014 if(SUCCEEDED(hres)) {
1015 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1016 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1017 if(FAILED(hres))
1018 IStream_Release(obj->marshal_stream);
1019 }
1020
1021 if(SUCCEEDED(hres))
1022 apt->local_server = obj;
1023 else
1024 heap_free(obj);
1025 }else {
1026 hres = E_OUTOFMEMORY;
1027 }
1028 }
1029
1030 if(SUCCEEDED(hres))
1031 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1032
1033 LeaveCriticalSection(&apt->cs);
1034
1035 if(FAILED(hres))
1036 ERR("Failed: %08x\n", hres);
1037 return hres;
1038 }
1039
1040 /***********************************************************************
1041 * CoRevokeClassObject [OLE32.@]
1042 *
1043 * Removes a class object from the class registry.
1044 *
1045 * PARAMS
1046 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1047 *
1048 * RETURNS
1049 * Success: S_OK.
1050 * Failure: HRESULT code.
1051 *
1052 * NOTES
1053 * Must be called from the same apartment that called CoRegisterClassObject(),
1054 * otherwise it will fail with RPC_E_WRONG_THREAD.
1055 *
1056 * SEE ALSO
1057 * CoRegisterClassObject
1058 */
1059 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1060 DWORD dwRegister)
1061 {
1062 HRESULT hr = E_INVALIDARG;
1063 RegisteredClass *curClass;
1064 APARTMENT *apt;
1065
1066 TRACE("(%08x)\n",dwRegister);
1067
1068 apt = COM_CurrentApt();
1069 if (!apt)
1070 {
1071 ERR("COM was not initialized\n");
1072 return CO_E_NOTINITIALIZED;
1073 }
1074
1075 EnterCriticalSection( &csRegisteredClassList );
1076
1077 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1078 {
1079 /*
1080 * Check if we have a match on the cookie.
1081 */
1082 if (curClass->dwCookie == dwRegister)
1083 {
1084 if (curClass->apartment_id == apt->oxid)
1085 {
1086 COM_RevokeRegisteredClassObject(curClass);
1087 hr = S_OK;
1088 }
1089 else
1090 {
1091 ERR("called from wrong apartment, should be called from %s\n",
1092 wine_dbgstr_longlong(curClass->apartment_id));
1093 hr = RPC_E_WRONG_THREAD;
1094 }
1095 break;
1096 }
1097 }
1098
1099 LeaveCriticalSection( &csRegisteredClassList );
1100
1101 return hr;
1102 }
1103
1104 /* frees unused libraries loaded by apartment_getclassobject by calling the
1105 * DLL's DllCanUnloadNow entry point */
1106 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1107 {
1108 struct apartment_loaded_dll *entry, *next;
1109 EnterCriticalSection(&apt->cs);
1110 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1111 {
1112 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1113 {
1114 DWORD real_delay = delay;
1115
1116 if (real_delay == INFINITE)
1117 {
1118 /* DLLs that return multi-threaded objects aren't unloaded
1119 * straight away to cope for programs that have races between
1120 * last object destruction and threads in the DLLs that haven't
1121 * finished, despite DllCanUnloadNow returning S_OK */
1122 if (entry->multi_threaded)
1123 real_delay = 10 * 60 * 1000; /* 10 minutes */
1124 else
1125 real_delay = 0;
1126 }
1127
1128 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1129 {
1130 list_remove(&entry->entry);
1131 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1132 HeapFree(GetProcessHeap(), 0, entry);
1133 }
1134 else
1135 {
1136 entry->unload_time = GetTickCount() + real_delay;
1137 if (!entry->unload_time) entry->unload_time = 1;
1138 }
1139 }
1140 else if (entry->unload_time)
1141 entry->unload_time = 0;
1142 }
1143 LeaveCriticalSection(&apt->cs);
1144 }
1145
1146 DWORD apartment_release(struct apartment *apt)
1147 {
1148 DWORD ret;
1149
1150 EnterCriticalSection(&csApartment);
1151
1152 ret = InterlockedDecrement(&apt->refs);
1153 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1154 /* destruction stuff that needs to happen under csApartment CS */
1155 if (ret == 0)
1156 {
1157 if (apt == MTA) MTA = NULL;
1158 else if (apt == MainApartment) MainApartment = NULL;
1159 list_remove(&apt->entry);
1160 }
1161
1162 LeaveCriticalSection(&csApartment);
1163
1164 if (ret == 0)
1165 {
1166 struct list *cursor, *cursor2;
1167
1168 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1169
1170 if(apt->local_server) {
1171 LocalServer *local_server = apt->local_server;
1172 LARGE_INTEGER zero;
1173
1174 memset(&zero, 0, sizeof(zero));
1175 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1176 CoReleaseMarshalData(local_server->marshal_stream);
1177 IStream_Release(local_server->marshal_stream);
1178 local_server->marshal_stream = NULL;
1179
1180 apt->local_server = NULL;
1181 local_server->apt = NULL;
1182 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1183 }
1184
1185 /* Release the references to the registered class objects */
1186 COM_RevokeAllClasses(apt);
1187
1188 /* no locking is needed for this apartment, because no other thread
1189 * can access it at this point */
1190
1191 apartment_disconnectproxies(apt);
1192
1193 if (apt->win) DestroyWindow(apt->win);
1194 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1195
1196 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1197 {
1198 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1199 /* release the implicit reference given by the fact that the
1200 * stub has external references (it must do since it is in the
1201 * stub manager list in the apartment and all non-apartment users
1202 * must have a ref on the apartment and so it cannot be destroyed).
1203 */
1204 stub_manager_int_release(stubmgr);
1205 }
1206
1207 /* if this assert fires, then another thread took a reference to a
1208 * stub manager without taking a reference to the containing
1209 * apartment, which it must do. */
1210 assert(list_empty(&apt->stubmgrs));
1211
1212 if (apt->filter) IMessageFilter_Release(apt->filter);
1213
1214 /* free as many unused libraries as possible... */
1215 apartment_freeunusedlibraries(apt, 0);
1216
1217 /* ... and free the memory for the apartment loaded dll entry and
1218 * release the dll list reference without freeing the library for the
1219 * rest */
1220 while ((cursor = list_head(&apt->loaded_dlls)))
1221 {
1222 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1223 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1224 list_remove(cursor);
1225 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1226 }
1227
1228 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1229 DeleteCriticalSection(&apt->cs);
1230
1231 HeapFree(GetProcessHeap(), 0, apt);
1232 }
1233
1234 return ret;
1235 }
1236
1237 /* The given OXID must be local to this process:
1238 *
1239 * The ref parameter is here mostly to ensure people remember that
1240 * they get one, you should normally take a ref for thread safety.
1241 */
1242 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1243 {
1244 APARTMENT *result = NULL;
1245 struct list *cursor;
1246
1247 EnterCriticalSection(&csApartment);
1248 LIST_FOR_EACH( cursor, &apts )
1249 {
1250 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1251 if (apt->oxid == oxid)
1252 {
1253 result = apt;
1254 if (ref) apartment_addref(result);
1255 break;
1256 }
1257 }
1258 LeaveCriticalSection(&csApartment);
1259
1260 return result;
1261 }
1262
1263 /* gets the apartment which has a given creator thread ID. The caller must
1264 * release the reference from the apartment as soon as the apartment pointer
1265 * is no longer required. */
1266 APARTMENT *apartment_findfromtid(DWORD tid)
1267 {
1268 APARTMENT *result = NULL;
1269 struct list *cursor;
1270
1271 EnterCriticalSection(&csApartment);
1272 LIST_FOR_EACH( cursor, &apts )
1273 {
1274 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1275 if (apt->tid == tid)
1276 {
1277 result = apt;
1278 apartment_addref(result);
1279 break;
1280 }
1281 }
1282 LeaveCriticalSection(&csApartment);
1283
1284 return result;
1285 }
1286
1287 /* gets the main apartment if it exists. The caller must
1288 * release the reference from the apartment as soon as the apartment pointer
1289 * is no longer required. */
1290 static APARTMENT *apartment_findmain(void)
1291 {
1292 APARTMENT *result;
1293
1294 EnterCriticalSection(&csApartment);
1295
1296 result = MainApartment;
1297 if (result) apartment_addref(result);
1298
1299 LeaveCriticalSection(&csApartment);
1300
1301 return result;
1302 }
1303
1304 /* gets the multi-threaded apartment if it exists. The caller must
1305 * release the reference from the apartment as soon as the apartment pointer
1306 * is no longer required. */
1307 static APARTMENT *apartment_find_multi_threaded(void)
1308 {
1309 APARTMENT *result = NULL;
1310 struct list *cursor;
1311
1312 EnterCriticalSection(&csApartment);
1313
1314 LIST_FOR_EACH( cursor, &apts )
1315 {
1316 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1317 if (apt->multi_threaded)
1318 {
1319 result = apt;
1320 apartment_addref(result);
1321 break;
1322 }
1323 }
1324
1325 LeaveCriticalSection(&csApartment);
1326 return result;
1327 }
1328
1329 /* gets the specified class object by loading the appropriate DLL, if
1330 * necessary and calls the DllGetClassObject function for the DLL */
1331 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1332 BOOL apartment_threaded,
1333 REFCLSID rclsid, REFIID riid, void **ppv)
1334 {
1335 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1336 HRESULT hr = S_OK;
1337 BOOL found = FALSE;
1338 struct apartment_loaded_dll *apartment_loaded_dll;
1339
1340 if (!strcmpiW(dllpath, wszOle32))
1341 {
1342 /* we don't need to control the lifetime of this dll, so use the local
1343 * implementation of DllGetClassObject directly */
1344 TRACE("calling ole32!DllGetClassObject\n");
1345 hr = DllGetClassObject(rclsid, riid, ppv);
1346
1347 if (hr != S_OK)
1348 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1349
1350 return hr;
1351 }
1352
1353 EnterCriticalSection(&apt->cs);
1354
1355 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1356 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1357 {
1358 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1359 found = TRUE;
1360 break;
1361 }
1362
1363 if (!found)
1364 {
1365 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1366 if (!apartment_loaded_dll)
1367 hr = E_OUTOFMEMORY;
1368 if (SUCCEEDED(hr))
1369 {
1370 apartment_loaded_dll->unload_time = 0;
1371 apartment_loaded_dll->multi_threaded = FALSE;
1372 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1373 if (FAILED(hr))
1374 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1375 }
1376 if (SUCCEEDED(hr))
1377 {
1378 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1379 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1380 }
1381 }
1382
1383 LeaveCriticalSection(&apt->cs);
1384
1385 if (SUCCEEDED(hr))
1386 {
1387 /* one component being multi-threaded overrides any number of
1388 * apartment-threaded components */
1389 if (!apartment_threaded)
1390 apartment_loaded_dll->multi_threaded = TRUE;
1391
1392 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1393 /* OK: get the ClassObject */
1394 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1395
1396 if (hr != S_OK)
1397 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1398 }
1399
1400 return hr;
1401 }
1402
1403 /***********************************************************************
1404 * COM_RegReadPath [internal]
1405 *
1406 * Reads a registry value and expands it when necessary
1407 */
1408 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1409 {
1410 DWORD ret;
1411
1412 if (regdata->hkey)
1413 {
1414 DWORD keytype;
1415 WCHAR src[MAX_PATH];
1416 DWORD dwLength = dstlen * sizeof(WCHAR);
1417
1418 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1419 if (keytype == REG_EXPAND_SZ) {
1420 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1421 } else {
1422 const WCHAR *quote_start;
1423 quote_start = strchrW(src, '\"');
1424 if (quote_start) {
1425 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1426 if (quote_end) {
1427 memmove(src, quote_start + 1,
1428 (quote_end - quote_start - 1) * sizeof(WCHAR));
1429 src[quote_end - quote_start - 1] = '\0';
1430 }
1431 }
1432 lstrcpynW(dst, src, dstlen);
1433 }
1434 }
1435 return ret;
1436 }
1437 else
1438 {
1439 ULONG_PTR cookie;
1440 WCHAR *nameW;
1441
1442 *dst = 0;
1443 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1444 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1445 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1446 DeactivateActCtx(0, cookie);
1447 return !*dst;
1448 }
1449 }
1450
1451 struct host_object_params
1452 {
1453 struct class_reg_data regdata;
1454 CLSID clsid; /* clsid of object to marshal */
1455 IID iid; /* interface to marshal */
1456 HANDLE event; /* event signalling when ready for multi-threaded case */
1457 HRESULT hr; /* result for multi-threaded case */
1458 IStream *stream; /* stream that the object will be marshaled into */
1459 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1460 };
1461
1462 static HRESULT apartment_hostobject(struct apartment *apt,
1463 const struct host_object_params *params)
1464 {
1465 IUnknown *object;
1466 HRESULT hr;
1467 static const LARGE_INTEGER llZero;
1468 WCHAR dllpath[MAX_PATH+1];
1469
1470 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1471
1472 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1473 {
1474 /* failure: CLSID is not found in registry */
1475 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1476 return REGDB_E_CLASSNOTREG;
1477 }
1478
1479 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1480 &params->clsid, &params->iid, (void **)&object);
1481 if (FAILED(hr))
1482 return hr;
1483
1484 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1485 if (FAILED(hr))
1486 IUnknown_Release(object);
1487 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1488
1489 return hr;
1490 }
1491
1492 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1493 {
1494 switch (msg)
1495 {
1496 case DM_EXECUTERPC:
1497 RPC_ExecuteCall((struct dispatch_params *)lParam);
1498 return 0;
1499 case DM_HOSTOBJECT:
1500 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1501 default:
1502 return DefWindowProcW(hWnd, msg, wParam, lParam);
1503 }
1504 }
1505
1506 struct host_thread_params
1507 {
1508 COINIT threading_model;
1509 HANDLE ready_event;
1510 HWND apartment_hwnd;
1511 };
1512
1513 /* thread for hosting an object to allow an object to appear to be created in
1514 * an apartment with an incompatible threading model */
1515 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1516 {
1517 struct host_thread_params *params = p;
1518 MSG msg;
1519 HRESULT hr;
1520 struct apartment *apt;
1521
1522 TRACE("\n");
1523
1524 hr = CoInitializeEx(NULL, params->threading_model);
1525 if (FAILED(hr)) return hr;
1526
1527 apt = COM_CurrentApt();
1528 if (params->threading_model == COINIT_APARTMENTTHREADED)
1529 {
1530 apartment_createwindowifneeded(apt);
1531 params->apartment_hwnd = apartment_getwindow(apt);
1532 }
1533 else
1534 params->apartment_hwnd = NULL;
1535
1536 /* force the message queue to be created before signaling parent thread */
1537 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1538
1539 SetEvent(params->ready_event);
1540 params = NULL; /* can't touch params after here as it may be invalid */
1541
1542 while (GetMessageW(&msg, NULL, 0, 0))
1543 {
1544 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1545 {
1546 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1547 obj_params->hr = apartment_hostobject(apt, obj_params);
1548 SetEvent(obj_params->event);
1549 }
1550 else
1551 {
1552 TranslateMessage(&msg);
1553 DispatchMessageW(&msg);
1554 }
1555 }
1556
1557 TRACE("exiting\n");
1558
1559 CoUninitialize();
1560
1561 return S_OK;
1562 }
1563
1564 /* finds or creates a host apartment, creates the object inside it and returns
1565 * a proxy to it so that the object can be used in the apartment of the
1566 * caller of this function */
1567 static HRESULT apartment_hostobject_in_hostapt(
1568 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1569 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1570 {
1571 struct host_object_params params;
1572 HWND apartment_hwnd = NULL;
1573 DWORD apartment_tid = 0;
1574 HRESULT hr;
1575
1576 if (!multi_threaded && main_apartment)
1577 {
1578 APARTMENT *host_apt = apartment_findmain();
1579 if (host_apt)
1580 {
1581 apartment_hwnd = apartment_getwindow(host_apt);
1582 apartment_release(host_apt);
1583 }
1584 }
1585
1586 if (!apartment_hwnd)
1587 {
1588 EnterCriticalSection(&apt->cs);
1589
1590 if (!apt->host_apt_tid)
1591 {
1592 struct host_thread_params thread_params;
1593 HANDLE handles[2];
1594 DWORD wait_value;
1595
1596 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1597 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1598 thread_params.apartment_hwnd = NULL;
1599 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1600 if (!handles[1])
1601 {
1602 CloseHandle(handles[0]);
1603 LeaveCriticalSection(&apt->cs);
1604 return E_OUTOFMEMORY;
1605 }
1606 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1607 CloseHandle(handles[0]);
1608 CloseHandle(handles[1]);
1609 if (wait_value == WAIT_OBJECT_0)
1610 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1611 else
1612 {
1613 LeaveCriticalSection(&apt->cs);
1614 return E_OUTOFMEMORY;
1615 }
1616 }
1617
1618 if (multi_threaded || !main_apartment)
1619 {
1620 apartment_hwnd = apt->host_apt_hwnd;
1621 apartment_tid = apt->host_apt_tid;
1622 }
1623
1624 LeaveCriticalSection(&apt->cs);
1625 }
1626
1627 /* another thread may have become the main apartment in the time it took
1628 * us to create the thread for the host apartment */
1629 if (!apartment_hwnd && !multi_threaded && main_apartment)
1630 {
1631 APARTMENT *host_apt = apartment_findmain();
1632 if (host_apt)
1633 {
1634 apartment_hwnd = apartment_getwindow(host_apt);
1635 apartment_release(host_apt);
1636 }
1637 }
1638
1639 params.regdata = *regdata;
1640 params.clsid = *rclsid;
1641 params.iid = *riid;
1642 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1643 if (FAILED(hr))
1644 return hr;
1645 params.apartment_threaded = !multi_threaded;
1646 if (multi_threaded)
1647 {
1648 params.hr = S_OK;
1649 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1650 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1651 hr = E_OUTOFMEMORY;
1652 else
1653 {
1654 WaitForSingleObject(params.event, INFINITE);
1655 hr = params.hr;
1656 }
1657 CloseHandle(params.event);
1658 }
1659 else
1660 {
1661 if (!apartment_hwnd)
1662 {
1663 ERR("host apartment didn't create window\n");
1664 hr = E_OUTOFMEMORY;
1665 }
1666 else
1667 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1668 }
1669 if (SUCCEEDED(hr))
1670 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1671 IStream_Release(params.stream);
1672 return hr;
1673 }
1674
1675 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1676 {
1677 WNDCLASSW wclass;
1678
1679 /* Dispatching to the correct thread in an apartment is done through
1680 * window messages rather than RPC transports. When an interface is
1681 * marshalled into another apartment in the same process, a window of the
1682 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1683 * application) is responsible for pumping the message loop in that thread.
1684 * The WM_USER messages which point to the RPCs are then dispatched to
1685 * apartment_wndproc by the user's code from the apartment in which the
1686 * interface was unmarshalled.
1687 */
1688 memset(&wclass, 0, sizeof(wclass));
1689 wclass.lpfnWndProc = apartment_wndproc;
1690 wclass.hInstance = hProxyDll;
1691 wclass.lpszClassName = wszAptWinClass;
1692 RegisterClassW(&wclass);
1693 return TRUE;
1694 }
1695
1696 /* create a window for the apartment or return the current one if one has
1697 * already been created */
1698 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1699 {
1700 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1701
1702 if (apt->multi_threaded)
1703 return S_OK;
1704
1705 if (!apt->win)
1706 {
1707 HWND hwnd;
1708
1709 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1710
1711 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1712 HWND_MESSAGE, 0, hProxyDll, NULL);
1713 if (!hwnd)
1714 {
1715 ERR("CreateWindow failed with error %d\n", GetLastError());
1716 return HRESULT_FROM_WIN32(GetLastError());
1717 }
1718 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1719 /* someone beat us to it */
1720 DestroyWindow(hwnd);
1721 }
1722
1723 return S_OK;
1724 }
1725
1726 /* retrieves the window for the main- or apartment-threaded apartment */
1727 HWND apartment_getwindow(const struct apartment *apt)
1728 {
1729 assert(!apt->multi_threaded);
1730 return apt->win;
1731 }
1732
1733 static void COM_TlsDestroy(void)
1734 {
1735 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1736 if (info)
1737 {
1738 if (info->apt) apartment_release(info->apt);
1739 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1740 if (info->state) IUnknown_Release(info->state);
1741 if (info->spy) IInitializeSpy_Release(info->spy);
1742 if (info->context_token) IObjContext_Release(info->context_token);
1743 HeapFree(GetProcessHeap(), 0, info);
1744 NtCurrentTeb()->ReservedForOle = NULL;
1745 }
1746 }
1747
1748 /******************************************************************************
1749 * CoBuildVersion [OLE32.@]
1750 *
1751 * Gets the build version of the DLL.
1752 *
1753 * PARAMS
1754 *
1755 * RETURNS
1756 * Current build version, hiword is majornumber, loword is minornumber
1757 */
1758 DWORD WINAPI CoBuildVersion(void)
1759 {
1760 TRACE("Returning version %d, build %d.\n", rmm, rup);
1761 return (rmm<<16)+rup;
1762 }
1763
1764 /******************************************************************************
1765 * CoRegisterInitializeSpy [OLE32.@]
1766 *
1767 * Add a Spy that watches CoInitializeEx calls
1768 *
1769 * PARAMS
1770 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1771 * cookie [II] cookie receiver
1772 *
1773 * RETURNS
1774 * Success: S_OK if not already initialized, S_FALSE otherwise.
1775 * Failure: HRESULT code.
1776 *
1777 * SEE ALSO
1778 * CoInitializeEx
1779 */
1780 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1781 {
1782 struct oletls *info = COM_CurrentInfo();
1783 HRESULT hr;
1784
1785 TRACE("(%p, %p)\n", spy, cookie);
1786
1787 if (!spy || !cookie || !info)
1788 {
1789 if (!info)
1790 WARN("Could not allocate tls\n");
1791 return E_INVALIDARG;
1792 }
1793
1794 if (info->spy)
1795 {
1796 FIXME("Already registered?\n");
1797 return E_UNEXPECTED;
1798 }
1799
1800 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1801 if (SUCCEEDED(hr))
1802 {
1803 cookie->QuadPart = (DWORD_PTR)spy;
1804 return S_OK;
1805 }
1806 return hr;
1807 }
1808
1809 /******************************************************************************
1810 * CoRevokeInitializeSpy [OLE32.@]
1811 *
1812 * Remove a spy that previously watched CoInitializeEx calls
1813 *
1814 * PARAMS
1815 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1816 *
1817 * RETURNS
1818 * Success: S_OK if a spy is removed
1819 * Failure: E_INVALIDARG
1820 *
1821 * SEE ALSO
1822 * CoInitializeEx
1823 */
1824 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1825 {
1826 struct oletls *info = COM_CurrentInfo();
1827 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1828
1829 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1830 return E_INVALIDARG;
1831
1832 IInitializeSpy_Release(info->spy);
1833 info->spy = NULL;
1834 return S_OK;
1835 }
1836
1837 HRESULT enter_apartment( struct oletls *info, DWORD model )
1838 {
1839 HRESULT hr = S_OK;
1840
1841 if (!info->apt)
1842 {
1843 if (!apartment_get_or_create( model ))
1844 return E_OUTOFMEMORY;
1845 }
1846 else if (!apartment_is_model( info->apt, model ))
1847 {
1848 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1849 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1850 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1851 return RPC_E_CHANGED_MODE;
1852 }
1853 else
1854 hr = S_FALSE;
1855
1856 info->inits++;
1857
1858 return hr;
1859 }
1860
1861 void leave_apartment( struct oletls *info )
1862 {
1863 if (!--info->inits)
1864 {
1865 if (info->ole_inits)
1866 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1867 apartment_release( info->apt );
1868 info->apt = NULL;
1869 }
1870 }
1871
1872 /******************************************************************************
1873 * CoInitialize [OLE32.@]
1874 *
1875 * Initializes the COM libraries by calling CoInitializeEx with
1876 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1877 *
1878 * PARAMS
1879 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1880 *
1881 * RETURNS
1882 * Success: S_OK if not already initialized, S_FALSE otherwise.
1883 * Failure: HRESULT code.
1884 *
1885 * SEE ALSO
1886 * CoInitializeEx
1887 */
1888 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1889 {
1890 /*
1891 * Just delegate to the newer method.
1892 */
1893 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1894 }
1895
1896 /******************************************************************************
1897 * CoInitializeEx [OLE32.@]
1898 *
1899 * Initializes the COM libraries.
1900 *
1901 * PARAMS
1902 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1903 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1904 *
1905 * RETURNS
1906 * S_OK if successful,
1907 * S_FALSE if this function was called already.
1908 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1909 * threading model.
1910 *
1911 * NOTES
1912 *
1913 * The behavior used to set the IMalloc used for memory management is
1914 * obsolete.
1915 * The dwCoInit parameter must specify one of the following apartment
1916 * threading models:
1917 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1918 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1919 * The parameter may also specify zero or more of the following flags:
1920 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1921 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1922 *
1923 * SEE ALSO
1924 * CoUninitialize
1925 */
1926 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1927 {
1928 struct oletls *info = COM_CurrentInfo();
1929 HRESULT hr;
1930
1931 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1932
1933 if (lpReserved!=NULL)
1934 {
1935 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1936 }
1937
1938 /*
1939 * Check the lock count. If this is the first time going through the initialize
1940 * process, we have to initialize the libraries.
1941 *
1942 * And crank-up that lock count.
1943 */
1944 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1945 {
1946 /*
1947 * Initialize the various COM libraries and data structures.
1948 */
1949 TRACE("() - Initializing the COM libraries\n");
1950
1951 /* we may need to defer this until after apartment initialisation */
1952 RunningObjectTableImpl_Initialize();
1953 }
1954
1955 if (info->spy)
1956 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1957
1958 hr = enter_apartment( info, dwCoInit );
1959
1960 if (info->spy)
1961 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1962
1963 return hr;
1964 }
1965
1966 /***********************************************************************
1967 * CoUninitialize [OLE32.@]
1968 *
1969 * This method will decrement the refcount on the current apartment, freeing
1970 * the resources associated with it if it is the last thread in the apartment.
1971 * If the last apartment is freed, the function will additionally release
1972 * any COM resources associated with the process.
1973 *
1974 * PARAMS
1975 *
1976 * RETURNS
1977 * Nothing.
1978 *
1979 * SEE ALSO
1980 * CoInitializeEx
1981 */
1982 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1983 {
1984 struct oletls * info = COM_CurrentInfo();
1985 LONG lCOMRefCnt;
1986
1987 TRACE("()\n");
1988
1989 /* will only happen on OOM */
1990 if (!info) return;
1991
1992 if (info->spy)
1993 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1994
1995 /* sanity check */
1996 if (!info->inits)
1997 {
1998 ERR("Mismatched CoUninitialize\n");
1999
2000 if (info->spy)
2001 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2002 return;
2003 }
2004
2005 leave_apartment( info );
2006
2007 /*
2008 * Decrease the reference count.
2009 * If we are back to 0 locks on the COM library, make sure we free
2010 * all the associated data structures.
2011 */
2012 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2013 if (lCOMRefCnt==1)
2014 {
2015 TRACE("() - Releasing the COM libraries\n");
2016
2017 revoke_registered_psclsids();
2018 RunningObjectTableImpl_UnInitialize();
2019 }
2020 else if (lCOMRefCnt<1) {
2021 ERR( "CoUninitialize() - not CoInitialized.\n" );
2022 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2023 }
2024 if (info->spy)
2025 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2026 }
2027
2028 /******************************************************************************
2029 * CoDisconnectObject [OLE32.@]
2030 *
2031 * Disconnects all connections to this object from remote processes. Dispatches
2032 * pending RPCs while blocking new RPCs from occurring, and then calls
2033 * IMarshal::DisconnectObject on the given object.
2034 *
2035 * Typically called when the object server is forced to shut down, for instance by
2036 * the user.
2037 *
2038 * PARAMS
2039 * lpUnk [I] The object whose stub should be disconnected.
2040 * reserved [I] Reserved. Should be set to 0.
2041 *
2042 * RETURNS
2043 * Success: S_OK.
2044 * Failure: HRESULT code.
2045 *
2046 * SEE ALSO
2047 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2048 */
2049 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2050 {
2051 struct stub_manager *manager;
2052 HRESULT hr;
2053 IMarshal *marshal;
2054 APARTMENT *apt;
2055
2056 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2057
2058 if (!lpUnk) return E_INVALIDARG;
2059
2060 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2061 if (hr == S_OK)
2062 {
2063 hr = IMarshal_DisconnectObject(marshal, reserved);
2064 IMarshal_Release(marshal);
2065 return hr;
2066 }
2067
2068 apt = COM_CurrentApt();
2069 if (!apt)
2070 return CO_E_NOTINITIALIZED;
2071
2072 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2073 if (manager) {
2074 stub_manager_disconnect(manager);
2075 /* Release stub manager twice, to remove the apartment reference. */
2076 stub_manager_int_release(manager);
2077 stub_manager_int_release(manager);
2078 }
2079
2080 /* Note: native is pretty broken here because it just silently
2081 * fails, without returning an appropriate error code if the object was
2082 * not found, making apps think that the object was disconnected, when
2083 * it actually wasn't */
2084
2085 return S_OK;
2086 }
2087
2088 /******************************************************************************
2089 * CoCreateGuid [OLE32.@]
2090 *
2091 * Simply forwards to UuidCreate in RPCRT4.
2092 *
2093 * PARAMS
2094 * pguid [O] Points to the GUID to initialize.
2095 *
2096 * RETURNS
2097 * Success: S_OK.
2098 * Failure: HRESULT code.
2099 *
2100 * SEE ALSO
2101 * UuidCreate
2102 */
2103 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2104 {
2105 DWORD status;
2106
2107 if(!pguid) return E_INVALIDARG;
2108
2109 status = UuidCreate(pguid);
2110 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2111 return HRESULT_FROM_WIN32( status );
2112 }
2113
2114 static inline BOOL is_valid_hex(WCHAR c)
2115 {
2116 if (!(((c >= '0') && (c <= '9')) ||
2117 ((c >= 'a') && (c <= 'f')) ||
2118 ((c >= 'A') && (c <= 'F'))))
2119 return FALSE;
2120 return TRUE;
2121 }
2122
2123 static const BYTE guid_conv_table[256] =
2124 {
2125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2128 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2129 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2131 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2132 };
2133
2134 /* conversion helper for CLSIDFromString/IIDFromString */
2135 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2136 {
2137 int i;
2138
2139 if (!s || s[0]!='{') {
2140 memset( id, 0, sizeof (CLSID) );
2141 if(!s) return TRUE;
2142 return FALSE;
2143 }
2144
2145 TRACE("%s -> %p\n", debugstr_w(s), id);
2146
2147 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2148
2149 id->Data1 = 0;
2150 for (i = 1; i < 9; i++) {
2151 if (!is_valid_hex(s[i])) return FALSE;
2152 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2153 }
2154 if (s[9]!='-') return FALSE;
2155
2156 id->Data2 = 0;
2157 for (i = 10; i < 14; i++) {
2158 if (!is_valid_hex(s[i])) return FALSE;
2159 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2160 }
2161 if (s[14]!='-') return FALSE;
2162
2163 id->Data3 = 0;
2164 for (i = 15; i < 19; i++) {
2165 if (!is_valid_hex(s[i])) return FALSE;
2166 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2167 }
2168 if (s[19]!='-') return FALSE;
2169
2170 for (i = 20; i < 37; i+=2) {
2171 if (i == 24) {
2172 if (s[i]!='-') return FALSE;
2173 i++;
2174 }
2175 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2176 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2177 }
2178
2179 if (s[37] == '}' && s[38] == '\0')
2180 return TRUE;
2181
2182 return FALSE;
2183 }
2184
2185 /*****************************************************************************/
2186
2187 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2188 {
2189 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2190 WCHAR buf2[CHARS_IN_GUID];
2191 LONG buf2len = sizeof(buf2);
2192 HKEY xhkey;
2193 WCHAR *buf;
2194
2195 memset(clsid, 0, sizeof(*clsid));
2196 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2197 if (!buf) return E_OUTOFMEMORY;
2198 strcpyW( buf, progid );
2199 strcatW( buf, clsidW );
2200 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2201 {
2202 HeapFree(GetProcessHeap(),0,buf);
2203 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2204 return CO_E_CLASSSTRING;
2205 }
2206 HeapFree(GetProcessHeap(),0,buf);
2207
2208 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2209 {
2210 RegCloseKey(xhkey);
2211 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2212 return CO_E_CLASSSTRING;
2213 }
2214 RegCloseKey(xhkey);
2215 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2216 }
2217
2218 /******************************************************************************
2219 * CLSIDFromString [OLE32.@]
2220 *
2221 * Converts a unique identifier from its string representation into
2222 * the GUID struct.
2223 *
2224 * PARAMS
2225 * idstr [I] The string representation of the GUID.
2226 * id [O] GUID converted from the string.
2227 *
2228 * RETURNS
2229 * S_OK on success
2230 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2231 *
2232 * SEE ALSO
2233 * StringFromCLSID
2234 */
2235 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2236 {
2237 HRESULT ret = CO_E_CLASSSTRING;
2238 CLSID tmp_id;
2239
2240 if (!id)
2241 return E_INVALIDARG;
2242
2243 if (guid_from_string(idstr, id))
2244 return S_OK;
2245
2246 /* It appears a ProgID is also valid */
2247 ret = clsid_from_string_reg(idstr, &tmp_id);
2248 if(SUCCEEDED(ret))
2249 *id = tmp_id;
2250
2251 return ret;
2252 }
2253
2254 /******************************************************************************
2255 * IIDFromString [OLE32.@]
2256 *
2257 * Converts an interface identifier from its string representation to
2258 * the IID struct.
2259 *
2260 * PARAMS
2261 * idstr [I] The string representation of the GUID.
2262 * id [O] IID converted from the string.
2263 *
2264 * RETURNS
2265 * S_OK on success
2266 * CO_E_IIDSTRING if idstr is not a valid IID
2267 *
2268 * SEE ALSO
2269 * StringFromIID
2270 */
2271 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2272 {
2273 TRACE("%s -> %p\n", debugstr_w(s), iid);
2274
2275 if (!s)
2276 {
2277 memset(iid, 0, sizeof(*iid));
2278 return S_OK;
2279 }
2280
2281 /* length mismatch is a special case */
2282 if (strlenW(s) + 1 != CHARS_IN_GUID)
2283 return E_INVALIDARG;
2284
2285 if (s[0] != '{')
2286 return CO_E_IIDSTRING;
2287
2288 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2289 }
2290
2291 /******************************************************************************
2292 * StringFromCLSID [OLE32.@]
2293 * StringFromIID [OLE32.@]
2294 *
2295 * Converts a GUID into the respective string representation.
2296 * The target string is allocated using the OLE IMalloc.
2297 *
2298 * PARAMS
2299 * id [I] the GUID to be converted.
2300 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2301 *
2302 * RETURNS
2303 * S_OK
2304 * E_FAIL
2305 *
2306 * SEE ALSO
2307 * StringFromGUID2, CLSIDFromString
2308 */
2309 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2310 {
2311 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2312 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2313 return S_OK;
2314 }
2315
2316 /******************************************************************************
2317 * StringFromGUID2 [OLE32.@]
2318 *
2319 * Modified version of StringFromCLSID that allows you to specify max
2320 * buffer size.
2321 *
2322 * PARAMS
2323 * id [I] GUID to convert to string.
2324 * str [O] Buffer where the result will be stored.
2325 * cmax [I] Size of the buffer in characters.
2326 *
2327 * RETURNS
2328 * Success: The length of the resulting string in characters.
2329 * Failure: 0.
2330 */
2331 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2332 {
2333 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2334 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2335 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2336 '%','0','2','X','%','0','2','X','}',0 };
2337 if (!id || cmax < CHARS_IN_GUID) return 0;
2338 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2339 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2340 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2341 return CHARS_IN_GUID;
2342 }
2343
2344 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2345 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2346 {
2347 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2348 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2349 LONG res;
2350 HKEY key;
2351
2352 strcpyW(path, wszCLSIDSlash);
2353 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2354 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2355 if (res == ERROR_FILE_NOT_FOUND)
2356 return REGDB_E_CLASSNOTREG;
2357 else if (res != ERROR_SUCCESS)
2358 return REGDB_E_READREGDB;
2359
2360 if (!keyname)
2361 {
2362 *subkey = key;
2363 return S_OK;
2364 }
2365
2366 res = open_classes_key(key, keyname, access, subkey);
2367 RegCloseKey(key);
2368 if (res == ERROR_FILE_NOT_FOUND)
2369 return REGDB_E_KEYMISSING;
2370 else if (res != ERROR_SUCCESS)
2371 return REGDB_E_READREGDB;
2372
2373 return S_OK;
2374 }
2375
2376 /* open HKCR\\AppId\\{string form of appid clsid} key */
2377 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2378 {
2379 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2380 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2381 DWORD res;
2382 WCHAR buf[CHARS_IN_GUID];
2383 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2384 DWORD size;
2385 HKEY hkey;
2386 DWORD type;
2387 HRESULT hr;
2388
2389 /* read the AppID value under the class's key */
2390 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2391 if (FAILED(hr))
2392 return hr;
2393
2394 size = sizeof(buf);
2395 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2396 RegCloseKey(hkey);
2397 if (res == ERROR_FILE_NOT_FOUND)
2398 return REGDB_E_KEYMISSING;
2399 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2400 return REGDB_E_READREGDB;
2401
2402 strcpyW(keyname, szAppIdKey);
2403 strcatW(keyname, buf);
2404 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2405 if (res == ERROR_FILE_NOT_FOUND)
2406 return REGDB_E_KEYMISSING;
2407 else if (res != ERROR_SUCCESS)
2408 return REGDB_E_READREGDB;
2409
2410 return S_OK;
2411 }
2412
2413 /******************************************************************************
2414 * ProgIDFromCLSID [OLE32.@]
2415 *
2416 * Converts a class id into the respective program ID.
2417 *
2418 * PARAMS
2419 * clsid [I] Class ID, as found in registry.
2420 * ppszProgID [O] Associated ProgID.
2421 *
2422 * RETURNS
2423 * S_OK
2424 * E_OUTOFMEMORY
2425 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2426 */
2427 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2428 {
2429 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2430 ACTCTX_SECTION_KEYED_DATA data;
2431 HKEY hkey;
2432 HRESULT ret;
2433 LONG progidlen = 0;
2434
2435 if (!ppszProgID)
2436 return E_INVALIDARG;
2437
2438 *ppszProgID = NULL;
2439
2440 data.cbSize = sizeof(data);
2441 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2442 clsid, &data))
2443 {
2444 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2445 if (comclass->progid_len)
2446 {
2447 WCHAR *ptrW;
2448
2449 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2450 if (!*ppszProgID) return E_OUTOFMEMORY;
2451
2452 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2453 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2454 return S_OK;
2455 }
2456 else
2457 return REGDB_E_CLASSNOTREG;
2458 }
2459
2460 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2461 if (FAILED(ret))
2462 return ret;
2463
2464 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2465 ret = REGDB_E_CLASSNOTREG;
2466
2467 if (ret == S_OK)
2468 {
2469 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2470 if (*ppszProgID)
2471 {
2472 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2473 ret = REGDB_E_CLASSNOTREG;
2474 CoTaskMemFree(*ppszProgID);
2475 *ppszProgID = NULL;
2476 }
2477 }
2478 else
2479 ret = E_OUTOFMEMORY;
2480 }
2481
2482 RegCloseKey(hkey);
2483 return ret;
2484 }
2485
2486 /******************************************************************************
2487 * CLSIDFromProgID [OLE32.@]
2488 *
2489 * Converts a program id into the respective GUID.
2490 *
2491 * PARAMS
2492 * progid [I] Unicode program ID, as found in registry.
2493 * clsid [O] Associated CLSID.
2494 *
2495 * RETURNS
2496 * Success: S_OK
2497 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2498 */
2499 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2500 {
2501 ACTCTX_SECTION_KEYED_DATA data;
2502
2503 if (!progid || !clsid)
2504 return E_INVALIDARG;
2505
2506 data.cbSize = sizeof(data);
2507 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2508 progid, &data))
2509 {
2510 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2511 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2512 *clsid = *alias;
2513 return S_OK;
2514 }
2515
2516 return clsid_from_string_reg(progid, clsid);
2517 }
2518
2519 /******************************************************************************
2520 * CLSIDFromProgIDEx [OLE32.@]
2521 */
2522 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2523 {
2524 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2525
2526 return CLSIDFromProgID(progid, clsid);
2527 }
2528
2529 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2530 {
2531 HKEY hkey;
2532 WCHAR value[CHARS_IN_GUID];
2533 DWORD len;
2534
2535 access |= KEY_READ;
2536
2537 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2538 return REGDB_E_IIDNOTREG;
2539
2540 len = sizeof(value);
2541 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2542 return REGDB_E_IIDNOTREG;
2543 RegCloseKey(hkey);
2544
2545 if (CLSIDFromString(value, pclsid) != NOERROR)
2546 return REGDB_E_IIDNOTREG;
2547
2548 return S_OK;
2549 }
2550
2551 /*****************************************************************************
2552 * CoGetPSClsid [OLE32.@]
2553 *
2554 * Retrieves the CLSID of the proxy/stub factory that implements
2555 * IPSFactoryBuffer for the specified interface.
2556 *
2557 * PARAMS
2558 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2559 * pclsid [O] Where to store returned proxy/stub CLSID.
2560 *
2561 * RETURNS
2562 * S_OK
2563 * E_OUTOFMEMORY
2564 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2565 *
2566 * NOTES
2567 *
2568 * The standard marshaller activates the object with the CLSID
2569 * returned and uses the CreateProxy and CreateStub methods on its
2570 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2571 * given object.
2572 *
2573 * CoGetPSClsid determines this CLSID by searching the
2574 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2575 * in the registry and any interface id registered by
2576 * CoRegisterPSClsid within the current process.
2577 *
2578 * BUGS
2579 *
2580 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2581 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2582 * considered a bug in native unless an application depends on this (unlikely).
2583 *
2584 * SEE ALSO
2585 * CoRegisterPSClsid.
2586 */
2587 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2588 {
2589 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2590 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2591 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2592 APARTMENT *apt = COM_CurrentApt();
2593 struct registered_psclsid *registered_psclsid;
2594 ACTCTX_SECTION_KEYED_DATA data;
2595 HRESULT hr;
2596 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2597 BOOL is_wow64;
2598
2599 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2600
2601 if (!apt)
2602 {
2603 ERR("apartment not initialised\n");
2604 return CO_E_NOTINITIALIZED;
2605 }
2606
2607 if (!pclsid)
2608 return E_INVALIDARG;
2609
2610 EnterCriticalSection(&cs_registered_psclsid_list);
2611
2612 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2613 if (IsEqualIID(&registered_psclsid->iid, riid))
2614 {
2615 *pclsid = registered_psclsid->clsid;
2616 LeaveCriticalSection(&cs_registered_psclsid_list);
2617 return S_OK;
2618 }
2619
2620 LeaveCriticalSection(&cs_registered_psclsid_list);
2621
2622 data.cbSize = sizeof(data);
2623 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2624 riid, &data))
2625 {
2626 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2627 *pclsid = ifaceps->iid;
2628 return S_OK;
2629 }
2630
2631 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2632 strcpyW(path, wszInterface);
2633 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2634 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2635
2636 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2637 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2638 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2639 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2640
2641 if (hr == S_OK)
2642 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2643 else
2644 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2645
2646 return hr;
2647 }
2648
2649 /*****************************************************************************
2650 * CoRegisterPSClsid [OLE32.@]
2651 *
2652 * Register a proxy/stub CLSID for the given interface in the current process
2653 * only.
2654 *
2655 * PARAMS
2656 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2657 * rclsid [I] CLSID of the proxy/stub.
2658 *
2659 * RETURNS
2660 * Success: S_OK
2661 * Failure: E_OUTOFMEMORY
2662 *
2663 * NOTES
2664 *
2665 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2666 * will be returned from other apartments in the same process.
2667 *
2668 * This function does not add anything to the registry and the effects are
2669 * limited to the lifetime of the current process.
2670 *
2671 * SEE ALSO
2672 * CoGetPSClsid.
2673 */
2674 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2675 {
2676 APARTMENT *apt = COM_CurrentApt();
2677 struct registered_psclsid *registered_psclsid;
2678
2679 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2680
2681 if (!apt)
2682 {
2683 ERR("apartment not initialised\n");
2684 return CO_E_NOTINITIALIZED;
2685 }
2686
2687 EnterCriticalSection(&cs_registered_psclsid_list);
2688
2689 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2690 if (IsEqualIID(&registered_psclsid->iid, riid))
2691 {
2692 registered_psclsid->clsid = *rclsid;
2693 LeaveCriticalSection(&cs_registered_psclsid_list);
2694 return S_OK;
2695 }
2696
2697 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2698 if (!registered_psclsid)
2699 {
2700 LeaveCriticalSection(&cs_registered_psclsid_list);
2701 return E_OUTOFMEMORY;
2702 }
2703
2704 registered_psclsid->iid = *riid;
2705 registered_psclsid->clsid = *rclsid;
2706 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2707
2708 LeaveCriticalSection(&cs_registered_psclsid_list);
2709
2710 return S_OK;
2711 }
2712
2713
2714 /***
2715 * COM_GetRegisteredClassObject
2716 *
2717 * This internal method is used to scan the registered class list to
2718 * find a class object.
2719 *
2720 * Params:
2721 * rclsid Class ID of the class to find.
2722 * dwClsContext Class context to match.
2723 * ppv [out] returns a pointer to the class object. Complying
2724 * to normal COM usage, this method will increase the
2725 * reference count on this object.
2726 */
2727 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2728 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2729 {
2730 HRESULT hr = S_FALSE;
2731 RegisteredClass *curClass;
2732
2733 EnterCriticalSection( &csRegisteredClassList );
2734
2735 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2736 {
2737 /*
2738 * Check if we have a match on the class ID and context.
2739 */
2740 if ((apt->oxid == curClass->apartment_id) &&
2741 (dwClsContext & curClass->runContext) &&
2742 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2743 {
2744 /*
2745 * We have a match, return the pointer to the class object.
2746 */
2747 *ppUnk = curClass->classObject;
2748
2749 IUnknown_AddRef(curClass->classObject);
2750
2751 hr = S_OK;
2752 break;
2753 }
2754 }
2755
2756 LeaveCriticalSection( &csRegisteredClassList );
2757
2758 return hr;
2759 }
2760
2761 /******************************************************************************
2762 * CoRegisterClassObject [OLE32.@]
2763 *
2764 * Registers the class object for a given class ID. Servers housed in EXE
2765 * files use this method instead of exporting DllGetClassObject to allow
2766 * other code to connect to their objects.
2767 *
2768 * PARAMS
2769 * rclsid [I] CLSID of the object to register.
2770 * pUnk [I] IUnknown of the object.
2771 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2772 * flags [I] REGCLS flags indicating how connections are made.
2773 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2774 *
2775 * RETURNS
2776 * S_OK on success,
2777 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2778 * CO_E_OBJISREG if the object is already registered. We should not return this.
2779 *
2780 * SEE ALSO
2781 * CoRevokeClassObject, CoGetClassObject
2782 *
2783 * NOTES
2784 * In-process objects are only registered for the current apartment.
2785 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2786 * in other apartments.
2787 *
2788 * BUGS
2789 * MSDN claims that multiple interface registrations are legal, but we
2790 * can't do that with our current implementation.
2791 */
2792 HRESULT WINAPI CoRegisterClassObject(
2793 REFCLSID rclsid,
2794 LPUNKNOWN pUnk,
2795 DWORD dwClsContext,
2796 DWORD flags,
2797 LPDWORD lpdwRegister)
2798 {
2799 static LONG next_cookie;
2800 RegisteredClass* newClass;
2801 LPUNKNOWN foundObject;
2802 HRESULT hr;
2803 APARTMENT *apt;
2804
2805 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2806 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2807
2808 if ( (lpdwRegister==0) || (pUnk==0) )
2809 return E_INVALIDARG;
2810
2811 apt = COM_CurrentApt();
2812 if (!apt)
2813 {
2814 ERR("COM was not initialized\n");
2815 return CO_E_NOTINITIALIZED;
2816 }
2817
2818 *lpdwRegister = 0;
2819
2820 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2821 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2822 if (flags & REGCLS_MULTIPLEUSE)
2823 dwClsContext |= CLSCTX_INPROC_SERVER;
2824
2825 /*
2826 * First, check if the class is already registered.
2827 * If it is, this should cause an error.
2828 */
2829 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2830 if (hr == S_OK) {
2831 if (flags & REGCLS_MULTIPLEUSE) {
2832 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2833 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2834 IUnknown_Release(foundObject);
2835 return hr;
2836 }
2837 IUnknown_Release(foundObject);
2838 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2839 return CO_E_OBJISREG;
2840 }
2841
2842 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2843 if ( newClass == NULL )
2844 return E_OUTOFMEMORY;
2845
2846 newClass->classIdentifier = *rclsid;
2847 newClass->apartment_id = apt->oxid;
2848 newClass->runContext = dwClsContext;
2849 newClass->connectFlags = flags;
2850 newClass->RpcRegistration = NULL;
2851
2852 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2853 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2854
2855 /*
2856 * Since we're making a copy of the object pointer, we have to increase its
2857 * reference count.
2858 */
2859 newClass->classObject = pUnk;
2860 IUnknown_AddRef(newClass->classObject);
2861
2862 EnterCriticalSection( &csRegisteredClassList );
2863 list_add_tail(&RegisteredClassList, &newClass->entry);
2864 LeaveCriticalSection( &csRegisteredClassList );
2865
2866 *lpdwRegister = newClass->dwCookie;
2867
2868 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2869 IStream *marshal_stream;
2870
2871 hr = get_local_server_stream(apt, &marshal_stream);
2872 if(FAILED(hr))
2873 return hr;
2874
2875 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2876 marshal_stream,
2877 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2878 &newClass->RpcRegistration);
2879 IStream_Release(marshal_stream);
2880 }
2881 return S_OK;
2882 }
2883
2884 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2885 {
2886 if (data->hkey)
2887 {
2888 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2889 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2890 static const WCHAR wszFree[] = {'F','r','e','e',0};
2891 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2892 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2893 DWORD dwLength = sizeof(threading_model);
2894 DWORD keytype;
2895 DWORD ret;
2896
2897 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2898 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2899 threading_model[0] = '\0';
2900
2901 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2902 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2903 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2904
2905 /* there's not specific handling for this case */
2906 if (threading_model[0]) return ThreadingModel_Neutral;
2907 return ThreadingModel_No;
2908 }
2909 else
2910 return data->u.actctx.data->model;
2911 }
2912
2913 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2914 REFCLSID rclsid, REFIID riid,
2915 BOOL hostifnecessary, void **ppv)
2916 {
2917 WCHAR dllpath[MAX_PATH+1];
2918 BOOL apartment_threaded;
2919
2920 if (hostifnecessary)
2921 {
2922 enum comclass_threadingmodel model = get_threading_model(regdata);
2923
2924 if (model == ThreadingModel_Apartment)
2925 {
2926 apartment_threaded = TRUE;
2927 if (apt->multi_threaded)
2928 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2929 }
2930 else if (model == ThreadingModel_Free)
2931 {
2932 apartment_threaded = FALSE;
2933 if (!apt->multi_threaded)
2934 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2935 }
2936 /* everything except "Apartment", "Free" and "Both" */
2937 else if (model != ThreadingModel_Both)
2938 {
2939 apartment_threaded = TRUE;
2940 /* everything else is main-threaded */
2941 if (model != ThreadingModel_No)
2942 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2943
2944 if (apt->multi_threaded || !apt->main)
2945 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2946 }
2947 else
2948 apartment_threaded = FALSE;
2949 }
2950 else
2951 apartment_threaded = !apt->multi_threaded;
2952
2953 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2954 {
2955 /* failure: CLSID is not found in registry */
2956 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2957 return REGDB_E_CLASSNOTREG;
2958 }
2959
2960 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2961 rclsid, riid, ppv);
2962 }
2963
2964 /***********************************************************************
2965 * CoGetClassObject [OLE32.@]
2966 *
2967 * Creates an object of the specified class.
2968 *
2969 * PARAMS
2970 * rclsid [I] Class ID to create an instance of.
2971 * dwClsContext [I] Flags to restrict the location of the created instance.
2972 * pServerInfo [I] Optional. Details for connecting to a remote server.
2973 * iid [I] The ID of the interface of the instance to return.
2974 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2975 *
2976 * RETURNS
2977 * Success: S_OK
2978 * Failure: HRESULT code.
2979 *
2980 * NOTES
2981 * The dwClsContext parameter can be one or more of the following:
2982 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2983 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2984 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2985 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2986 *
2987 * SEE ALSO
2988 * CoCreateInstance()
2989 */
2990 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2991 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2992 REFIID iid, LPVOID *ppv)
2993 {
2994 struct class_reg_data clsreg;
2995 IUnknown *regClassObject;
2996 HRESULT hres = E_UNEXPECTED;
2997 APARTMENT *apt;
2998 BOOL release_apt = FALSE;
2999
3000 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3001
3002 if (!ppv)
3003 return E_INVALIDARG;
3004
3005 *ppv = NULL;
3006
3007 if (!(apt = COM_CurrentApt()))
3008 {
3009 if (!(apt = apartment_find_multi_threaded()))
3010 {
3011 ERR("apartment not initialised\n");
3012 return CO_E_NOTINITIALIZED;
3013 }
3014 release_apt = TRUE;
3015 }
3016
3017 if (pServerInfo) {
3018 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3019 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3020 }
3021
3022 if (CLSCTX_INPROC_SERVER & dwClsContext)
3023 {
3024 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3025 {
3026 if (release_apt) apartment_release(apt);
3027 return FTMarshalCF_Create(iid, ppv);
3028 }
3029 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3030 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3031 }
3032
3033 if (CLSCTX_INPROC & dwClsContext)
3034 {
3035 ACTCTX_SECTION_KEYED_DATA data;
3036
3037 data.cbSize = sizeof(data);
3038 /* search activation context first */
3039 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3040 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3041 rclsid, &data))
3042 {
3043 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3044
3045 clsreg.u.actctx.hactctx = data.hActCtx;
3046 clsreg.u.actctx.data = data.lpData;
3047 clsreg.u.actctx.section = data.lpSectionBase;
3048 clsreg.hkey = FALSE;
3049
3050 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3051 ReleaseActCtx(data.hActCtx);
3052 if (release_apt) apartment_release(apt);
3053 return hres;
3054 }
3055 }
3056
3057 /*
3058 * First, try and see if we can't match the class ID with one of the
3059 * registered classes.
3060 */
3061 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3062 &regClassObject))
3063 {
3064 /* Get the required interface from the retrieved pointer. */
3065 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3066
3067 /*
3068 * Since QI got another reference on the pointer, we want to release the
3069 * one we already have. If QI was unsuccessful, this will release the object. This
3070 * is good since we are not returning it in the "out" parameter.
3071 */
3072 IUnknown_Release(regClassObject);
3073 if (release_apt) apartment_release(apt);
3074 return hres;
3075 }
3076
3077 /* First try in-process server */
3078 if (CLSCTX_INPROC_SERVER & dwClsContext)
3079 {
3080 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3081 HKEY hkey;
3082
3083 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3084 if (FAILED(hres))
3085 {
3086 if (hres == REGDB_E_CLASSNOTREG)
3087 ERR("class %s not registered\n", debugstr_guid(rclsid));
3088 else if (hres == REGDB_E_KEYMISSING)
3089 {
3090 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3091 hres = REGDB_E_CLASSNOTREG;
3092 }
3093 }
3094
3095 if (SUCCEEDED(hres))
3096 {
3097 clsreg.u.hkey = hkey;
3098 clsreg.hkey = TRUE;
3099
3100 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3101 RegCloseKey(hkey);
3102 }
3103
3104 /* return if we got a class, otherwise fall through to one of the
3105 * other types */
3106 if (SUCCEEDED(hres))
3107 {
3108 if (release_apt) apartment_release(apt);
3109 return hres;
3110 }
3111 }
3112
3113 /* Next try in-process handler */
3114 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3115 {
3116 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3117 HKEY hkey;
3118
3119 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3120 if (FAILED(hres))
3121 {
3122 if (hres == REGDB_E_CLASSNOTREG)
3123 ERR("class %s not registered\n", debugstr_guid(rclsid));
3124 else if (hres == REGDB_E_KEYMISSING)
3125 {
3126 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3127 hres = REGDB_E_CLASSNOTREG;
3128 }
3129 }
3130
3131 if (SUCCEEDED(hres))
3132 {
3133 clsreg.u.hkey = hkey;
3134 clsreg.hkey = TRUE;
3135
3136 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3137 RegCloseKey(hkey);
3138 }
3139
3140 /* return if we got a class, otherwise fall through to one of the
3141 * other types */
3142 if (SUCCEEDED(hres))
3143 {
3144 if (release_apt) apartment_release(apt);
3145 return hres;
3146 }
3147 }
3148 if (release_apt) apartment_release(apt);
3149
3150 /* Next try out of process */
3151 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3152 {
3153 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3154 if (SUCCEEDED(hres))
3155 return hres;
3156 }
3157
3158 /* Finally try remote: this requires networked DCOM (a lot of work) */
3159 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3160 {
3161 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3162 hres = REGDB_E_CLASSNOTREG;
3163 }
3164
3165 if (FAILED(hres))
3166 ERR("no class object %s could be created for context 0x%x\n",
3167 debugstr_guid(rclsid), dwClsContext);
3168 return hres;
3169 }
3170
3171 /***********************************************************************
3172 * CoResumeClassObjects (OLE32.@)
3173 *
3174 * Resumes all class objects registered with REGCLS_SUSPENDED.
3175 *
3176 * RETURNS
3177 * Success: S_OK.
3178 * Failure: HRESULT code.
3179 */
3180 HRESULT WINAPI CoResumeClassObjects(void)
3181 {
3182 FIXME("stub\n");
3183 return S_OK;
3184 }
3185
3186 /***********************************************************************
3187 * CoCreateInstance [OLE32.@]
3188 *
3189 * Creates an instance of the specified class.
3190 *
3191 * PARAMS
3192 * rclsid [I] Class ID to create an instance of.
3193 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3194 * dwClsContext [I] Flags to restrict the location of the created instance.
3195 * iid [I] The ID of the interface of the instance to return.
3196 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3197 *
3198 * RETURNS
3199 * Success: S_OK
3200 * Failure: HRESULT code.
3201 *
3202 * NOTES
3203 * The dwClsContext parameter can be one or more of the following:
3204 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3205 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3206 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3207 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3208 *
3209 * Aggregation is the concept of deferring the IUnknown of an object to another
3210 * object. This allows a separate object to behave as though it was part of
3211 * the object and to allow this the pUnkOuter parameter can be set. Note that
3212 * not all objects support having an outer of unknown.
3213 *
3214 * SEE ALSO
3215 * CoGetClassObject()
3216 */
3217 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3218 REFCLSID rclsid,
3219 LPUNKNOWN pUnkOuter,
3220 DWORD dwClsContext,
3221 REFIID iid,
3222 LPVOID *ppv)
3223 {
3224 MULTI_QI multi_qi = { iid };
3225 HRESULT hres;
3226
3227 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3228 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3229
3230 if (ppv==0)
3231 return E_POINTER;
3232
3233 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3234 *ppv = multi_qi.pItf;
3235 return hres;
3236 }
3237
3238 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3239 {
3240 ULONG i;
3241
3242 for (i = 0; i < count; i++)
3243 {
3244 mqi[i].pItf = NULL;
3245 mqi[i].hr = hr;
3246 }
3247 }
3248
3249 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3250 {
3251 ULONG index = 0, fetched = 0;
3252
3253 if (include_unk)
3254 {
3255 mqi[0].hr = S_OK;
3256 mqi[0].pItf = unk;
3257 index = fetched = 1;
3258 }
3259
3260 for (; index < count; index++)
3261 {
3262 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3263 if (mqi[index].hr == S_OK)
3264 fetched++;
3265 }
3266
3267 if (!include_unk)
3268 IUnknown_Release(unk);
3269
3270 if (fetched == 0)
3271 return E_NOINTERFACE;
3272
3273 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3274 }
3275
3276 /***********************************************************************
3277 * CoCreateInstanceEx [OLE32.@]
3278 */
3279 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3280 REFCLSID rclsid,
3281 LPUNKNOWN pUnkOuter,
3282 DWORD dwClsContext,
3283 COSERVERINFO* pServerInfo,
3284 ULONG cmq,
3285 MULTI_QI* pResults)
3286 {
3287 IUnknown *unk = NULL;
3288 IClassFactory *cf;
3289 APARTMENT *apt;
3290 CLSID clsid;
3291 HRESULT hres;
3292
3293 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3294
3295 if (!cmq || !pResults)
3296 return E_INVALIDARG;
3297
3298 if (pServerInfo)
3299 FIXME("() non-NULL pServerInfo not supported!\n");
3300
3301 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3302
3303 hres = CoGetTreatAsClass(rclsid, &clsid);
3304 if(FAILED(hres))
3305 clsid = *rclsid;
3306
3307 if (!(apt = COM_CurrentApt()))
3308 {
3309 if (!(apt = apartment_find_multi_threaded()))
3310 {
3311 ERR("apartment not initialised\n");
3312 return CO_E_NOTINITIALIZED;
3313 }
3314 apartment_release(apt);
3315 }
3316
3317 /*
3318 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3319 */
3320 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3321 {
3322 IGlobalInterfaceTable *git = get_std_git();
3323 TRACE("Retrieving GIT\n");
3324 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3325 }
3326
3327 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3328 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3329 if (FAILED(hres))
3330 return hres;
3331 return return_multi_qi(unk, cmq, pResults, TRUE);
3332 }
3333
3334 /*
3335 * Get a class factory to construct the object we want.
3336 */
3337 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3338 if (FAILED(hres))
3339 return hres;
3340
3341 /*
3342 * Create the object and don't forget to release the factory
3343 */
3344 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3345 IClassFactory_Release(cf);
3346 if (FAILED(hres))
3347 {
3348 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3349 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3350 else
3351 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3352 debugstr_guid(pResults[0].pIID),
3353 debugstr_guid(&clsid),hres);
3354 return hres;
3355 }
3356
3357 return return_multi_qi(unk, cmq, pResults, TRUE);
3358 }
3359
3360 /***********************************************************************
3361 * CoGetInstanceFromFile [OLE32.@]
3362 */
3363 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3364 COSERVERINFO *server_info,
3365 CLSID *rclsid,
3366 IUnknown *outer,
3367 DWORD cls_context,
3368 DWORD grfmode,
3369 OLECHAR *filename,
3370 DWORD count,
3371 MULTI_QI *results
3372 )
3373 {
3374 IPersistFile *pf = NULL;
3375 IUnknown* unk = NULL;
3376 CLSID clsid;
3377 HRESULT hr;
3378
3379 if (count == 0 || !results)
3380 return E_INVALIDARG;
3381
3382 if (server_info)
3383 FIXME("() non-NULL server_info not supported\n");
3384
3385 init_multi_qi(count, results, E_NOINTERFACE);
3386
3387 /* optionally get CLSID from a file */
3388 if (!rclsid)
3389 {
3390 hr = GetClassFile(filename, &clsid);
3391 if (FAILED(hr))
3392 {
3393 ERR("failed to get CLSID from a file\n");
3394 return hr;
3395 }
3396
3397 rclsid = &clsid;
3398 }
3399
3400 hr = CoCreateInstance(rclsid,
3401 outer,
3402 cls_context,
3403 &IID_IUnknown,
3404 (void**)&unk);
3405
3406 if (hr != S_OK)
3407 {
3408 init_multi_qi(count, results, hr);
3409 return hr;
3410 }
3411
3412 /* init from file */
3413 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3414 if (FAILED(hr))
3415 {
3416 init_multi_qi(count, results, hr);
3417 IUnknown_Release(unk);
3418 return hr;
3419 }
3420
3421 hr = IPersistFile_Load(pf, filename, grfmode);
3422 IPersistFile_Release(pf);
3423 if (SUCCEEDED(hr))
3424 return return_multi_qi(unk, count, results, FALSE);
3425 else
3426 {
3427 init_multi_qi(count, results, hr);
3428 IUnknown_Release(unk);
3429 return hr;
3430 }
3431 }
3432
3433 /***********************************************************************
3434 * CoGetInstanceFromIStorage [OLE32.@]
3435 */
3436 HRESULT WINAPI CoGetInstanceFromIStorage(
3437 COSERVERINFO *server_info,
3438 CLSID *rclsid,
3439 IUnknown *outer,
3440 DWORD cls_context,
3441 IStorage *storage,
3442 DWORD count,
3443 MULTI_QI *results
3444 )
3445 {
3446 IPersistStorage *ps = NULL;
3447 IUnknown* unk = NULL;
3448 STATSTG stat;
3449 HRESULT hr;
3450
3451 if (count == 0 || !results || !storage)
3452 return E_INVALIDARG;
3453
3454 if (server_info)
3455 FIXME("() non-NULL server_info not supported\n");
3456
3457 init_multi_qi(count, results, E_NOINTERFACE);
3458
3459 /* optionally get CLSID from a file */
3460 if (!rclsid)
3461 {
3462 memset(&stat.clsid, 0, sizeof(stat.clsid));
3463 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3464 if (FAILED(hr))
3465 {
3466 ERR("failed to get CLSID from a file\n");
3467 return hr;
3468 }
3469
3470 rclsid = &stat.clsid;
3471 }
3472
3473 hr = CoCreateInstance(rclsid,
3474 outer,
3475 cls_context,
3476 &IID_IUnknown,
3477 (void**)&unk);
3478
3479 if (hr != S_OK)
3480 return hr;
3481
3482 /* init from IStorage */
3483 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3484 if (FAILED(hr))
3485 ERR("failed to get IPersistStorage\n");
3486
3487 if (ps)
3488 {
3489 IPersistStorage_Load(ps, storage);
3490 IPersistStorage_Release(ps);
3491 }
3492
3493 return return_multi_qi(unk, count, results, FALSE);
3494 }
3495
3496 /***********************************************************************
3497 * CoLoadLibrary (OLE32.@)
3498 *
3499 * Loads a library.
3500 *
3501 * PARAMS
3502 * lpszLibName [I] Path to library.
3503 * bAutoFree [I] Whether the library should automatically be freed.
3504 *
3505 * RETURNS
3506 * Success: Handle to loaded library.
3507 * Failure: NULL.
3508 *
3509 * SEE ALSO
3510 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3511 */
3512 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3513 {
3514 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3515
3516 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3517 }
3518
3519 /***********************************************************************
3520 * CoFreeLibrary [OLE32.@]
3521 *
3522 * Unloads a library from memory.
3523 *
3524 * PARAMS
3525 * hLibrary [I] Handle to library to unload.
3526 *
3527 * RETURNS
3528 * Nothing
3529 *
3530 * SEE ALSO
3531 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3532 */
3533 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3534 {
3535 FreeLibrary(hLibrary);
3536 }
3537
3538
3539 /***********************************************************************
3540 * CoFreeAllLibraries [OLE32.@]
3541 *
3542 * Function for backwards compatibility only. Does nothing.
3543 *
3544 * RETURNS
3545 * Nothing.
3546 *
3547 * SEE ALSO
3548 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3549 */
3550 void WINAPI CoFreeAllLibraries(void)
3551 {
3552 /* NOP */
3553 }
3554
3555 /***********************************************************************
3556 * CoFreeUnusedLibrariesEx [OLE32.@]
3557 *
3558 * Frees any previously unused libraries whose delay has expired and marks
3559 * currently unused libraries for unloading. Unused are identified as those that
3560 * return S_OK from their DllCanUnloadNow function.
3561 *
3562 * PARAMS
3563 * dwUnloadDelay [I] Unload delay in milliseconds.
3564 * dwReserved [I] Reserved. Set to 0.
3565 *
3566 * RETURNS
3567 * Nothing.
3568 *
3569 * SEE ALSO
3570 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3571 */
3572 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3573 {
3574 struct apartment *apt = COM_CurrentApt();
3575 if (!apt)
3576 {
3577 ERR("apartment not initialised\n");
3578 return;
3579 }
3580
3581 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3582 }
3583
3584 /***********************************************************************
3585 * CoFreeUnusedLibraries [OLE32.@]
3586 *
3587 * Frees any unused libraries. Unused are identified as those that return
3588 * S_OK from their DllCanUnloadNow function.
3589 *
3590 * RETURNS
3591 * Nothing.
3592 *
3593 * SEE ALSO
3594 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3595 */
3596 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3597 {
3598 CoFreeUnusedLibrariesEx(INFINITE, 0);
3599 }
3600
3601 /***********************************************************************
3602 * CoFileTimeNow [OLE32.@]
3603 *
3604 * Retrieves the current time in FILETIME format.
3605 *
3606 * PARAMS
3607 * lpFileTime [O] The current time.
3608 *
3609 * RETURNS
3610 * S_OK.
3611 */
3612 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3613 {
3614 GetSystemTimeAsFileTime( lpFileTime );
3615 return S_OK;
3616 }
3617
3618 /******************************************************************************
3619 * CoLockObjectExternal [OLE32.@]
3620 *
3621 * Increments or decrements the external reference count of a stub object.
3622 *
3623 * PARAMS
3624 * pUnk [I] Stub object.
3625 * fLock [I] If TRUE then increments the external ref-count,
3626 * otherwise decrements.
3627 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3628 * calling CoDisconnectObject.
3629 *
3630 * RETURNS
3631 * Success: S_OK.
3632 * Failure: HRESULT code.
3633 *
3634 * NOTES
3635 * If fLock is TRUE and an object is passed in that doesn't have a stub
3636 * manager then a new stub manager is created for the object.
3637 */
3638 HRESULT WINAPI CoLockObjectExternal(
3639 LPUNKNOWN pUnk,
3640 BOOL fLock,
3641 BOOL fLastUnlockReleases)
3642 {
3643 struct stub_manager *stubmgr;
3644 struct apartment *apt;
3645
3646 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3647 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3648
3649 apt = COM_CurrentApt();
3650 if (!apt) return CO_E_NOTINITIALIZED;
3651
3652 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3653 if (!stubmgr)
3654 {
3655 WARN("stub object not found %p\n", pUnk);
3656 /* Note: native is pretty broken here because it just silently
3657 * fails, without returning an appropriate error code, making apps
3658 * think that the object was disconnected, when it actually wasn't */
3659 return S_OK;
3660 }
3661
3662 if (fLock)
3663 stub_manager_ext_addref(stubmgr, 1, FALSE);
3664 else
3665 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3666
3667 stub_manager_int_release(stubmgr);
3668 return S_OK;
3669 }
3670
3671 /***********************************************************************
3672 * CoInitializeWOW (OLE32.@)
3673 *
3674 * WOW equivalent of CoInitialize?
3675 *
3676 * PARAMS
3677 * x [I] Unknown.
3678 * y [I] Unknown.
3679 *
3680 * RETURNS
3681 * Unknown.
3682 */
3683 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3684 {
3685 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3686 return 0;
3687 }
3688
3689 /***********************************************************************
3690 * CoGetState [OLE32.@]
3691 *
3692 * Retrieves the thread state object previously stored by CoSetState().
3693 *
3694 * PARAMS
3695 * ppv [I] Address where pointer to object will be stored.
3696 *
3697 * RETURNS
3698 * Success: S_OK.
3699 * Failure: E_OUTOFMEMORY.
3700 *
3701 * NOTES
3702 * Crashes on all invalid ppv addresses, including NULL.
3703 * If the function returns a non-NULL object then the caller must release its
3704 * reference on the object when the object is no longer required.
3705 *
3706 * SEE ALSO
3707 * CoSetState().
3708 */
3709 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3710 {
3711 struct oletls *info = COM_CurrentInfo();
3712 if (!info) return E_OUTOFMEMORY;
3713
3714 *ppv = NULL;
3715
3716 if (info->state)
3717 {
3718 IUnknown_AddRef(info->state);
3719 *ppv = info->state;
3720 TRACE("apt->state=%p\n", info->state);
3721 }
3722
3723 return S_OK;
3724 }
3725
3726 /***********************************************************************
3727 * CoSetState [OLE32.@]
3728 *
3729 * Sets the thread state object.
3730 *
3731 * PARAMS
3732 * pv [I] Pointer to state object to be stored.
3733 *
3734 * NOTES
3735 * The system keeps a reference on the object while the object stored.
3736 *
3737 * RETURNS
3738 * Success: S_OK.
3739 * Failure: E_OUTOFMEMORY.
3740 */
3741 HRESULT WINAPI CoSetState(IUnknown * pv)
3742 {
3743 struct oletls *info = COM_CurrentInfo();
3744 if (!info) return E_OUTOFMEMORY;
3745
3746 if (pv) IUnknown_AddRef(pv);
3747
3748 if (info->state)
3749 {
3750 TRACE("-- release %p now\n", info->state);
3751 IUnknown_Release(info->state);
3752 }
3753
3754 info->state = pv;
3755
3756 return S_OK;
3757 }
3758
3759
3760 /******************************************************************************
3761 * CoTreatAsClass [OLE32.@]
3762 *
3763 * Sets the TreatAs value of a class.
3764 *
3765 * PARAMS
3766 * clsidOld [I] Class to set TreatAs value on.
3767 * clsidNew [I] The class the clsidOld should be treated as.
3768 *
3769 * RETURNS
3770 * Success: S_OK.
3771 * Failure: HRESULT code.
3772 *
3773 * SEE ALSO
3774 * CoGetTreatAsClass
3775 */
3776 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3777 {
3778 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3779 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3780 HKEY hkey = NULL;
3781 WCHAR szClsidNew[CHARS_IN_GUID];
3782 HRESULT res = S_OK;
3783 WCHAR auto_treat_as[CHARS_IN_GUID];
3784 LONG auto_treat_as_size = sizeof(auto_treat_as);
3785 CLSID id;
3786
3787 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3788 if (FAILED(res))
3789 goto done;
3790
3791 if (IsEqualGUID( clsidOld, clsidNew ))
3792 {
3793 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3794 CLSIDFromString(auto_treat_as, &id) == S_OK)
3795 {
3796 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3797 {
3798 res = REGDB_E_WRITEREGDB;
3799 goto done;
3800 }
3801 }
3802 else
3803 {
3804 if(RegDeleteKeyW(hkey, wszTreatAs))
3805 res = REGDB_E_WRITEREGDB;
3806 goto done;
3807 }
3808 }
3809 else
3810 {
3811 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3812 RegDeleteKeyW(hkey, wszTreatAs);
3813 }else{
3814 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3815 WARN("StringFromGUID2 failed\n");
3816 res = E_FAIL;
3817 goto done;
3818 }
3819
3820 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3821 WARN("RegSetValue failed\n");
3822 res = REGDB_E_WRITEREGDB;
3823 goto done;
3824 }
3825 }
3826 }
3827
3828 done:
3829 if (hkey) RegCloseKey(hkey);
3830 return res;
3831 }
3832
3833 /******************************************************************************
3834 * CoGetTreatAsClass [OLE32.@]
3835 *
3836 * Gets the TreatAs value of a class.
3837 *
3838 * PARAMS
3839 * clsidOld [I] Class to get the TreatAs value of.
3840 * clsidNew [I] The class the clsidOld should be treated as.
3841 *
3842 * RETURNS
3843 * Success: S_OK.
3844 * Failure: HRESULT code.
3845 *
3846 * SEE ALSO
3847 * CoSetTreatAsClass
3848 */
3849 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3850 {
3851 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3852 HKEY hkey = NULL;
3853 WCHAR szClsidNew[CHARS_IN_GUID];
3854 HRESULT res = S_OK;
3855 LONG len = sizeof(szClsidNew);
3856
3857 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3858
3859 if (!clsidOld || !clsidNew)
3860 return E_INVALIDARG;
3861
3862 *clsidNew = *clsidOld; /* copy over old value */
3863
3864 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3865 if (FAILED(res))
3866 {
3867 res = S_FALSE;
3868 goto done;
3869 }
3870 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3871 {
3872 res = S_FALSE;
3873 goto done;
3874 }
3875 res = CLSIDFromString(szClsidNew,clsidNew);
3876 if (FAILED(res))
3877 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3878 done:
3879 if (hkey) RegCloseKey(hkey);
3880 return res;
3881 }
3882
3883 /******************************************************************************
3884 * CoGetCurrentProcess [OLE32.@]
3885 *
3886 * Gets the current process ID.
3887 *
3888 * RETURNS
3889 * The current process ID.
3890 *
3891 * NOTES
3892 * Is DWORD really the correct return type for this function?
3893 */
3894 DWORD WINAPI CoGetCurrentProcess(void)
3895 {
3896 return GetCurrentProcessId();
3897 }
3898
3899 /***********************************************************************
3900 * CoGetCurrentLogicalThreadId [OLE32.@]
3901 */
3902 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3903 {
3904 TRACE("(%p)\n", id);
3905
3906 if (!id)
3907 return E_INVALIDARG;
3908
3909 *id = COM_CurrentCausalityId();
3910 return S_OK;
3911 }
3912
3913 /******************************************************************************
3914 * CoRegisterMessageFilter [OLE32.@]
3915 *
3916 * Registers a message filter.
3917 *
3918 * PARAMS
3919 * lpMessageFilter [I] Pointer to interface.
3920 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3921 *
3922 * RETURNS
3923 * Success: S_OK.
3924 * Failure: HRESULT code.
3925 *
3926 * NOTES
3927 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3928 * lpMessageFilter removes the message filter.
3929 *
3930 * If lplpMessageFilter is not NULL the previous message filter will be
3931 * returned in the memory pointer to this parameter and the caller is
3932 * responsible for releasing the object.
3933 *
3934 * The current thread be in an apartment otherwise the function will crash.
3935 */
3936 HRESULT WINAPI CoRegisterMessageFilter(
3937 LPMESSAGEFILTER lpMessageFilter,
3938 LPMESSAGEFILTER *lplpMessageFilter)
3939 {
3940 struct apartment *apt;
3941 IMessageFilter *lpOldMessageFilter;
3942
3943 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3944
3945 apt = COM_CurrentApt();
3946
3947 /* can't set a message filter in a multi-threaded apartment */
3948 if (!apt || apt->multi_threaded)
3949 {
3950 WARN("can't set message filter in MTA or uninitialized apt\n");
3951 return CO_E_NOT_SUPPORTED;
3952 }
3953
3954 if (lpMessageFilter)
3955 IMessageFilter_AddRef(lpMessageFilter);
3956
3957 EnterCriticalSection(&apt->cs);
3958
3959 lpOldMessageFilter = apt->filter;
3960 apt->filter = lpMessageFilter;
3961
3962 LeaveCriticalSection(&apt->cs);
3963
3964 if (lplpMessageFilter)
3965 *lplpMessageFilter = lpOldMessageFilter;
3966 else if (lpOldMessageFilter)
3967 IMessageFilter_Release(lpOldMessageFilter);
3968
3969 return S_OK;
3970 }
3971
3972 /***********************************************************************
3973 * CoIsOle1Class [OLE32.@]
3974 *
3975 * Determines whether the specified class an OLE v1 class.
3976 *
3977 * PARAMS
3978 * clsid [I] Class to test.
3979 *
3980 * RETURNS
3981 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3982 */
3983 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3984 {
3985 FIXME("%s\n", debugstr_guid(clsid));
3986 return FALSE;
3987 }
3988
3989 /***********************************************************************
3990 * IsEqualGUID [OLE32.@]
3991 *
3992 * Compares two Unique Identifiers.
3993 *
3994 * PARAMS
3995 * rguid1 [I] The first GUID to compare.
3996 * rguid2 [I] The other GUID to compare.
3997 *
3998 * RETURNS
3999 * TRUE if equal
4000 */
4001 #undef IsEqualGUID
4002 BOOL WINAPI IsEqualGUID(
4003 REFGUID rguid1,
4004 REFGUID rguid2)
4005 {
4006 return !memcmp(rguid1,rguid2,sizeof(GUID));
4007 }
4008
4009 /***********************************************************************
4010 * CoInitializeSecurity [OLE32.@]
4011 */
4012 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
4013 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4014 void* pReserved1, DWORD dwAuthnLevel,
4015 DWORD dwImpLevel, void* pReserved2,
4016 DWORD dwCapabilities, void* pReserved3)
4017 {
4018 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4019 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4020 dwCapabilities, pReserved3);
4021 return S_OK;
4022 }
4023
4024 /***********************************************************************
4025 * CoSuspendClassObjects [OLE32.@]
4026 *
4027 * Suspends all registered class objects to prevent further requests coming in
4028 * for those objects.
4029 *
4030 * RETURNS
4031 * Success: S_OK.
4032 * Failure: HRESULT code.
4033 */
4034 HRESULT WINAPI CoSuspendClassObjects(void)
4035 {
4036 FIXME("\n");
4037 return S_OK;
4038 }
4039
4040 /***********************************************************************
4041 * CoAddRefServerProcess [OLE32.@]
4042 *
4043 * Helper function for incrementing the reference count of a local-server
4044 * process.
4045 *
4046 * RETURNS
4047 * New reference count.
4048 *
4049 * SEE ALSO
4050 * CoReleaseServerProcess().
4051 */
4052 ULONG WINAPI CoAddRefServerProcess(void)
4053 {
4054 ULONG refs;
4055
4056 TRACE("\n");
4057
4058 EnterCriticalSection(&csRegisteredClassList);
4059 refs = ++s_COMServerProcessReferences;
4060 LeaveCriticalSection(&csRegisteredClassList);
4061
4062 TRACE("refs before: %d\n", refs - 1);
4063
4064 return refs;
4065 }
4066
4067 /***********************************************************************
4068 * CoReleaseServerProcess [OLE32.@]
4069 *
4070 * Helper function for decrementing the reference count of a local-server
4071 * process.
4072 *
4073 * RETURNS
4074 * New reference count.
4075 *
4076 * NOTES
4077 * When reference count reaches 0, this function suspends all registered
4078 * classes so no new connections are accepted.
4079 *
4080 * SEE ALSO
4081 * CoAddRefServerProcess(), CoSuspendClassObjects().
4082 */
4083 ULONG WINAPI CoReleaseServerProcess(void)
4084 {
4085 ULONG refs;
4086
4087 TRACE("\n");
4088
4089 EnterCriticalSection(&csRegisteredClassList);
4090
4091 refs = --s_COMServerProcessReferences;
4092 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4093
4094 LeaveCriticalSection(&csRegisteredClassList);
4095
4096 TRACE("refs after: %d\n", refs);
4097
4098 return refs;
4099 }
4100
4101 /***********************************************************************
4102 * CoIsHandlerConnected [OLE32.@]
4103 *
4104 * Determines whether a proxy is connected to a remote stub.
4105 *
4106 * PARAMS
4107 * pUnk [I] Pointer to object that may or may not be connected.
4108 *
4109 * RETURNS
4110 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4111 * FALSE otherwise.
4112 */
4113 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4114 {
4115 FIXME("%p\n", pUnk);
4116
4117 return TRUE;
4118 }
4119
4120 /***********************************************************************
4121 * CoAllowSetForegroundWindow [OLE32.@]
4122 *
4123 */
4124 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4125 {
4126 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4127 return S_OK;
4128 }
4129
4130 /***********************************************************************
4131 * CoQueryProxyBlanket [OLE32.@]
4132 *
4133 * Retrieves the security settings being used by a proxy.
4134 *
4135 * PARAMS
4136 * pProxy [I] Pointer to the proxy object.
4137 * pAuthnSvc [O] The type of authentication service.
4138 * pAuthzSvc [O] The type of authorization service.
4139 * ppServerPrincName [O] Optional. The server prinicple name.
4140 * pAuthnLevel [O] The authentication level.
4141 * pImpLevel [O] The impersonation level.
4142 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4143 * pCapabilities [O] Flags affecting the security behaviour.
4144 *
4145 * RETURNS
4146 * Success: S_OK.
4147 * Failure: HRESULT code.
4148 *
4149 * SEE ALSO
4150 * CoCopyProxy, CoSetProxyBlanket.
4151 */
4152 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4153 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4154 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4155 {
4156 IClientSecurity *pCliSec;
4157 HRESULT hr;
4158
4159 TRACE("%p\n", pProxy);
4160
4161 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4162 if (SUCCEEDED(hr))
4163 {
4164 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4165 pAuthzSvc, ppServerPrincName,
4166 pAuthnLevel, pImpLevel, ppAuthInfo,
4167 pCapabilities);
4168 IClientSecurity_Release(pCliSec);
4169 }
4170
4171 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4172 return hr;
4173 }
4174
4175 /***********************************************************************
4176 * CoSetProxyBlanket [OLE32.@]
4177 *
4178 * Sets the security settings for a proxy.
4179 *
4180 * PARAMS
4181 * pProxy [I] Pointer to the proxy object.
4182 * AuthnSvc [I] The type of authentication service.
4183 * AuthzSvc [I] The type of authorization service.
4184 * pServerPrincName [I] The server prinicple name.
4185 * AuthnLevel [I] The authentication level.
4186 * ImpLevel [I] The impersonation level.
4187 * pAuthInfo [I] Information specific to the authorization/authentication service.
4188 * Capabilities [I] Flags affecting the security behaviour.
4189 *
4190 * RETURNS
4191 * Success: S_OK.
4192 * Failure: HRESULT code.
4193 *
4194 * SEE ALSO
4195 * CoQueryProxyBlanket, CoCopyProxy.
4196 */
4197 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4198 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4199 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4200 {
4201 IClientSecurity *pCliSec;
4202 HRESULT hr;
4203
4204 TRACE("%p\n", pProxy);
4205
4206 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4207 if (SUCCEEDED(hr))
4208 {
4209 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4210 AuthzSvc, pServerPrincName,
4211 AuthnLevel, ImpLevel, pAuthInfo,
4212 Capabilities);
4213 IClientSecurity_Release(pCliSec);
4214 }
4215
4216 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4217 return hr;
4218 }
4219
4220 /***********************************************************************
4221 * CoCopyProxy [OLE32.@]
4222 *
4223 * Copies a proxy.
4224 *
4225 * PARAMS
4226 * pProxy [I] Pointer to the proxy object.
4227 * ppCopy [O] Copy of the proxy.
4228 *
4229 * RETURNS
4230 * Success: S_OK.
4231 * Failure: HRESULT code.
4232 *
4233 * SEE ALSO
4234 * CoQueryProxyBlanket, CoSetProxyBlanket.
4235 */
4236 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4237 {
4238 IClientSecurity *pCliSec;
4239 HRESULT hr;
4240
4241 TRACE("%p\n", pProxy);
4242
4243 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4244 if (SUCCEEDED(hr))
4245 {
4246 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4247 IClientSecurity_Release(pCliSec);
4248 }
4249
4250 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4251 return hr;
4252 }
4253
4254
4255 /***********************************************************************
4256 * CoGetCallContext [OLE32.@]
4257 *
4258 * Gets the context of the currently executing server call in the current
4259 * thread.
4260 *
4261 * PARAMS
4262 * riid [I] Context interface to return.
4263 * ppv [O] Pointer to memory that will receive the context on return.
4264 *
4265 * RETURNS
4266 * Success: S_OK.
4267 * Failure: HRESULT code.
4268 */
4269 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4270 {
4271 struct oletls *info = COM_CurrentInfo();
4272
4273 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4274
4275 if (!info)
4276 return E_OUTOFMEMORY;
4277
4278 if (!info->call_state)
4279 return RPC_E_CALL_COMPLETE;
4280
4281 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4282 }
4283
4284 /***********************************************************************
4285 * CoSwitchCallContext [OLE32.@]
4286 *
4287 * Switches the context of the currently executing server call in the current
4288 * thread.
4289 *
4290 * PARAMS
4291 * pObject [I] Pointer to new context object
4292 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4293 *
4294 * RETURNS
4295 * Success: S_OK.
4296 * Failure: HRESULT code.
4297 */
4298 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4299 {
4300 struct oletls *info = COM_CurrentInfo();
4301
4302 TRACE("(%p, %p)\n", pObject, ppOldObject);
4303
4304 if (!info)
4305 return E_OUTOFMEMORY;
4306
4307 *ppOldObject = info->call_state;
4308 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4309
4310 return S_OK;
4311 }
4312
4313 /***********************************************************************
4314 * CoQueryClientBlanket [OLE32.@]
4315 *
4316 * Retrieves the authentication information about the client of the currently
4317 * executing server call in the current thread.
4318 *
4319 * PARAMS
4320 * pAuthnSvc [O] Optional. The type of authentication service.
4321 * pAuthzSvc [O] Optional. The type of authorization service.
4322 * pServerPrincName [O] Optional. The server prinicple name.
4323 * pAuthnLevel [O] Optional. The authentication level.
4324 * pImpLevel [O] Optional. The impersonation level.
4325 * pPrivs [O] Optional. Information about the privileges of the client.
4326 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4327 *
4328 * RETURNS
4329 * Success: S_OK.
4330 * Failure: HRESULT code.
4331 *
4332 * SEE ALSO
4333 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4334 */
4335 HRESULT WINAPI CoQueryClientBlanket(
4336 DWORD *pAuthnSvc,
4337 DWORD *pAuthzSvc,
4338 OLECHAR **pServerPrincName,
4339 DWORD *pAuthnLevel,
4340 DWORD *pImpLevel,
4341 RPC_AUTHZ_HANDLE *pPrivs,
4342 DWORD *pCapabilities)
4343 {
4344 IServerSecurity *pSrvSec;
4345 HRESULT hr;
4346
4347 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4348 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4349 pPrivs, pCapabilities);
4350
4351 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4352 if (SUCCEEDED(hr))
4353 {
4354 hr = IServerSecurity_QueryBlanket(
4355 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4356 pImpLevel, pPrivs, pCapabilities);
4357 IServerSecurity_Release(pSrvSec);
4358 }
4359
4360 return hr;
4361 }
4362
4363 /***********************************************************************
4364 * CoImpersonateClient [OLE32.@]
4365 *
4366 * Impersonates the client of the currently executing server call in the
4367 * current thread.
4368 *
4369 * PARAMS
4370 * None.
4371 *
4372 * RETURNS
4373 * Success: S_OK.
4374 * Failure: HRESULT code.
4375 *
4376 * NOTES
4377 * If this function fails then the current thread will not be impersonating
4378 * the client and all actions will take place on behalf of the server.
4379 * Therefore, it is important to check the return value from this function.
4380 *
4381 * SEE ALSO
4382 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4383 */
4384 HRESULT WINAPI CoImpersonateClient(void)
4385 {
4386 IServerSecurity *pSrvSec;
4387 HRESULT hr;
4388
4389 TRACE("\n");
4390
4391 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4392 if (SUCCEEDED(hr))
4393 {
4394 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4395 IServerSecurity_Release(pSrvSec);
4396 }
4397
4398 return hr;
4399 }
4400
4401 /***********************************************************************
4402 * CoRevertToSelf [OLE32.@]
4403 *
4404 * Ends the impersonation of the client of the currently executing server
4405 * call in the current thread.
4406 *
4407 * PARAMS
4408 * None.
4409 *
4410 * RETURNS
4411 * Success: S_OK.
4412 * Failure: HRESULT code.
4413 *
4414 * SEE ALSO
4415 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4416 */
4417 HRESULT WINAPI CoRevertToSelf(void)
4418 {
4419 IServerSecurity *pSrvSec;
4420 HRESULT hr;
4421
4422 TRACE("\n");
4423
4424 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4425 if (SUCCEEDED(hr))
4426 {
4427 hr = IServerSecurity_RevertToSelf(pSrvSec);
4428 IServerSecurity_Release(pSrvSec);
4429 }
4430
4431 return hr;
4432 }
4433
4434 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4435 {
4436 /* first try to retrieve messages for incoming COM calls to the apartment window */
4437 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4438 /* next retrieve other messages necessary for the app to remain responsive */
4439 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4440 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4441 }
4442
4443 /***********************************************************************
4444 * CoWaitForMultipleHandles [OLE32.@]
4445 *
4446 * Waits for one or more handles to become signaled.
4447 *
4448 * PARAMS
4449 * dwFlags [I] Flags. See notes.
4450 * dwTimeout [I] Timeout in milliseconds.
4451 * cHandles [I] Number of handles pointed to by pHandles.
4452 * pHandles [I] Handles to wait for.
4453 * lpdwindex [O] Index of handle that was signaled.
4454 *
4455 * RETURNS
4456 * Success: S_OK.
4457 * Failure: RPC_S_CALLPENDING on timeout.
4458 *
4459 * NOTES
4460 *
4461 * The dwFlags parameter can be zero or more of the following:
4462 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4463 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4464 *
4465 * SEE ALSO
4466 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4467 */
4468 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4469 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4470 {
4471 HRESULT hr = S_OK;
4472 DWORD start_time = GetTickCount();
4473 APARTMENT *apt = COM_CurrentApt();
4474 BOOL message_loop = apt && !apt->multi_threaded;
4475 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4476 BOOL post_quit = FALSE;
4477 UINT exit_code;
4478
4479 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4480 pHandles, lpdwindex);
4481
4482 if (!lpdwindex)
4483 return E_INVALIDARG;
4484
4485 *lpdwindex = 0;
4486
4487 if (!pHandles)
4488 return E_INVALIDARG;
4489
4490 if (!cHandles)
4491 return RPC_E_NO_SYNC;
4492
4493 while (TRUE)
4494 {
4495 DWORD now = GetTickCount();
4496 DWORD res;
4497
4498 if (now - start_time > dwTimeout)
4499 {
4500 hr = RPC_S_CALLPENDING;
4501 break;
4502 }
4503
4504 if (message_loop)
4505 {
4506 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4507 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4508
4509 TRACE("waiting for rpc completion or window message\n");
4510
4511 res = WAIT_TIMEOUT;
4512
4513 if (check_apc)
4514 {
4515 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4516 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4517 check_apc = FALSE;
4518 }
4519
4520 if (res == WAIT_TIMEOUT)
4521 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4522 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4523 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4524
4525 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4526 {
4527 MSG msg;
4528 int count = 0;
4529
4530 /* call message filter */
4531
4532 if (COM_CurrentApt()->filter)
4533 {
4534 PENDINGTYPE pendingtype =
4535 COM_CurrentInfo()->pending_call_count_server ?
4536 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4537 DWORD be_handled = IMessageFilter_MessagePending(
4538 COM_CurrentApt()->filter, 0 /* FIXME */,
4539 now - start_time, pendingtype);
4540 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4541 switch (be_handled)
4542 {
4543 case PENDINGMSG_CANCELCALL:
4544 WARN("call canceled\n");
4545 hr = RPC_E_CALL_CANCELED;
4546 break;
4547 case PENDINGMSG_WAITNOPROCESS:
4548 case PENDINGMSG_WAITDEFPROCESS:
4549 default:
4550 /* FIXME: MSDN is very vague about the difference
4551 * between WAITNOPROCESS and WAITDEFPROCESS - there
4552 * appears to be none, so it is possibly a left-over
4553 * from the 16-bit world. */
4554 break;
4555 }
4556 }
4557
4558 if (!apt->win)
4559 {
4560 /* If window is NULL on apartment, peek at messages so that it will not trigger
4561 * MsgWaitForMultipleObjects next time. */
4562 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
4563 }
4564 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4565 * so after processing 100 messages we go back to checking the wait handles */
4566 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4567 {
4568 if (msg.message == WM_QUIT)
4569 {
4570 TRACE("received WM_QUIT message\n");
4571 post_quit = TRUE;
4572 exit_code = msg.wParam;
4573 }
4574 else
4575 {
4576 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4577 TranslateMessage(&msg);
4578 DispatchMessageW(&msg);
4579 }
4580 }
4581 continue;
4582 }
4583 }
4584 else
4585 {
4586 TRACE("waiting for rpc completion\n");
4587
4588 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4589 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4590 (dwFlags & COWAIT_ALERTABLE) != 0);
4591 }
4592
4593 switch (res)
4594 {
4595 case WAIT_TIMEOUT:
4596 hr = RPC_S_CALLPENDING;
4597 break;
4598 case WAIT_FAILED:
4599 hr = HRESULT_FROM_WIN32( GetLastError() );
4600 break;
4601 default:
4602 *lpdwindex = res;
4603 break;
4604 }
4605 break;
4606 }
4607 if (post_quit) PostQuitMessage(exit_code);
4608 TRACE("-- 0x%08x\n", hr);
4609 return hr;
4610 }
4611
4612
4613 /***********************************************************************
4614 * CoGetObject [OLE32.@]
4615 *
4616 * Gets the object named by converting the name to a moniker and binding to it.
4617 *
4618 * PARAMS
4619 * pszName [I] String representing the object.
4620 * pBindOptions [I] Parameters affecting the binding to the named object.
4621 * riid [I] Interface to bind to on the objecct.
4622 * ppv [O] On output, the interface riid of the object represented
4623 * by pszName.
4624 *
4625 * RETURNS
4626 * Success: S_OK.
4627 * Failure: HRESULT code.
4628 *
4629 * SEE ALSO
4630 * MkParseDisplayName.
4631 */
4632 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4633 REFIID riid, void **ppv)
4634 {
4635 IBindCtx *pbc;
4636 HRESULT hr;
4637
4638 *ppv = NULL;
4639
4640 hr = CreateBindCtx(0, &pbc);
4641 if (SUCCEEDED(hr))
4642 {
4643 if (pBindOptions)
4644 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4645
4646 if (SUCCEEDED(hr))
4647 {
4648 ULONG chEaten;
4649 IMoniker *pmk;
4650
4651 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4652 if (SUCCEEDED(hr))
4653 {
4654 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4655 IMoniker_Release(pmk);
4656 }
4657 }
4658
4659 IBindCtx_Release(pbc);
4660 }
4661 return hr;
4662 }
4663
4664 /***********************************************************************
4665 * CoRegisterChannelHook [OLE32.@]
4666 *
4667 * Registers a process-wide hook that is called during ORPC calls.
4668 *
4669 * PARAMS
4670 * guidExtension [I] GUID of the channel hook to register.
4671 * pChannelHook [I] Channel hook object to register.
4672 *
4673 * RETURNS
4674 * Success: S_OK.
4675 * Failure: HRESULT code.
4676 */
4677 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4678 {
4679 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4680
4681 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4682 }
4683
4684 typedef struct Context
4685 {
4686 IComThreadingInfo IComThreadingInfo_iface;
4687 IContextCallback IContextCallback_iface;
4688 IObjContext IObjContext_iface;
4689 LONG refs;
4690 } Context;
4691
4692 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4693 {
4694 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4695 }
4696
4697 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4698 {
4699 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4700 }
4701
4702 static inline Context *impl_from_IObjContext( IObjContext *iface )
4703 {
4704 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4705 }
4706
4707 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4708 {
4709 *ppv = NULL;
4710
4711 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4712 IsEqualIID(riid, &IID_IUnknown))
4713 {
4714 *ppv = &iface->IComThreadingInfo_iface;
4715 }
4716 else if (IsEqualIID(riid, &IID_IContextCallback))
4717 {
4718 *ppv = &iface->IContextCallback_iface;
4719 }
4720 else if (IsEqualIID(riid, &IID_IObjContext))
4721 {
4722 *ppv = &iface->IObjContext_iface;
4723 }
4724
4725 if (*ppv)
4726 {
4727 IUnknown_AddRef((IUnknown*)*ppv);
4728 return S_OK;
4729 }
4730
4731 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4732 return E_NOINTERFACE;
4733 }
4734
4735 static ULONG Context_AddRef(Context *This)
4736 {
4737 return InterlockedIncrement(&This->refs);
4738 }
4739
4740 static ULONG Context_Release(Context *This)
4741 {
4742 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4743 releasing context while refcount is at 0 destroys it. */
4744 if (!This->refs)
4745 {
4746 HeapFree(GetProcessHeap(), 0, This);
4747 return 0;
4748 }
4749
4750 return InterlockedDecrement(&This->refs);
4751 }
4752
4753 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4754 {
4755 Context *This = impl_from_IComThreadingInfo(iface);
4756 return Context_QueryInterface(This, riid, ppv);
4757 }
4758
4759 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4760 {
4761 Context *This = impl_from_IComThreadingInfo(iface);
4762 return Context_AddRef(This);
4763 }
4764
4765 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4766 {
4767 Context *This = impl_from_IComThreadingInfo(iface);
4768 return Context_Release(This);
4769 }
4770
4771 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4772 {
4773 APTTYPEQUALIFIER qualifier;
4774
4775 TRACE("(%p)\n", apttype);
4776
4777 return CoGetApartmentType(apttype, &qualifier);
4778 }
4779
4780 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4781 {
4782 APTTYPEQUALIFIER qualifier;
4783 APTTYPE apttype;
4784 HRESULT hr;
4785
4786 hr = CoGetApartmentType(&apttype, &qualifier);
4787 if (FAILED(hr))
4788 return hr;
4789
4790 TRACE("(%p)\n", thdtype);
4791
4792 switch (apttype)
4793 {
4794 case APTTYPE_STA:
4795 case APTTYPE_MAINSTA:
4796 *thdtype = THDTYPE_PROCESSMESSAGES;
4797 break;
4798 default:
4799 *thdtype = THDTYPE_BLOCKMESSAGES;
4800 break;
4801 }
4802 return S_OK;
4803 }
4804
4805 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4806 {
4807 TRACE("(%p)\n", logical_thread_id);
4808 return CoGetCurrentLogicalThreadId(logical_thread_id);
4809 }
4810
4811 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4812 {
4813 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4814 return E_NOTIMPL;
4815 }
4816
4817 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4818 {
4819 Context_CTI_QueryInterface,
4820 Context_CTI_AddRef,
4821 Context_CTI_Release,
4822 Context_CTI_GetCurrentApartmentType,
4823 Context_CTI_GetCurrentThreadType,
4824 Context_CTI_GetCurrentLogicalThreadId,
4825 Context_CTI_SetCurrentLogicalThreadId
4826 };
4827
4828 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4829 {
4830 Context *This = impl_from_IContextCallback(iface);
4831 return Context_QueryInterface(This, riid, ppv);
4832 }
4833
4834 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4835 {
4836 Context *This = impl_from_IContextCallback(iface);
4837 return Context_AddRef(This);
4838 }
4839
4840 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4841 {
4842 Context *This = impl_from_IContextCallback(iface);
4843 return Context_Release(This);
4844 }
4845
4846 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4847 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4848 {
4849 Context *This = impl_from_IContextCallback(iface);
4850
4851 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4852 return E_NOTIMPL;
4853 }
4854
4855 static const IContextCallbackVtbl Context_Callback_Vtbl =
4856 {
4857 Context_CC_QueryInterface,
4858 Context_CC_AddRef,
4859 Context_CC_Release,
4860 Context_CC_ContextCallback
4861 };
4862
4863 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4864 {
4865 Context *This = impl_from_IObjContext(iface);
4866 return Context_QueryInterface(This, riid, ppv);
4867 }
4868
4869 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4870 {
4871 Context *This = impl_from_IObjContext(iface);
4872 return Context_AddRef(This);
4873 }
4874
4875 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4876 {
4877 Context *This = impl_from_IObjContext(iface);
4878 return Context_Release(This);
4879 }
4880
4881 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4882 {
4883 Context *This = impl_from_IObjContext(iface);
4884
4885 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4886 return E_NOTIMPL;
4887 }
4888
4889 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4890 {
4891 Context *This = impl_from_IObjContext(iface);
4892
4893 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4894 return E_NOTIMPL;
4895 }
4896
4897 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4898 {
4899 Context *This = impl_from_IObjContext(iface);
4900
4901 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4902 return E_NOTIMPL;
4903 }
4904
4905 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4906 {
4907 Context *This = impl_from_IObjContext(iface);
4908
4909 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4910 return E_NOTIMPL;
4911 }
4912
4913 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4914 {
4915 Context *This = impl_from_IObjContext(iface);
4916 FIXME("(%p/%p)\n", This, iface);
4917 }
4918
4919 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4920 {
4921 Context *This = impl_from_IObjContext(iface);
4922 FIXME("(%p/%p)\n", This, iface);
4923 }
4924
4925 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4926 {
4927 Context *This = impl_from_IObjContext(iface);
4928 FIXME("(%p/%p)\n", This, iface);
4929 }
4930
4931 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4932 {
4933 Context *This = impl_from_IObjContext(iface);
4934 FIXME("(%p/%p)\n", This, iface);
4935 }
4936
4937 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4938 {
4939 Context *This = impl_from_IObjContext(iface);
4940 FIXME("(%p/%p)\n", This, iface);
4941 }
4942
4943 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4944 {
4945 Context *This = impl_from_IObjContext(iface);
4946 FIXME("(%p/%p)\n", This, iface);
4947 }
4948
4949 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4950 {
4951 Context *This = impl_from_IObjContext(iface);
4952 FIXME("(%p/%p)\n", This, iface);
4953 }
4954
4955 static const IObjContextVtbl Context_Object_Vtbl =
4956 {
4957 Context_OC_QueryInterface,
4958 Context_OC_AddRef,
4959 Context_OC_Release,
4960 Context_OC_SetProperty,
4961 Context_OC_RemoveProperty,
4962 Context_OC_GetProperty,
4963 Context_OC_EnumContextProps,
4964 Context_OC_Reserved1,
4965 Context_OC_Reserved2,
4966 Context_OC_Reserved3,
4967 Context_OC_Reserved4,
4968 Context_OC_Reserved5,
4969 Context_OC_Reserved6,
4970 Context_OC_Reserved7
4971 };
4972
4973 /***********************************************************************
4974 * CoGetObjectContext [OLE32.@]
4975 *
4976 * Retrieves an object associated with the current context (i.e. apartment).
4977 *
4978 * PARAMS
4979 * riid [I] ID of the interface of the object to retrieve.
4980 * ppv [O] Address where object will be stored on return.
4981 *
4982 * RETURNS
4983 * Success: S_OK.
4984 * Failure: HRESULT code.
4985 */
4986 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4987 {
4988 IObjContext *context;
4989 HRESULT hr;
4990
4991 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4992
4993 *ppv = NULL;
4994 hr = CoGetContextToken((ULONG_PTR*)&context);
4995 if (FAILED(hr))
4996 return hr;
4997
4998 return IObjContext_QueryInterface(context, riid, ppv);
4999 }
5000
5001 /***********************************************************************
5002 * CoGetContextToken [OLE32.@]
5003 */
5004 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
5005 {
5006 struct oletls *info = COM_CurrentInfo();
5007
5008 TRACE("(%p)\n", token);
5009
5010 if (!info)
5011 return E_OUTOFMEMORY;
5012
5013 if (!info->apt)
5014 {
5015 APARTMENT *apt;
5016 if (!(apt = apartment_find_multi_threaded()))
5017 {
5018 ERR("apartment not initialised\n");
5019 return CO_E_NOTINITIALIZED;
5020 }
5021 apartment_release(apt);
5022 }
5023
5024 if (!token)
5025 return E_POINTER;
5026
5027 if (!info->context_token)
5028 {
5029 Context *context;
5030
5031 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5032 if (!context)
5033 return E_OUTOFMEMORY;
5034
5035 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5036 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5037 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5038 /* Context token does not take a reference, it's always zero until the
5039 interface is explicitly requested with CoGetObjectContext(). */
5040 context->refs = 0;
5041
5042 info->context_token = &context->IObjContext_iface;
5043 }
5044
5045 *token = (ULONG_PTR)info->context_token;
5046 TRACE("context_token=%p\n", info->context_token);
5047
5048 return S_OK;
5049 }
5050
5051 /***********************************************************************
5052 * CoGetDefaultContext [OLE32.@]
5053 */
5054 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5055 {
5056 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5057 return E_NOINTERFACE;
5058 }
5059
5060 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5061 {
5062 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5063 HKEY hkey;
5064 HRESULT hres;
5065
5066 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5067 if (SUCCEEDED(hres))
5068 {
5069 struct class_reg_data regdata;
5070 WCHAR dllpath[MAX_PATH+1];
5071
5072 regdata.u.hkey = hkey;
5073 regdata.hkey = TRUE;
5074
5075 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5076 {
5077 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5078 if (!strcmpiW(dllpath, wszOle32))
5079 {
5080 RegCloseKey(hkey);
5081 return HandlerCF_Create(rclsid, riid, ppv);
5082 }
5083 }
5084 else
5085 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5086 RegCloseKey(hkey);
5087 }
5088
5089 return CLASS_E_CLASSNOTAVAILABLE;
5090 }
5091
5092 /***********************************************************************
5093 * CoGetApartmentType [OLE32.@]
5094 */
5095 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5096 {
5097 struct oletls *info = COM_CurrentInfo();
5098
5099 FIXME("(%p, %p): semi-stub\n", type, qualifier);
5100
5101 if (!type || !qualifier)
5102 return E_INVALIDARG;
5103
5104 if (!info)
5105 return E_OUTOFMEMORY;
5106
5107 if (!info->apt)
5108 *type = APTTYPE_CURRENT;
5109 else if (info->apt->multi_threaded)
5110 *type = APTTYPE_MTA;
5111 else if (info->apt->main)
5112 *type = APTTYPE_MAINSTA;
5113 else
5114 *type = APTTYPE_STA;
5115
5116 *qualifier = APTTYPEQUALIFIER_NONE;
5117
5118 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5119 }
5120
5121 /***********************************************************************
5122 * CoRegisterSurrogate [OLE32.@]
5123 */
5124 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5125 {
5126 FIXME("(%p): stub\n", surrogate);
5127
5128 return E_NOTIMPL;
5129 }
5130
5131 /***********************************************************************
5132 * CoRegisterSurrogateEx [OLE32.@]
5133 */
5134 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5135 {
5136 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5137
5138 return E_NOTIMPL;
5139 }
5140
5141 typedef struct {
5142 IGlobalOptions IGlobalOptions_iface;
5143 LONG ref;
5144 } GlobalOptions;
5145
5146 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5147 {
5148 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5149 }
5150
5151 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5152 {
5153 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5154
5155 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5156
5157 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5158 {
5159 *ppv = iface;
5160 }
5161 else
5162 {
5163 *ppv = NULL;
5164 return E_NOINTERFACE;
5165 }
5166
5167 IUnknown_AddRef((IUnknown*)*ppv);
5168 return S_OK;
5169 }
5170
5171 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5172 {
5173 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5174 LONG ref = InterlockedIncrement(&This->ref);
5175
5176 TRACE("(%p) ref=%d\n", This, ref);
5177
5178 return ref;
5179 }
5180
5181 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5182 {
5183 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5184 LONG ref = InterlockedDecrement(&This->ref);
5185
5186 TRACE("(%p) ref=%d\n", This, ref);
5187
5188 if (!ref)
5189 heap_free(This);
5190
5191 return ref;
5192 }
5193
5194 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5195 {
5196 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5197 FIXME("(%p)->(%u %lx)\n", This, property, value);
5198 return S_OK;
5199 }
5200
5201 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5202 {
5203 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5204 FIXME("(%p)->(%u %p)\n", This, property, value);
5205 return E_NOTIMPL;
5206 }
5207
5208 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5209 GlobalOptions_QueryInterface,
5210 GlobalOptions_AddRef,
5211 GlobalOptions_Release,
5212 GlobalOptions_Set,
5213 GlobalOptions_Query
5214 };
5215
5216 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5217 {
5218 GlobalOptions *global_options;
5219 HRESULT hres;
5220
5221 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5222
5223 if (outer)
5224 return E_INVALIDARG;
5225
5226 global_options = heap_alloc(sizeof(*global_options));
5227 if (!global_options)
5228 return E_OUTOFMEMORY;
5229 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5230 global_options->ref = 1;
5231
5232 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5233 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5234 return hres;
5235 }
5236
5237 /***********************************************************************
5238 * DllMain (OLE32.@)
5239 */
5240 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5241 {
5242 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5243
5244 switch(fdwReason) {
5245 case DLL_PROCESS_ATTACH:
5246 hProxyDll = hinstDLL;
5247 break;
5248
5249 case DLL_PROCESS_DETACH:
5250 if (reserved) break;
5251 release_std_git();
5252 UnregisterClassW( wszAptWinClass, hProxyDll );
5253 RPC_UnregisterAllChannelHooks();
5254 COMPOBJ_DllList_Free();
5255 DeleteCriticalSection(&csRegisteredClassList);
5256 DeleteCriticalSection(&csApartment);
5257 break;
5258
5259 case DLL_THREAD_DETACH:
5260 COM_TlsDestroy();
5261 break;
5262 }
5263 return TRUE;
5264 }
5265
5266 /***********************************************************************
5267 * DllRegisterServer (OLE32.@)
5268 */
5269 HRESULT WINAPI DllRegisterServer(void)
5270 {
5271 return OLE32_DllRegisterServer();
5272 }
5273
5274 /***********************************************************************
5275 * DllUnregisterServer (OLE32.@)
5276 */
5277 HRESULT WINAPI DllUnregisterServer(void)
5278 {
5279 return OLE32_DllUnregisterServer();
5280 }