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