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