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