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