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