ole32: Check source pointer in StringFromGUID2.
[wine] / dlls / 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 (!id || 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 */