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