rpcrt4: For full pointers the state consists of flags, so or new flags into the field...
[wine] / dlls / ole32 / compobj.c
1 /*
2  *      COMPOBJ library
3  *
4  *      Copyright 1995  Martin von Loewis
5  *      Copyright 1998  Justin Bradford
6  *      Copyright 1999  Francis Beaudet
7  *      Copyright 1999  Sylvain St-Germain
8  *      Copyright 2002  Marcus Meissner
9  *      Copyright 2004  Mike Hearn
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  *
25  * Note
26  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27  *    Therefore do not test against COINIT_MULTITHREADED
28  *
29  * TODO list:           (items bunched together depend on each other)
30  *
31  *   - Implement the service control manager (in rpcss) to keep track
32  *     of registered class objects: ISCM::ServerRegisterClsid et al
33  *   - Implement the OXID resolver so we don't need magic endpoint names for
34  *     clients and servers to meet up
35  *
36  *   - Call IMessageFilter functions.
37  *
38  *   - Make all ole interface marshaling use NDR to be wire compatible with
39  *     native DCOM
40  *   - Use & interpret ORPCTHIS & ORPCTHAT.
41  *
42  */
43
44 #include "config.h"
45
46 #include <stdlib.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <assert.h>
51
52 #define COBJMACROS
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
55
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winerror.h"
59 #include "winreg.h"
60 #include "winuser.h"
61 #include "objbase.h"
62 #include "ole2.h"
63 #include "ole2ver.h"
64
65 #include "compobj_private.h"
66
67 #include "wine/unicode.h"
68 #include "wine/debug.h"
69
70 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71
72 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
73
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75
76 /****************************************************************************
77  * This section defines variables internal to the COM module.
78  *
79  * TODO: Most of these things will have to be made thread-safe.
80  */
81
82 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN*  ppUnk);
83 static void COM_RevokeAllClasses(void);
84
85 APARTMENT *MTA; /* protected by csApartment */
86 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
87
88 static CRITICAL_SECTION csApartment;
89 static CRITICAL_SECTION_DEBUG critsect_debug =
90 {
91     0, 0, &csApartment,
92     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
93       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
94 };
95 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
96
97 /*
98  * This lock count counts the number of times CoInitialize is called. It is
99  * decreased every time CoUninitialize is called. When it hits 0, the COM
100  * libraries are freed
101  */
102 static LONG s_COMLockCount = 0;
103
104 /*
105  * This linked list contains the list of registered class objects. These
106  * are mostly used to register the factories for out-of-proc servers of OLE
107  * objects.
108  *
109  * TODO: Make this data structure aware of inter-process communication. This
110  *       means that parts of this will be exported to the Wine Server.
111  */
112 typedef struct tagRegisteredClass
113 {
114   CLSID     classIdentifier;
115   LPUNKNOWN classObject;
116   DWORD     runContext;
117   DWORD     connectFlags;
118   DWORD     dwCookie;
119   LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
120   struct tagRegisteredClass* nextClass;
121 } RegisteredClass;
122
123 static RegisteredClass* firstRegisteredClass = NULL;
124
125 static CRITICAL_SECTION csRegisteredClassList;
126 static CRITICAL_SECTION_DEBUG class_cs_debug =
127 {
128     0, 0, &csRegisteredClassList,
129     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
130       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
131 };
132 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
133
134 /*****************************************************************************
135  * This section contains OpenDllList definitions
136  *
137  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
138  * other functions that do LoadLibrary _without_ giving back a HMODULE.
139  * Without this list these handles would never be freed.
140  *
141  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
142  * next unload-call but not before 600 sec.
143  */
144
145 typedef struct tagOpenDll {
146   HINSTANCE hLibrary;
147   struct tagOpenDll *next;
148 } OpenDll;
149
150 static OpenDll *openDllList = NULL; /* linked list of open dlls */
151
152 static CRITICAL_SECTION csOpenDllList;
153 static CRITICAL_SECTION_DEBUG dll_cs_debug =
154 {
155     0, 0, &csOpenDllList,
156     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
157       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
158 };
159 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
160
161 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
162                                        '0','x','#','#','#','#','#','#','#','#',' ',0};
163 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
164
165 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
166 static void COMPOBJ_DllList_FreeUnused(int Timeout);
167
168 static void COMPOBJ_InitProcess( void )
169 {
170     WNDCLASSW wclass;
171
172     /* Dispatching to the correct thread in an apartment is done through
173      * window messages rather than RPC transports. When an interface is
174      * marshalled into another apartment in the same process, a window of the
175      * following class is created. The *caller* of CoMarshalInterface (ie the
176      * application) is responsible for pumping the message loop in that thread.
177      * The WM_USER messages which point to the RPCs are then dispatched to
178      * COM_AptWndProc by the user's code from the apartment in which the interface
179      * was unmarshalled.
180      */
181     memset(&wclass, 0, sizeof(wclass));
182     wclass.lpfnWndProc = apartment_wndproc;
183     wclass.hInstance = OLE32_hInstance;
184     wclass.lpszClassName = wszAptWinClass;
185     RegisterClassW(&wclass);
186 }
187
188 static void COMPOBJ_UninitProcess( void )
189 {
190     UnregisterClassW(wszAptWinClass, OLE32_hInstance);
191 }
192
193 static void COM_TlsDestroy(void)
194 {
195     struct oletls *info = NtCurrentTeb()->ReservedForOle;
196     if (info)
197     {
198         if (info->apt) apartment_release(info->apt);
199         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
200         if (info->state) IUnknown_Release(info->state);
201         HeapFree(GetProcessHeap(), 0, info);
202         NtCurrentTeb()->ReservedForOle = NULL;
203     }
204 }
205
206 /******************************************************************************
207  * Manage apartments.
208  */
209
210 /* allocates memory and fills in the necessary fields for a new apartment
211  * object */
212 static APARTMENT *apartment_construct(DWORD model)
213 {
214     APARTMENT *apt;
215
216     TRACE("creating new apartment, model=%ld\n", model);
217
218     apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
219     apt->tid = GetCurrentThreadId();
220
221     list_init(&apt->proxies);
222     list_init(&apt->stubmgrs);
223     apt->ipidc = 0;
224     apt->refs = 1;
225     apt->remunk_exported = FALSE;
226     apt->oidc = 1;
227     InitializeCriticalSection(&apt->cs);
228     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
229
230     apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
231
232     if (apt->multi_threaded)
233     {
234         /* FIXME: should be randomly generated by in an RPC call to rpcss */
235         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
236     }
237     else
238     {
239         /* FIXME: should be randomly generated by in an RPC call to rpcss */
240         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
241     }
242
243     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
244
245     /* the locking here is not currently needed for the MTA case, but it
246      * doesn't hurt and makes the code simpler */
247     EnterCriticalSection(&csApartment);
248     list_add_head(&apts, &apt->entry);
249     LeaveCriticalSection(&csApartment);
250
251     return apt;
252 }
253
254 /* gets and existing apartment if one exists or otherwise creates an apartment
255  * structure which stores OLE apartment-local information and stores a pointer
256  * to it in the thread-local storage */
257 static APARTMENT *apartment_get_or_create(DWORD model)
258 {
259     APARTMENT *apt = COM_CurrentApt();
260
261     if (!apt)
262     {
263         if (model & COINIT_APARTMENTTHREADED)
264         {
265             apt = apartment_construct(model);
266             COM_CurrentInfo()->apt = apt;
267         }
268         else
269         {
270             EnterCriticalSection(&csApartment);
271
272             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
273              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
274              * in a process */
275             if (MTA)
276             {
277                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
278                 apartment_addref(MTA);
279             }
280             else
281                 MTA = apartment_construct(model);
282
283             apt = MTA;
284             COM_CurrentInfo()->apt = apt;
285
286             LeaveCriticalSection(&csApartment);
287         }
288     }
289
290     return apt;
291 }
292
293 static inline BOOL apartment_is_model(APARTMENT *apt, DWORD model)
294 {
295     return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
296 }
297
298 DWORD apartment_addref(struct apartment *apt)
299 {
300     DWORD refs = InterlockedIncrement(&apt->refs);
301     TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
302     return refs;
303 }
304
305 DWORD apartment_release(struct apartment *apt)
306 {
307     DWORD ret;
308
309     EnterCriticalSection(&csApartment);
310
311     ret = InterlockedDecrement(&apt->refs);
312     TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
313     /* destruction stuff that needs to happen under csApartment CS */
314     if (ret == 0)
315     {
316         if (apt == MTA) MTA = NULL;
317         list_remove(&apt->entry);
318     }
319
320     LeaveCriticalSection(&csApartment);
321
322     if (ret == 0)
323     {
324         struct list *cursor, *cursor2;
325
326         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
327
328         /* no locking is needed for this apartment, because no other thread
329          * can access it at this point */
330
331         apartment_disconnectproxies(apt);
332
333         if (apt->win) DestroyWindow(apt->win);
334
335         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
336         {
337             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
338             /* release the implicit reference given by the fact that the
339              * stub has external references (it must do since it is in the
340              * stub manager list in the apartment and all non-apartment users
341              * must have a ref on the apartment and so it cannot be destroyed).
342              */
343             stub_manager_int_release(stubmgr);
344         }
345
346         /* if this assert fires, then another thread took a reference to a
347          * stub manager without taking a reference to the containing
348          * apartment, which it must do. */
349         assert(list_empty(&apt->stubmgrs));
350
351         if (apt->filter) IUnknown_Release(apt->filter);
352
353         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
354         DeleteCriticalSection(&apt->cs);
355
356         HeapFree(GetProcessHeap(), 0, apt);
357     }
358
359     return ret;
360 }
361
362 /* The given OXID must be local to this process: 
363  *
364  * The ref parameter is here mostly to ensure people remember that
365  * they get one, you should normally take a ref for thread safety.
366  */
367 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
368 {
369     APARTMENT *result = NULL;
370     struct list *cursor;
371
372     EnterCriticalSection(&csApartment);
373     LIST_FOR_EACH( cursor, &apts )
374     {
375         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
376         if (apt->oxid == oxid)
377         {
378             result = apt;
379             if (ref) apartment_addref(result);
380             break;
381         }
382     }
383     LeaveCriticalSection(&csApartment);
384
385     return result;
386 }
387
388 /* gets the apartment which has a given creator thread ID. The caller must
389  * release the reference from the apartment as soon as the apartment pointer
390  * is no longer required. */
391 APARTMENT *apartment_findfromtid(DWORD tid)
392 {
393     APARTMENT *result = NULL;
394     struct list *cursor;
395
396     EnterCriticalSection(&csApartment);
397     LIST_FOR_EACH( cursor, &apts )
398     {
399         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
400         if (apt->tid == tid)
401         {
402             result = apt;
403             apartment_addref(result);
404             break;
405         }
406     }
407     LeaveCriticalSection(&csApartment);
408
409     return result;
410 }
411
412 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
413 {
414     switch (msg)
415     {
416     case DM_EXECUTERPC:
417         RPC_ExecuteCall((struct dispatch_params *)lParam);
418         return 0;
419     default:
420         return DefWindowProcW(hWnd, msg, wParam, lParam);
421     }
422 }
423
424 HRESULT apartment_createwindowifneeded(struct apartment *apt)
425 {
426     if (apt->multi_threaded)
427         return S_OK;
428
429     if (!apt->win)
430     {
431         HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
432                                   0, 0, 0, 0,
433                                   0, 0, OLE32_hInstance, NULL);
434         if (!hwnd)
435         {
436             ERR("CreateWindow failed with error %ld\n", GetLastError());
437             return HRESULT_FROM_WIN32(GetLastError());
438         }
439         if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
440             /* someone beat us to it */
441             DestroyWindow(hwnd);
442     }
443
444     return S_OK;
445 }
446
447 HWND apartment_getwindow(struct apartment *apt)
448 {
449     assert(!apt->multi_threaded);
450     return apt->win;
451 }
452
453 void apartment_joinmta(void)
454 {
455     apartment_addref(MTA);
456     COM_CurrentInfo()->apt = MTA;
457 }
458
459 /*****************************************************************************
460  * This section contains OpenDllList implemantation
461  */
462
463 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
464 {
465     OpenDll *ptr;
466     OpenDll *tmp;
467
468     TRACE("\n");
469
470     EnterCriticalSection( &csOpenDllList );
471
472     if (openDllList == NULL) {
473         /* empty list -- add first node */
474         openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
475         openDllList->hLibrary=hLibrary;
476         openDllList->next = NULL;
477     } else {
478         /* search for this dll */
479         int found = FALSE;
480         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
481             if (ptr->hLibrary == hLibrary) {
482                 found = TRUE;
483                 break;
484             }
485         }
486         if (!found) {
487             /* dll not found, add it */
488             tmp = openDllList;
489             openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
490             openDllList->hLibrary = hLibrary;
491             openDllList->next = tmp;
492         }
493     }
494
495     LeaveCriticalSection( &csOpenDllList );
496 }
497
498 static void COMPOBJ_DllList_FreeUnused(int Timeout)
499 {
500     OpenDll *curr, *next, *prev = NULL;
501     typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
502     DllCanUnloadNowFunc DllCanUnloadNow;
503
504     TRACE("\n");
505
506     EnterCriticalSection( &csOpenDllList );
507
508     for (curr = openDllList; curr != NULL; ) {
509         DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
510
511         if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
512             next = curr->next;
513
514             TRACE("freeing %p\n", curr->hLibrary);
515             FreeLibrary(curr->hLibrary);
516
517             HeapFree(GetProcessHeap(), 0, curr);
518             if (curr == openDllList) {
519                 openDllList = next;
520             } else {
521               prev->next = next;
522             }
523
524             curr = next;
525         } else {
526             prev = curr;
527             curr = curr->next;
528         }
529     }
530
531     LeaveCriticalSection( &csOpenDllList );
532 }
533
534 /******************************************************************************
535  *           CoBuildVersion [OLE32.@]
536  *           CoBuildVersion [COMPOBJ.1]
537  *
538  * Gets the build version of the DLL.
539  *
540  * PARAMS
541  *
542  * RETURNS
543  *      Current build version, hiword is majornumber, loword is minornumber
544  */
545 DWORD WINAPI CoBuildVersion(void)
546 {
547     TRACE("Returning version %d, build %d.\n", rmm, rup);
548     return (rmm<<16)+rup;
549 }
550
551 /******************************************************************************
552  *              CoInitialize    [OLE32.@]
553  *
554  * Initializes the COM libraries by calling CoInitializeEx with
555  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
556  *
557  * PARAMS
558  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
559  *
560  * RETURNS
561  *  Success: S_OK if not already initialized, S_FALSE otherwise.
562  *  Failure: HRESULT code.
563  *
564  * SEE ALSO
565  *   CoInitializeEx
566  */
567 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
568 {
569   /*
570    * Just delegate to the newer method.
571    */
572   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
573 }
574
575 /******************************************************************************
576  *              CoInitializeEx  [OLE32.@]
577  *
578  * Initializes the COM libraries.
579  *
580  * PARAMS
581  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
582  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
583  *
584  * RETURNS
585  *  S_OK               if successful,
586  *  S_FALSE            if this function was called already.
587  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
588  *                     threading model.
589  *
590  * NOTES
591  *
592  * The behavior used to set the IMalloc used for memory management is
593  * obsolete.
594  * The dwCoInit parameter must specify of of the following apartment
595  * threading models:
596  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
597  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
598  * The parameter may also specify zero or more of the following flags:
599  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
600  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
601  *
602  * SEE ALSO
603  *   CoUninitialize
604  */
605 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
606 {
607   HRESULT hr = S_OK;
608   APARTMENT *apt;
609
610   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
611
612   if (lpReserved!=NULL)
613   {
614     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
615   }
616
617   /*
618    * Check the lock count. If this is the first time going through the initialize
619    * process, we have to initialize the libraries.
620    *
621    * And crank-up that lock count.
622    */
623   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
624   {
625     /*
626      * Initialize the various COM libraries and data structures.
627      */
628     TRACE("() - Initializing the COM libraries\n");
629
630     /* we may need to defer this until after apartment initialisation */
631     RunningObjectTableImpl_Initialize();
632   }
633
634   if (!(apt = COM_CurrentInfo()->apt))
635   {
636     apt = apartment_get_or_create(dwCoInit);
637     if (!apt) return E_OUTOFMEMORY;
638   }
639   else if (!apartment_is_model(apt, dwCoInit))
640   {
641     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
642        code then we are probably using the wrong threading model to implement that API. */
643     ERR("Attempt to change threading model of this apartment from %s to %s\n",
644         apt->multi_threaded ? "multi-threaded" : "apartment threaded",
645         dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
646     return RPC_E_CHANGED_MODE;
647   }
648   else
649     hr = S_FALSE;
650
651   COM_CurrentInfo()->inits++;
652
653   return hr;
654 }
655
656 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
657    pending RPCs are ignored. Non-COM messages are discarded at this point.
658  */
659 static void COM_FlushMessageQueue(void)
660 {
661     MSG message;
662     APARTMENT *apt = COM_CurrentApt();
663
664     if (!apt || !apt->win) return;
665
666     TRACE("Flushing STA message queue\n");
667
668     while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
669     {
670         if (message.hwnd != apt->win)
671         {
672             WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
673             continue;
674         }
675
676         TranslateMessage(&message);
677         DispatchMessageA(&message);
678     }
679 }
680
681 /***********************************************************************
682  *           CoUninitialize   [OLE32.@]
683  *
684  * This method will decrement the refcount on the current apartment, freeing
685  * the resources associated with it if it is the last thread in the apartment.
686  * If the last apartment is freed, the function will additionally release
687  * any COM resources associated with the process.
688  *
689  * PARAMS
690  *
691  * RETURNS
692  *  Nothing.
693  *
694  * SEE ALSO
695  *   CoInitializeEx
696  */
697 void WINAPI CoUninitialize(void)
698 {
699   struct oletls * info = COM_CurrentInfo();
700   LONG lCOMRefCnt;
701
702   TRACE("()\n");
703
704   /* will only happen on OOM */
705   if (!info) return;
706
707   /* sanity check */
708   if (!info->inits)
709   {
710     ERR("Mismatched CoUninitialize\n");
711     return;
712   }
713
714   if (!--info->inits)
715   {
716     apartment_release(info->apt);
717     info->apt = NULL;
718   }
719
720   /*
721    * Decrease the reference count.
722    * If we are back to 0 locks on the COM library, make sure we free
723    * all the associated data structures.
724    */
725   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
726   if (lCOMRefCnt==1)
727   {
728     TRACE("() - Releasing the COM libraries\n");
729
730     RunningObjectTableImpl_UnInitialize();
731
732     /* Release the references to the registered class objects */
733     COM_RevokeAllClasses();
734
735     /* This will free the loaded COM Dlls  */
736     CoFreeAllLibraries();
737
738     /* This ensures we deal with any pending RPCs */
739     COM_FlushMessageQueue();
740   }
741   else if (lCOMRefCnt<1) {
742     ERR( "CoUninitialize() - not CoInitialized.\n" );
743     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
744   }
745 }
746
747 /******************************************************************************
748  *              CoDisconnectObject      [OLE32.@]
749  *              CoDisconnectObject      [COMPOBJ.15]
750  *
751  * Disconnects all connections to this object from remote processes. Dispatches
752  * pending RPCs while blocking new RPCs from occurring, and then calls
753  * IMarshal::DisconnectObject on the given object.
754  *
755  * Typically called when the object server is forced to shut down, for instance by
756  * the user.
757  *
758  * PARAMS
759  *  lpUnk    [I] The object whose stub should be disconnected.
760  *  reserved [I] Reserved. Should be set to 0.
761  *
762  * RETURNS
763  *  Success: S_OK.
764  *  Failure: HRESULT code.
765  *
766  * SEE ALSO
767  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
768  */
769 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
770 {
771     HRESULT hr;
772     IMarshal *marshal;
773     APARTMENT *apt;
774
775     TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
776
777     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
778     if (hr == S_OK)
779     {
780         hr = IMarshal_DisconnectObject(marshal, reserved);
781         IMarshal_Release(marshal);
782         return hr;
783     }
784
785     apt = COM_CurrentApt();
786     if (!apt)
787         return CO_E_NOTINITIALIZED;
788
789     apartment_disconnectobject(apt, lpUnk);
790
791     /* Note: native is pretty broken here because it just silently
792      * fails, without returning an appropriate error code if the object was
793      * not found, making apps think that the object was disconnected, when
794      * it actually wasn't */
795
796     return S_OK;
797 }
798
799 /******************************************************************************
800  *              CoCreateGuid [OLE32.@]
801  *
802  * Simply forwards to UuidCreate in RPCRT4.
803  *
804  * PARAMS
805  *  pguid [O] Points to the GUID to initialize.
806  *
807  * RETURNS
808  *  Success: S_OK.
809  *  Failure: HRESULT code.
810  *
811  * SEE ALSO
812  *   UuidCreate
813  */
814 HRESULT WINAPI CoCreateGuid(GUID *pguid)
815 {
816     return UuidCreate(pguid);
817 }
818
819 /******************************************************************************
820  *              CLSIDFromString [OLE32.@]
821  *              IIDFromString   [OLE32.@]
822  *
823  * Converts a unique identifier from its string representation into
824  * the GUID struct.
825  *
826  * PARAMS
827  *  idstr [I] The string representation of the GUID.
828  *  id    [O] GUID converted from the string.
829  *
830  * RETURNS
831  *   S_OK on success
832  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
833  *
834  * SEE ALSO
835  *  StringFromCLSID
836  */
837 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
838 {
839   int   i;
840   BYTE table[256];
841
842   if (!s) {
843     memset( id, 0, sizeof (CLSID) );
844     return S_OK;
845   }
846
847   /* validate the CLSID string */
848   if (strlenW(s) != 38)
849     return CO_E_CLASSSTRING;
850
851   if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
852     return CO_E_CLASSSTRING;
853
854   for (i=1; i<37; i++) {
855     if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
856     if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
857           ((s[i] >= 'a') && (s[i] <= 'f'))  ||
858           ((s[i] >= 'A') && (s[i] <= 'F'))))
859        return CO_E_CLASSSTRING;
860   }
861
862   TRACE("%s -> %p\n", debugstr_w(s), id);
863
864   /* quick lookup table */
865   memset(table, 0, 256);
866
867   for (i = 0; i < 10; i++) {
868     table['0' + i] = i;
869   }
870   for (i = 0; i < 6; i++) {
871     table['A' + i] = i+10;
872     table['a' + i] = i+10;
873   }
874
875   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
876
877   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
878                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
879   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
880   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
881
882   /* these are just sequential bytes */
883   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
884   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
885   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
886   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
887   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
888   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
889   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
890   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
891
892   return S_OK;
893 }
894
895 /*****************************************************************************/
896
897 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
898 {
899     HRESULT ret;
900
901     ret = __CLSIDFromString(idstr, id);
902     if(ret != S_OK) { /* It appears a ProgID is also valid */
903         ret = CLSIDFromProgID(idstr, id);
904     }
905     return ret;
906 }
907
908 /* Converts a GUID into the respective string representation. */
909 HRESULT WINE_StringFromCLSID(
910         const CLSID *id,        /* [in] GUID to be converted */
911         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
912 ) {
913   static const char *hex = "0123456789ABCDEF";
914   char *s;
915   int   i;
916
917   if (!id)
918         { ERR("called with id=Null\n");
919           *idstr = 0x00;
920           return E_FAIL;
921         }
922
923   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
924           id->Data1, id->Data2, id->Data3,
925           id->Data4[0], id->Data4[1]);
926   s = &idstr[25];
927
928   /* 6 hex bytes */
929   for (i = 2; i < 8; i++) {
930     *s++ = hex[id->Data4[i]>>4];
931     *s++ = hex[id->Data4[i] & 0xf];
932   }
933
934   *s++ = '}';
935   *s++ = '\0';
936
937   TRACE("%p->%s\n", id, idstr);
938
939   return S_OK;
940 }
941
942
943 /******************************************************************************
944  *              StringFromCLSID [OLE32.@]
945  *              StringFromIID   [OLE32.@]
946  *
947  * Converts a GUID into the respective string representation.
948  * The target string is allocated using the OLE IMalloc.
949  *
950  * PARAMS
951  *  id    [I] the GUID to be converted.
952  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
953  *
954  * RETURNS
955  *   S_OK
956  *   E_FAIL
957  *
958  * SEE ALSO
959  *  StringFromGUID2, CLSIDFromString
960  */
961 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
962 {
963         char            buf[80];
964         HRESULT       ret;
965         LPMALLOC        mllc;
966
967         if ((ret = CoGetMalloc(0,&mllc)))
968                 return ret;
969
970         ret=WINE_StringFromCLSID(id,buf);
971         if (!ret) {
972             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
973             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
974             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
975         }
976         return ret;
977 }
978
979 /******************************************************************************
980  *              StringFromGUID2 [OLE32.@]
981  *              StringFromGUID2 [COMPOBJ.76]
982  *
983  * Modified version of StringFromCLSID that allows you to specify max
984  * buffer size.
985  *
986  * PARAMS
987  *  id   [I] GUID to convert to string.
988  *  str  [O] Buffer where the result will be stored.
989  *  cmax [I] Size of the buffer in characters.
990  *
991  * RETURNS
992  *      Success: The length of the resulting string in characters.
993  *  Failure: 0.
994  */
995 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
996 {
997   char          xguid[80];
998
999   if (WINE_StringFromCLSID(id,xguid))
1000         return 0;
1001   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1002 }
1003
1004 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1005 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1006 {
1007     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1008     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1009     LONG res;
1010     HKEY key;
1011
1012     strcpyW(path, wszCLSIDSlash);
1013     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1014     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1015     if (res == ERROR_FILE_NOT_FOUND)
1016         return REGDB_E_CLASSNOTREG;
1017     else if (res != ERROR_SUCCESS)
1018         return REGDB_E_READREGDB;
1019
1020     if (!keyname)
1021     {
1022         *subkey = key;
1023         return S_OK;
1024     }
1025
1026     res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1027     RegCloseKey(key);
1028     if (res == ERROR_FILE_NOT_FOUND)
1029         return REGDB_E_KEYMISSING;
1030     else if (res != ERROR_SUCCESS)
1031         return REGDB_E_READREGDB;
1032
1033     return S_OK;
1034 }
1035
1036 /******************************************************************************
1037  *               ProgIDFromCLSID [OLE32.@]
1038  *
1039  * Converts a class id into the respective program ID.
1040  *
1041  * PARAMS
1042  *  clsid        [I] Class ID, as found in registry.
1043  *  lplpszProgID [O] Associated ProgID.
1044  *
1045  * RETURNS
1046  *   S_OK
1047  *   E_OUTOFMEMORY
1048  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1049  */
1050 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1051 {
1052     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1053     HKEY     hkey;
1054     HRESULT  ret;
1055     LONG progidlen = 0;
1056
1057     *lplpszProgID = NULL;
1058     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1059     if (FAILED(ret))
1060         return ret;
1061
1062     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1063       ret = REGDB_E_CLASSNOTREG;
1064
1065     if (ret == S_OK)
1066     {
1067       *lplpszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1068       if (*lplpszProgID)
1069       {
1070         if (RegQueryValueW(hkey, NULL, *lplpszProgID, &progidlen))
1071           ret = REGDB_E_CLASSNOTREG;
1072       }
1073       else
1074         ret = E_OUTOFMEMORY;
1075     }
1076
1077     RegCloseKey(hkey);
1078     return ret;
1079 }
1080
1081 /******************************************************************************
1082  *              CLSIDFromProgID [OLE32.@]
1083  *
1084  * Converts a program id into the respective GUID.
1085  *
1086  * PARAMS
1087  *  progid [I] Unicode program ID, as found in registry.
1088  *  riid   [O] Associated CLSID.
1089  *
1090  * RETURNS
1091  *      Success: S_OK
1092  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1093  */
1094 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1095 {
1096     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1097     WCHAR buf2[CHARS_IN_GUID];
1098     LONG buf2len = sizeof(buf2);
1099     HKEY xhkey;
1100
1101     WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1102     strcpyW( buf, progid );
1103     strcatW( buf, clsidW );
1104     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1105     {
1106         HeapFree(GetProcessHeap(),0,buf);
1107         return CO_E_CLASSSTRING;
1108     }
1109     HeapFree(GetProcessHeap(),0,buf);
1110
1111     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1112     {
1113         RegCloseKey(xhkey);
1114         return CO_E_CLASSSTRING;
1115     }
1116     RegCloseKey(xhkey);
1117     return CLSIDFromString(buf2,riid);
1118 }
1119
1120
1121 /*****************************************************************************
1122  *             CoGetPSClsid [OLE32.@]
1123  *
1124  * Retrieves the CLSID of the proxy/stub factory that implements
1125  * IPSFactoryBuffer for the specified interface.
1126  *
1127  * PARAMS
1128  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
1129  *  pclsid [O] Where to store returned proxy/stub CLSID.
1130  * 
1131  * RETURNS
1132  *   S_OK
1133  *   E_OUTOFMEMORY
1134  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1135  *
1136  * NOTES
1137  *
1138  * The standard marshaller activates the object with the CLSID
1139  * returned and uses the CreateProxy and CreateStub methods on its
1140  * IPSFactoryBuffer interface to construct the proxies and stubs for a
1141  * given object.
1142  *
1143  * CoGetPSClsid determines this CLSID by searching the
1144  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1145  * in the registry and any interface id registered by
1146  * CoRegisterPSClsid within the current process.
1147  *
1148  * BUGS
1149  *
1150  * We only search the registry, not ids registered with
1151  * CoRegisterPSClsid.
1152  * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1153  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1154  * considered a bug in native unless an application depends on this (unlikely).
1155  */
1156 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1157 {
1158     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1159     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1160     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1161     WCHAR value[CHARS_IN_GUID];
1162     LONG len;
1163     HKEY hkey;
1164
1165     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1166
1167     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1168     strcpyW(path, wszInterface);
1169     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1170     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1171
1172     /* Open the key.. */
1173     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1174     {
1175         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1176         return REGDB_E_IIDNOTREG;
1177     }
1178
1179     /* ... Once we have the key, query the registry to get the
1180        value of CLSID as a string, and convert it into a
1181        proper CLSID structure to be passed back to the app */
1182     len = sizeof(value);
1183     if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1184     {
1185         RegCloseKey(hkey);
1186         return REGDB_E_IIDNOTREG;
1187     }
1188     RegCloseKey(hkey);
1189
1190     /* We have the CLSid we want back from the registry as a string, so
1191        lets convert it into a CLSID structure */
1192     if (CLSIDFromString(value, pclsid) != NOERROR)
1193         return REGDB_E_IIDNOTREG;
1194
1195     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1196     return S_OK;
1197 }
1198
1199
1200
1201 /***********************************************************************
1202  *              WriteClassStm (OLE32.@)
1203  *
1204  * Writes a CLSID to a stream.
1205  *
1206  * PARAMS
1207  *  pStm   [I] Stream to write to.
1208  *  rclsid [I] CLSID to write.
1209  *
1210  * RETURNS
1211  *  Success: S_OK.
1212  *  Failure: HRESULT code.
1213  */
1214 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1215 {
1216     TRACE("(%p,%p)\n",pStm,rclsid);
1217
1218     if (rclsid==NULL)
1219         return E_INVALIDARG;
1220
1221     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1222 }
1223
1224 /***********************************************************************
1225  *              ReadClassStm (OLE32.@)
1226  *
1227  * Reads a CLSID from a stream.
1228  *
1229  * PARAMS
1230  *  pStm   [I] Stream to read from.
1231  *  rclsid [O] CLSID to read.
1232  *
1233  * RETURNS
1234  *  Success: S_OK.
1235  *  Failure: HRESULT code.
1236  */
1237 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1238 {
1239     ULONG nbByte;
1240     HRESULT res;
1241
1242     TRACE("(%p,%p)\n",pStm,pclsid);
1243
1244     if (pclsid==NULL)
1245         return E_INVALIDARG;
1246
1247     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1248
1249     if (FAILED(res))
1250         return res;
1251
1252     if (nbByte != sizeof(CLSID))
1253         return S_FALSE;
1254     else
1255         return S_OK;
1256 }
1257
1258
1259 /***
1260  * COM_GetRegisteredClassObject
1261  *
1262  * This internal method is used to scan the registered class list to
1263  * find a class object.
1264  *
1265  * Params:
1266  *   rclsid        Class ID of the class to find.
1267  *   dwClsContext  Class context to match.
1268  *   ppv           [out] returns a pointer to the class object. Complying
1269  *                 to normal COM usage, this method will increase the
1270  *                 reference count on this object.
1271  */
1272 static HRESULT COM_GetRegisteredClassObject(
1273         REFCLSID    rclsid,
1274         DWORD       dwClsContext,
1275         LPUNKNOWN*  ppUnk)
1276 {
1277   HRESULT hr = S_FALSE;
1278   RegisteredClass* curClass;
1279
1280   EnterCriticalSection( &csRegisteredClassList );
1281
1282   /*
1283    * Sanity check
1284    */
1285   assert(ppUnk!=0);
1286
1287   /*
1288    * Iterate through the whole list and try to match the class ID.
1289    */
1290   curClass = firstRegisteredClass;
1291
1292   while (curClass != 0)
1293   {
1294     /*
1295      * Check if we have a match on the class ID.
1296      */
1297     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1298     {
1299       /*
1300        * Since we don't do out-of process or DCOM just right away, let's ignore the
1301        * class context.
1302        */
1303
1304       /*
1305        * We have a match, return the pointer to the class object.
1306        */
1307       *ppUnk = curClass->classObject;
1308
1309       IUnknown_AddRef(curClass->classObject);
1310
1311       hr = S_OK;
1312       goto end;
1313     }
1314
1315     /*
1316      * Step to the next class in the list.
1317      */
1318     curClass = curClass->nextClass;
1319   }
1320
1321 end:
1322   LeaveCriticalSection( &csRegisteredClassList );
1323   /*
1324    * If we get to here, we haven't found our class.
1325    */
1326   return hr;
1327 }
1328
1329 /******************************************************************************
1330  *              CoRegisterClassObject   [OLE32.@]
1331  *
1332  * Registers the class object for a given class ID. Servers housed in EXE
1333  * files use this method instead of exporting DllGetClassObject to allow
1334  * other code to connect to their objects.
1335  *
1336  * PARAMS
1337  *  rclsid       [I] CLSID of the object to register.
1338  *  pUnk         [I] IUnknown of the object.
1339  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1340  *  flags        [I] REGCLS flags indicating how connections are made.
1341  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1342  *
1343  * RETURNS
1344  *   S_OK on success,
1345  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
1346  *   CO_E_OBJISREG if the object is already registered. We should not return this.
1347  *
1348  * SEE ALSO
1349  *   CoRevokeClassObject, CoGetClassObject
1350  *
1351  * BUGS
1352  *  MSDN claims that multiple interface registrations are legal, but we
1353  *  can't do that with our current implementation.
1354  */
1355 HRESULT WINAPI CoRegisterClassObject(
1356     REFCLSID rclsid,
1357     LPUNKNOWN pUnk,
1358     DWORD dwClsContext,
1359     DWORD flags,
1360     LPDWORD lpdwRegister)
1361 {
1362   RegisteredClass* newClass;
1363   LPUNKNOWN        foundObject;
1364   HRESULT          hr;
1365
1366   TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1367         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1368
1369   if ( (lpdwRegister==0) || (pUnk==0) )
1370     return E_INVALIDARG;
1371
1372   if (!COM_CurrentApt())
1373   {
1374       ERR("COM was not initialized\n");
1375       return CO_E_NOTINITIALIZED;
1376   }
1377
1378   *lpdwRegister = 0;
1379
1380   /*
1381    * First, check if the class is already registered.
1382    * If it is, this should cause an error.
1383    */
1384   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1385   if (hr == S_OK) {
1386     if (flags & REGCLS_MULTIPLEUSE) {
1387       if (dwClsContext & CLSCTX_LOCAL_SERVER)
1388         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1389       IUnknown_Release(foundObject);
1390       return hr;
1391     }
1392     IUnknown_Release(foundObject);
1393     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1394     return CO_E_OBJISREG;
1395   }
1396
1397   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1398   if ( newClass == NULL )
1399     return E_OUTOFMEMORY;
1400
1401   EnterCriticalSection( &csRegisteredClassList );
1402
1403   newClass->classIdentifier = *rclsid;
1404   newClass->runContext      = dwClsContext;
1405   newClass->connectFlags    = flags;
1406   newClass->pMarshaledData  = NULL;
1407
1408   /*
1409    * Use the address of the chain node as the cookie since we are sure it's
1410    * unique. FIXME: not on 64-bit platforms.
1411    */
1412   newClass->dwCookie        = (DWORD)newClass;
1413   newClass->nextClass       = firstRegisteredClass;
1414
1415   /*
1416    * Since we're making a copy of the object pointer, we have to increase its
1417    * reference count.
1418    */
1419   newClass->classObject     = pUnk;
1420   IUnknown_AddRef(newClass->classObject);
1421
1422   firstRegisteredClass = newClass;
1423   LeaveCriticalSection( &csRegisteredClassList );
1424
1425   *lpdwRegister = newClass->dwCookie;
1426
1427   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1428       IClassFactory *classfac;
1429
1430       hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1431                                    (LPVOID*)&classfac);
1432       if (hr) return hr;
1433
1434       hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1435       if (hr) {
1436           FIXME("Failed to create stream on hglobal, %lx\n", hr);
1437           IUnknown_Release(classfac);
1438           return hr;
1439       }
1440       hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1441                               (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1442                               MSHLFLAGS_TABLESTRONG);
1443       if (hr) {
1444           FIXME("CoMarshalInterface failed, %lx!\n",hr);
1445           IUnknown_Release(classfac);
1446           return hr;
1447       }
1448
1449       IUnknown_Release(classfac);
1450
1451       RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1452   }
1453   return S_OK;
1454 }
1455
1456 /***********************************************************************
1457  *           CoRevokeClassObject [OLE32.@]
1458  *
1459  * Removes a class object from the class registry.
1460  *
1461  * PARAMS
1462  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
1463  *
1464  * RETURNS
1465  *  Success: S_OK.
1466  *  Failure: HRESULT code.
1467  *
1468  * SEE ALSO
1469  *  CoRegisterClassObject
1470  */
1471 HRESULT WINAPI CoRevokeClassObject(
1472         DWORD dwRegister)
1473 {
1474   HRESULT hr = E_INVALIDARG;
1475   RegisteredClass** prevClassLink;
1476   RegisteredClass*  curClass;
1477
1478   TRACE("(%08lx)\n",dwRegister);
1479
1480   EnterCriticalSection( &csRegisteredClassList );
1481
1482   /*
1483    * Iterate through the whole list and try to match the cookie.
1484    */
1485   curClass      = firstRegisteredClass;
1486   prevClassLink = &firstRegisteredClass;
1487
1488   while (curClass != 0)
1489   {
1490     /*
1491      * Check if we have a match on the cookie.
1492      */
1493     if (curClass->dwCookie == dwRegister)
1494     {
1495       /*
1496        * Remove the class from the chain.
1497        */
1498       *prevClassLink = curClass->nextClass;
1499
1500       /*
1501        * Release the reference to the class object.
1502        */
1503       IUnknown_Release(curClass->classObject);
1504
1505       if (curClass->pMarshaledData)
1506       {
1507         LARGE_INTEGER zero;
1508         memset(&zero, 0, sizeof(zero));
1509         /* FIXME: stop local server thread */
1510         IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1511         CoReleaseMarshalData(curClass->pMarshaledData);
1512       }
1513
1514       /*
1515        * Free the memory used by the chain node.
1516        */
1517       HeapFree(GetProcessHeap(), 0, curClass);
1518
1519       hr = S_OK;
1520       goto end;
1521     }
1522
1523     /*
1524      * Step to the next class in the list.
1525      */
1526     prevClassLink = &(curClass->nextClass);
1527     curClass      = curClass->nextClass;
1528   }
1529
1530 end:
1531   LeaveCriticalSection( &csRegisteredClassList );
1532   /*
1533    * If we get to here, we haven't found our class.
1534    */
1535   return hr;
1536 }
1537
1538 /***********************************************************************
1539  *      COM_RegReadPath [internal]
1540  *
1541  *      Reads a registry value and expands it when necessary
1542  */
1543 HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
1544 {
1545         HRESULT hres;
1546         HKEY key;
1547         DWORD keytype;
1548         WCHAR src[MAX_PATH];
1549         DWORD dwLength = dstlen * sizeof(WCHAR);
1550
1551         if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1552           if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1553             if (keytype == REG_EXPAND_SZ) {
1554               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1555             } else {
1556               lstrcpynW(dst, src, dstlen);
1557             }
1558           }
1559           RegCloseKey (key);
1560         }
1561         return hres;
1562 }
1563
1564 static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1565 {
1566     HINSTANCE hLibrary;
1567     typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1568     DllGetClassObjectFunc DllGetClassObject;
1569     WCHAR dllpath[MAX_PATH+1];
1570
1571     if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1572     {
1573         /* failure: CLSID is not found in registry */
1574         WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
1575         return REGDB_E_CLASSNOTREG;
1576     }
1577
1578     if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
1579     {
1580         /* failure: DLL could not be loaded */
1581         ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
1582         return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1583     }
1584
1585     if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
1586     {
1587         /* failure: the dll did not export DllGetClassObject */
1588         ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
1589         FreeLibrary( hLibrary );
1590         return CO_E_DLLNOTFOUND;
1591     }
1592
1593     /* OK: get the ClassObject */
1594     COMPOBJ_DLLList_Add( hLibrary );
1595     return DllGetClassObject(rclsid, riid, ppv);
1596 }
1597
1598 /***********************************************************************
1599  *           CoGetClassObject [OLE32.@]
1600  *
1601  * FIXME.  If request allows of several options and there is a failure
1602  *         with one (other than not being registered) do we try the
1603  *         others or return failure?  (E.g. inprocess is registered but
1604  *         the DLL is not found but the server version works)
1605  */
1606 HRESULT WINAPI CoGetClassObject(
1607     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1608     REFIID iid, LPVOID *ppv)
1609 {
1610     LPUNKNOWN   regClassObject;
1611     HRESULT     hres = E_UNEXPECTED;
1612
1613     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1614
1615     if (pServerInfo) {
1616         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1617         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1618     }
1619
1620     /*
1621      * First, try and see if we can't match the class ID with one of the
1622      * registered classes.
1623      */
1624     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1625     {
1626       /* Get the required interface from the retrieved pointer. */
1627       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1628
1629       /*
1630        * Since QI got another reference on the pointer, we want to release the
1631        * one we already have. If QI was unsuccessful, this will release the object. This
1632        * is good since we are not returning it in the "out" parameter.
1633        */
1634       IUnknown_Release(regClassObject);
1635
1636       return hres;
1637     }
1638
1639     /* First try in-process server */
1640     if (CLSCTX_INPROC_SERVER & dwClsContext)
1641     {
1642         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
1643         HKEY hkey;
1644
1645         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
1646             return FTMarshalCF_Create(iid, ppv);
1647
1648         hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
1649         if (FAILED(hres))
1650         {
1651             if (hres == REGDB_E_CLASSNOTREG)
1652                 ERR("class %s not registered\n", debugstr_guid(rclsid));
1653             else
1654                 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1655         }
1656
1657         if (SUCCEEDED(hres))
1658         {
1659             hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1660             RegCloseKey(hkey);
1661         }
1662
1663         /* return if we got a class, otherwise fall through to one of the
1664          * other types */
1665         if (SUCCEEDED(hres))
1666             return hres;
1667     }
1668
1669     /* Next try in-process handler */
1670     if (CLSCTX_INPROC_HANDLER & dwClsContext)
1671     {
1672         static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
1673         HKEY hkey;
1674
1675         hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
1676         if (FAILED(hres))
1677         {
1678             if (hres == REGDB_E_CLASSNOTREG)
1679                 ERR("class %s not registered\n", debugstr_guid(rclsid));
1680             else
1681                 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1682         }
1683
1684         if (SUCCEEDED(hres))
1685         {
1686             hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
1687             RegCloseKey(hkey);
1688         }
1689
1690         /* return if we got a class, otherwise fall through to one of the
1691          * other types */
1692         if (SUCCEEDED(hres))
1693             return hres;
1694     }
1695
1696     /* Next try out of process */
1697     if (CLSCTX_LOCAL_SERVER & dwClsContext)
1698     {
1699         hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
1700         if (SUCCEEDED(hres))
1701             return hres;
1702     }
1703
1704     /* Finally try remote: this requires networked DCOM (a lot of work) */
1705     if (CLSCTX_REMOTE_SERVER & dwClsContext)
1706     {
1707         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1708         hres = E_NOINTERFACE;
1709     }
1710
1711     if (FAILED(hres))
1712         ERR("no class object %s could be created for context 0x%lx\n",
1713             debugstr_guid(rclsid), dwClsContext);
1714     return hres;
1715 }
1716
1717 /***********************************************************************
1718  *        CoResumeClassObjects (OLE32.@)
1719  *
1720  * Resumes all class objects registered with REGCLS_SUSPENDED.
1721  *
1722  * RETURNS
1723  *  Success: S_OK.
1724  *  Failure: HRESULT code.
1725  */
1726 HRESULT WINAPI CoResumeClassObjects(void)
1727 {
1728        FIXME("stub\n");
1729         return S_OK;
1730 }
1731
1732 /***********************************************************************
1733  *        GetClassFile (OLE32.@)
1734  *
1735  * This function supplies the CLSID associated with the given filename.
1736  */
1737 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1738 {
1739     IStorage *pstg=0;
1740     HRESULT res;
1741     int nbElm, length, i;
1742     LONG sizeProgId;
1743     LPOLESTR *pathDec=0,absFile=0,progId=0;
1744     LPWSTR extension;
1745     static const WCHAR bkslashW[] = {'\\',0};
1746     static const WCHAR dotW[] = {'.',0};
1747
1748     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1749
1750     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1751     if((StgIsStorageFile(filePathName))==S_OK){
1752
1753         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1754
1755         if (SUCCEEDED(res))
1756             res=ReadClassStg(pstg,pclsid);
1757
1758         IStorage_Release(pstg);
1759
1760         return res;
1761     }
1762     /* if the file is not a storage object then attemps to match various bits in the file against a
1763        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1764        this case
1765
1766      for(i=0;i<nFileTypes;i++)
1767
1768         for(i=0;j<nPatternsForType;j++){
1769
1770             PATTERN pat;
1771             HANDLE  hFile;
1772
1773             pat=ReadPatternFromRegistry(i,j);
1774             hFile=CreateFileW(filePathName,,,,,,hFile);
1775             SetFilePosition(hFile,pat.offset);
1776             ReadFile(hFile,buf,pat.size,&r,NULL);
1777             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1778
1779                 *pclsid=ReadCLSIDFromRegistry(i);
1780                 return S_OK;
1781             }
1782         }
1783      */
1784
1785     /* if the above strategies fail then search for the extension key in the registry */
1786
1787     /* get the last element (absolute file) in the path name */
1788     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1789     absFile=pathDec[nbElm-1];
1790
1791     /* failed if the path represente a directory and not an absolute file name*/
1792     if (!lstrcmpW(absFile, bkslashW))
1793         return MK_E_INVALIDEXTENSION;
1794
1795     /* get the extension of the file */
1796     extension = NULL;
1797     length=lstrlenW(absFile);
1798     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1799         /* nothing */;
1800
1801     if (!extension || !lstrcmpW(extension, dotW))
1802         return MK_E_INVALIDEXTENSION;
1803
1804     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1805
1806     /* get the progId associated to the extension */
1807     progId = CoTaskMemAlloc(sizeProgId);
1808     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1809
1810     if (res==ERROR_SUCCESS)
1811         /* return the clsid associated to the progId */
1812         res= CLSIDFromProgID(progId,pclsid);
1813
1814     for(i=0; pathDec[i]!=NULL;i++)
1815         CoTaskMemFree(pathDec[i]);
1816     CoTaskMemFree(pathDec);
1817
1818     CoTaskMemFree(progId);
1819
1820     if (res==ERROR_SUCCESS)
1821         return res;
1822
1823     return MK_E_INVALIDEXTENSION;
1824 }
1825
1826 /***********************************************************************
1827  *           CoCreateInstance [OLE32.@]
1828  */
1829 HRESULT WINAPI CoCreateInstance(
1830         REFCLSID rclsid,
1831         LPUNKNOWN pUnkOuter,
1832         DWORD dwClsContext,
1833         REFIID iid,
1834         LPVOID *ppv)
1835 {
1836   HRESULT hres;
1837   LPCLASSFACTORY lpclf = 0;
1838
1839   TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08lx, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
1840         pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
1841
1842   /*
1843    * Sanity check
1844    */
1845   if (ppv==0)
1846     return E_POINTER;
1847
1848   /*
1849    * Initialize the "out" parameter
1850    */
1851   *ppv = 0;
1852
1853   if (!COM_CurrentApt())
1854   {
1855       ERR("apartment not initialised\n");
1856       return CO_E_NOTINITIALIZED;
1857   }
1858
1859   /*
1860    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1861    * Rather than create a class factory, we can just check for it here
1862    */
1863   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1864     if (StdGlobalInterfaceTableInstance == NULL)
1865       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1866     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1867     if (hres) return hres;
1868
1869     TRACE("Retrieved GIT (%p)\n", *ppv);
1870     return S_OK;
1871   }
1872
1873   /*
1874    * Get a class factory to construct the object we want.
1875    */
1876   hres = CoGetClassObject(rclsid,
1877                           dwClsContext,
1878                           NULL,
1879                           &IID_IClassFactory,
1880                           (LPVOID)&lpclf);
1881
1882   if (FAILED(hres))
1883     return hres;
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 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
2645 {
2646     /* first try to retrieve messages for incoming COM calls to the apartment window */
2647     return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
2648            /* next retrieve other messages necessary for the app to remain responsive */
2649            PeekMessageW(msg, NULL, 0, WM_USER - 1, PM_REMOVE|PM_NOYIELD);
2650 }
2651
2652 /***********************************************************************
2653  *           CoWaitForMultipleHandles [OLE32.@]
2654  *
2655  * Waits for one or more handles to become signaled.
2656  *
2657  * PARAMS
2658  *  dwFlags   [I] Flags. See notes.
2659  *  dwTimeout [I] Timeout in milliseconds.
2660  *  cHandles  [I] Number of handles pointed to by pHandles.
2661  *  pHandles  [I] Handles to wait for.
2662  *  lpdwindex [O] Index of handle that was signaled.
2663  *
2664  * RETURNS
2665  *  Success: S_OK.
2666  *  Failure: RPC_S_CALLPENDING on timeout.
2667  *
2668  * NOTES
2669  *
2670  * The dwFlags parameter can be zero or more of the following:
2671  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2672  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2673  *
2674  * SEE ALSO
2675  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
2676  */
2677 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2678     ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2679 {
2680     HRESULT hr = S_OK;
2681     DWORD start_time = GetTickCount();
2682     APARTMENT *apt = COM_CurrentApt();
2683     BOOL message_loop = apt && !apt->multi_threaded;
2684
2685     TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2686         pHandles, lpdwindex);
2687
2688     while (TRUE)
2689     {
2690         DWORD now = GetTickCount();
2691         DWORD res;
2692
2693         if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2694         {
2695             hr = RPC_S_CALLPENDING;
2696             break;
2697         }
2698
2699         if (message_loop)
2700         {
2701             DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2702                     (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2703
2704             TRACE("waiting for rpc completion or window message\n");
2705
2706             res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2707                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2708                 QS_ALLINPUT, wait_flags);
2709
2710             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
2711             {
2712                 MSG msg;
2713                 while (COM_PeekMessage(apt, &msg))
2714                 {
2715                     /* FIXME: filter the messages here */
2716                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2717                     TranslateMessage(&msg);
2718                     DispatchMessageW(&msg);
2719                     if (msg.message == WM_QUIT)
2720                     {
2721                         TRACE("resending WM_QUIT to outer message loop\n");
2722                         PostQuitMessage(msg.wParam);
2723                         /* no longer need to process messages */
2724                         message_loop = FALSE;
2725                         break;
2726                     }
2727                 }
2728                 continue;
2729             }
2730         }
2731         else
2732         {
2733             TRACE("waiting for rpc completion\n");
2734
2735             res = WaitForMultipleObjectsEx(cHandles, pHandles,
2736                 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
2737                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2738                 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
2739         }
2740
2741         if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2742         {
2743             /* handle signaled, store index */
2744             *lpdwindex = (res - WAIT_OBJECT_0);
2745             break;
2746         }
2747         else if (res == WAIT_TIMEOUT)
2748         {
2749             hr = RPC_S_CALLPENDING;
2750             break;
2751         }
2752         else
2753         {
2754             ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2755             hr = E_UNEXPECTED;
2756             break;
2757         }
2758     }
2759     TRACE("-- 0x%08lx\n", hr);
2760     return hr;
2761 }
2762
2763 /***********************************************************************
2764  *              DllMain (OLE32.@)
2765  */
2766 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2767 {
2768     TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2769
2770     switch(fdwReason) {
2771     case DLL_PROCESS_ATTACH:
2772         OLE32_hInstance = hinstDLL;
2773         COMPOBJ_InitProcess();
2774         if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2775         break;
2776
2777     case DLL_PROCESS_DETACH:
2778         if (TRACE_ON(ole)) CoRevokeMallocSpy();
2779         COMPOBJ_UninitProcess();
2780         OLE32_hInstance = 0;
2781         break;
2782
2783     case DLL_THREAD_DETACH:
2784         COM_TlsDestroy();
2785         break;
2786     }
2787     return TRUE;
2788 }
2789
2790 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */