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