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