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