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