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