ole32: Don't loop while peeking messages in CoWaitForMultipleHandles.
[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 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1544 {
1545         DWORD ret;
1546         HKEY key;
1547         DWORD keytype;
1548         WCHAR src[MAX_PATH];
1549         DWORD dwLength = dstlen * sizeof(WCHAR);
1550
1551         if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1552           if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1553             if (keytype == REG_EXPAND_SZ) {
1554               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1555             } else {
1556               lstrcpynW(dst, src, dstlen);
1557             }
1558           }
1559           RegCloseKey (key);
1560         }
1561         return ret;
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  * NOTES
2103  *  If fLock is TRUE and an object is passed in that doesn't have a stub
2104  *  manager then a new stub manager is created for the object.
2105  */
2106 HRESULT WINAPI CoLockObjectExternal(
2107     LPUNKNOWN pUnk,
2108     BOOL fLock,
2109     BOOL fLastUnlockReleases)
2110 {
2111     struct stub_manager *stubmgr;
2112     struct apartment *apt;
2113
2114     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2115           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2116
2117     apt = COM_CurrentApt();
2118     if (!apt) return CO_E_NOTINITIALIZED;
2119
2120     stubmgr = get_stub_manager_from_object(apt, pUnk);
2121     
2122     if (stubmgr)
2123     {
2124         if (fLock)
2125             stub_manager_ext_addref(stubmgr, 1);
2126         else
2127             stub_manager_ext_release(stubmgr, 1);
2128         
2129         stub_manager_int_release(stubmgr);
2130
2131         return S_OK;
2132     }
2133     else if (fLock)
2134     {
2135         stubmgr = new_stub_manager(apt, pUnk);
2136
2137         if (stubmgr)
2138         {
2139             stub_manager_ext_addref(stubmgr, 1);
2140             stub_manager_int_release(stubmgr);
2141         }
2142
2143         return S_OK;
2144     }
2145     else
2146     {
2147         WARN("stub object not found %p\n", pUnk);
2148         /* Note: native is pretty broken here because it just silently
2149          * fails, without returning an appropriate error code, making apps
2150          * think that the object was disconnected, when it actually wasn't */
2151         return S_OK;
2152     }
2153 }
2154
2155 /***********************************************************************
2156  *           CoInitializeWOW (OLE32.@)
2157  *
2158  * WOW equivalent of CoInitialize?
2159  *
2160  * PARAMS
2161  *  x [I] Unknown.
2162  *  y [I] Unknown.
2163  *
2164  * RETURNS
2165  *  Unknown.
2166  */
2167 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2168 {
2169     FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2170     return 0;
2171 }
2172
2173 /***********************************************************************
2174  *           CoGetState [OLE32.@]
2175  *
2176  * Retrieves the thread state object previously stored by CoSetState().
2177  *
2178  * PARAMS
2179  *  ppv [I] Address where pointer to object will be stored.
2180  *
2181  * RETURNS
2182  *  Success: S_OK.
2183  *  Failure: E_OUTOFMEMORY.
2184  *
2185  * NOTES
2186  *  Crashes on all invalid ppv addresses, including NULL.
2187  *  If the function returns a non-NULL object then the caller must release its
2188  *  reference on the object when the object is no longer required.
2189  *
2190  * SEE ALSO
2191  *  CoSetState().
2192  */
2193 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2194 {
2195     struct oletls *info = COM_CurrentInfo();
2196     if (!info) return E_OUTOFMEMORY;
2197
2198     *ppv = NULL;
2199
2200     if (info->state)
2201     {
2202         IUnknown_AddRef(info->state);
2203         *ppv = info->state;
2204         TRACE("apt->state=%p\n", info->state);
2205     }
2206
2207     return S_OK;
2208 }
2209
2210 /***********************************************************************
2211  *           CoSetState [OLE32.@]
2212  *
2213  * Sets the thread state object.
2214  *
2215  * PARAMS
2216  *  pv [I] Pointer to state object to be stored.
2217  *
2218  * NOTES
2219  *  The system keeps a reference on the object while the object stored.
2220  *
2221  * RETURNS
2222  *  Success: S_OK.
2223  *  Failure: E_OUTOFMEMORY.
2224  */
2225 HRESULT WINAPI CoSetState(IUnknown * pv)
2226 {
2227     struct oletls *info = COM_CurrentInfo();
2228     if (!info) return E_OUTOFMEMORY;
2229
2230     if (pv) IUnknown_AddRef(pv);
2231
2232     if (info->state)
2233     {
2234         TRACE("-- release %p now\n", info->state);
2235         IUnknown_Release(info->state);
2236     }
2237
2238     info->state = pv;
2239
2240     return S_OK;
2241 }
2242
2243
2244 /******************************************************************************
2245  *              OleGetAutoConvert        [OLE32.@]
2246  */
2247 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2248 {
2249     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2250     HKEY hkey = NULL;
2251     WCHAR buf[CHARS_IN_GUID];
2252     LONG len;
2253     HRESULT res = S_OK;
2254
2255     res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2256     if (FAILED(res))
2257         goto done;
2258
2259     len = sizeof(buf);
2260     if (RegQueryValueW(hkey, NULL, buf, &len))
2261     {
2262         res = REGDB_E_KEYMISSING;
2263         goto done;
2264     }
2265     res = CLSIDFromString(buf, pClsidNew);
2266 done:
2267     if (hkey) RegCloseKey(hkey);
2268     return res;
2269 }
2270
2271 /******************************************************************************
2272  *              CoTreatAsClass        [OLE32.@]
2273  *
2274  * Sets the TreatAs value of a class.
2275  *
2276  * PARAMS
2277  *  clsidOld [I] Class to set TreatAs value on.
2278  *  clsidNew [I] The class the clsidOld should be treated as.
2279  *
2280  * RETURNS
2281  *  Success: S_OK.
2282  *  Failure: HRESULT code.
2283  *
2284  * SEE ALSO
2285  *  CoGetTreatAsClass
2286  */
2287 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2288 {
2289     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2290     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2291     HKEY hkey = NULL;
2292     WCHAR szClsidNew[CHARS_IN_GUID];
2293     HRESULT res = S_OK;
2294     WCHAR auto_treat_as[CHARS_IN_GUID];
2295     LONG auto_treat_as_size = sizeof(auto_treat_as);
2296     CLSID id;
2297
2298     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2299     if (FAILED(res))
2300         goto done;
2301     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2302     {
2303        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2304            !CLSIDFromString(auto_treat_as, &id))
2305        {
2306            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2307            {
2308                res = REGDB_E_WRITEREGDB;
2309                goto done;
2310            }
2311        }
2312        else
2313        {
2314            RegDeleteKeyW(hkey, wszTreatAs);
2315            goto done;
2316        }
2317     }
2318     else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2319              !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2320     {
2321         res = REGDB_E_WRITEREGDB;
2322         goto done;
2323     }
2324
2325 done:
2326     if (hkey) RegCloseKey(hkey);
2327     return res;
2328 }
2329
2330 /******************************************************************************
2331  *              CoGetTreatAsClass        [OLE32.@]
2332  *
2333  * Gets the TreatAs value of a class.
2334  *
2335  * PARAMS
2336  *  clsidOld [I] Class to get the TreatAs value of.
2337  *  clsidNew [I] The class the clsidOld should be treated as.
2338  *
2339  * RETURNS
2340  *  Success: S_OK.
2341  *  Failure: HRESULT code.
2342  *
2343  * SEE ALSO
2344  *  CoSetTreatAsClass
2345  */
2346 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2347 {
2348     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2349     HKEY hkey = NULL;
2350     WCHAR szClsidNew[CHARS_IN_GUID];
2351     HRESULT res = S_OK;
2352     LONG len = sizeof(szClsidNew);
2353
2354     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2355     memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2356
2357     res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2358     if (FAILED(res))
2359         goto done;
2360     if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2361     {
2362         res = S_FALSE;
2363         goto done;
2364     }
2365     res = CLSIDFromString(szClsidNew,clsidNew);
2366     if (FAILED(res))
2367         ERR("Failed CLSIDFromStringA(%s), hres 0x%08lx\n", debugstr_w(szClsidNew), res);
2368 done:
2369     if (hkey) RegCloseKey(hkey);
2370     return res;
2371 }
2372
2373 /******************************************************************************
2374  *              CoGetCurrentProcess     [OLE32.@]
2375  *              CoGetCurrentProcess     [COMPOBJ.34]
2376  *
2377  * Gets the current process ID.
2378  *
2379  * RETURNS
2380  *  The current process ID.
2381  *
2382  * NOTES
2383  *   Is DWORD really the correct return type for this function?
2384  */
2385 DWORD WINAPI CoGetCurrentProcess(void)
2386 {
2387         return GetCurrentProcessId();
2388 }
2389
2390 /******************************************************************************
2391  *              CoRegisterMessageFilter [OLE32.@]
2392  *
2393  * Registers a message filter.
2394  *
2395  * PARAMS
2396  *  lpMessageFilter [I] Pointer to interface.
2397  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2398  *
2399  * RETURNS
2400  *  Success: S_OK.
2401  *  Failure: HRESULT code.
2402  */
2403 HRESULT WINAPI CoRegisterMessageFilter(
2404     LPMESSAGEFILTER lpMessageFilter,
2405     LPMESSAGEFILTER *lplpMessageFilter)
2406 {
2407     FIXME("stub\n");
2408     if (lplpMessageFilter) {
2409         *lplpMessageFilter = NULL;
2410     }
2411     return S_OK;
2412 }
2413
2414 /***********************************************************************
2415  *           CoIsOle1Class [OLE32.@]
2416  *
2417  * Determines whether the specified class an OLE v1 class.
2418  *
2419  * PARAMS
2420  *  clsid [I] Class to test.
2421  *
2422  * RETURNS
2423  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
2424  */
2425 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2426 {
2427   FIXME("%s\n", debugstr_guid(clsid));
2428   return FALSE;
2429 }
2430
2431 /***********************************************************************
2432  *           IsEqualGUID [OLE32.@]
2433  *
2434  * Compares two Unique Identifiers.
2435  *
2436  * PARAMS
2437  *  rguid1 [I] The first GUID to compare.
2438  *  rguid2 [I] The other GUID to compare.
2439  *
2440  * RETURNS
2441  *      TRUE if equal
2442  */
2443 #undef IsEqualGUID
2444 BOOL WINAPI IsEqualGUID(
2445      REFGUID rguid1,
2446      REFGUID rguid2)
2447 {
2448     return !memcmp(rguid1,rguid2,sizeof(GUID));
2449 }
2450
2451 /***********************************************************************
2452  *           CoInitializeSecurity [OLE32.@]
2453  */
2454 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2455                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2456                                     void* pReserved1, DWORD dwAuthnLevel,
2457                                     DWORD dwImpLevel, void* pReserved2,
2458                                     DWORD dwCapabilities, void* pReserved3)
2459 {
2460   FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2461         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2462         dwCapabilities, pReserved3);
2463   return S_OK;
2464 }
2465
2466 /***********************************************************************
2467  *           CoSuspendClassObjects [OLE32.@]
2468  *
2469  * Suspends all registered class objects to prevent further requests coming in
2470  * for those objects.
2471  *
2472  * RETURNS
2473  *  Success: S_OK.
2474  *  Failure: HRESULT code.
2475  */
2476 HRESULT WINAPI CoSuspendClassObjects(void)
2477 {
2478     FIXME("\n");
2479     return S_OK;
2480 }
2481
2482 /***********************************************************************
2483  *           CoAddRefServerProcess [OLE32.@]
2484  *
2485  * Helper function for incrementing the reference count of a local-server
2486  * process.
2487  *
2488  * RETURNS
2489  *  New reference count.
2490  */
2491 ULONG WINAPI CoAddRefServerProcess(void)
2492 {
2493     FIXME("\n");
2494     return 2;
2495 }
2496
2497 /***********************************************************************
2498  *           CoReleaseServerProcess [OLE32.@]
2499  *
2500  * Helper function for decrementing the reference count of a local-server
2501  * process.
2502  *
2503  * RETURNS
2504  *  New reference count.
2505  */
2506 ULONG WINAPI CoReleaseServerProcess(void)
2507 {
2508     FIXME("\n");
2509     return 1;
2510 }
2511
2512 /***********************************************************************
2513  *           CoIsHandlerConnected [OLE32.@]
2514  *
2515  * Determines whether a proxy is connected to a remote stub.
2516  *
2517  * PARAMS
2518  *  pUnk [I] Pointer to object that may or may not be connected.
2519  *
2520  * RETURNS
2521  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2522  *  FALSE otherwise.
2523  */
2524 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2525 {
2526     FIXME("%p\n", pUnk);
2527
2528     return TRUE;
2529 }
2530
2531 /***********************************************************************
2532  *           CoAllowSetForegroundWindow [OLE32.@]
2533  *
2534  */
2535 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
2536 {
2537     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
2538     return S_OK;
2539 }
2540  
2541 /***********************************************************************
2542  *           CoQueryProxyBlanket [OLE32.@]
2543  *
2544  * Retrieves the security settings being used by a proxy.
2545  *
2546  * PARAMS
2547  *  pProxy        [I] Pointer to the proxy object.
2548  *  pAuthnSvc     [O] The type of authentication service.
2549  *  pAuthzSvc     [O] The type of authorization service.
2550  *  ppServerPrincName [O] Optional. The server prinicple name.
2551  *  pAuthnLevel   [O] The authentication level.
2552  *  pImpLevel     [O] The impersonation level.
2553  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
2554  *  pCapabilities [O] Flags affecting the security behaviour.
2555  *
2556  * RETURNS
2557  *  Success: S_OK.
2558  *  Failure: HRESULT code.
2559  *
2560  * SEE ALSO
2561  *  CoCopyProxy, CoSetProxyBlanket.
2562  */
2563 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2564     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2565     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2566 {
2567     IClientSecurity *pCliSec;
2568     HRESULT hr;
2569
2570     TRACE("%p\n", pProxy);
2571
2572     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2573     if (SUCCEEDED(hr))
2574     {
2575         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2576                                           pAuthzSvc, ppServerPrincName,
2577                                           pAuthnLevel, pImpLevel, ppAuthInfo,
2578                                           pCapabilities);
2579         IClientSecurity_Release(pCliSec);
2580     }
2581
2582     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2583     return hr;
2584 }
2585
2586 /***********************************************************************
2587  *           CoSetProxyBlanket [OLE32.@]
2588  *
2589  * Sets the security settings for a proxy.
2590  *
2591  * PARAMS
2592  *  pProxy       [I] Pointer to the proxy object.
2593  *  AuthnSvc     [I] The type of authentication service.
2594  *  AuthzSvc     [I] The type of authorization service.
2595  *  pServerPrincName [I] The server prinicple name.
2596  *  AuthnLevel   [I] The authentication level.
2597  *  ImpLevel     [I] The impersonation level.
2598  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
2599  *  Capabilities [I] Flags affecting the security behaviour.
2600  *
2601  * RETURNS
2602  *  Success: S_OK.
2603  *  Failure: HRESULT code.
2604  *
2605  * SEE ALSO
2606  *  CoQueryProxyBlanket, CoCopyProxy.
2607  */
2608 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2609     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2610     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2611 {
2612     IClientSecurity *pCliSec;
2613     HRESULT hr;
2614
2615     TRACE("%p\n", pProxy);
2616
2617     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2618     if (SUCCEEDED(hr))
2619     {
2620         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2621                                         AuthzSvc, pServerPrincName,
2622                                         AuthnLevel, ImpLevel, pAuthInfo,
2623                                         Capabilities);
2624         IClientSecurity_Release(pCliSec);
2625     }
2626
2627     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2628     return hr;
2629 }
2630
2631 /***********************************************************************
2632  *           CoCopyProxy [OLE32.@]
2633  *
2634  * Copies a proxy.
2635  *
2636  * PARAMS
2637  *  pProxy [I] Pointer to the proxy object.
2638  *  ppCopy [O] Copy of the proxy.
2639  *
2640  * RETURNS
2641  *  Success: S_OK.
2642  *  Failure: HRESULT code.
2643  *
2644  * SEE ALSO
2645  *  CoQueryProxyBlanket, CoSetProxyBlanket.
2646  */
2647 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2648 {
2649     IClientSecurity *pCliSec;
2650     HRESULT hr;
2651
2652     TRACE("%p\n", pProxy);
2653
2654     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2655     if (SUCCEEDED(hr))
2656     {
2657         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2658         IClientSecurity_Release(pCliSec);
2659     }
2660
2661     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2662     return hr;
2663 }
2664
2665
2666 /***********************************************************************
2667  *           CoGetCallContext [OLE32.@]
2668  *
2669  * Gets the context of the currently executing server call in the current
2670  * thread.
2671  *
2672  * PARAMS
2673  *  riid [I] Context interface to return.
2674  *  ppv  [O] Pointer to memory that will receive the context on return.
2675  *
2676  * RETURNS
2677  *  Success: S_OK.
2678  *  Failure: HRESULT code.
2679  */
2680 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
2681 {
2682     FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
2683
2684     *ppv = NULL;
2685     return E_NOINTERFACE;
2686 }
2687
2688 /***********************************************************************
2689  *           CoQueryClientBlanket [OLE32.@]
2690  *
2691  * Retrieves the authentication information about the client of the currently
2692  * executing server call in the current thread.
2693  *
2694  * PARAMS
2695  *  pAuthnSvc     [O] Optional. The type of authentication service.
2696  *  pAuthzSvc     [O] Optional. The type of authorization service.
2697  *  pServerPrincName [O] Optional. The server prinicple name.
2698  *  pAuthnLevel   [O] Optional. The authentication level.
2699  *  pImpLevel     [O] Optional. The impersonation level.
2700  *  pPrivs        [O] Optional. Information about the privileges of the client.
2701  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
2702  *
2703  * RETURNS
2704  *  Success: S_OK.
2705  *  Failure: HRESULT code.
2706  *
2707  * SEE ALSO
2708  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
2709  */
2710 HRESULT WINAPI CoQueryClientBlanket(
2711     DWORD *pAuthnSvc,
2712     DWORD *pAuthzSvc,
2713     OLECHAR **pServerPrincName,
2714     DWORD *pAuthnLevel,
2715     DWORD *pImpLevel,
2716     RPC_AUTHZ_HANDLE *pPrivs,
2717     DWORD *pCapabilities)
2718 {
2719     IServerSecurity *pSrvSec;
2720     HRESULT hr;
2721
2722     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
2723         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
2724         pPrivs, pCapabilities);
2725
2726     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2727     if (SUCCEEDED(hr))
2728     {
2729         hr = IServerSecurity_QueryBlanket(
2730             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
2731             pImpLevel, pPrivs, pCapabilities);
2732         IServerSecurity_Release(pSrvSec);
2733     }
2734
2735     return hr;
2736 }
2737
2738 /***********************************************************************
2739  *           CoImpersonateClient [OLE32.@]
2740  *
2741  * Impersonates the client of the currently executing server call in the
2742  * current thread.
2743  *
2744  * PARAMS
2745  *  None.
2746  *
2747  * RETURNS
2748  *  Success: S_OK.
2749  *  Failure: HRESULT code.
2750  *
2751  * NOTES
2752  *  If this function fails then the current thread will not be impersonating
2753  *  the client and all actions will take place on behalf of the server.
2754  *  Therefore, it is important to check the return value from this function.
2755  *
2756  * SEE ALSO
2757  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
2758  */
2759 HRESULT WINAPI CoImpersonateClient(void)
2760 {
2761     IServerSecurity *pSrvSec;
2762     HRESULT hr;
2763
2764     TRACE("\n");
2765
2766     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2767     if (SUCCEEDED(hr))
2768     {
2769         hr = IServerSecurity_ImpersonateClient(pSrvSec);
2770         IServerSecurity_Release(pSrvSec);
2771     }
2772
2773     return hr;
2774 }
2775
2776 /***********************************************************************
2777  *           CoRevertToSelf [OLE32.@]
2778  *
2779  * Ends the impersonation of the client of the currently executing server
2780  * call in the current thread.
2781  *
2782  * PARAMS
2783  *  None.
2784  *
2785  * RETURNS
2786  *  Success: S_OK.
2787  *  Failure: HRESULT code.
2788  *
2789  * SEE ALSO
2790  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
2791  */
2792 HRESULT WINAPI CoRevertToSelf(void)
2793 {
2794     IServerSecurity *pSrvSec;
2795     HRESULT hr;
2796
2797     TRACE("\n");
2798
2799     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
2800     if (SUCCEEDED(hr))
2801     {
2802         hr = IServerSecurity_RevertToSelf(pSrvSec);
2803         IServerSecurity_Release(pSrvSec);
2804     }
2805
2806     return hr;
2807 }
2808
2809 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2810 {
2811     /* first try to retrieve messages for incoming COM calls to the apartment window */
2812     return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2813            /* next retrieve other messages necessary for the app to remain responsive */
2814            PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2815 }
2816
2817 /***********************************************************************
2818  *           CoWaitForMultipleHandles [OLE32.@]
2819  *
2820  * Waits for one or more handles to become signaled.
2821  *
2822  * PARAMS
2823  *  dwFlags   [I] Flags. See notes.
2824  *  dwTimeout [I] Timeout in milliseconds.
2825  *  cHandles  [I] Number of handles pointed to by pHandles.
2826  *  pHandles  [I] Handles to wait for.
2827  *  lpdwindex [O] Index of handle that was signaled.
2828  *
2829  * RETURNS
2830  *  Success: S_OK.
2831  *  Failure: RPC_S_CALLPENDING on timeout.
2832  *
2833  * NOTES
2834  *
2835  * The dwFlags parameter can be zero or more of the following:
2836  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2837  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2838  *
2839  * SEE ALSO
2840  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
2841  */
2842 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2843     ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2844 {
2845     HRESULT hr = S_OK;
2846     DWORD start_time = GetTickCount();
2847     APARTMENT *apt = COM_CurrentApt();
2848     BOOL message_loop = apt && !apt->multi_threaded;
2849
2850     TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2851         pHandles, lpdwindex);
2852
2853     while (TRUE)
2854     {
2855         DWORD now = GetTickCount();
2856         DWORD res;
2857
2858         if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2859         {
2860             hr = RPC_S_CALLPENDING;
2861             break;
2862         }
2863
2864         if (message_loop)
2865         {
2866             DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2867                     (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2868
2869             TRACE("waiting for rpc completion or window message\n");
2870
2871             res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2872                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2873                 QS_ALLINPUT, wait_flags);
2874
2875             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
2876             {
2877                 MSG msg;
2878
2879                 /* note: using "if" here instead of "while" might seem less
2880                  * efficient, but only if we are optimising for quick delivery
2881                  * of pending messages, rather than quick completion of the
2882                  * COM call */
2883                 if (COM_PeekMessage(apt, &msg))
2884                 {
2885                     /* FIXME: filter the messages here */
2886                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2887                     TranslateMessage(&msg);
2888                     DispatchMessageW(&msg);
2889                     if (msg.message == WM_QUIT)
2890                     {
2891                         TRACE("resending WM_QUIT to outer message loop\n");
2892                         PostQuitMessage(msg.wParam);
2893                         /* no longer need to process messages */
2894                         message_loop = FALSE;
2895                     }
2896                 }
2897                 continue;
2898             }
2899         }
2900         else
2901         {
2902             TRACE("waiting for rpc completion\n");
2903
2904             res = WaitForMultipleObjectsEx(cHandles, pHandles,
2905                 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
2906                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2907                 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
2908         }
2909
2910         if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2911         {
2912             /* handle signaled, store index */
2913             *lpdwindex = (res - WAIT_OBJECT_0);
2914             break;
2915         }
2916         else if (res == WAIT_TIMEOUT)
2917         {
2918             hr = RPC_S_CALLPENDING;
2919             break;
2920         }
2921         else
2922         {
2923             ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2924             hr = E_UNEXPECTED;
2925             break;
2926         }
2927     }
2928     TRACE("-- 0x%08lx\n", hr);
2929     return hr;
2930 }
2931
2932
2933 /***********************************************************************
2934  *           CoGetObject [OLE32.@]
2935  *
2936  * Gets the object named by coverting the name to a moniker and binding to it.
2937  *
2938  * PARAMS
2939  *  pszName      [I] String representing the object.
2940  *  pBindOptions [I] Parameters affecting the binding to the named object.
2941  *  riid         [I] Interface to bind to on the objecct.
2942  *  ppv          [O] On output, the interface riid of the object represented
2943  *                   by pszName.
2944  *
2945  * RETURNS
2946  *  Success: S_OK.
2947  *  Failure: HRESULT code.
2948  *
2949  * SEE ALSO
2950  *  MkParseDisplayName.
2951  */
2952 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
2953     REFIID riid, void **ppv)
2954 {
2955     IBindCtx *pbc;
2956     HRESULT hr;
2957
2958     *ppv = NULL;
2959
2960     hr = CreateBindCtx(0, &pbc);
2961     if (SUCCEEDED(hr))
2962     {
2963         if (pBindOptions)
2964             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
2965
2966         if (SUCCEEDED(hr))
2967         {
2968             ULONG chEaten;
2969             IMoniker *pmk;
2970
2971             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
2972             if (SUCCEEDED(hr))
2973             {
2974                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
2975                 IMoniker_Release(pmk);
2976             }
2977         }
2978
2979         IBindCtx_Release(pbc);
2980     }
2981     return hr;
2982 }
2983
2984 /***********************************************************************
2985  *              DllMain (OLE32.@)
2986  */
2987 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2988 {
2989     TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2990
2991     switch(fdwReason) {
2992     case DLL_PROCESS_ATTACH:
2993         OLE32_hInstance = hinstDLL;
2994         COMPOBJ_InitProcess();
2995         if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2996         break;
2997
2998     case DLL_PROCESS_DETACH:
2999         if (TRACE_ON(ole)) CoRevokeMallocSpy();
3000         COMPOBJ_UninitProcess();
3001         OLE32_hInstance = 0;
3002         break;
3003
3004     case DLL_THREAD_DETACH:
3005         COM_TlsDestroy();
3006         break;
3007     }
3008     return TRUE;
3009 }
3010
3011 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */