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