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