Hopefully create a branch and not destroy the svn repository.
[reactos.git] / dll / win32 / ole32 / compobj.c
1 /*
2 * COMPOBJ library
3 *
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 *
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
29 *
30 * TODO list: (items bunched together depend on each other)
31 *
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
36 *
37 */
38
39 #include "config.h"
40
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
49
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #define USE_COM_CONTEXT_DEF
56 #include "objbase.h"
57 #include "ole2.h"
58 #include "ole2ver.h"
59 #include "ctxtcall.h"
60 #include "dde.h"
61
62 #include "compobj_private.h"
63
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
66
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
68
69 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
70
71 /****************************************************************************
72 * This section defines variables internal to the COM module.
73 */
74
75 static APARTMENT *MTA; /* protected by csApartment */
76 static APARTMENT *MainApartment; /* the first STA apartment */
77 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
78
79 static CRITICAL_SECTION csApartment;
80 static CRITICAL_SECTION_DEBUG critsect_debug =
81 {
82 0, 0, &csApartment,
83 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
84 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
85 };
86 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
87
88 struct registered_psclsid
89 {
90 struct list entry;
91 IID iid;
92 CLSID clsid;
93 };
94
95 /*
96 * This lock count counts the number of times CoInitialize is called. It is
97 * decreased every time CoUninitialize is called. When it hits 0, the COM
98 * libraries are freed
99 */
100 static LONG s_COMLockCount = 0;
101 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
102 static LONG s_COMServerProcessReferences = 0;
103
104 /*
105 * This linked list contains the list of registered class objects. These
106 * are mostly used to register the factories for out-of-proc servers of OLE
107 * objects.
108 *
109 * TODO: Make this data structure aware of inter-process communication. This
110 * means that parts of this will be exported to rpcss.
111 */
112 typedef struct tagRegisteredClass
113 {
114 struct list entry;
115 CLSID classIdentifier;
116 OXID apartment_id;
117 LPUNKNOWN classObject;
118 DWORD runContext;
119 DWORD connectFlags;
120 DWORD dwCookie;
121 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
122 void *RpcRegistration;
123 } RegisteredClass;
124
125 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
126
127 static CRITICAL_SECTION csRegisteredClassList;
128 static CRITICAL_SECTION_DEBUG class_cs_debug =
129 {
130 0, 0, &csRegisteredClassList,
131 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
133 };
134 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
135
136 /*****************************************************************************
137 * This section contains OpenDllList definitions
138 *
139 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
140 * other functions that do LoadLibrary _without_ giving back a HMODULE.
141 * Without this list these handles would never be freed.
142 *
143 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
144 * next unload-call but not before 600 sec.
145 */
146
147 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
148 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
149
150 typedef struct tagOpenDll
151 {
152 LONG refs;
153 LPWSTR library_name;
154 HANDLE library;
155 DllGetClassObjectFunc DllGetClassObject;
156 DllCanUnloadNowFunc DllCanUnloadNow;
157 struct list entry;
158 } OpenDll;
159
160 static struct list openDllList = LIST_INIT(openDllList);
161
162 static CRITICAL_SECTION csOpenDllList;
163 static CRITICAL_SECTION_DEBUG dll_cs_debug =
164 {
165 0, 0, &csOpenDllList,
166 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
168 };
169 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
170
171 struct apartment_loaded_dll
172 {
173 struct list entry;
174 OpenDll *dll;
175 DWORD unload_time;
176 BOOL multi_threaded;
177 };
178
179 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',' ',
180 '0','x','#','#','#','#','#','#','#','#',' ',0};
181
182 /*****************************************************************************
183 * This section contains OpenDllList implementation
184 */
185
186 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
187 {
188 OpenDll *ptr;
189 OpenDll *ret = NULL;
190 EnterCriticalSection(&csOpenDllList);
191 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
192 {
193 if (!strcmpiW(library_name, ptr->library_name) &&
194 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
195 {
196 ret = ptr;
197 break;
198 }
199 }
200 LeaveCriticalSection(&csOpenDllList);
201 return ret;
202 }
203
204 /* caller must ensure that library_name is not already in the open dll list */
205 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
206 {
207 OpenDll *entry;
208 int len;
209 HRESULT hr = S_OK;
210 HANDLE hLibrary;
211 DllCanUnloadNowFunc DllCanUnloadNow;
212 DllGetClassObjectFunc DllGetClassObject;
213
214 TRACE("\n");
215
216 *ret = COMPOBJ_DllList_Get(library_name);
217 if (*ret) return S_OK;
218
219 /* do this outside the csOpenDllList to avoid creating a lock dependency on
220 * the loader lock */
221 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
222 if (!hLibrary)
223 {
224 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
225 /* failure: DLL could not be loaded */
226 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
227 }
228
229 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
230 /* Note: failing to find DllCanUnloadNow is not a failure */
231 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
232 if (!DllGetClassObject)
233 {
234 /* failure: the dll did not export DllGetClassObject */
235 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
236 FreeLibrary(hLibrary);
237 return CO_E_DLLNOTFOUND;
238 }
239
240 EnterCriticalSection( &csOpenDllList );
241
242 *ret = COMPOBJ_DllList_Get(library_name);
243 if (*ret)
244 {
245 /* another caller to this function already added the dll while we
246 * weren't in the critical section */
247 FreeLibrary(hLibrary);
248 }
249 else
250 {
251 len = strlenW(library_name);
252 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
253 if (entry)
254 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
255 if (entry && entry->library_name)
256 {
257 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
258 entry->library = hLibrary;
259 entry->refs = 1;
260 entry->DllCanUnloadNow = DllCanUnloadNow;
261 entry->DllGetClassObject = DllGetClassObject;
262 list_add_tail(&openDllList, &entry->entry);
263 }
264 else
265 {
266 HeapFree(GetProcessHeap(), 0, entry);
267 hr = E_OUTOFMEMORY;
268 FreeLibrary(hLibrary);
269 }
270 *ret = entry;
271 }
272
273 LeaveCriticalSection( &csOpenDllList );
274
275 return hr;
276 }
277
278 /* pass FALSE for free_entry to release a reference without destroying the
279 * entry if it reaches zero or TRUE otherwise */
280 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
281 {
282 if (!InterlockedDecrement(&entry->refs) && free_entry)
283 {
284 EnterCriticalSection(&csOpenDllList);
285 list_remove(&entry->entry);
286 LeaveCriticalSection(&csOpenDllList);
287
288 TRACE("freeing %p\n", entry->library);
289 FreeLibrary(entry->library);
290
291 HeapFree(GetProcessHeap(), 0, entry->library_name);
292 HeapFree(GetProcessHeap(), 0, entry);
293 }
294 }
295
296 /* frees memory associated with active dll list */
297 static void COMPOBJ_DllList_Free(void)
298 {
299 OpenDll *entry, *cursor2;
300 EnterCriticalSection(&csOpenDllList);
301 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
302 {
303 list_remove(&entry->entry);
304
305 HeapFree(GetProcessHeap(), 0, entry->library_name);
306 HeapFree(GetProcessHeap(), 0, entry);
307 }
308 LeaveCriticalSection(&csOpenDllList);
309 }
310
311 /******************************************************************************
312 * Manage apartments.
313 */
314
315 static DWORD apartment_addref(struct apartment *apt)
316 {
317 DWORD refs = InterlockedIncrement(&apt->refs);
318 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
319 return refs;
320 }
321
322 /* allocates memory and fills in the necessary fields for a new apartment
323 * object. must be called inside apartment cs */
324 static APARTMENT *apartment_construct(DWORD model)
325 {
326 APARTMENT *apt;
327
328 TRACE("creating new apartment, model=%d\n", model);
329
330 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
331 apt->tid = GetCurrentThreadId();
332
333 list_init(&apt->proxies);
334 list_init(&apt->stubmgrs);
335 list_init(&apt->psclsids);
336 list_init(&apt->loaded_dlls);
337 apt->ipidc = 0;
338 apt->refs = 1;
339 apt->remunk_exported = FALSE;
340 apt->oidc = 1;
341 InitializeCriticalSection(&apt->cs);
342 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
343
344 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
345
346 if (apt->multi_threaded)
347 {
348 /* FIXME: should be randomly generated by in an RPC call to rpcss */
349 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
350 }
351 else
352 {
353 /* FIXME: should be randomly generated by in an RPC call to rpcss */
354 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
355 }
356
357 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
358
359 list_add_head(&apts, &apt->entry);
360
361 return apt;
362 }
363
364 /* gets and existing apartment if one exists or otherwise creates an apartment
365 * structure which stores OLE apartment-local information and stores a pointer
366 * to it in the thread-local storage */
367 static APARTMENT *apartment_get_or_create(DWORD model)
368 {
369 APARTMENT *apt = COM_CurrentApt();
370
371 if (!apt)
372 {
373 if (model & COINIT_APARTMENTTHREADED)
374 {
375 EnterCriticalSection(&csApartment);
376
377 apt = apartment_construct(model);
378 if (!MainApartment)
379 {
380 MainApartment = apt;
381 apt->main = TRUE;
382 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
383 }
384
385 LeaveCriticalSection(&csApartment);
386
387 if (apt->main)
388 apartment_createwindowifneeded(apt);
389 }
390 else
391 {
392 EnterCriticalSection(&csApartment);
393
394 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
395 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
396 * in a process */
397 if (MTA)
398 {
399 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
400 apartment_addref(MTA);
401 }
402 else
403 MTA = apartment_construct(model);
404
405 apt = MTA;
406
407 LeaveCriticalSection(&csApartment);
408 }
409 COM_CurrentInfo()->apt = apt;
410 }
411
412 return apt;
413 }
414
415 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
416 {
417 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
418 }
419
420 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
421 {
422 list_remove(&curClass->entry);
423
424 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
425 RPC_StopLocalServer(curClass->RpcRegistration);
426
427 /*
428 * Release the reference to the class object.
429 */
430 IUnknown_Release(curClass->classObject);
431
432 if (curClass->pMarshaledData)
433 {
434 LARGE_INTEGER zero;
435 memset(&zero, 0, sizeof(zero));
436 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
437 CoReleaseMarshalData(curClass->pMarshaledData);
438 IStream_Release(curClass->pMarshaledData);
439 }
440
441 HeapFree(GetProcessHeap(), 0, curClass);
442 }
443
444 static void COM_RevokeAllClasses(const struct apartment *apt)
445 {
446 RegisteredClass *curClass, *cursor;
447
448 EnterCriticalSection( &csRegisteredClassList );
449
450 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
451 {
452 if (curClass->apartment_id == apt->oxid)
453 COM_RevokeRegisteredClassObject(curClass);
454 }
455
456 LeaveCriticalSection( &csRegisteredClassList );
457 }
458
459 /***********************************************************************
460 * CoRevokeClassObject [OLE32.@]
461 *
462 * Removes a class object from the class registry.
463 *
464 * PARAMS
465 * dwRegister [I] Cookie returned from CoRegisterClassObject().
466 *
467 * RETURNS
468 * Success: S_OK.
469 * Failure: HRESULT code.
470 *
471 * NOTES
472 * Must be called from the same apartment that called CoRegisterClassObject(),
473 * otherwise it will fail with RPC_E_WRONG_THREAD.
474 *
475 * SEE ALSO
476 * CoRegisterClassObject
477 */
478 HRESULT WINAPI CoRevokeClassObject(
479 DWORD dwRegister)
480 {
481 HRESULT hr = E_INVALIDARG;
482 RegisteredClass *curClass;
483 APARTMENT *apt;
484
485 TRACE("(%08x)\n",dwRegister);
486
487 apt = COM_CurrentApt();
488 if (!apt)
489 {
490 ERR("COM was not initialized\n");
491 return CO_E_NOTINITIALIZED;
492 }
493
494 EnterCriticalSection( &csRegisteredClassList );
495
496 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
497 {
498 /*
499 * Check if we have a match on the cookie.
500 */
501 if (curClass->dwCookie == dwRegister)
502 {
503 if (curClass->apartment_id == apt->oxid)
504 {
505 COM_RevokeRegisteredClassObject(curClass);
506 hr = S_OK;
507 }
508 else
509 {
510 ERR("called from wrong apartment, should be called from %s\n",
511 wine_dbgstr_longlong(curClass->apartment_id));
512 hr = RPC_E_WRONG_THREAD;
513 }
514 break;
515 }
516 }
517
518 LeaveCriticalSection( &csRegisteredClassList );
519
520 return hr;
521 }
522
523 /* frees unused libraries loaded by apartment_getclassobject by calling the
524 * DLL's DllCanUnloadNow entry point */
525 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
526 {
527 struct apartment_loaded_dll *entry, *next;
528 EnterCriticalSection(&apt->cs);
529 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
530 {
531 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
532 {
533 DWORD real_delay = delay;
534
535 if (real_delay == INFINITE)
536 {
537 /* DLLs that return multi-threaded objects aren't unloaded
538 * straight away to cope for programs that have races between
539 * last object destruction and threads in the DLLs that haven't
540 * finished, despite DllCanUnloadNow returning S_OK */
541 if (entry->multi_threaded)
542 real_delay = 10 * 60 * 1000; /* 10 minutes */
543 else
544 real_delay = 0;
545 }
546
547 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
548 {
549 list_remove(&entry->entry);
550 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
551 HeapFree(GetProcessHeap(), 0, entry);
552 }
553 else
554 entry->unload_time = GetTickCount() + real_delay;
555 }
556 else if (entry->unload_time)
557 entry->unload_time = 0;
558 }
559 LeaveCriticalSection(&apt->cs);
560 }
561
562 DWORD apartment_release(struct apartment *apt)
563 {
564 DWORD ret;
565
566 EnterCriticalSection(&csApartment);
567
568 ret = InterlockedDecrement(&apt->refs);
569 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
570 /* destruction stuff that needs to happen under csApartment CS */
571 if (ret == 0)
572 {
573 if (apt == MTA) MTA = NULL;
574 else if (apt == MainApartment) MainApartment = NULL;
575 list_remove(&apt->entry);
576 }
577
578 LeaveCriticalSection(&csApartment);
579
580 if (ret == 0)
581 {
582 struct list *cursor, *cursor2;
583
584 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
585
586 /* Release the references to the registered class objects */
587 COM_RevokeAllClasses(apt);
588
589 /* no locking is needed for this apartment, because no other thread
590 * can access it at this point */
591
592 apartment_disconnectproxies(apt);
593
594 if (apt->win) DestroyWindow(apt->win);
595 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
596
597 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
598 {
599 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
600 /* release the implicit reference given by the fact that the
601 * stub has external references (it must do since it is in the
602 * stub manager list in the apartment and all non-apartment users
603 * must have a ref on the apartment and so it cannot be destroyed).
604 */
605 stub_manager_int_release(stubmgr);
606 }
607
608 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
609 {
610 struct registered_psclsid *registered_psclsid =
611 LIST_ENTRY(cursor, struct registered_psclsid, entry);
612
613 list_remove(&registered_psclsid->entry);
614 HeapFree(GetProcessHeap(), 0, registered_psclsid);
615 }
616
617 /* if this assert fires, then another thread took a reference to a
618 * stub manager without taking a reference to the containing
619 * apartment, which it must do. */
620 assert(list_empty(&apt->stubmgrs));
621
622 if (apt->filter) IUnknown_Release(apt->filter);
623
624 /* free as many unused libraries as possible... */
625 apartment_freeunusedlibraries(apt, 0);
626
627 /* ... and free the memory for the apartment loaded dll entry and
628 * release the dll list reference without freeing the library for the
629 * rest */
630 while ((cursor = list_head(&apt->loaded_dlls)))
631 {
632 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
633 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
634 list_remove(cursor);
635 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
636 }
637
638 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
639 DeleteCriticalSection(&apt->cs);
640
641 HeapFree(GetProcessHeap(), 0, apt);
642 }
643
644 return ret;
645 }
646
647 /* The given OXID must be local to this process:
648 *
649 * The ref parameter is here mostly to ensure people remember that
650 * they get one, you should normally take a ref for thread safety.
651 */
652 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
653 {
654 APARTMENT *result = NULL;
655 struct list *cursor;
656
657 EnterCriticalSection(&csApartment);
658 LIST_FOR_EACH( cursor, &apts )
659 {
660 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
661 if (apt->oxid == oxid)
662 {
663 result = apt;
664 if (ref) apartment_addref(result);
665 break;
666 }
667 }
668 LeaveCriticalSection(&csApartment);
669
670 return result;
671 }
672
673 /* gets the apartment which has a given creator thread ID. The caller must
674 * release the reference from the apartment as soon as the apartment pointer
675 * is no longer required. */
676 APARTMENT *apartment_findfromtid(DWORD tid)
677 {
678 APARTMENT *result = NULL;
679 struct list *cursor;
680
681 EnterCriticalSection(&csApartment);
682 LIST_FOR_EACH( cursor, &apts )
683 {
684 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
685 if (apt->tid == tid)
686 {
687 result = apt;
688 apartment_addref(result);
689 break;
690 }
691 }
692 LeaveCriticalSection(&csApartment);
693
694 return result;
695 }
696
697 /* gets the main apartment if it exists. The caller must
698 * release the reference from the apartment as soon as the apartment pointer
699 * is no longer required. */
700 static APARTMENT *apartment_findmain(void)
701 {
702 APARTMENT *result;
703
704 EnterCriticalSection(&csApartment);
705
706 result = MainApartment;
707 if (result) apartment_addref(result);
708
709 LeaveCriticalSection(&csApartment);
710
711 return result;
712 }
713
714 /* gets the multi-threaded apartment if it exists. The caller must
715 * release the reference from the apartment as soon as the apartment pointer
716 * is no longer required. */
717 static APARTMENT *apartment_find_multi_threaded(void)
718 {
719 APARTMENT *result = NULL;
720 struct list *cursor;
721
722 EnterCriticalSection(&csApartment);
723
724 LIST_FOR_EACH( cursor, &apts )
725 {
726 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
727 if (apt->multi_threaded)
728 {
729 result = apt;
730 apartment_addref(result);
731 break;
732 }
733 }
734
735 LeaveCriticalSection(&csApartment);
736 return result;
737 }
738
739 /* gets the specified class object by loading the appropriate DLL, if
740 * necessary and calls the DllGetClassObject function for the DLL */
741 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
742 BOOL apartment_threaded,
743 REFCLSID rclsid, REFIID riid, void **ppv)
744 {
745 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
746 HRESULT hr = S_OK;
747 BOOL found = FALSE;
748 struct apartment_loaded_dll *apartment_loaded_dll;
749
750 if (!strcmpiW(dllpath, wszOle32))
751 {
752 /* we don't need to control the lifetime of this dll, so use the local
753 * implementation of DllGetClassObject directly */
754 TRACE("calling ole32!DllGetClassObject\n");
755 hr = DllGetClassObject(rclsid, riid, ppv);
756
757 if (hr != S_OK)
758 ERR("DllGetClassObject returned error 0x%08x\n", hr);
759
760 return hr;
761 }
762
763 EnterCriticalSection(&apt->cs);
764
765 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
766 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
767 {
768 TRACE("found %s already loaded\n", debugstr_w(dllpath));
769 found = TRUE;
770 break;
771 }
772
773 if (!found)
774 {
775 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
776 if (!apartment_loaded_dll)
777 hr = E_OUTOFMEMORY;
778 if (SUCCEEDED(hr))
779 {
780 apartment_loaded_dll->unload_time = 0;
781 apartment_loaded_dll->multi_threaded = FALSE;
782 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
783 if (FAILED(hr))
784 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
785 }
786 if (SUCCEEDED(hr))
787 {
788 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
789 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
790 }
791 }
792
793 LeaveCriticalSection(&apt->cs);
794
795 if (SUCCEEDED(hr))
796 {
797 /* one component being multi-threaded overrides any number of
798 * apartment-threaded components */
799 if (!apartment_threaded)
800 apartment_loaded_dll->multi_threaded = TRUE;
801
802 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
803 /* OK: get the ClassObject */
804 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
805
806 if (hr != S_OK)
807 ERR("DllGetClassObject returned error 0x%08x\n", hr);
808 }
809
810 return hr;
811 }
812
813 /***********************************************************************
814 * COM_RegReadPath [internal]
815 *
816 * Reads a registry value and expands it when necessary
817 */
818 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
819 {
820 DWORD ret;
821 HKEY key;
822 DWORD keytype;
823 WCHAR src[MAX_PATH];
824 DWORD dwLength = dstlen * sizeof(WCHAR);
825
826 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
827 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
828 if (keytype == REG_EXPAND_SZ) {
829 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
830 } else {
831 lstrcpynW(dst, src, dstlen);
832 }
833 }
834 RegCloseKey (key);
835 }
836 return ret;
837 }
838
839 struct host_object_params
840 {
841 HKEY hkeydll;
842 CLSID clsid; /* clsid of object to marshal */
843 IID iid; /* interface to marshal */
844 HANDLE event; /* event signalling when ready for multi-threaded case */
845 HRESULT hr; /* result for multi-threaded case */
846 IStream *stream; /* stream that the object will be marshaled into */
847 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
848 };
849
850 static HRESULT apartment_hostobject(struct apartment *apt,
851 const struct host_object_params *params)
852 {
853 IUnknown *object;
854 HRESULT hr;
855 static const LARGE_INTEGER llZero;
856 WCHAR dllpath[MAX_PATH+1];
857
858 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
859
860 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
861 {
862 /* failure: CLSID is not found in registry */
863 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
864 return REGDB_E_CLASSNOTREG;
865 }
866
867 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
868 &params->clsid, &params->iid, (void **)&object);
869 if (FAILED(hr))
870 return hr;
871
872 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
873 if (FAILED(hr))
874 IUnknown_Release(object);
875 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
876
877 return hr;
878 }
879
880 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
881 {
882 switch (msg)
883 {
884 case DM_EXECUTERPC:
885 RPC_ExecuteCall((struct dispatch_params *)lParam);
886 return 0;
887 case DM_HOSTOBJECT:
888 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
889 default:
890 return DefWindowProcW(hWnd, msg, wParam, lParam);
891 }
892 }
893
894 struct host_thread_params
895 {
896 COINIT threading_model;
897 HANDLE ready_event;
898 HWND apartment_hwnd;
899 };
900
901 /* thread for hosting an object to allow an object to appear to be created in
902 * an apartment with an incompatible threading model */
903 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
904 {
905 struct host_thread_params *params = p;
906 MSG msg;
907 HRESULT hr;
908 struct apartment *apt;
909
910 TRACE("\n");
911
912 hr = CoInitializeEx(NULL, params->threading_model);
913 if (FAILED(hr)) return hr;
914
915 apt = COM_CurrentApt();
916 if (params->threading_model == COINIT_APARTMENTTHREADED)
917 {
918 apartment_createwindowifneeded(apt);
919 params->apartment_hwnd = apartment_getwindow(apt);
920 }
921 else
922 params->apartment_hwnd = NULL;
923
924 /* force the message queue to be created before signaling parent thread */
925 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
926
927 SetEvent(params->ready_event);
928 params = NULL; /* can't touch params after here as it may be invalid */
929
930 while (GetMessageW(&msg, NULL, 0, 0))
931 {
932 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
933 {
934 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
935 obj_params->hr = apartment_hostobject(apt, obj_params);
936 SetEvent(obj_params->event);
937 }
938 else
939 {
940 TranslateMessage(&msg);
941 DispatchMessageW(&msg);
942 }
943 }
944
945 TRACE("exiting\n");
946
947 CoUninitialize();
948
949 return S_OK;
950 }
951
952 /* finds or creates a host apartment, creates the object inside it and returns
953 * a proxy to it so that the object can be used in the apartment of the
954 * caller of this function */
955 static HRESULT apartment_hostobject_in_hostapt(
956 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
957 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
958 {
959 struct host_object_params params;
960 HWND apartment_hwnd = NULL;
961 DWORD apartment_tid = 0;
962 HRESULT hr;
963
964 if (!multi_threaded && main_apartment)
965 {
966 APARTMENT *host_apt = apartment_findmain();
967 if (host_apt)
968 {
969 apartment_hwnd = apartment_getwindow(host_apt);
970 apartment_release(host_apt);
971 }
972 }
973
974 if (!apartment_hwnd)
975 {
976 EnterCriticalSection(&apt->cs);
977
978 if (!apt->host_apt_tid)
979 {
980 struct host_thread_params thread_params;
981 HANDLE handles[2];
982 DWORD wait_value;
983
984 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
985 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
986 thread_params.apartment_hwnd = NULL;
987 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
988 if (!handles[1])
989 {
990 CloseHandle(handles[0]);
991 LeaveCriticalSection(&apt->cs);
992 return E_OUTOFMEMORY;
993 }
994 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
995 CloseHandle(handles[0]);
996 CloseHandle(handles[1]);
997 if (wait_value == WAIT_OBJECT_0)
998 apt->host_apt_hwnd = thread_params.apartment_hwnd;
999 else
1000 {
1001 LeaveCriticalSection(&apt->cs);
1002 return E_OUTOFMEMORY;
1003 }
1004 }
1005
1006 if (multi_threaded || !main_apartment)
1007 {
1008 apartment_hwnd = apt->host_apt_hwnd;
1009 apartment_tid = apt->host_apt_tid;
1010 }
1011
1012 LeaveCriticalSection(&apt->cs);
1013 }
1014
1015 /* another thread may have become the main apartment in the time it took
1016 * us to create the thread for the host apartment */
1017 if (!apartment_hwnd && !multi_threaded && main_apartment)
1018 {
1019 APARTMENT *host_apt = apartment_findmain();
1020 if (host_apt)
1021 {
1022 apartment_hwnd = apartment_getwindow(host_apt);
1023 apartment_release(host_apt);
1024 }
1025 }
1026
1027 params.hkeydll = hkeydll;
1028 params.clsid = *rclsid;
1029 params.iid = *riid;
1030 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1031 if (FAILED(hr))
1032 return hr;
1033 params.apartment_threaded = !multi_threaded;
1034 if (multi_threaded)
1035 {
1036 params.hr = S_OK;
1037 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1038 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1039 hr = E_OUTOFMEMORY;
1040 else
1041 {
1042 WaitForSingleObject(params.event, INFINITE);
1043 hr = params.hr;
1044 }
1045 CloseHandle(params.event);
1046 }
1047 else
1048 {
1049 if (!apartment_hwnd)
1050 {
1051 ERR("host apartment didn't create window\n");
1052 hr = E_OUTOFMEMORY;
1053 }
1054 else
1055 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1056 }
1057 if (SUCCEEDED(hr))
1058 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1059 IStream_Release(params.stream);
1060 return hr;
1061 }
1062
1063 /* create a window for the apartment or return the current one if one has
1064 * already been created */
1065 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1066 {
1067 if (apt->multi_threaded)
1068 return S_OK;
1069
1070 if (!apt->win)
1071 {
1072 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1073 0, 0, 0, 0,
1074 HWND_MESSAGE, 0, hProxyDll, NULL);
1075 if (!hwnd)
1076 {
1077 ERR("CreateWindow failed with error %d\n", GetLastError());
1078 return HRESULT_FROM_WIN32(GetLastError());
1079 }
1080 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1081 /* someone beat us to it */
1082 DestroyWindow(hwnd);
1083 }
1084
1085 return S_OK;
1086 }
1087
1088 /* retrieves the window for the main- or apartment-threaded apartment */
1089 HWND apartment_getwindow(const struct apartment *apt)
1090 {
1091 assert(!apt->multi_threaded);
1092 return apt->win;
1093 }
1094
1095 void apartment_joinmta(void)
1096 {
1097 apartment_addref(MTA);
1098 COM_CurrentInfo()->apt = MTA;
1099 }
1100
1101 static void COMPOBJ_InitProcess( void )
1102 {
1103 WNDCLASSW wclass;
1104
1105 /* Dispatching to the correct thread in an apartment is done through
1106 * window messages rather than RPC transports. When an interface is
1107 * marshalled into another apartment in the same process, a window of the
1108 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1109 * application) is responsible for pumping the message loop in that thread.
1110 * The WM_USER messages which point to the RPCs are then dispatched to
1111 * apartment_wndproc by the user's code from the apartment in which the
1112 * interface was unmarshalled.
1113 */
1114 memset(&wclass, 0, sizeof(wclass));
1115 wclass.lpfnWndProc = apartment_wndproc;
1116 wclass.hInstance = hProxyDll;
1117 wclass.lpszClassName = wszAptWinClass;
1118 RegisterClassW(&wclass);
1119 }
1120
1121 static void COMPOBJ_UninitProcess( void )
1122 {
1123 UnregisterClassW(wszAptWinClass, hProxyDll);
1124 }
1125
1126 static void COM_TlsDestroy(void)
1127 {
1128 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1129 if (info)
1130 {
1131 if (info->apt) apartment_release(info->apt);
1132 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1133 if (info->state) IUnknown_Release(info->state);
1134 if (info->spy) IUnknown_Release(info->spy);
1135 if (info->context_token) IObjContext_Release(info->context_token);
1136 HeapFree(GetProcessHeap(), 0, info);
1137 NtCurrentTeb()->ReservedForOle = NULL;
1138 }
1139 }
1140
1141 /******************************************************************************
1142 * CoBuildVersion [OLE32.@]
1143 *
1144 * Gets the build version of the DLL.
1145 *
1146 * PARAMS
1147 *
1148 * RETURNS
1149 * Current build version, hiword is majornumber, loword is minornumber
1150 */
1151 DWORD WINAPI CoBuildVersion(void)
1152 {
1153 TRACE("Returning version %d, build %d.\n", rmm, rup);
1154 return (rmm<<16)+rup;
1155 }
1156
1157 /******************************************************************************
1158 * CoRegisterInitializeSpy [OLE32.@]
1159 *
1160 * Add a Spy that watches CoInitializeEx calls
1161 *
1162 * PARAMS
1163 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1164 * cookie [II] cookie receiver
1165 *
1166 * RETURNS
1167 * Success: S_OK if not already initialized, S_FALSE otherwise.
1168 * Failure: HRESULT code.
1169 *
1170 * SEE ALSO
1171 * CoInitializeEx
1172 */
1173 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1174 {
1175 struct oletls *info = COM_CurrentInfo();
1176 HRESULT hr;
1177
1178 TRACE("(%p, %p)\n", spy, cookie);
1179
1180 if (!spy || !cookie || !info)
1181 {
1182 if (!info)
1183 WARN("Could not allocate tls\n");
1184 return E_INVALIDARG;
1185 }
1186
1187 if (info->spy)
1188 {
1189 FIXME("Already registered?\n");
1190 return E_UNEXPECTED;
1191 }
1192
1193 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1194 if (SUCCEEDED(hr))
1195 {
1196 cookie->QuadPart = (DWORD_PTR)spy;
1197 return S_OK;
1198 }
1199 return hr;
1200 }
1201
1202 /******************************************************************************
1203 * CoRevokeInitializeSpy [OLE32.@]
1204 *
1205 * Remove a spy that previously watched CoInitializeEx calls
1206 *
1207 * PARAMS
1208 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1209 *
1210 * RETURNS
1211 * Success: S_OK if a spy is removed
1212 * Failure: E_INVALIDARG
1213 *
1214 * SEE ALSO
1215 * CoInitializeEx
1216 */
1217 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1218 {
1219 struct oletls *info = COM_CurrentInfo();
1220 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1221
1222 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1223 return E_INVALIDARG;
1224
1225 IUnknown_Release(info->spy);
1226 info->spy = NULL;
1227 return S_OK;
1228 }
1229
1230
1231 /******************************************************************************
1232 * CoInitialize [OLE32.@]
1233 *
1234 * Initializes the COM libraries by calling CoInitializeEx with
1235 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1236 *
1237 * PARAMS
1238 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1239 *
1240 * RETURNS
1241 * Success: S_OK if not already initialized, S_FALSE otherwise.
1242 * Failure: HRESULT code.
1243 *
1244 * SEE ALSO
1245 * CoInitializeEx
1246 */
1247 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1248 {
1249 /*
1250 * Just delegate to the newer method.
1251 */
1252 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1253 }
1254
1255 /******************************************************************************
1256 * CoInitializeEx [OLE32.@]
1257 *
1258 * Initializes the COM libraries.
1259 *
1260 * PARAMS
1261 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1262 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1263 *
1264 * RETURNS
1265 * S_OK if successful,
1266 * S_FALSE if this function was called already.
1267 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1268 * threading model.
1269 *
1270 * NOTES
1271 *
1272 * The behavior used to set the IMalloc used for memory management is
1273 * obsolete.
1274 * The dwCoInit parameter must specify one of the following apartment
1275 * threading models:
1276 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1277 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1278 * The parameter may also specify zero or more of the following flags:
1279 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1280 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1281 *
1282 * SEE ALSO
1283 * CoUninitialize
1284 */
1285 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1286 {
1287 struct oletls *info = COM_CurrentInfo();
1288 HRESULT hr = S_OK;
1289 APARTMENT *apt;
1290
1291 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1292
1293 if (lpReserved!=NULL)
1294 {
1295 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1296 }
1297
1298 /*
1299 * Check the lock count. If this is the first time going through the initialize
1300 * process, we have to initialize the libraries.
1301 *
1302 * And crank-up that lock count.
1303 */
1304 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1305 {
1306 /*
1307 * Initialize the various COM libraries and data structures.
1308 */
1309 TRACE("() - Initializing the COM libraries\n");
1310
1311 /* we may need to defer this until after apartment initialisation */
1312 RunningObjectTableImpl_Initialize();
1313 }
1314
1315 if (info->spy)
1316 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1317
1318 if (!(apt = info->apt))
1319 {
1320 apt = apartment_get_or_create(dwCoInit);
1321 if (!apt) return E_OUTOFMEMORY;
1322 }
1323 else if (!apartment_is_model(apt, dwCoInit))
1324 {
1325 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1326 code then we are probably using the wrong threading model to implement that API. */
1327 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1328 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1329 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1330 return RPC_E_CHANGED_MODE;
1331 }
1332 else
1333 hr = S_FALSE;
1334
1335 info->inits++;
1336
1337 if (info->spy)
1338 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1339
1340 return hr;
1341 }
1342
1343 /***********************************************************************
1344 * CoUninitialize [OLE32.@]
1345 *
1346 * This method will decrement the refcount on the current apartment, freeing
1347 * the resources associated with it if it is the last thread in the apartment.
1348 * If the last apartment is freed, the function will additionally release
1349 * any COM resources associated with the process.
1350 *
1351 * PARAMS
1352 *
1353 * RETURNS
1354 * Nothing.
1355 *
1356 * SEE ALSO
1357 * CoInitializeEx
1358 */
1359 void WINAPI CoUninitialize(void)
1360 {
1361 struct oletls * info = COM_CurrentInfo();
1362 LONG lCOMRefCnt;
1363
1364 TRACE("()\n");
1365
1366 /* will only happen on OOM */
1367 if (!info) return;
1368
1369 if (info->spy)
1370 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1371
1372 /* sanity check */
1373 if (!info->inits)
1374 {
1375 ERR("Mismatched CoUninitialize\n");
1376
1377 if (info->spy)
1378 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1379 return;
1380 }
1381
1382 if (!--info->inits)
1383 {
1384 apartment_release(info->apt);
1385 info->apt = NULL;
1386 }
1387
1388 /*
1389 * Decrease the reference count.
1390 * If we are back to 0 locks on the COM library, make sure we free
1391 * all the associated data structures.
1392 */
1393 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1394 if (lCOMRefCnt==1)
1395 {
1396 TRACE("() - Releasing the COM libraries\n");
1397
1398 RunningObjectTableImpl_UnInitialize();
1399 }
1400 else if (lCOMRefCnt<1) {
1401 ERR( "CoUninitialize() - not CoInitialized.\n" );
1402 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1403 }
1404 if (info->spy)
1405 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1406 }
1407
1408 /******************************************************************************
1409 * CoDisconnectObject [OLE32.@]
1410 *
1411 * Disconnects all connections to this object from remote processes. Dispatches
1412 * pending RPCs while blocking new RPCs from occurring, and then calls
1413 * IMarshal::DisconnectObject on the given object.
1414 *
1415 * Typically called when the object server is forced to shut down, for instance by
1416 * the user.
1417 *
1418 * PARAMS
1419 * lpUnk [I] The object whose stub should be disconnected.
1420 * reserved [I] Reserved. Should be set to 0.
1421 *
1422 * RETURNS
1423 * Success: S_OK.
1424 * Failure: HRESULT code.
1425 *
1426 * SEE ALSO
1427 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1428 */
1429 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1430 {
1431 HRESULT hr;
1432 IMarshal *marshal;
1433 APARTMENT *apt;
1434
1435 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1436
1437 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1438 if (hr == S_OK)
1439 {
1440 hr = IMarshal_DisconnectObject(marshal, reserved);
1441 IMarshal_Release(marshal);
1442 return hr;
1443 }
1444
1445 apt = COM_CurrentApt();
1446 if (!apt)
1447 return CO_E_NOTINITIALIZED;
1448
1449 apartment_disconnectobject(apt, lpUnk);
1450
1451 /* Note: native is pretty broken here because it just silently
1452 * fails, without returning an appropriate error code if the object was
1453 * not found, making apps think that the object was disconnected, when
1454 * it actually wasn't */
1455
1456 return S_OK;
1457 }
1458
1459 /******************************************************************************
1460 * CoCreateGuid [OLE32.@]
1461 *
1462 * Simply forwards to UuidCreate in RPCRT4.
1463 *
1464 * PARAMS
1465 * pguid [O] Points to the GUID to initialize.
1466 *
1467 * RETURNS
1468 * Success: S_OK.
1469 * Failure: HRESULT code.
1470 *
1471 * SEE ALSO
1472 * UuidCreate
1473 */
1474 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1475 {
1476 DWORD status = UuidCreate(pguid);
1477 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1478 return HRESULT_FROM_WIN32( status );
1479 }
1480
1481 /******************************************************************************
1482 * CLSIDFromString [OLE32.@]
1483 * IIDFromString [OLE32.@]
1484 *
1485 * Converts a unique identifier from its string representation into
1486 * the GUID struct.
1487 *
1488 * PARAMS
1489 * idstr [I] The string representation of the GUID.
1490 * id [O] GUID converted from the string.
1491 *
1492 * RETURNS
1493 * S_OK on success
1494 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1495 *
1496 * SEE ALSO
1497 * StringFromCLSID
1498 */
1499 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1500 {
1501 int i;
1502 BYTE table[256];
1503
1504 if (!s) {
1505 memset( id, 0, sizeof (CLSID) );
1506 return S_OK;
1507 }
1508
1509 /* validate the CLSID string */
1510 if (strlenW(s) != 38)
1511 return CO_E_CLASSSTRING;
1512
1513 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1514 return CO_E_CLASSSTRING;
1515
1516 for (i=1; i<37; i++) {
1517 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1518 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1519 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1520 ((s[i] >= 'A') && (s[i] <= 'F'))))
1521 return CO_E_CLASSSTRING;
1522 }
1523
1524 TRACE("%s -> %p\n", debugstr_w(s), id);
1525
1526 /* quick lookup table */
1527 memset(table, 0, 256);
1528
1529 for (i = 0; i < 10; i++) {
1530 table['0' + i] = i;
1531 }
1532 for (i = 0; i < 6; i++) {
1533 table['A' + i] = i+10;
1534 table['a' + i] = i+10;
1535 }
1536
1537 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1538
1539 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1540 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1541 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1542 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1543
1544 /* these are just sequential bytes */
1545 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1546 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1547 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1548 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1549 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1550 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1551 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1552 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1553
1554 return S_OK;
1555 }
1556
1557 /*****************************************************************************/
1558
1559 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1560 {
1561 HRESULT ret;
1562
1563 if (!id)
1564 return E_INVALIDARG;
1565
1566 ret = __CLSIDFromString(idstr, id);
1567 if(ret != S_OK) { /* It appears a ProgID is also valid */
1568 ret = CLSIDFromProgID(idstr, id);
1569 }
1570 return ret;
1571 }
1572
1573
1574 /******************************************************************************
1575 * StringFromCLSID [OLE32.@]
1576 * StringFromIID [OLE32.@]
1577 *
1578 * Converts a GUID into the respective string representation.
1579 * The target string is allocated using the OLE IMalloc.
1580 *
1581 * PARAMS
1582 * id [I] the GUID to be converted.
1583 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1584 *
1585 * RETURNS
1586 * S_OK
1587 * E_FAIL
1588 *
1589 * SEE ALSO
1590 * StringFromGUID2, CLSIDFromString
1591 */
1592 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1593 {
1594 HRESULT ret;
1595 LPMALLOC mllc;
1596
1597 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1598 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1599 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1600 return S_OK;
1601 }
1602
1603 /******************************************************************************
1604 * StringFromGUID2 [OLE32.@]
1605 *
1606 * Modified version of StringFromCLSID that allows you to specify max
1607 * buffer size.
1608 *
1609 * PARAMS
1610 * id [I] GUID to convert to string.
1611 * str [O] Buffer where the result will be stored.
1612 * cmax [I] Size of the buffer in characters.
1613 *
1614 * RETURNS
1615 * Success: The length of the resulting string in characters.
1616 * Failure: 0.
1617 */
1618 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1619 {
1620 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1621 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1622 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1623 '%','0','2','X','%','0','2','X','}',0 };
1624 if (cmax < CHARS_IN_GUID) return 0;
1625 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1626 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1627 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1628 return CHARS_IN_GUID;
1629 }
1630
1631 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1632 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1633 {
1634 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1635 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1636 LONG res;
1637 HKEY key;
1638
1639 strcpyW(path, wszCLSIDSlash);
1640 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1641 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1642 if (res == ERROR_FILE_NOT_FOUND)
1643 return REGDB_E_CLASSNOTREG;
1644 else if (res != ERROR_SUCCESS)
1645 return REGDB_E_READREGDB;
1646
1647 if (!keyname)
1648 {
1649 *subkey = key;
1650 return S_OK;
1651 }
1652
1653 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1654 RegCloseKey(key);
1655 if (res == ERROR_FILE_NOT_FOUND)
1656 return REGDB_E_KEYMISSING;
1657 else if (res != ERROR_SUCCESS)
1658 return REGDB_E_READREGDB;
1659
1660 return S_OK;
1661 }
1662
1663 /* open HKCR\\AppId\\{string form of appid clsid} key */
1664 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1665 {
1666 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1667 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1668 DWORD res;
1669 WCHAR buf[CHARS_IN_GUID];
1670 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1671 DWORD size;
1672 HKEY hkey;
1673 DWORD type;
1674 HRESULT hr;
1675
1676 /* read the AppID value under the class's key */
1677 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1678 if (FAILED(hr))
1679 return hr;
1680
1681 size = sizeof(buf);
1682 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1683 RegCloseKey(hkey);
1684 if (res == ERROR_FILE_NOT_FOUND)
1685 return REGDB_E_KEYMISSING;
1686 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1687 return REGDB_E_READREGDB;
1688
1689 strcpyW(keyname, szAppIdKey);
1690 strcatW(keyname, buf);
1691 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1692 if (res == ERROR_FILE_NOT_FOUND)
1693 return REGDB_E_KEYMISSING;
1694 else if (res != ERROR_SUCCESS)
1695 return REGDB_E_READREGDB;
1696
1697 return S_OK;
1698 }
1699
1700 /******************************************************************************
1701 * ProgIDFromCLSID [OLE32.@]
1702 *
1703 * Converts a class id into the respective program ID.
1704 *
1705 * PARAMS
1706 * clsid [I] Class ID, as found in registry.
1707 * ppszProgID [O] Associated ProgID.
1708 *
1709 * RETURNS
1710 * S_OK
1711 * E_OUTOFMEMORY
1712 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1713 */
1714 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1715 {
1716 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1717 HKEY hkey;
1718 HRESULT ret;
1719 LONG progidlen = 0;
1720
1721 if (!ppszProgID)
1722 {
1723 ERR("ppszProgId isn't optional\n");
1724 return E_INVALIDARG;
1725 }
1726
1727 *ppszProgID = NULL;
1728 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1729 if (FAILED(ret))
1730 return ret;
1731
1732 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1733 ret = REGDB_E_CLASSNOTREG;
1734
1735 if (ret == S_OK)
1736 {
1737 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1738 if (*ppszProgID)
1739 {
1740 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1741 ret = REGDB_E_CLASSNOTREG;
1742 }
1743 else
1744 ret = E_OUTOFMEMORY;
1745 }
1746
1747 RegCloseKey(hkey);
1748 return ret;
1749 }
1750
1751 /******************************************************************************
1752 * CLSIDFromProgID [OLE32.@]
1753 *
1754 * Converts a program id into the respective GUID.
1755 *
1756 * PARAMS
1757 * progid [I] Unicode program ID, as found in registry.
1758 * clsid [O] Associated CLSID.
1759 *
1760 * RETURNS
1761 * Success: S_OK
1762 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1763 */
1764 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1765 {
1766 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1767 WCHAR buf2[CHARS_IN_GUID];
1768 LONG buf2len = sizeof(buf2);
1769 HKEY xhkey;
1770 WCHAR *buf;
1771
1772 if (!progid || !clsid)
1773 {
1774 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1775 return E_INVALIDARG;
1776 }
1777
1778 /* initialise clsid in case of failure */
1779 memset(clsid, 0, sizeof(*clsid));
1780
1781 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1782 strcpyW( buf, progid );
1783 strcatW( buf, clsidW );
1784 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1785 {
1786 HeapFree(GetProcessHeap(),0,buf);
1787 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1788 return CO_E_CLASSSTRING;
1789 }
1790 HeapFree(GetProcessHeap(),0,buf);
1791
1792 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1793 {
1794 RegCloseKey(xhkey);
1795 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1796 return CO_E_CLASSSTRING;
1797 }
1798 RegCloseKey(xhkey);
1799 return __CLSIDFromString(buf2,clsid);
1800 }
1801
1802
1803 /*****************************************************************************
1804 * CoGetPSClsid [OLE32.@]
1805 *
1806 * Retrieves the CLSID of the proxy/stub factory that implements
1807 * IPSFactoryBuffer for the specified interface.
1808 *
1809 * PARAMS
1810 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1811 * pclsid [O] Where to store returned proxy/stub CLSID.
1812 *
1813 * RETURNS
1814 * S_OK
1815 * E_OUTOFMEMORY
1816 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1817 *
1818 * NOTES
1819 *
1820 * The standard marshaller activates the object with the CLSID
1821 * returned and uses the CreateProxy and CreateStub methods on its
1822 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1823 * given object.
1824 *
1825 * CoGetPSClsid determines this CLSID by searching the
1826 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1827 * in the registry and any interface id registered by
1828 * CoRegisterPSClsid within the current process.
1829 *
1830 * BUGS
1831 *
1832 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1833 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1834 * considered a bug in native unless an application depends on this (unlikely).
1835 *
1836 * SEE ALSO
1837 * CoRegisterPSClsid.
1838 */
1839 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1840 {
1841 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1842 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1843 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1844 WCHAR value[CHARS_IN_GUID];
1845 LONG len;
1846 HKEY hkey;
1847 APARTMENT *apt = COM_CurrentApt();
1848 struct registered_psclsid *registered_psclsid;
1849
1850 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1851
1852 if (!apt)
1853 {
1854 ERR("apartment not initialised\n");
1855 return CO_E_NOTINITIALIZED;
1856 }
1857
1858 if (!pclsid)
1859 {
1860 ERR("pclsid isn't optional\n");
1861 return E_INVALIDARG;
1862 }
1863
1864 EnterCriticalSection(&apt->cs);
1865
1866 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1867 if (IsEqualIID(&registered_psclsid->iid, riid))
1868 {
1869 *pclsid = registered_psclsid->clsid;
1870 LeaveCriticalSection(&apt->cs);
1871 return S_OK;
1872 }
1873
1874 LeaveCriticalSection(&apt->cs);
1875
1876 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1877 strcpyW(path, wszInterface);
1878 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1879 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1880
1881 /* Open the key.. */
1882 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1883 {
1884 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1885 return REGDB_E_IIDNOTREG;
1886 }
1887
1888 /* ... Once we have the key, query the registry to get the
1889 value of CLSID as a string, and convert it into a
1890 proper CLSID structure to be passed back to the app */
1891 len = sizeof(value);
1892 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1893 {
1894 RegCloseKey(hkey);
1895 return REGDB_E_IIDNOTREG;
1896 }
1897 RegCloseKey(hkey);
1898
1899 /* We have the CLSID we want back from the registry as a string, so
1900 let's convert it into a CLSID structure */
1901 if (CLSIDFromString(value, pclsid) != NOERROR)
1902 return REGDB_E_IIDNOTREG;
1903
1904 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1905 return S_OK;
1906 }
1907
1908 /*****************************************************************************
1909 * CoRegisterPSClsid [OLE32.@]
1910 *
1911 * Register a proxy/stub CLSID for the given interface in the current process
1912 * only.
1913 *
1914 * PARAMS
1915 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1916 * rclsid [I] CLSID of the proxy/stub.
1917 *
1918 * RETURNS
1919 * Success: S_OK
1920 * Failure: E_OUTOFMEMORY
1921 *
1922 * NOTES
1923 *
1924 * This function does not add anything to the registry and the effects are
1925 * limited to the lifetime of the current process.
1926 *
1927 * SEE ALSO
1928 * CoGetPSClsid.
1929 */
1930 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1931 {
1932 APARTMENT *apt = COM_CurrentApt();
1933 struct registered_psclsid *registered_psclsid;
1934
1935 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1936
1937 if (!apt)
1938 {
1939 ERR("apartment not initialised\n");
1940 return CO_E_NOTINITIALIZED;
1941 }
1942
1943 EnterCriticalSection(&apt->cs);
1944
1945 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1946 if (IsEqualIID(&registered_psclsid->iid, riid))
1947 {
1948 registered_psclsid->clsid = *rclsid;
1949 LeaveCriticalSection(&apt->cs);
1950 return S_OK;
1951 }
1952
1953 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1954 if (!registered_psclsid)
1955 {
1956 LeaveCriticalSection(&apt->cs);
1957 return E_OUTOFMEMORY;
1958 }
1959
1960 registered_psclsid->iid = *riid;
1961 registered_psclsid->clsid = *rclsid;
1962 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1963
1964 LeaveCriticalSection(&apt->cs);
1965
1966 return S_OK;
1967 }
1968
1969
1970 /***
1971 * COM_GetRegisteredClassObject
1972 *
1973 * This internal method is used to scan the registered class list to
1974 * find a class object.
1975 *
1976 * Params:
1977 * rclsid Class ID of the class to find.
1978 * dwClsContext Class context to match.
1979 * ppv [out] returns a pointer to the class object. Complying
1980 * to normal COM usage, this method will increase the
1981 * reference count on this object.
1982 */
1983 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1984 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1985 {
1986 HRESULT hr = S_FALSE;
1987 RegisteredClass *curClass;
1988
1989 EnterCriticalSection( &csRegisteredClassList );
1990
1991 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1992 {
1993 /*
1994 * Check if we have a match on the class ID and context.
1995 */
1996 if ((apt->oxid == curClass->apartment_id) &&
1997 (dwClsContext & curClass->runContext) &&
1998 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1999 {
2000 /*
2001 * We have a match, return the pointer to the class object.
2002 */
2003 *ppUnk = curClass->classObject;
2004
2005 IUnknown_AddRef(curClass->classObject);
2006
2007 hr = S_OK;
2008 break;
2009 }
2010 }
2011
2012 LeaveCriticalSection( &csRegisteredClassList );
2013
2014 return hr;
2015 }
2016
2017 /******************************************************************************
2018 * CoRegisterClassObject [OLE32.@]
2019 *
2020 * Registers the class object for a given class ID. Servers housed in EXE
2021 * files use this method instead of exporting DllGetClassObject to allow
2022 * other code to connect to their objects.
2023 *
2024 * PARAMS
2025 * rclsid [I] CLSID of the object to register.
2026 * pUnk [I] IUnknown of the object.
2027 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2028 * flags [I] REGCLS flags indicating how connections are made.
2029 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2030 *
2031 * RETURNS
2032 * S_OK on success,
2033 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2034 * CO_E_OBJISREG if the object is already registered. We should not return this.
2035 *
2036 * SEE ALSO
2037 * CoRevokeClassObject, CoGetClassObject
2038 *
2039 * NOTES
2040 * In-process objects are only registered for the current apartment.
2041 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2042 * in other apartments.
2043 *
2044 * BUGS
2045 * MSDN claims that multiple interface registrations are legal, but we
2046 * can't do that with our current implementation.
2047 */
2048 HRESULT WINAPI CoRegisterClassObject(
2049 REFCLSID rclsid,
2050 LPUNKNOWN pUnk,
2051 DWORD dwClsContext,
2052 DWORD flags,
2053 LPDWORD lpdwRegister)
2054 {
2055 RegisteredClass* newClass;
2056 LPUNKNOWN foundObject;
2057 HRESULT hr;
2058 APARTMENT *apt;
2059
2060 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2061 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2062
2063 if ( (lpdwRegister==0) || (pUnk==0) )
2064 return E_INVALIDARG;
2065
2066 apt = COM_CurrentApt();
2067 if (!apt)
2068 {
2069 ERR("COM was not initialized\n");
2070 return CO_E_NOTINITIALIZED;
2071 }
2072
2073 *lpdwRegister = 0;
2074
2075 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2076 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2077 if (flags & REGCLS_MULTIPLEUSE)
2078 dwClsContext |= CLSCTX_INPROC_SERVER;
2079
2080 /*
2081 * First, check if the class is already registered.
2082 * If it is, this should cause an error.
2083 */
2084 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2085 if (hr == S_OK) {
2086 if (flags & REGCLS_MULTIPLEUSE) {
2087 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2088 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2089 IUnknown_Release(foundObject);
2090 return hr;
2091 }
2092 IUnknown_Release(foundObject);
2093 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2094 return CO_E_OBJISREG;
2095 }
2096
2097 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2098 if ( newClass == NULL )
2099 return E_OUTOFMEMORY;
2100
2101 newClass->classIdentifier = *rclsid;
2102 newClass->apartment_id = apt->oxid;
2103 newClass->runContext = dwClsContext;
2104 newClass->connectFlags = flags;
2105 newClass->pMarshaledData = NULL;
2106 newClass->RpcRegistration = NULL;
2107
2108 /*
2109 * Use the address of the chain node as the cookie since we are sure it's
2110 * unique. FIXME: not on 64-bit platforms.
2111 */
2112 newClass->dwCookie = (DWORD)newClass;
2113
2114 /*
2115 * Since we're making a copy of the object pointer, we have to increase its
2116 * reference count.
2117 */
2118 newClass->classObject = pUnk;
2119 IUnknown_AddRef(newClass->classObject);
2120
2121 EnterCriticalSection( &csRegisteredClassList );
2122 list_add_tail(&RegisteredClassList, &newClass->entry);
2123 LeaveCriticalSection( &csRegisteredClassList );
2124
2125 *lpdwRegister = newClass->dwCookie;
2126
2127 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2128 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2129 if (hr) {
2130 FIXME("Failed to create stream on hglobal, %x\n", hr);
2131 return hr;
2132 }
2133 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2134 newClass->classObject, MSHCTX_LOCAL, NULL,
2135 MSHLFLAGS_TABLESTRONG);
2136 if (hr) {
2137 FIXME("CoMarshalInterface failed, %x!\n",hr);
2138 return hr;
2139 }
2140
2141 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2142 newClass->pMarshaledData,
2143 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2144 &newClass->RpcRegistration);
2145 }
2146 return S_OK;
2147 }
2148
2149 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2150 {
2151 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2152 DWORD keytype;
2153 DWORD ret;
2154 DWORD dwLength = len * sizeof(WCHAR);
2155
2156 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2157 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2158 value[0] = '\0';
2159 }
2160
2161 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2162 REFCLSID rclsid, REFIID riid,
2163 BOOL hostifnecessary, void **ppv)
2164 {
2165 WCHAR dllpath[MAX_PATH+1];
2166 BOOL apartment_threaded;
2167
2168 if (hostifnecessary)
2169 {
2170 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2171 static const WCHAR wszFree[] = {'F','r','e','e',0};
2172 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2173 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2174
2175 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2176 /* "Apartment" */
2177 if (!strcmpiW(threading_model, wszApartment))
2178 {
2179 apartment_threaded = TRUE;
2180 if (apt->multi_threaded)
2181 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2182 }
2183 /* "Free" */
2184 else if (!strcmpiW(threading_model, wszFree))
2185 {
2186 apartment_threaded = FALSE;
2187 if (!apt->multi_threaded)
2188 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2189 }
2190 /* everything except "Apartment", "Free" and "Both" */
2191 else if (strcmpiW(threading_model, wszBoth))
2192 {
2193 apartment_threaded = TRUE;
2194 /* everything else is main-threaded */
2195 if (threading_model[0])
2196 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2197 debugstr_w(threading_model), debugstr_guid(rclsid));
2198
2199 if (apt->multi_threaded || !apt->main)
2200 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2201 }
2202 else
2203 apartment_threaded = FALSE;
2204 }
2205 else
2206 apartment_threaded = !apt->multi_threaded;
2207
2208 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2209 {
2210 /* failure: CLSID is not found in registry */
2211 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2212 return REGDB_E_CLASSNOTREG;
2213 }
2214
2215 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2216 rclsid, riid, ppv);
2217 }
2218
2219 /***********************************************************************
2220 * CoGetClassObject [OLE32.@]
2221 *
2222 * Creates an object of the specified class.
2223 *
2224 * PARAMS
2225 * rclsid [I] Class ID to create an instance of.
2226 * dwClsContext [I] Flags to restrict the location of the created instance.
2227 * pServerInfo [I] Optional. Details for connecting to a remote server.
2228 * iid [I] The ID of the interface of the instance to return.
2229 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2230 *
2231 * RETURNS
2232 * Success: S_OK
2233 * Failure: HRESULT code.
2234 *
2235 * NOTES
2236 * The dwClsContext parameter can be one or more of the following:
2237 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2238 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2239 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2240 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2241 *
2242 * SEE ALSO
2243 * CoCreateInstance()
2244 */
2245 HRESULT WINAPI CoGetClassObject(
2246 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2247 REFIID iid, LPVOID *ppv)
2248 {
2249 LPUNKNOWN regClassObject;
2250 HRESULT hres = E_UNEXPECTED;
2251 APARTMENT *apt;
2252 BOOL release_apt = FALSE;
2253
2254 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2255
2256 if (!ppv)
2257 return E_INVALIDARG;
2258
2259 *ppv = NULL;
2260
2261 if (!(apt = COM_CurrentApt()))
2262 {
2263 if (!(apt = apartment_find_multi_threaded()))
2264 {
2265 ERR("apartment not initialised\n");
2266 return CO_E_NOTINITIALIZED;
2267 }
2268 release_apt = TRUE;
2269 }
2270
2271 if (pServerInfo) {
2272 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2273 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2274 }
2275
2276 /*
2277 * First, try and see if we can't match the class ID with one of the
2278 * registered classes.
2279 */
2280 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2281 &regClassObject))
2282 {
2283 /* Get the required interface from the retrieved pointer. */
2284 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2285
2286 /*
2287 * Since QI got another reference on the pointer, we want to release the
2288 * one we already have. If QI was unsuccessful, this will release the object. This
2289 * is good since we are not returning it in the "out" parameter.
2290 */
2291 IUnknown_Release(regClassObject);
2292 if (release_apt) apartment_release(apt);
2293 return hres;
2294 }
2295
2296 /* First try in-process server */
2297 if (CLSCTX_INPROC_SERVER & dwClsContext)
2298 {
2299 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2300 HKEY hkey;
2301
2302 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2303 {
2304 if (release_apt) apartment_release(apt);
2305 return FTMarshalCF_Create(iid, ppv);
2306 }
2307
2308 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2309 if (FAILED(hres))
2310 {
2311 if (hres == REGDB_E_CLASSNOTREG)
2312 ERR("class %s not registered\n", debugstr_guid(rclsid));
2313 else if (hres == REGDB_E_KEYMISSING)
2314 {
2315 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2316 hres = REGDB_E_CLASSNOTREG;
2317 }
2318 }
2319
2320 if (SUCCEEDED(hres))
2321 {
2322 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2323 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2324 RegCloseKey(hkey);
2325 }
2326
2327 /* return if we got a class, otherwise fall through to one of the
2328 * other types */
2329 if (SUCCEEDED(hres))
2330 {
2331 if (release_apt) apartment_release(apt);
2332 return hres;
2333 }
2334 }
2335
2336 /* Next try in-process handler */
2337 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2338 {
2339 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2340 HKEY hkey;
2341
2342 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2343 if (FAILED(hres))
2344 {
2345 if (hres == REGDB_E_CLASSNOTREG)
2346 ERR("class %s not registered\n", debugstr_guid(rclsid));
2347 else if (hres == REGDB_E_KEYMISSING)
2348 {
2349 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2350 hres = REGDB_E_CLASSNOTREG;
2351 }
2352 }
2353
2354 if (SUCCEEDED(hres))
2355 {
2356 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2357 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2358 RegCloseKey(hkey);
2359 }
2360
2361 /* return if we got a class, otherwise fall through to one of the
2362 * other types */
2363 if (SUCCEEDED(hres))
2364 {
2365 if (release_apt) apartment_release(apt);
2366 return hres;
2367 }
2368 }
2369 if (release_apt) apartment_release(apt);
2370
2371 /* Next try out of process */
2372 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2373 {
2374 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2375 if (SUCCEEDED(hres))
2376 return hres;
2377 }
2378
2379 /* Finally try remote: this requires networked DCOM (a lot of work) */
2380 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2381 {
2382 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2383 hres = E_NOINTERFACE;
2384 }
2385
2386 if (FAILED(hres))
2387 ERR("no class object %s could be created for context 0x%x\n",
2388 debugstr_guid(rclsid), dwClsContext);
2389 return hres;
2390 }
2391
2392 /***********************************************************************
2393 * CoResumeClassObjects (OLE32.@)
2394 *
2395 * Resumes all class objects registered with REGCLS_SUSPENDED.
2396 *
2397 * RETURNS
2398 * Success: S_OK.
2399 * Failure: HRESULT code.
2400 */
2401 HRESULT WINAPI CoResumeClassObjects(void)
2402 {
2403 FIXME("stub\n");
2404 return S_OK;
2405 }
2406
2407 /***********************************************************************
2408 * CoCreateInstance [OLE32.@]
2409 *
2410 * Creates an instance of the specified class.
2411 *
2412 * PARAMS
2413 * rclsid [I] Class ID to create an instance of.
2414 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2415 * dwClsContext [I] Flags to restrict the location of the created instance.
2416 * iid [I] The ID of the interface of the instance to return.
2417 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2418 *
2419 * RETURNS
2420 * Success: S_OK
2421 * Failure: HRESULT code.
2422 *
2423 * NOTES
2424 * The dwClsContext parameter can be one or more of the following:
2425 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2426 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2427 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2428 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2429 *
2430 * Aggregation is the concept of deferring the IUnknown of an object to another
2431 * object. This allows a separate object to behave as though it was part of
2432 * the object and to allow this the pUnkOuter parameter can be set. Note that
2433 * not all objects support having an outer of unknown.
2434 *
2435 * SEE ALSO
2436 * CoGetClassObject()
2437 */
2438 HRESULT WINAPI CoCreateInstance(
2439 REFCLSID rclsid,
2440 LPUNKNOWN pUnkOuter,
2441 DWORD dwClsContext,
2442 REFIID iid,
2443 LPVOID *ppv)
2444 {
2445 HRESULT hres;
2446 LPCLASSFACTORY lpclf = 0;
2447 APARTMENT *apt;
2448
2449 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2450 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2451
2452 /*
2453 * Sanity check
2454 */
2455 if (ppv==0)
2456 return E_POINTER;
2457
2458 /*
2459 * Initialize the "out" parameter
2460 */
2461 *ppv = 0;
2462
2463 if (!(apt = COM_CurrentApt()))
2464 {
2465 if (!(apt = apartment_find_multi_threaded()))
2466 {
2467 ERR("apartment not initialised\n");
2468 return CO_E_NOTINITIALIZED;
2469 }
2470 apartment_release(apt);
2471 }
2472
2473 /*
2474 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2475 * Rather than create a class factory, we can just check for it here
2476 */
2477 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2478 if (StdGlobalInterfaceTableInstance == NULL)
2479 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2480 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2481 if (hres) return hres;
2482
2483 TRACE("Retrieved GIT (%p)\n", *ppv);
2484 return S_OK;
2485 }
2486
2487 /*
2488 * Get a class factory to construct the object we want.
2489 */
2490 hres = CoGetClassObject(rclsid,
2491 dwClsContext,
2492 NULL,
2493 &IID_IClassFactory,
2494 (LPVOID)&lpclf);
2495
2496 if (FAILED(hres))
2497 return hres;
2498
2499 /*
2500 * Create the object and don't forget to release the factory
2501 */
2502 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2503 IClassFactory_Release(lpclf);
2504 if(FAILED(hres))
2505 {
2506 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2507 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2508 else
2509 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2510 }
2511
2512 return hres;
2513 }
2514
2515 /***********************************************************************
2516 * CoCreateInstanceEx [OLE32.@]
2517 */
2518 HRESULT WINAPI CoCreateInstanceEx(
2519 REFCLSID rclsid,
2520 LPUNKNOWN pUnkOuter,
2521 DWORD dwClsContext,
2522 COSERVERINFO* pServerInfo,
2523 ULONG cmq,
2524 MULTI_QI* pResults)
2525 {
2526 IUnknown* pUnk = NULL;
2527 HRESULT hr;
2528 ULONG index;
2529 ULONG successCount = 0;
2530
2531 /*
2532 * Sanity check
2533 */
2534 if ( (cmq==0) || (pResults==NULL))
2535 return E_INVALIDARG;
2536
2537 if (pServerInfo!=NULL)
2538 FIXME("() non-NULL pServerInfo not supported!\n");
2539
2540 /*
2541 * Initialize all the "out" parameters.
2542 */
2543 for (index = 0; index < cmq; index++)
2544 {
2545 pResults[index].pItf = NULL;
2546 pResults[index].hr = E_NOINTERFACE;
2547 }
2548
2549 /*
2550 * Get the object and get its IUnknown pointer.
2551 */
2552 hr = CoCreateInstance(rclsid,
2553 pUnkOuter,
2554 dwClsContext,
2555 &IID_IUnknown,
2556 (VOID**)&pUnk);
2557
2558 if (hr)
2559 return hr;
2560
2561 /*
2562 * Then, query for all the interfaces requested.
2563 */
2564 for (index = 0; index < cmq; index++)
2565 {
2566 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2567 pResults[index].pIID,
2568 (VOID**)&(pResults[index].pItf));
2569
2570 if (pResults[index].hr == S_OK)
2571 successCount++;
2572 }
2573
2574 /*
2575 * Release our temporary unknown pointer.
2576 */
2577 IUnknown_Release(pUnk);
2578
2579 if (successCount == 0)
2580 return E_NOINTERFACE;
2581
2582 if (successCount!=cmq)
2583 return CO_S_NOTALLINTERFACES;
2584
2585 return S_OK;
2586 }
2587
2588 /***********************************************************************
2589 * CoLoadLibrary (OLE32.@)
2590 *
2591 * Loads a library.
2592 *
2593 * PARAMS
2594 * lpszLibName [I] Path to library.
2595 * bAutoFree [I] Whether the library should automatically be freed.
2596 *
2597 * RETURNS
2598 * Success: Handle to loaded library.
2599 * Failure: NULL.
2600 *
2601 * SEE ALSO
2602 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2603 */
2604 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2605 {
2606 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2607
2608 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2609 }
2610
2611 /***********************************************************************
2612 * CoFreeLibrary [OLE32.@]
2613 *
2614 * Unloads a library from memory.
2615 *
2616 * PARAMS
2617 * hLibrary [I] Handle to library to unload.
2618 *
2619 * RETURNS
2620 * Nothing
2621 *
2622 * SEE ALSO
2623 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2624 */
2625 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2626 {
2627 FreeLibrary(hLibrary);
2628 }
2629
2630
2631 /***********************************************************************
2632 * CoFreeAllLibraries [OLE32.@]
2633 *
2634 * Function for backwards compatibility only. Does nothing.
2635 *
2636 * RETURNS
2637 * Nothing.
2638 *
2639 * SEE ALSO
2640 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2641 */
2642 void WINAPI CoFreeAllLibraries(void)
2643 {
2644 /* NOP */
2645 }
2646
2647 /***********************************************************************
2648 * CoFreeUnusedLibrariesEx [OLE32.@]
2649 *
2650 * Frees any previously unused libraries whose delay has expired and marks
2651 * currently unused libraries for unloading. Unused are identified as those that
2652 * return S_OK from their DllCanUnloadNow function.
2653 *
2654 * PARAMS
2655 * dwUnloadDelay [I] Unload delay in milliseconds.
2656 * dwReserved [I] Reserved. Set to 0.
2657 *
2658 * RETURNS
2659 * Nothing.
2660 *
2661 * SEE ALSO
2662 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2663 */
2664 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2665 {
2666 struct apartment *apt = COM_CurrentApt();
2667 if (!apt)
2668 {
2669 ERR("apartment not initialised\n");
2670 return;
2671 }
2672
2673 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2674 }
2675
2676 /***********************************************************************
2677 * CoFreeUnusedLibraries [OLE32.@]
2678 *
2679 * Frees any unused libraries. Unused are identified as those that return
2680 * S_OK from their DllCanUnloadNow function.
2681 *
2682 * RETURNS
2683 * Nothing.
2684 *
2685 * SEE ALSO
2686 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2687 */
2688 void WINAPI CoFreeUnusedLibraries(void)
2689 {
2690 CoFreeUnusedLibrariesEx(INFINITE, 0);
2691 }
2692
2693 /***********************************************************************
2694 * CoFileTimeNow [OLE32.@]
2695 *
2696 * Retrieves the current time in FILETIME format.
2697 *
2698 * PARAMS
2699 * lpFileTime [O] The current time.
2700 *
2701 * RETURNS
2702 * S_OK.
2703 */
2704 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2705 {
2706 GetSystemTimeAsFileTime( lpFileTime );
2707 return S_OK;
2708 }
2709
2710 /******************************************************************************
2711 * CoLockObjectExternal [OLE32.@]
2712 *
2713 * Increments or decrements the external reference count of a stub object.
2714 *
2715 * PARAMS
2716 * pUnk [I] Stub object.
2717 * fLock [I] If TRUE then increments the external ref-count,
2718 * otherwise decrements.
2719 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2720 * calling CoDisconnectObject.
2721 *
2722 * RETURNS
2723 * Success: S_OK.
2724 * Failure: HRESULT code.
2725 *
2726 * NOTES
2727 * If fLock is TRUE and an object is passed in that doesn't have a stub
2728 * manager then a new stub manager is created for the object.
2729 */
2730 HRESULT WINAPI CoLockObjectExternal(
2731 LPUNKNOWN pUnk,
2732 BOOL fLock,
2733 BOOL fLastUnlockReleases)
2734 {
2735 struct stub_manager *stubmgr;
2736 struct apartment *apt;
2737
2738 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2739 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2740
2741 apt = COM_CurrentApt();
2742 if (!apt) return CO_E_NOTINITIALIZED;
2743
2744 stubmgr = get_stub_manager_from_object(apt, pUnk);
2745
2746 if (stubmgr)
2747 {
2748 if (fLock)
2749 stub_manager_ext_addref(stubmgr, 1, FALSE);
2750 else
2751 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2752
2753 stub_manager_int_release(stubmgr);
2754
2755 return S_OK;
2756 }
2757 else if (fLock)
2758 {
2759 stubmgr = new_stub_manager(apt, pUnk);
2760
2761 if (stubmgr)
2762 {
2763 stub_manager_ext_addref(stubmgr, 1, FALSE);
2764 stub_manager_int_release(stubmgr);
2765 }
2766
2767 return S_OK;
2768 }
2769 else
2770 {
2771 WARN("stub object not found %p\n", pUnk);
2772 /* Note: native is pretty broken here because it just silently
2773 * fails, without returning an appropriate error code, making apps
2774 * think that the object was disconnected, when it actually wasn't */
2775 return S_OK;
2776 }
2777 }
2778
2779 /***********************************************************************
2780 * CoInitializeWOW (OLE32.@)
2781 *
2782 * WOW equivalent of CoInitialize?
2783 *
2784 * PARAMS
2785 * x [I] Unknown.
2786 * y [I] Unknown.
2787 *
2788 * RETURNS
2789 * Unknown.
2790 */
2791 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2792 {
2793 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2794 return 0;
2795 }
2796
2797 /***********************************************************************
2798 * CoGetState [OLE32.@]
2799 *
2800 * Retrieves the thread state object previously stored by CoSetState().
2801 *
2802 * PARAMS
2803 * ppv [I] Address where pointer to object will be stored.
2804 *
2805 * RETURNS
2806 * Success: S_OK.
2807 * Failure: E_OUTOFMEMORY.
2808 *
2809 * NOTES
2810 * Crashes on all invalid ppv addresses, including NULL.
2811 * If the function returns a non-NULL object then the caller must release its
2812 * reference on the object when the object is no longer required.
2813 *
2814 * SEE ALSO
2815 * CoSetState().
2816 */
2817 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2818 {
2819 struct oletls *info = COM_CurrentInfo();
2820 if (!info) return E_OUTOFMEMORY;
2821
2822 *ppv = NULL;
2823
2824 if (info->state)
2825 {
2826 IUnknown_AddRef(info->state);
2827 *ppv = info->state;
2828 TRACE("apt->state=%p\n", info->state);
2829 }
2830
2831 return S_OK;
2832 }
2833
2834 /***********************************************************************
2835 * CoSetState [OLE32.@]
2836 *
2837 * Sets the thread state object.
2838 *
2839 * PARAMS
2840 * pv [I] Pointer to state object to be stored.
2841 *
2842 * NOTES
2843 * The system keeps a reference on the object while the object stored.
2844 *
2845 * RETURNS
2846 * Success: S_OK.
2847 * Failure: E_OUTOFMEMORY.
2848 */
2849 HRESULT WINAPI CoSetState(IUnknown * pv)
2850 {
2851 struct oletls *info = COM_CurrentInfo();
2852 if (!info) return E_OUTOFMEMORY;
2853
2854 if (pv) IUnknown_AddRef(pv);
2855
2856 if (info->state)
2857 {
2858 TRACE("-- release %p now\n", info->state);
2859 IUnknown_Release(info->state);
2860 }
2861
2862 info->state = pv;
2863
2864 return S_OK;
2865 }
2866
2867
2868 /******************************************************************************
2869 * CoTreatAsClass [OLE32.@]
2870 *
2871 * Sets the TreatAs value of a class.
2872 *
2873 * PARAMS
2874 * clsidOld [I] Class to set TreatAs value on.
2875 * clsidNew [I] The class the clsidOld should be treated as.
2876 *
2877 * RETURNS
2878 * Success: S_OK.
2879 * Failure: HRESULT code.
2880 *
2881 * SEE ALSO
2882 * CoGetTreatAsClass
2883 */
2884 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2885 {
2886 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2887 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2888 HKEY hkey = NULL;
2889 WCHAR szClsidNew[CHARS_IN_GUID];
2890 HRESULT res = S_OK;
2891 WCHAR auto_treat_as[CHARS_IN_GUID];
2892 LONG auto_treat_as_size = sizeof(auto_treat_as);
2893 CLSID id;
2894
2895 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2896 if (FAILED(res))
2897 goto done;
2898 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2899 {
2900 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2901 CLSIDFromString(auto_treat_as, &id) == S_OK)
2902 {
2903 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2904 {
2905 res = REGDB_E_WRITEREGDB;
2906 goto done;
2907 }
2908 }
2909 else
2910 {
2911 RegDeleteKeyW(hkey, wszTreatAs);
2912 goto done;
2913 }
2914 }
2915 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2916 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2917 {
2918 res = REGDB_E_WRITEREGDB;
2919 goto done;
2920 }
2921
2922 done:
2923 if (hkey) RegCloseKey(hkey);
2924 return res;
2925 }
2926
2927 /******************************************************************************
2928 * CoGetTreatAsClass [OLE32.@]
2929 *
2930 * Gets the TreatAs value of a class.
2931 *
2932 * PARAMS
2933 * clsidOld [I] Class to get the TreatAs value of.
2934 * clsidNew [I] The class the clsidOld should be treated as.
2935 *
2936 * RETURNS
2937 * Success: S_OK.
2938 * Failure: HRESULT code.
2939 *
2940 * SEE ALSO
2941 * CoSetTreatAsClass
2942 */
2943 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2944 {
2945 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2946 HKEY hkey = NULL;
2947 WCHAR szClsidNew[CHARS_IN_GUID];
2948 HRESULT res = S_OK;
2949 LONG len = sizeof(szClsidNew);
2950
2951 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2952 *clsidNew = *clsidOld; /* copy over old value */
2953
2954 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2955 if (FAILED(res))
2956 {
2957 res = S_FALSE;
2958 goto done;
2959 }
2960 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2961 {
2962 res = S_FALSE;
2963 goto done;
2964 }
2965 res = CLSIDFromString(szClsidNew,clsidNew);
2966 if (FAILED(res))
2967 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2968 done:
2969 if (hkey) RegCloseKey(hkey);
2970 return res;
2971 }
2972
2973 /******************************************************************************
2974 * CoGetCurrentProcess [OLE32.@]
2975 *
2976 * Gets the current process ID.
2977 *
2978 * RETURNS
2979 * The current process ID.
2980 *
2981 * NOTES
2982 * Is DWORD really the correct return type for this function?
2983 */
2984 DWORD WINAPI CoGetCurrentProcess(void)
2985 {
2986 return GetCurrentProcessId();
2987 }
2988
2989 /******************************************************************************
2990 * CoRegisterMessageFilter [OLE32.@]
2991 *
2992 * Registers a message filter.
2993 *
2994 * PARAMS
2995 * lpMessageFilter [I] Pointer to interface.
2996 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2997 *
2998 * RETURNS
2999 * Success: S_OK.
3000 * Failure: HRESULT code.
3001 *
3002 * NOTES
3003 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3004 * lpMessageFilter removes the message filter.
3005 *
3006 * If lplpMessageFilter is not NULL the previous message filter will be
3007 * returned in the memory pointer to this parameter and the caller is
3008 * responsible for releasing the object.
3009 *
3010 * The current thread be in an apartment otherwise the function will crash.
3011 */
3012 HRESULT WINAPI CoRegisterMessageFilter(
3013 LPMESSAGEFILTER lpMessageFilter,
3014 LPMESSAGEFILTER *lplpMessageFilter)
3015 {
3016 struct apartment *apt;
3017 IMessageFilter *lpOldMessageFilter;
3018
3019 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3020
3021 apt = COM_CurrentApt();
3022
3023 /* can't set a message filter in a multi-threaded apartment */
3024 if (!apt || apt->multi_threaded)
3025 {
3026 WARN("can't set message filter in MTA or uninitialized apt\n");
3027 return CO_E_NOT_SUPPORTED;
3028 }
3029
3030 if (lpMessageFilter)
3031 IMessageFilter_AddRef(lpMessageFilter);
3032
3033 EnterCriticalSection(&apt->cs);
3034
3035 lpOldMessageFilter = apt->filter;
3036 apt->filter = lpMessageFilter;
3037
3038 LeaveCriticalSection(&apt->cs);
3039
3040 if (lplpMessageFilter)
3041 *lplpMessageFilter = lpOldMessageFilter;
3042 else if (lpOldMessageFilter)
3043 IMessageFilter_Release(lpOldMessageFilter);
3044
3045 return S_OK;
3046 }
3047
3048 /***********************************************************************
3049 * CoIsOle1Class [OLE32.@]
3050 *
3051 * Determines whether the specified class an OLE v1 class.
3052 *
3053 * PARAMS
3054 * clsid [I] Class to test.
3055 *
3056 * RETURNS
3057 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3058 */
3059 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3060 {
3061 FIXME("%s\n", debugstr_guid(clsid));
3062 return FALSE;
3063 }
3064
3065 /***********************************************************************
3066 * IsEqualGUID [OLE32.@]
3067 *
3068 * Compares two Unique Identifiers.
3069 *
3070 * PARAMS
3071 * rguid1 [I] The first GUID to compare.
3072 * rguid2 [I] The other GUID to compare.
3073 *
3074 * RETURNS
3075 * TRUE if equal
3076 */
3077 #undef IsEqualGUID
3078 BOOL WINAPI IsEqualGUID(
3079 REFGUID rguid1,
3080 REFGUID rguid2)
3081 {
3082 return !memcmp(rguid1,rguid2,sizeof(GUID));
3083 }
3084
3085 /***********************************************************************
3086 * CoInitializeSecurity [OLE32.@]
3087 */
3088 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3089 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3090 void* pReserved1, DWORD dwAuthnLevel,
3091 DWORD dwImpLevel, void* pReserved2,
3092 DWORD dwCapabilities, void* pReserved3)
3093 {
3094 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3095 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3096 dwCapabilities, pReserved3);
3097 return S_OK;
3098 }
3099
3100 /***********************************************************************
3101 * CoSuspendClassObjects [OLE32.@]
3102 *
3103 * Suspends all registered class objects to prevent further requests coming in
3104 * for those objects.
3105 *
3106 * RETURNS
3107 * Success: S_OK.
3108 * Failure: HRESULT code.
3109 */
3110 HRESULT WINAPI CoSuspendClassObjects(void)
3111 {
3112 FIXME("\n");
3113 return S_OK;
3114 }
3115
3116 /***********************************************************************
3117 * CoAddRefServerProcess [OLE32.@]
3118 *
3119 * Helper function for incrementing the reference count of a local-server
3120 * process.
3121 *
3122 * RETURNS
3123 * New reference count.
3124 *
3125 * SEE ALSO
3126 * CoReleaseServerProcess().
3127 */
3128 ULONG WINAPI CoAddRefServerProcess(void)
3129 {
3130 ULONG refs;
3131
3132 TRACE("\n");
3133
3134 EnterCriticalSection(&csRegisteredClassList);
3135 refs = ++s_COMServerProcessReferences;
3136 LeaveCriticalSection(&csRegisteredClassList);
3137
3138 TRACE("refs before: %d\n", refs - 1);
3139
3140 return refs;
3141 }
3142
3143 /***********************************************************************
3144 * CoReleaseServerProcess [OLE32.@]
3145 *
3146 * Helper function for decrementing the reference count of a local-server
3147 * process.
3148 *
3149 * RETURNS
3150 * New reference count.
3151 *
3152 * NOTES
3153 * When reference count reaches 0, this function suspends all registered
3154 * classes so no new connections are accepted.
3155 *
3156 * SEE ALSO
3157 * CoAddRefServerProcess(), CoSuspendClassObjects().
3158 */
3159 ULONG WINAPI CoReleaseServerProcess(void)
3160 {
3161 ULONG refs;
3162
3163 TRACE("\n");
3164
3165 EnterCriticalSection(&csRegisteredClassList);
3166
3167 refs = --s_COMServerProcessReferences;
3168 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3169
3170 LeaveCriticalSection(&csRegisteredClassList);
3171
3172 TRACE("refs after: %d\n", refs);
3173
3174 return refs;
3175 }
3176
3177 /***********************************************************************
3178 * CoIsHandlerConnected [OLE32.@]
3179 *
3180 * Determines whether a proxy is connected to a remote stub.
3181 *
3182 * PARAMS
3183 * pUnk [I] Pointer to object that may or may not be connected.
3184 *
3185 * RETURNS
3186 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3187 * FALSE otherwise.
3188 */
3189 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3190 {
3191 FIXME("%p\n", pUnk);
3192
3193 return TRUE;
3194 }
3195
3196 /***********************************************************************
3197 * CoAllowSetForegroundWindow [OLE32.@]
3198 *
3199 */
3200 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3201 {
3202 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3203 return S_OK;
3204 }
3205
3206 /***********************************************************************
3207 * CoQueryProxyBlanket [OLE32.@]
3208 *
3209 * Retrieves the security settings being used by a proxy.
3210 *
3211 * PARAMS
3212 * pProxy [I] Pointer to the proxy object.
3213 * pAuthnSvc [O] The type of authentication service.
3214 * pAuthzSvc [O] The type of authorization service.
3215 * ppServerPrincName [O] Optional. The server prinicple name.
3216 * pAuthnLevel [O] The authentication level.
3217 * pImpLevel [O] The impersonation level.
3218 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3219 * pCapabilities [O] Flags affecting the security behaviour.
3220 *
3221 * RETURNS
3222 * Success: S_OK.
3223 * Failure: HRESULT code.
3224 *
3225 * SEE ALSO
3226 * CoCopyProxy, CoSetProxyBlanket.
3227 */
3228 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3229 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3230 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3231 {
3232 IClientSecurity *pCliSec;
3233 HRESULT hr;
3234
3235 TRACE("%p\n", pProxy);
3236
3237 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3238 if (SUCCEEDED(hr))
3239 {
3240 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3241 pAuthzSvc, ppServerPrincName,
3242 pAuthnLevel, pImpLevel, ppAuthInfo,
3243 pCapabilities);
3244 IClientSecurity_Release(pCliSec);
3245 }
3246
3247 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3248 return hr;
3249 }
3250
3251 /***********************************************************************
3252 * CoSetProxyBlanket [OLE32.@]
3253 *
3254 * Sets the security settings for a proxy.
3255 *
3256 * PARAMS
3257 * pProxy [I] Pointer to the proxy object.
3258 * AuthnSvc [I] The type of authentication service.
3259 * AuthzSvc [I] The type of authorization service.
3260 * pServerPrincName [I] The server prinicple name.
3261 * AuthnLevel [I] The authentication level.
3262 * ImpLevel [I] The impersonation level.
3263 * pAuthInfo [I] Information specific to the authorization/authentication service.
3264 * Capabilities [I] Flags affecting the security behaviour.
3265 *
3266 * RETURNS
3267 * Success: S_OK.
3268 * Failure: HRESULT code.
3269 *
3270 * SEE ALSO
3271 * CoQueryProxyBlanket, CoCopyProxy.
3272 */
3273 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3274 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3275 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3276 {
3277 IClientSecurity *pCliSec;
3278 HRESULT hr;
3279
3280 TRACE("%p\n", pProxy);
3281
3282 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3283 if (SUCCEEDED(hr))
3284 {
3285 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3286 AuthzSvc, pServerPrincName,
3287 AuthnLevel, ImpLevel, pAuthInfo,
3288 Capabilities);
3289 IClientSecurity_Release(pCliSec);
3290 }
3291
3292 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3293 return hr;
3294 }
3295
3296 /***********************************************************************
3297 * CoCopyProxy [OLE32.@]
3298 *
3299 * Copies a proxy.
3300 *
3301 * PARAMS
3302 * pProxy [I] Pointer to the proxy object.
3303 * ppCopy [O] Copy of the proxy.
3304 *
3305 * RETURNS
3306 * Success: S_OK.
3307 * Failure: HRESULT code.
3308 *
3309 * SEE ALSO
3310 * CoQueryProxyBlanket, CoSetProxyBlanket.
3311 */
3312 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3313 {
3314 IClientSecurity *pCliSec;
3315 HRESULT hr;
3316
3317 TRACE("%p\n", pProxy);
3318
3319 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3320 if (SUCCEEDED(hr))
3321 {
3322 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3323 IClientSecurity_Release(pCliSec);
3324 }
3325
3326 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3327 return hr;
3328 }
3329
3330
3331 /***********************************************************************
3332 * CoGetCallContext [OLE32.@]
3333 *
3334 * Gets the context of the currently executing server call in the current
3335 * thread.
3336 *
3337 * PARAMS
3338 * riid [I] Context interface to return.
3339 * ppv [O] Pointer to memory that will receive the context on return.
3340 *
3341 * RETURNS
3342 * Success: S_OK.
3343 * Failure: HRESULT code.
3344 */
3345 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3346 {
3347 struct oletls *info = COM_CurrentInfo();
3348
3349 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3350
3351 if (!info)
3352 return E_OUTOFMEMORY;
3353
3354 if (!info->call_state)
3355 return RPC_E_CALL_COMPLETE;
3356
3357 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3358 }
3359
3360 /***********************************************************************
3361 * CoSwitchCallContext [OLE32.@]
3362 *
3363 * Switches the context of the currently executing server call in the current
3364 * thread.
3365 *
3366 * PARAMS
3367 * pObject [I] Pointer to new context object
3368 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3369 *
3370 * RETURNS
3371 * Success: S_OK.
3372 * Failure: HRESULT code.
3373 */
3374 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3375 {
3376 struct oletls *info = COM_CurrentInfo();
3377
3378 TRACE("(%p, %p)\n", pObject, ppOldObject);
3379
3380 if (!info)
3381 return E_OUTOFMEMORY;
3382
3383 *ppOldObject = info->call_state;
3384 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3385
3386 return S_OK;
3387 }
3388
3389 /***********************************************************************
3390 * CoQueryClientBlanket [OLE32.@]
3391 *
3392 * Retrieves the authentication information about the client of the currently
3393 * executing server call in the current thread.
3394 *
3395 * PARAMS
3396 * pAuthnSvc [O] Optional. The type of authentication service.
3397 * pAuthzSvc [O] Optional. The type of authorization service.
3398 * pServerPrincName [O] Optional. The server prinicple name.
3399 * pAuthnLevel [O] Optional. The authentication level.
3400 * pImpLevel [O] Optional. The impersonation level.
3401 * pPrivs [O] Optional. Information about the privileges of the client.
3402 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3403 *
3404 * RETURNS
3405 * Success: S_OK.
3406 * Failure: HRESULT code.
3407 *
3408 * SEE ALSO
3409 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3410 */
3411 HRESULT WINAPI CoQueryClientBlanket(
3412 DWORD *pAuthnSvc,
3413 DWORD *pAuthzSvc,
3414 OLECHAR **pServerPrincName,
3415 DWORD *pAuthnLevel,
3416 DWORD *pImpLevel,
3417 RPC_AUTHZ_HANDLE *pPrivs,
3418 DWORD *pCapabilities)
3419 {
3420 IServerSecurity *pSrvSec;
3421 HRESULT hr;
3422
3423 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3424 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3425 pPrivs, pCapabilities);
3426
3427 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3428 if (SUCCEEDED(hr))
3429 {
3430 hr = IServerSecurity_QueryBlanket(
3431 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3432 pImpLevel, pPrivs, pCapabilities);
3433 IServerSecurity_Release(pSrvSec);
3434 }
3435
3436 return hr;
3437 }
3438
3439 /***********************************************************************
3440 * CoImpersonateClient [OLE32.@]
3441 *
3442 * Impersonates the client of the currently executing server call in the
3443 * current thread.
3444 *
3445 * PARAMS
3446 * None.
3447 *
3448 * RETURNS
3449 * Success: S_OK.
3450 * Failure: HRESULT code.
3451 *
3452 * NOTES
3453 * If this function fails then the current thread will not be impersonating
3454 * the client and all actions will take place on behalf of the server.
3455 * Therefore, it is important to check the return value from this function.
3456 *
3457 * SEE ALSO
3458 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3459 */
3460 HRESULT WINAPI CoImpersonateClient(void)
3461 {
3462 IServerSecurity *pSrvSec;
3463 HRESULT hr;
3464
3465 TRACE("\n");
3466
3467 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3468 if (SUCCEEDED(hr))
3469 {
3470 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3471 IServerSecurity_Release(pSrvSec);
3472 }
3473
3474 return hr;
3475 }
3476
3477 /***********************************************************************
3478 * CoRevertToSelf [OLE32.@]
3479 *
3480 * Ends the impersonation of the client of the currently executing server
3481 * call in the current thread.
3482 *
3483 * PARAMS
3484 * None.
3485 *
3486 * RETURNS
3487 * Success: S_OK.
3488 * Failure: HRESULT code.
3489 *
3490 * SEE ALSO
3491 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3492 */
3493 HRESULT WINAPI CoRevertToSelf(void)
3494 {
3495 IServerSecurity *pSrvSec;
3496 HRESULT hr;
3497
3498 TRACE("\n");
3499
3500 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3501 if (SUCCEEDED(hr))
3502 {
3503 hr = IServerSecurity_RevertToSelf(pSrvSec);
3504 IServerSecurity_Release(pSrvSec);
3505 }
3506
3507 return hr;
3508 }
3509
3510 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3511 {
3512 /* first try to retrieve messages for incoming COM calls to the apartment window */
3513 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3514 /* next retrieve other messages necessary for the app to remain responsive */
3515 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3516 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3517 }
3518
3519 /***********************************************************************
3520 * CoWaitForMultipleHandles [OLE32.@]
3521 *
3522 * Waits for one or more handles to become signaled.
3523 *
3524 * PARAMS
3525 * dwFlags [I] Flags. See notes.
3526 * dwTimeout [I] Timeout in milliseconds.
3527 * cHandles [I] Number of handles pointed to by pHandles.
3528 * pHandles [I] Handles to wait for.
3529 * lpdwindex [O] Index of handle that was signaled.
3530 *
3531 * RETURNS
3532 * Success: S_OK.
3533 * Failure: RPC_S_CALLPENDING on timeout.
3534 *
3535 * NOTES
3536 *
3537 * The dwFlags parameter can be zero or more of the following:
3538 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3539 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3540 *
3541 * SEE ALSO
3542 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3543 */
3544 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3545 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3546 {
3547 HRESULT hr = S_OK;
3548 DWORD start_time = GetTickCount();
3549 APARTMENT *apt = COM_CurrentApt();
3550 BOOL message_loop = apt && !apt->multi_threaded;
3551
3552 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3553 pHandles, lpdwindex);
3554
3555 while (TRUE)
3556 {
3557 DWORD now = GetTickCount();
3558 DWORD res;
3559
3560 if (now - start_time > dwTimeout)
3561 {
3562 hr = RPC_S_CALLPENDING;
3563 break;
3564 }
3565
3566 if (message_loop)
3567 {
3568 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3569 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3570
3571 TRACE("waiting for rpc completion or window message\n");
3572
3573 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3574 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3575 QS_ALLINPUT, wait_flags);
3576
3577 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3578 {
3579 MSG msg;
3580
3581 /* call message filter */
3582
3583 if (COM_CurrentApt()->filter)
3584 {
3585 PENDINGTYPE pendingtype =
3586 COM_CurrentInfo()->pending_call_count_server ?
3587 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3588 DWORD be_handled = IMessageFilter_MessagePending(
3589 COM_CurrentApt()->filter, 0 /* FIXME */,
3590 now - start_time, pendingtype);
3591 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3592 switch (be_handled)
3593 {
3594 case PENDINGMSG_CANCELCALL:
3595 WARN("call canceled\n");
3596 hr = RPC_E_CALL_CANCELED;
3597 break;
3598 case PENDINGMSG_WAITNOPROCESS:
3599 case PENDINGMSG_WAITDEFPROCESS:
3600 default:
3601 /* FIXME: MSDN is very vague about the difference
3602 * between WAITNOPROCESS and WAITDEFPROCESS - there
3603 * appears to be none, so it is possibly a left-over
3604 * from the 16-bit world. */
3605 break;
3606 }
3607 }
3608
3609 /* note: using "if" here instead of "while" might seem less
3610 * efficient, but only if we are optimising for quick delivery
3611 * of pending messages, rather than quick completion of the
3612 * COM call */
3613 if (COM_PeekMessage(apt, &msg))
3614 {
3615 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3616 TranslateMessage(&msg);
3617 DispatchMessageW(&msg);
3618 if (msg.message == WM_QUIT)
3619 {
3620 TRACE("resending WM_QUIT to outer message loop\n");
3621 PostQuitMessage(msg.wParam);
3622 /* no longer need to process messages */
3623 message_loop = FALSE;
3624 }
3625 }
3626 continue;
3627 }
3628 }
3629 else
3630 {
3631 TRACE("waiting for rpc completion\n");
3632
3633 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3634 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3635 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3636 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3637 }
3638
3639 if (res < WAIT_OBJECT_0 + cHandles)
3640 {
3641 /* handle signaled, store index */
3642 *lpdwindex = (res - WAIT_OBJECT_0);
3643 break;
3644 }
3645 else if (res == WAIT_TIMEOUT)
3646 {
3647 hr = RPC_S_CALLPENDING;
3648 break;
3649 }
3650 else
3651 {
3652 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3653 hr = E_UNEXPECTED;
3654 break;
3655 }
3656 }
3657 TRACE("-- 0x%08x\n", hr);
3658 return hr;
3659 }
3660
3661
3662 /***********************************************************************
3663 * CoGetObject [OLE32.@]
3664 *
3665 * Gets the object named by converting the name to a moniker and binding to it.
3666 *
3667 * PARAMS
3668 * pszName [I] String representing the object.
3669 * pBindOptions [I] Parameters affecting the binding to the named object.
3670 * riid [I] Interface to bind to on the objecct.
3671 * ppv [O] On output, the interface riid of the object represented
3672 * by pszName.
3673 *
3674 * RETURNS
3675 * Success: S_OK.
3676 * Failure: HRESULT code.
3677 *
3678 * SEE ALSO
3679 * MkParseDisplayName.
3680 */
3681 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3682 REFIID riid, void **ppv)
3683 {
3684 IBindCtx *pbc;
3685 HRESULT hr;
3686
3687 *ppv = NULL;
3688
3689 hr = CreateBindCtx(0, &pbc);
3690 if (SUCCEEDED(hr))
3691 {
3692 if (pBindOptions)
3693 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3694
3695 if (SUCCEEDED(hr))
3696 {
3697 ULONG chEaten;
3698 IMoniker *pmk;
3699
3700 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3701 if (SUCCEEDED(hr))
3702 {
3703 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3704 IMoniker_Release(pmk);
3705 }
3706 }
3707
3708 IBindCtx_Release(pbc);
3709 }
3710 return hr;
3711 }
3712
3713 /***********************************************************************
3714 * CoRegisterChannelHook [OLE32.@]
3715 *
3716 * Registers a process-wide hook that is called during ORPC calls.
3717 *
3718 * PARAMS
3719 * guidExtension [I] GUID of the channel hook to register.
3720 * pChannelHook [I] Channel hook object to register.
3721 *
3722 * RETURNS
3723 * Success: S_OK.
3724 * Failure: HRESULT code.
3725 */
3726 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3727 {
3728 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3729
3730 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3731 }
3732
3733 typedef struct Context
3734 {
3735 const IComThreadingInfoVtbl *lpVtbl;
3736 const IContextCallbackVtbl *lpCallbackVtbl;
3737 const IObjContextVtbl *lpContextVtbl;
3738 LONG refs;
3739 APTTYPE apttype;
3740 } Context;
3741
3742 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3743 {
3744 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3745 }
3746
3747 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3748 {
3749 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3750 }
3751
3752 static inline Context *impl_from_IObjContext( IObjContext *iface )
3753 {
3754 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl));
3755 }
3756
3757 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3758 {
3759 *ppv = NULL;
3760
3761 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3762 IsEqualIID(riid, &IID_IUnknown))
3763 {
3764 *ppv = &iface->lpVtbl;
3765 }
3766 else if (IsEqualIID(riid, &IID_IContextCallback))
3767 {
3768 *ppv = &iface->lpCallbackVtbl;
3769 }
3770 else if (IsEqualIID(riid, &IID_IObjContext))
3771 {
3772 *ppv = &iface->lpContextVtbl;
3773 }
3774
3775 if (*ppv)
3776 {
3777 IUnknown_AddRef((IUnknown*)*ppv);
3778 return S_OK;
3779 }
3780
3781 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3782 return E_NOINTERFACE;
3783 }
3784
3785 static ULONG Context_AddRef(Context *This)
3786 {
3787 return InterlockedIncrement(&This->refs);
3788 }
3789
3790 static ULONG Context_Release(Context *This)
3791 {
3792 ULONG refs = InterlockedDecrement(&This->refs);
3793 if (!refs)
3794 HeapFree(GetProcessHeap(), 0, This);
3795 return refs;
3796 }
3797
3798 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3799 {
3800 Context *This = impl_from_IComThreadingInfo(iface);
3801 return Context_QueryInterface(This, riid, ppv);
3802 }
3803
3804 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3805 {
3806 Context *This = impl_from_IComThreadingInfo(iface);
3807 return Context_AddRef(This);
3808 }
3809
3810 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3811 {
3812 Context *This = impl_from_IComThreadingInfo(iface);
3813 return Context_Release(This);
3814 }
3815
3816 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3817 {
3818 Context *This = impl_from_IComThreadingInfo(iface);
3819
3820 TRACE("(%p)\n", apttype);
3821
3822 *apttype = This->apttype;
3823 return S_OK;
3824 }
3825
3826 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3827 {
3828 Context *This = impl_from_IComThreadingInfo(iface);
3829
3830 TRACE("(%p)\n", thdtype);
3831
3832 switch (This->apttype)
3833 {
3834 case APTTYPE_STA:
3835 case APTTYPE_MAINSTA:
3836 *thdtype = THDTYPE_PROCESSMESSAGES;
3837 break;
3838 default:
3839 *thdtype = THDTYPE_BLOCKMESSAGES;
3840 break;
3841 }
3842 return S_OK;
3843 }
3844
3845 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3846 {
3847 FIXME("(%p): stub\n", logical_thread_id);
3848 return E_NOTIMPL;
3849 }
3850
3851 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3852 {
3853 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3854 return E_NOTIMPL;
3855 }
3856
3857 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3858 {
3859 Context_CTI_QueryInterface,
3860 Context_CTI_AddRef,
3861 Context_CTI_Release,
3862 Context_CTI_GetCurrentApartmentType,
3863 Context_CTI_GetCurrentThreadType,
3864 Context_CTI_GetCurrentLogicalThreadId,
3865 Context_CTI_SetCurrentLogicalThreadId
3866 };
3867
3868 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3869 {
3870 Context *This = impl_from_IContextCallback(iface);
3871 return Context_QueryInterface(This, riid, ppv);
3872 }
3873
3874 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3875 {
3876 Context *This = impl_from_IContextCallback(iface);
3877 return Context_AddRef(This);
3878 }
3879
3880 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3881 {
3882 Context *This = impl_from_IContextCallback(iface);
3883 return Context_Release(This);
3884 }
3885
3886 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3887 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3888 {
3889 Context *This = impl_from_IContextCallback(iface);
3890
3891 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3892 return E_NOTIMPL;
3893 }
3894
3895 static const IContextCallbackVtbl Context_Callback_Vtbl =
3896 {
3897 Context_CC_QueryInterface,
3898 Context_CC_AddRef,
3899 Context_CC_Release,
3900 Context_CC_ContextCallback
3901 };
3902
3903 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3904 {
3905 Context *This = impl_from_IObjContext(iface);
3906 return Context_QueryInterface(This, riid, ppv);
3907 }
3908
3909 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3910 {
3911 Context *This = impl_from_IObjContext(iface);
3912 return Context_AddRef(This);
3913 }
3914
3915 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3916 {
3917 Context *This = impl_from_IObjContext(iface);
3918 return Context_Release(This);
3919 }
3920
3921 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3922 {
3923 Context *This = impl_from_IObjContext(iface);
3924
3925 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3926 return E_NOTIMPL;
3927 }
3928
3929 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3930 {
3931 Context *This = impl_from_IObjContext(iface);
3932
3933 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3934 return E_NOTIMPL;
3935 }
3936
3937 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3938 {
3939 Context *This = impl_from_IObjContext(iface);
3940
3941 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3942 return E_NOTIMPL;
3943 }
3944
3945 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
3946 {
3947 Context *This = impl_from_IObjContext(iface);
3948
3949 FIXME("(%p/%p)->(%p)\n", This, iface, props);
3950 return E_NOTIMPL;
3951 }
3952
3953 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
3954 {
3955 Context *This = impl_from_IObjContext(iface);
3956 FIXME("(%p/%p)\n", This, iface);
3957 }
3958
3959 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
3960 {
3961 Context *This = impl_from_IObjContext(iface);
3962 FIXME("(%p/%p)\n", This, iface);
3963 }
3964
3965 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
3966 {
3967 Context *This = impl_from_IObjContext(iface);
3968 FIXME("(%p/%p)\n", This, iface);
3969 }
3970
3971 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
3972 {
3973 Context *This = impl_from_IObjContext(iface);
3974 FIXME("(%p/%p)\n", This, iface);
3975 }
3976
3977 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
3978 {
3979 Context *This = impl_from_IObjContext(iface);
3980 FIXME("(%p/%p)\n", This, iface);
3981 }
3982
3983 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
3984 {
3985 Context *This = impl_from_IObjContext(iface);
3986 FIXME("(%p/%p)\n", This, iface);
3987 }
3988
3989 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
3990 {
3991 Context *This = impl_from_IObjContext(iface);
3992 FIXME("(%p/%p)\n", This, iface);
3993 }
3994
3995 static const IObjContextVtbl Context_Object_Vtbl =
3996 {
3997 Context_OC_QueryInterface,
3998 Context_OC_AddRef,
3999 Context_OC_Release,
4000 Context_OC_SetProperty,
4001 Context_OC_RemoveProperty,
4002 Context_OC_GetProperty,
4003 Context_OC_EnumContextProps,
4004 Context_OC_Reserved1,
4005 Context_OC_Reserved2,
4006 Context_OC_Reserved3,
4007 Context_OC_Reserved4,
4008 Context_OC_Reserved5,
4009 Context_OC_Reserved6,
4010 Context_OC_Reserved7
4011 };
4012
4013 /***********************************************************************
4014 * CoGetObjectContext [OLE32.@]
4015 *
4016 * Retrieves an object associated with the current context (i.e. apartment).
4017 *
4018 * PARAMS
4019 * riid [I] ID of the interface of the object to retrieve.
4020 * ppv [O] Address where object will be stored on return.
4021 *
4022 * RETURNS
4023 * Success: S_OK.
4024 * Failure: HRESULT code.
4025 */
4026 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4027 {
4028 APARTMENT *apt = COM_CurrentApt();
4029 Context *context;
4030 HRESULT hr;
4031
4032 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4033
4034 *ppv = NULL;
4035 if (!apt)
4036 {
4037 if (!(apt = apartment_find_multi_threaded()))
4038 {
4039 ERR("apartment not initialised\n");
4040 return CO_E_NOTINITIALIZED;
4041 }
4042 apartment_release(apt);
4043 }
4044
4045 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4046 if (!context)
4047 return E_OUTOFMEMORY;
4048
4049 context->lpVtbl = &Context_Threading_Vtbl;
4050 context->lpCallbackVtbl = &Context_Callback_Vtbl;
4051 context->lpContextVtbl = &Context_Object_Vtbl;
4052 context->refs = 1;
4053 if (apt->multi_threaded)
4054 context->apttype = APTTYPE_MTA;
4055 else if (apt->main)
4056 context->apttype = APTTYPE_MAINSTA;
4057 else
4058 context->apttype = APTTYPE_STA;
4059
4060 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
4061 IUnknown_Release((IUnknown *)&context->lpVtbl);
4062
4063 return hr;
4064 }
4065
4066
4067 /***********************************************************************
4068 * CoGetContextToken [OLE32.@]
4069 */
4070 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4071 {
4072 struct oletls *info = COM_CurrentInfo();
4073
4074 TRACE("(%p)\n", token);
4075
4076 if (!info)
4077 return E_OUTOFMEMORY;
4078
4079 if (!info->apt)
4080 {
4081 APARTMENT *apt;
4082 if (!(apt = apartment_find_multi_threaded()))
4083 {
4084 ERR("apartment not initialised\n");
4085 return CO_E_NOTINITIALIZED;
4086 }
4087 apartment_release(apt);
4088 }
4089
4090 if (!token)
4091 return E_POINTER;
4092
4093 if (!info->context_token)
4094 {
4095 HRESULT hr;
4096 IObjContext *ctx;
4097
4098 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4099 if (FAILED(hr)) return hr;
4100 info->context_token = ctx;
4101 }
4102
4103 *token = (ULONG_PTR)info->context_token;
4104 TRACE("apt->context_token=%p\n", info->context_token);
4105
4106 return S_OK;
4107 }
4108
4109
4110 /***********************************************************************
4111 * DllMain (OLE32.@)
4112 */
4113 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4114 {
4115 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4116
4117 switch(fdwReason) {
4118 case DLL_PROCESS_ATTACH:
4119 hProxyDll = hinstDLL;
4120 COMPOBJ_InitProcess();
4121 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
4122 break;
4123
4124 case DLL_PROCESS_DETACH:
4125 if (TRACE_ON(ole)) CoRevokeMallocSpy();
4126 OLEDD_UnInitialize();
4127 COMPOBJ_UninitProcess();
4128 RPC_UnregisterAllChannelHooks();
4129 COMPOBJ_DllList_Free();
4130 break;
4131
4132 case DLL_THREAD_DETACH:
4133 COM_TlsDestroy();
4134 break;
4135 }
4136 return TRUE;
4137 }
4138
4139 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */