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