Disconnect proxies at COM shutdown to release the corresponding
[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
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "objbase.h"
40 #include "ole2.h"
41 #include "ole2ver.h"
42 #include "rpc.h"
43 #include "winerror.h"
44 #include "winreg.h"
45 #include "wownt32.h"
46 #include "wine/unicode.h"
47 #include "objbase.h"
48 #include "ole32_main.h"
49 #include "compobj_private.h"
50
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54
55 typedef LPCSTR LPCOLESTR16;
56
57 /****************************************************************************
58  * This section defines variables internal to the COM module.
59  *
60  * TODO: Most of these things will have to be made thread-safe.
61  */
62 HINSTANCE       COMPOBJ_hInstance32 = 0;
63
64 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN*  ppUnk);
65 static void COM_RevokeAllClasses();
66 static void COM_ExternalLockFreeList();
67
68 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
69
70 APARTMENT MTA, *apts;
71
72 static CRITICAL_SECTION csApartment;
73 static CRITICAL_SECTION_DEBUG critsect_debug =
74 {
75     0, 0, &csApartment,
76     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
77       0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
78 };
79 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
80
81 /*
82  * This lock count counts the number of times CoInitialize is called. It is
83  * decreased every time CoUninitialize is called. When it hits 0, the COM
84  * libraries are freed
85  */
86 static LONG s_COMLockCount = 0;
87
88 /*
89  * This linked list contains the list of registered class objects. These
90  * are mostly used to register the factories for out-of-proc servers of OLE
91  * objects.
92  *
93  * TODO: Make this data structure aware of inter-process communication. This
94  *       means that parts of this will be exported to the Wine Server.
95  */
96 typedef struct tagRegisteredClass
97 {
98   CLSID     classIdentifier;
99   LPUNKNOWN classObject;
100   DWORD     runContext;
101   DWORD     connectFlags;
102   DWORD     dwCookie;
103   HANDLE    hThread; /* only for localserver */
104   struct tagRegisteredClass* nextClass;
105 } RegisteredClass;
106
107 static RegisteredClass* firstRegisteredClass = NULL;
108
109 static CRITICAL_SECTION csRegisteredClassList;
110 static CRITICAL_SECTION_DEBUG class_cs_debug =
111 {
112     0, 0, &csRegisteredClassList,
113     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
114       0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
115 };
116 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
117
118 /*****************************************************************************
119  * This section contains OpenDllList definitions
120  *
121  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
122  * other functions that do LoadLibrary _without_ giving back a HMODULE.
123  * Without this list these handles would never be freed.
124  *
125  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
126  * next unload-call but not before 600 sec.
127  */
128
129 typedef struct tagOpenDll {
130   HINSTANCE hLibrary;
131   struct tagOpenDll *next;
132 } OpenDll;
133
134 static OpenDll *openDllList = NULL; /* linked list of open dlls */
135
136 static CRITICAL_SECTION csOpenDllList;
137 static CRITICAL_SECTION_DEBUG dll_cs_debug =
138 {
139     0, 0, &csOpenDllList,
140     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
141       0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
142 };
143 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
144
145 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
146 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
147
148 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
149 static void COMPOBJ_DllList_FreeUnused(int Timeout);
150
151 void COMPOBJ_InitProcess( void )
152 {
153     WNDCLASSA wclass;
154
155     /* Dispatching to the correct thread in an apartment is done through
156      * window messages rather than RPC transports. When an interface is
157      * marshalled into another apartment in the same process, a window of the
158      * following class is created. The *caller* of CoMarshalInterface (ie the
159      * application) is responsible for pumping the message loop in that thread.
160      * The WM_USER messages which point to the RPCs are then dispatched to
161      * COM_AptWndProc by the user's code.
162      */
163     memset(&wclass, 0, sizeof(wclass));
164     wclass.lpfnWndProc = &COM_AptWndProc;
165     wclass.hInstance = OLE32_hInstance;
166     wclass.lpszClassName = aptWinClass;
167     RegisterClassA(&wclass);
168 }
169
170 void COMPOBJ_UninitProcess( void )
171 {
172     UnregisterClassA(aptWinClass, OLE32_hInstance);
173 }
174
175 /******************************************************************************
176  * Manage apartments.
177  */
178
179
180 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
181    with free threaded (ie thread safe) COM objects. There is only ever one MTA
182    in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
183  */
184 static void COM_InitMTA(void)
185 {
186     /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
187        within a network. That is, two different MTAs on different machines will have
188        different OXIDs.
189
190        This method of generating an OXID is therefore wrong as it doesn't work across
191        a network, but for local RPC only it's OK. We can distinguish between MTAs and
192        STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
193      */
194     MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
195     InitializeCriticalSection(&MTA.cs);
196 }
197
198 static void COM_UninitMTA(void)
199 {
200     DeleteCriticalSection(&MTA.cs);
201     MTA.oxid = 0;
202 }
203
204 /* creates an apartment structure which stores OLE thread-local
205  * information. Call with COINIT_UNINITIALIZED to create an apartment
206  * that will be initialized with a model later. Note: do not call
207  * with COINIT_UNINITIALIZED if the apartment has already been initialized
208  * with a different COINIT value */
209 APARTMENT* COM_CreateApartment(DWORD model)
210 {
211     APARTMENT *apt;
212     BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
213
214     if (create)
215     {
216         apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
217         apt->tid = GetCurrentThreadId();
218         DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
219                         GetCurrentProcess(), &apt->thread,
220                         THREAD_ALL_ACCESS, FALSE, 0);
221     }
222     else
223         apt = NtCurrentTeb()->ReservedForOle;
224
225     apt->model = model;
226     if (model & COINIT_APARTMENTTHREADED) {
227       /* FIXME: how does windoze create OXIDs? */
228       apt->oxid = MTA.oxid | GetCurrentThreadId();
229       apt->win = CreateWindowA(aptWinClass, NULL, 0,
230                                0, 0, 0, 0,
231                                0, 0, OLE32_hInstance, NULL);
232       InitializeCriticalSection(&apt->cs);
233     }
234     else if (!(model & COINIT_UNINITIALIZED)) {
235       apt->parent = &MTA;
236       apt->oxid = MTA.oxid;
237     }
238     EnterCriticalSection(&csApartment);
239     if (create)
240     {
241         if (apts) apts->prev = apt;
242         apt->next = apts;
243         apts = apt;
244     }
245     LeaveCriticalSection(&csApartment);
246     NtCurrentTeb()->ReservedForOle = apt;
247     return apt;
248 }
249
250 static void COM_DestroyApartment(APARTMENT *apt)
251 {
252     EnterCriticalSection(&csApartment);
253     if (apt->prev) apt->prev->next = apt->next;
254     if (apt->next) apt->next->prev = apt->prev;
255     if (apts == apt) apts = apt->next;
256     apt->prev = NULL; apt->next = NULL;
257     LeaveCriticalSection(&csApartment);
258     if (apt->model & COINIT_APARTMENTTHREADED) {
259       if (apt->win) DestroyWindow(apt->win);
260       DeleteCriticalSection(&apt->cs);
261     }
262     CloseHandle(apt->thread);
263     HeapFree(GetProcessHeap(), 0, apt);
264 }
265
266 /* The given OXID must be local to this process: you cannot use apartment
267    windows to send RPCs to other processes */
268 HWND COM_GetApartmentWin(OXID oxid)
269 {
270     APARTMENT *apt;
271     HWND win = 0;
272
273     EnterCriticalSection(&csApartment);
274     apt = apts;
275     while (apt && apt->oxid != oxid) apt = apt->next;
276     if (apt) win = apt->win;
277     LeaveCriticalSection(&csApartment);
278     return win;
279 }
280
281 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
282 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
283 {
284   return DefWindowProcA(hWnd, msg, wParam, lParam);
285
286
287 /*****************************************************************************
288  * This section contains OpenDllList implemantation
289  */
290
291 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
292 {
293     OpenDll *ptr;
294     OpenDll *tmp;
295
296     TRACE("\n");
297
298     EnterCriticalSection( &csOpenDllList );
299
300     if (openDllList == NULL) {
301         /* empty list -- add first node */
302         openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
303         openDllList->hLibrary=hLibrary;
304         openDllList->next = NULL;
305     } else {
306         /* search for this dll */
307         int found = FALSE;
308         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
309             if (ptr->hLibrary == hLibrary) {
310                 found = TRUE;
311                 break;
312             }
313         }
314         if (!found) {
315             /* dll not found, add it */
316             tmp = openDllList;
317             openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
318             openDllList->hLibrary = hLibrary;
319             openDllList->next = tmp;
320         }
321     }
322
323     LeaveCriticalSection( &csOpenDllList );
324 }
325
326 static void COMPOBJ_DllList_FreeUnused(int Timeout)
327 {
328     OpenDll *curr, *next, *prev = NULL;
329     typedef HRESULT(*DllCanUnloadNowFunc)(void);
330     DllCanUnloadNowFunc DllCanUnloadNow;
331
332     TRACE("\n");
333
334     EnterCriticalSection( &csOpenDllList );
335
336     for (curr = openDllList; curr != NULL; ) {
337         DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
338
339         if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
340             next = curr->next;
341
342             TRACE("freeing %p\n", curr->hLibrary);
343             FreeLibrary(curr->hLibrary);
344
345             HeapFree(GetProcessHeap(), 0, curr);
346             if (curr == openDllList) {
347                 openDllList = next;
348             } else {
349               prev->next = next;
350             }
351
352             curr = next;
353         } else {
354             prev = curr;
355             curr = curr->next;
356         }
357     }
358
359     LeaveCriticalSection( &csOpenDllList );
360 }
361
362 /******************************************************************************
363  *           CoBuildVersion [COMPOBJ.1]
364  *           CoBuildVersion [OLE32.@]
365  *
366  * RETURNS
367  *      Current build version, hiword is majornumber, loword is minornumber
368  */
369 DWORD WINAPI CoBuildVersion(void)
370 {
371     TRACE("Returning version %d, build %d.\n", rmm, rup);
372     return (rmm<<16)+rup;
373 }
374
375 /******************************************************************************
376  *              CoInitialize    [OLE32.@]
377  *
378  * Initializes the COM libraries.
379  *
380  * See CoInitializeEx
381  */
382 HRESULT WINAPI CoInitialize(
383         LPVOID lpReserved       /* [in] pointer to win32 malloc interface
384                                    (obsolete, should be NULL) */
385 )
386 {
387   /*
388    * Just delegate to the newer method.
389    */
390   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
391 }
392
393 /******************************************************************************
394  *              CoInitializeEx  [OLE32.@]
395  *
396  * Initializes the COM libraries. The behavior used to set the win32 IMalloc
397  * used for memory management is obsolete.
398  *
399  * RETURNS
400  *  S_OK               if successful,
401  *  S_FALSE            if this function was called already.
402  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
403  *                     threading model.
404  */
405 HRESULT WINAPI CoInitializeEx(
406         LPVOID lpReserved,      /* [in] pointer to win32 malloc interface
407                                    (obsolete, should be NULL) */
408         DWORD dwCoInit          /* [in] A value from COINIT specifies the threading model */
409 )
410 {
411   HRESULT hr = S_OK;
412   APARTMENT *apt;
413
414   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
415
416   if (lpReserved!=NULL)
417   {
418     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
419   }
420
421   apt = NtCurrentTeb()->ReservedForOle;
422   if (apt && !(apt->model == COINIT_UNINITIALIZED))
423   {
424     if (dwCoInit != apt->model)
425     {
426       /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
427          code then we are probably using the wrong threading model to implement that API. */
428       WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
429       return RPC_E_CHANGED_MODE;
430     }
431     hr = S_FALSE;
432   }
433   else
434     hr = S_OK;
435
436   /*
437    * Check the lock count. If this is the first time going through the initialize
438    * process, we have to initialize the libraries.
439    *
440    * And crank-up that lock count.
441    */
442   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
443   {
444     /*
445      * Initialize the various COM libraries and data structures.
446      */
447     TRACE("() - Initializing the COM libraries\n");
448
449     COM_InitMTA();
450
451     RunningObjectTableImpl_Initialize();
452   }
453
454   if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
455
456   InterlockedIncrement(&apt->inits);
457   if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
458
459   return hr;
460 }
461
462 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
463    pending RPCs are ignored. Non-COM messages are discarded at this point.
464  */
465 void COM_FlushMessageQueue(void)
466 {
467     MSG message;
468     APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
469
470     if (!apt || !apt->win) return;
471
472     TRACE("Flushing STA message queue\n");
473
474     while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
475         if (message.hwnd != apt->win) continue;
476         TranslateMessage(&message);
477         DispatchMessageA(&message);
478     }
479 }
480
481 /***********************************************************************
482  *           CoUninitialize   [OLE32.@]
483  *
484  * This method will release the COM libraries.
485  *
486  * See the windows documentation for more details.
487  */
488 void WINAPI CoUninitialize(void)
489 {
490   LONG lCOMRefCnt;
491   APARTMENT *apt;
492
493   TRACE("()\n");
494
495   apt = NtCurrentTeb()->ReservedForOle;
496   if (!apt) return;
497   if (InterlockedDecrement(&apt->inits)==0) {
498     NtCurrentTeb()->ReservedForOle = NULL;
499     COM_DestroyApartment(apt);
500     apt = NULL;
501   }
502
503   /*
504    * Decrease the reference count.
505    * If we are back to 0 locks on the COM library, make sure we free
506    * all the associated data structures.
507    */
508   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
509   if (lCOMRefCnt==1)
510   {
511     TRACE("() - Releasing the COM libraries\n");
512
513     RunningObjectTableImpl_UnInitialize();
514
515     /* disconnect proxies to release the corresponding stubs.
516      * FIXME: native version might not do this and we might just be working
517      * around bugs elsewhere. */
518     MARSHAL_Disconnect_Proxies();
519
520     /* Release the references to the registered class objects */
521     COM_RevokeAllClasses();
522
523     /* This will free the loaded COM Dlls  */
524     CoFreeAllLibraries();
525
526     /* This will free list of external references to COM objects */
527     COM_ExternalLockFreeList();
528
529     /* This ensures we deal with any pending RPCs */
530     COM_FlushMessageQueue();
531
532     COM_UninitMTA();
533   }
534   else if (lCOMRefCnt<1) {
535     ERR( "CoUninitialize() - not CoInitialized.\n" );
536     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
537   }
538 }
539
540 /******************************************************************************
541  *              CoDisconnectObject      [COMPOBJ.15]
542  *              CoDisconnectObject      [OLE32.@]
543  *
544  * Disconnects all connections to this object from remote processes. Dispatches
545  * pending RPCs while blocking new RPCs from occurring, and then calls
546  * IMarshal::DisconnectObject on the given object.
547  *
548  * Typically called when the object server is forced to shut down, for instance by
549  * the user.
550  */
551 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
552 {
553     FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
554     return S_OK;
555 }
556
557 /******************************************************************************
558  *              CoCreateGuid[OLE32.@]
559  *
560  */
561 HRESULT WINAPI CoCreateGuid(
562         GUID *pguid /* [out] points to the GUID to initialize */
563 ) {
564     return UuidCreate(pguid);
565 }
566
567 /******************************************************************************
568  *              CLSIDFromString [OLE32.@]
569  *              IIDFromString   [OLE32.@]
570  * Converts a unique identifier from its string representation into
571  * the GUID struct.
572  *
573  * UNDOCUMENTED
574  *      If idstr is not a valid CLSID string then it gets treated as a ProgID
575  *
576  * RETURNS
577  *      the converted GUID
578  */
579 HRESULT WINAPI __CLSIDFromStringA(
580         LPCSTR idstr,           /* [in] string representation of guid */
581         CLSID *id)              /* [out] GUID converted from string */
582 {
583   const BYTE *s = (BYTE *) idstr;
584   int   i;
585   BYTE table[256];
586
587   if (!s)
588           s = "{00000000-0000-0000-0000-000000000000}";
589   else {  /* validate the CLSID string */
590
591       if (strlen(s) != 38)
592           return CO_E_CLASSSTRING;
593
594       if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
595           return CO_E_CLASSSTRING;
596
597       for (i=1; i<37; i++) {
598           if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
599           if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
600                 ((s[i] >= 'a') && (s[i] <= 'f'))  ||
601                 ((s[i] >= 'A') && (s[i] <= 'F'))))
602               return CO_E_CLASSSTRING;
603       }
604   }
605
606   TRACE("%s -> %p\n", s, id);
607
608   /* quick lookup table */
609   memset(table, 0, 256);
610
611   for (i = 0; i < 10; i++) {
612     table['0' + i] = i;
613   }
614   for (i = 0; i < 6; i++) {
615     table['A' + i] = i+10;
616     table['a' + i] = i+10;
617   }
618
619   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
620
621   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
622                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
623   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
624   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
625
626   /* these are just sequential bytes */
627   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
628   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
629   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
630   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
631   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
632   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
633   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
634   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
635
636   return S_OK;
637 }
638
639 /*****************************************************************************/
640
641 HRESULT WINAPI CLSIDFromString(
642         LPOLESTR idstr,         /* [in] string representation of GUID */
643         CLSID *id )             /* [out] GUID represented by above string */
644 {
645     char xid[40];
646     HRESULT ret;
647
648     if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
649         return CO_E_CLASSSTRING;
650
651
652     ret = __CLSIDFromStringA(xid,id);
653     if(ret != S_OK) { /* It appears a ProgID is also valid */
654         ret = CLSIDFromProgID(idstr, id);
655     }
656     return ret;
657 }
658
659 /******************************************************************************
660  *              WINE_StringFromCLSID    [Internal]
661  * Converts a GUID into the respective string representation.
662  *
663  * NOTES
664  *
665  * RETURNS
666  *      the string representation and HRESULT
667  */
668 HRESULT WINE_StringFromCLSID(
669         const CLSID *id,        /* [in] GUID to be converted */
670         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
671 ) {
672   static const char *hex = "0123456789ABCDEF";
673   char *s;
674   int   i;
675
676   if (!id)
677         { ERR("called with id=Null\n");
678           *idstr = 0x00;
679           return E_FAIL;
680         }
681
682   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
683           id->Data1, id->Data2, id->Data3,
684           id->Data4[0], id->Data4[1]);
685   s = &idstr[25];
686
687   /* 6 hex bytes */
688   for (i = 2; i < 8; i++) {
689     *s++ = hex[id->Data4[i]>>4];
690     *s++ = hex[id->Data4[i] & 0xf];
691   }
692
693   *s++ = '}';
694   *s++ = '\0';
695
696   TRACE("%p->%s\n", id, idstr);
697
698   return S_OK;
699 }
700
701
702 /******************************************************************************
703  *              StringFromCLSID [OLE32.@]
704  *              StringFromIID   [OLE32.@]
705  * Converts a GUID into the respective string representation.
706  * The target string is allocated using the OLE IMalloc.
707  * RETURNS
708  *      the string representation and HRESULT
709  */
710 HRESULT WINAPI StringFromCLSID(
711         REFCLSID id,            /* [in] the GUID to be converted */
712         LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
713 ) {
714         char            buf[80];
715         HRESULT       ret;
716         LPMALLOC        mllc;
717
718         if ((ret=CoGetMalloc(0,&mllc)))
719                 return ret;
720
721         ret=WINE_StringFromCLSID(id,buf);
722         if (!ret) {
723             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
724             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
725             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
726         }
727         return ret;
728 }
729
730 /******************************************************************************
731  *              StringFromGUID2 [COMPOBJ.76]
732  *              StringFromGUID2 [OLE32.@]
733  *
734  * Converts a global unique identifier into a string of an API-
735  * specified fixed format. (The usual {.....} stuff.)
736  *
737  * RETURNS
738  *      The (UNICODE) string representation of the GUID in 'str'
739  *      The length of the resulting string, 0 if there was any problem.
740  */
741 INT WINAPI
742 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
743 {
744   char          xguid[80];
745
746   if (WINE_StringFromCLSID(id,xguid))
747         return 0;
748   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
749 }
750
751 /******************************************************************************
752  * ProgIDFromCLSID [OLE32.@]
753  * Converts a class id into the respective Program ID. (By using a registry lookup)
754  * RETURNS S_OK on success
755  * riid associated with the progid
756  */
757
758 HRESULT WINAPI ProgIDFromCLSID(
759   REFCLSID clsid, /* [in] class id as found in registry */
760   LPOLESTR *lplpszProgID/* [out] associated Prog ID */
761 )
762 {
763   char     strCLSID[50], *buf, *buf2;
764   DWORD    buf2len;
765   HKEY     xhkey;
766   LPMALLOC mllc;
767   HRESULT  ret = S_OK;
768
769   WINE_StringFromCLSID(clsid, strCLSID);
770
771   buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
772   sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
773   if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
774     ret = REGDB_E_CLASSNOTREG;
775
776   HeapFree(GetProcessHeap(), 0, buf);
777
778   if (ret == S_OK)
779   {
780     buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
781     buf2len = 255;
782     if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
783       ret = REGDB_E_CLASSNOTREG;
784
785     if (ret == S_OK)
786     {
787       if (CoGetMalloc(0,&mllc))
788         ret = E_OUTOFMEMORY;
789       else
790       {
791           DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
792           *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
793           MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
794       }
795     }
796     HeapFree(GetProcessHeap(), 0, buf2);
797   }
798
799   RegCloseKey(xhkey);
800   return ret;
801 }
802
803 /******************************************************************************
804  *              CLSIDFromProgID [COMPOBJ.61]
805  * Converts a program id into the respective GUID. (By using a registry lookup)
806  * RETURNS
807  *      riid associated with the progid
808  */
809 HRESULT WINAPI CLSIDFromProgID16(
810         LPCOLESTR16 progid,     /* [in] program id as found in registry */
811         LPCLSID riid            /* [out] associated CLSID */
812 ) {
813         char    *buf,buf2[80];
814         DWORD   buf2len;
815         HRESULT err;
816         HKEY    xhkey;
817
818         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
819         sprintf(buf,"%s\\CLSID",progid);
820         if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
821                 HeapFree(GetProcessHeap(),0,buf);
822                 return CO_E_CLASSSTRING;
823         }
824         HeapFree(GetProcessHeap(),0,buf);
825         buf2len = sizeof(buf2);
826         if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
827                 RegCloseKey(xhkey);
828                 return CO_E_CLASSSTRING;
829         }
830         RegCloseKey(xhkey);
831         return __CLSIDFromStringA(buf2,riid);
832 }
833
834 /******************************************************************************
835  *              CLSIDFromProgID [OLE32.@]
836  * Converts a program id into the respective GUID. (By using a registry lookup)
837  * RETURNS
838  *      riid associated with the progid
839  */
840 HRESULT WINAPI CLSIDFromProgID(
841         LPCOLESTR progid,       /* [in] program id as found in registry */
842         LPCLSID riid )          /* [out] associated CLSID */
843 {
844     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
845     char buf2[80];
846     DWORD buf2len = sizeof(buf2);
847     HKEY xhkey;
848
849     WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
850     strcpyW( buf, progid );
851     strcatW( buf, clsidW );
852     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
853     {
854         HeapFree(GetProcessHeap(),0,buf);
855         return CO_E_CLASSSTRING;
856     }
857     HeapFree(GetProcessHeap(),0,buf);
858
859     if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
860     {
861         RegCloseKey(xhkey);
862         return CO_E_CLASSSTRING;
863     }
864     RegCloseKey(xhkey);
865     return __CLSIDFromStringA(buf2,riid);
866 }
867
868
869
870 /*****************************************************************************
871  *             CoGetPSClsid [OLE32.@]
872  *
873  * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
874  * for the specified interface.
875  *
876  * The standard marshaller activates the object with the CLSID returned and uses the
877  * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
878  * the proxies and stubs for a given object.
879  *
880  * CoGetPSClsid determines this CLSID by searching the
881  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
882  * and any interface id registered by CoRegisterPSClsid within the current process.
883  *
884  * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
885  */
886 HRESULT WINAPI CoGetPSClsid(
887           REFIID riid,     /* [in]  Interface whose proxy/stub CLSID is to be returned */
888           CLSID *pclsid )    /* [out] Where to store returned proxy/stub CLSID */
889 {
890     char *buf, buf2[40];
891     DWORD buf2len;
892     HKEY xhkey;
893
894     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
895
896     /* Get the input iid as a string */
897     WINE_StringFromCLSID(riid, buf2);
898     /* Allocate memory for the registry key we will construct.
899        (length of iid string plus constant length of static text */
900     buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
901     if (buf == NULL)
902     {
903        return (E_OUTOFMEMORY);
904     }
905
906     /* Construct the registry key we want */
907     sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
908
909     /* Open the key.. */
910     if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
911     {
912        WARN("No PSFactoryBuffer object is registered for this IID\n");
913        HeapFree(GetProcessHeap(),0,buf);
914        return (E_INVALIDARG);
915     }
916     HeapFree(GetProcessHeap(),0,buf);
917
918     /* ... Once we have the key, query the registry to get the
919        value of CLSID as a string, and convert it into a
920        proper CLSID structure to be passed back to the app */
921     buf2len = sizeof(buf2);
922     if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
923     {
924        RegCloseKey(xhkey);
925        return E_INVALIDARG;
926     }
927     RegCloseKey(xhkey);
928
929     /* We have the CLSid we want back from the registry as a string, so
930        lets convert it into a CLSID structure */
931     if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
932        return E_INVALIDARG;
933     }
934
935     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
936     return (S_OK);
937 }
938
939
940
941 /***********************************************************************
942  *              WriteClassStm (OLE32.@)
943  *
944  * This function write a CLSID on stream
945  */
946 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
947 {
948     TRACE("(%p,%p)\n",pStm,rclsid);
949
950     if (rclsid==NULL)
951         return E_INVALIDARG;
952
953     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
954 }
955
956 /***********************************************************************
957  *              ReadClassStm (OLE32.@)
958  *
959  * This function read a CLSID from a stream
960  */
961 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
962 {
963     ULONG nbByte;
964     HRESULT res;
965
966     TRACE("(%p,%p)\n",pStm,pclsid);
967
968     if (pclsid==NULL)
969         return E_INVALIDARG;
970
971     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
972
973     if (FAILED(res))
974         return res;
975
976     if (nbByte != sizeof(CLSID))
977         return S_FALSE;
978     else
979         return S_OK;
980 }
981
982
983 /***
984  * COM_GetRegisteredClassObject
985  *
986  * This internal method is used to scan the registered class list to
987  * find a class object.
988  *
989  * Params:
990  *   rclsid        Class ID of the class to find.
991  *   dwClsContext  Class context to match.
992  *   ppv           [out] returns a pointer to the class object. Complying
993  *                 to normal COM usage, this method will increase the
994  *                 reference count on this object.
995  */
996 static HRESULT COM_GetRegisteredClassObject(
997         REFCLSID    rclsid,
998         DWORD       dwClsContext,
999         LPUNKNOWN*  ppUnk)
1000 {
1001   HRESULT hr = S_FALSE;
1002   RegisteredClass* curClass;
1003
1004   EnterCriticalSection( &csRegisteredClassList );
1005
1006   /*
1007    * Sanity check
1008    */
1009   assert(ppUnk!=0);
1010
1011   /*
1012    * Iterate through the whole list and try to match the class ID.
1013    */
1014   curClass = firstRegisteredClass;
1015
1016   while (curClass != 0)
1017   {
1018     /*
1019      * Check if we have a match on the class ID.
1020      */
1021     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1022     {
1023       /*
1024        * Since we don't do out-of process or DCOM just right away, let's ignore the
1025        * class context.
1026        */
1027
1028       /*
1029        * We have a match, return the pointer to the class object.
1030        */
1031       *ppUnk = curClass->classObject;
1032
1033       IUnknown_AddRef(curClass->classObject);
1034
1035       hr = S_OK;
1036       goto end;
1037     }
1038
1039     /*
1040      * Step to the next class in the list.
1041      */
1042     curClass = curClass->nextClass;
1043   }
1044
1045 end:
1046   LeaveCriticalSection( &csRegisteredClassList );
1047   /*
1048    * If we get to here, we haven't found our class.
1049    */
1050   return hr;
1051 }
1052
1053 static DWORD WINAPI
1054 _LocalServerThread(LPVOID param) {
1055     HANDLE              hPipe;
1056     char                pipefn[200];
1057     RegisteredClass *newClass = (RegisteredClass*)param;
1058     HRESULT             hres;
1059     IStream             *pStm;
1060     STATSTG             ststg;
1061     unsigned char       *buffer;
1062     int                 buflen;
1063     IClassFactory       *classfac;
1064     LARGE_INTEGER       seekto;
1065     ULARGE_INTEGER      newpos;
1066     ULONG               res;
1067
1068     TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1069
1070     strcpy(pipefn,PIPEPREF);
1071     WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1072
1073     hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1074                PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1075                4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1076     if (hPipe == INVALID_HANDLE_VALUE) {
1077         FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1078         return 1;
1079     }
1080     while (1) {
1081         if (!ConnectNamedPipe(hPipe,NULL)) {
1082             ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1083             break;
1084         }
1085
1086         TRACE("marshalling IClassFactory to client\n");
1087         
1088         hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1089         if (hres) return hres;
1090
1091         hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1092         if (hres) {
1093             FIXME("Failed to create stream on hglobal.\n");
1094             return hres;
1095         }
1096         hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1097         if (hres) {
1098             FIXME("CoMarshalInterface failed, %lx!\n",hres);
1099             return hres;
1100         }
1101
1102         IUnknown_Release(classfac); /* is this right? */
1103
1104         hres = IStream_Stat(pStm,&ststg,0);
1105         if (hres) return hres;
1106
1107         buflen = ststg.cbSize.u.LowPart;
1108         buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1109         seekto.u.LowPart = 0;
1110         seekto.u.HighPart = 0;
1111         hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1112         if (hres) {
1113             FIXME("IStream_Seek failed, %lx\n",hres);
1114             return hres;
1115         }
1116         
1117         hres = IStream_Read(pStm,buffer,buflen,&res);
1118         if (hres) {
1119             FIXME("Stream Read failed, %lx\n",hres);
1120             return hres;
1121         }
1122         
1123         IStream_Release(pStm);
1124
1125         WriteFile(hPipe,buffer,buflen,&res,NULL);
1126         FlushFileBuffers(hPipe);
1127         DisconnectNamedPipe(hPipe);
1128
1129         TRACE("done marshalling IClassFactory\n");
1130     }
1131     CloseHandle(hPipe);
1132     return 0;
1133 }
1134
1135 /******************************************************************************
1136  *              CoRegisterClassObject   [OLE32.@]
1137  *
1138  * This method will register the class object for a given class ID. Servers housed
1139  * in EXE files use this method instead of exporting DllGetClassObject to allow other
1140  * code to connect to their objects.
1141  *
1142  * When a class object (an object which implements IClassFactory) is registered in
1143  * this way, a new thread is started which listens for connections on a named pipe
1144  * specific to the registered CLSID. When something else connects to it, it writes
1145  * out the marshalled IClassFactory interface to the pipe. The code on the other end
1146  * uses this buffer to unmarshal the class factory, and can then call methods on it.
1147  *
1148  * In Windows, such objects are registered with the RPC endpoint mapper, not with
1149  * a unique named pipe.
1150  *
1151  * See the Windows documentation for more details.
1152  */
1153 HRESULT WINAPI CoRegisterClassObject(
1154         REFCLSID rclsid,
1155         LPUNKNOWN pUnk,
1156         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1157         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
1158         LPDWORD lpdwRegister
1159 )
1160 {
1161   RegisteredClass* newClass;
1162   LPUNKNOWN        foundObject;
1163   HRESULT          hr;
1164
1165   TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1166         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1167
1168   if ( (lpdwRegister==0) || (pUnk==0) )
1169     return E_INVALIDARG;
1170
1171   *lpdwRegister = 0;
1172
1173   /*
1174    * First, check if the class is already registered.
1175    * If it is, this should cause an error.
1176    *
1177    * MSDN claims that multiple interface registrations are legal, but we can't do that with
1178    * our current implementation.
1179    */
1180   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1181   if (hr == S_OK) {
1182     IUnknown_Release(foundObject);
1183     return CO_E_OBJISREG;
1184   }
1185
1186   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1187   if ( newClass == NULL )
1188     return E_OUTOFMEMORY;
1189
1190   EnterCriticalSection( &csRegisteredClassList );
1191
1192   newClass->classIdentifier = *rclsid;
1193   newClass->runContext      = dwClsContext;
1194   newClass->connectFlags    = flags;
1195   /*
1196    * Use the address of the chain node as the cookie since we are sure it's
1197    * unique.
1198    */
1199   newClass->dwCookie        = (DWORD)newClass;
1200   newClass->nextClass       = firstRegisteredClass;
1201
1202   /*
1203    * Since we're making a copy of the object pointer, we have to increase its
1204    * reference count.
1205    */
1206   newClass->classObject     = pUnk;
1207   IUnknown_AddRef(newClass->classObject);
1208
1209   firstRegisteredClass = newClass;
1210   LeaveCriticalSection( &csRegisteredClassList );
1211
1212   *lpdwRegister = newClass->dwCookie;
1213
1214   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1215       DWORD tid;
1216
1217       STUBMGR_Start();
1218       newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1219   }
1220   return S_OK;
1221 }
1222
1223 /***********************************************************************
1224  *           CoRevokeClassObject [OLE32.@]
1225  *
1226  * This method will remove a class object from the class registry
1227  *
1228  * See the Windows documentation for more details.
1229  */
1230 HRESULT WINAPI CoRevokeClassObject(
1231         DWORD dwRegister)
1232 {
1233   HRESULT hr = E_INVALIDARG;
1234   RegisteredClass** prevClassLink;
1235   RegisteredClass*  curClass;
1236
1237   TRACE("(%08lx)\n",dwRegister);
1238
1239   EnterCriticalSection( &csRegisteredClassList );
1240
1241   /*
1242    * Iterate through the whole list and try to match the cookie.
1243    */
1244   curClass      = firstRegisteredClass;
1245   prevClassLink = &firstRegisteredClass;
1246
1247   while (curClass != 0)
1248   {
1249     /*
1250      * Check if we have a match on the cookie.
1251      */
1252     if (curClass->dwCookie == dwRegister)
1253     {
1254       /*
1255        * Remove the class from the chain.
1256        */
1257       *prevClassLink = curClass->nextClass;
1258
1259       /*
1260        * Release the reference to the class object.
1261        */
1262       IUnknown_Release(curClass->classObject);
1263
1264       /*
1265        * Free the memory used by the chain node.
1266        */
1267       HeapFree(GetProcessHeap(), 0, curClass);
1268
1269       hr = S_OK;
1270       goto end;
1271     }
1272
1273     /*
1274      * Step to the next class in the list.
1275      */
1276     prevClassLink = &(curClass->nextClass);
1277     curClass      = curClass->nextClass;
1278   }
1279
1280 end:
1281   LeaveCriticalSection( &csRegisteredClassList );
1282   /*
1283    * If we get to here, we haven't found our class.
1284    */
1285   return hr;
1286 }
1287
1288 /***********************************************************************
1289  *      compobj_RegReadPath     [internal]
1290  *
1291  *      Reads a registry value and expands it when necessary
1292  */
1293 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1294 {
1295         HRESULT hres;
1296         HKEY key;
1297         DWORD keytype;
1298         char src[MAX_PATH];
1299         DWORD dwLength = dstlen;
1300
1301         if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1302           if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1303             if (keytype == REG_EXPAND_SZ) {
1304               if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1305             } else {
1306               strncpy(dst, src, dstlen);
1307             }
1308           }
1309           RegCloseKey (key);
1310         }
1311         return hres;
1312 }
1313
1314 /***********************************************************************
1315  *           CoGetClassObject [COMPOBJ.7]
1316  *           CoGetClassObject [OLE32.@]
1317  *
1318  * FIXME.  If request allows of several options and there is a failure
1319  *         with one (other than not being registered) do we try the
1320  *         others or return failure?  (E.g. inprocess is registered but
1321  *         the DLL is not found but the server version works)
1322  */
1323 HRESULT WINAPI CoGetClassObject(
1324     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1325     REFIID iid, LPVOID *ppv
1326 ) {
1327     LPUNKNOWN   regClassObject;
1328     HRESULT     hres = E_UNEXPECTED;
1329     char        xclsid[80];
1330     HINSTANCE hLibrary;
1331     typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1332     DllGetClassObjectFunc DllGetClassObject;
1333
1334     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1335
1336     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1337
1338     if (pServerInfo) {
1339         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1340         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1341     }
1342
1343     /*
1344      * First, try and see if we can't match the class ID with one of the
1345      * registered classes.
1346      */
1347     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1348     {
1349       /*
1350        * Get the required interface from the retrieved pointer.
1351        */
1352       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1353
1354       /*
1355        * Since QI got another reference on the pointer, we want to release the
1356        * one we already have. If QI was unsuccessful, this will release the object. This
1357        * is good since we are not returning it in the "out" parameter.
1358        */
1359       IUnknown_Release(regClassObject);
1360
1361       return hres;
1362     }
1363
1364     /* first try: in-process */
1365     if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1366         char keyname[MAX_PATH];
1367         char dllpath[MAX_PATH+1];
1368
1369         sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1370
1371         if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1372             /* failure: CLSID is not found in registry */
1373            WARN("class %s not registered inproc\n", xclsid);
1374             hres = REGDB_E_CLASSNOTREG;
1375         } else {
1376           if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1377             /* failure: DLL could not be loaded */
1378             ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1379             hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1380           } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1381             /* failure: the dll did not export DllGetClassObject */
1382             ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1383             FreeLibrary( hLibrary );
1384             hres = CO_E_DLLNOTFOUND;
1385           } else {
1386             /* OK: get the ClassObject */
1387             COMPOBJ_DLLList_Add( hLibrary );
1388             return DllGetClassObject(rclsid, iid, ppv);
1389           }
1390         }
1391     }
1392
1393     /* Next try out of process */
1394     if (CLSCTX_LOCAL_SERVER & dwClsContext)
1395     {
1396         return create_marshalled_proxy(rclsid,iid,ppv);
1397     }
1398
1399     /* Finally try remote: this requires networked DCOM (a lot of work) */
1400     if (CLSCTX_REMOTE_SERVER & dwClsContext)
1401     {
1402         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1403         hres = E_NOINTERFACE;
1404     }
1405
1406     return hres;
1407 }
1408 /***********************************************************************
1409  *        CoResumeClassObjects (OLE32.@)
1410  *
1411  * Resumes classobjects registered with REGCLS suspended
1412  */
1413 HRESULT WINAPI CoResumeClassObjects(void)
1414 {
1415        FIXME("stub\n");
1416         return S_OK;
1417 }
1418
1419 /***********************************************************************
1420  *        GetClassFile (OLE32.@)
1421  *
1422  * This function supplies the CLSID associated with the given filename.
1423  */
1424 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1425 {
1426     IStorage *pstg=0;
1427     HRESULT res;
1428     int nbElm, length, i;
1429     LONG sizeProgId;
1430     LPOLESTR *pathDec=0,absFile=0,progId=0;
1431     LPWSTR extension;
1432     static const WCHAR bkslashW[] = {'\\',0};
1433     static const WCHAR dotW[] = {'.',0};
1434
1435     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1436
1437     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1438     if((StgIsStorageFile(filePathName))==S_OK){
1439
1440         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1441
1442         if (SUCCEEDED(res))
1443             res=ReadClassStg(pstg,pclsid);
1444
1445         IStorage_Release(pstg);
1446
1447         return res;
1448     }
1449     /* if the file is not a storage object then attemps to match various bits in the file against a
1450        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1451        this case
1452
1453      for(i=0;i<nFileTypes;i++)
1454
1455         for(i=0;j<nPatternsForType;j++){
1456
1457             PATTERN pat;
1458             HANDLE  hFile;
1459
1460             pat=ReadPatternFromRegistry(i,j);
1461             hFile=CreateFileW(filePathName,,,,,,hFile);
1462             SetFilePosition(hFile,pat.offset);
1463             ReadFile(hFile,buf,pat.size,NULL,NULL);
1464             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1465
1466                 *pclsid=ReadCLSIDFromRegistry(i);
1467                 return S_OK;
1468             }
1469         }
1470      */
1471
1472     /* if the above strategies fail then search for the extension key in the registry */
1473
1474     /* get the last element (absolute file) in the path name */
1475     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1476     absFile=pathDec[nbElm-1];
1477
1478     /* failed if the path represente a directory and not an absolute file name*/
1479     if (!lstrcmpW(absFile, bkslashW))
1480         return MK_E_INVALIDEXTENSION;
1481
1482     /* get the extension of the file */
1483     extension = NULL;
1484     length=lstrlenW(absFile);
1485     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1486         /* nothing */;
1487
1488     if (!extension || !lstrcmpW(extension, dotW))
1489         return MK_E_INVALIDEXTENSION;
1490
1491     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1492
1493     /* get the progId associated to the extension */
1494     progId = CoTaskMemAlloc(sizeProgId);
1495     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1496
1497     if (res==ERROR_SUCCESS)
1498         /* return the clsid associated to the progId */
1499         res= CLSIDFromProgID(progId,pclsid);
1500
1501     for(i=0; pathDec[i]!=NULL;i++)
1502         CoTaskMemFree(pathDec[i]);
1503     CoTaskMemFree(pathDec);
1504
1505     CoTaskMemFree(progId);
1506
1507     if (res==ERROR_SUCCESS)
1508         return res;
1509
1510     return MK_E_INVALIDEXTENSION;
1511 }
1512 /***********************************************************************
1513  *           CoCreateInstance [COMPOBJ.13]
1514  *           CoCreateInstance [OLE32.@]
1515  */
1516 HRESULT WINAPI CoCreateInstance(
1517         REFCLSID rclsid,
1518         LPUNKNOWN pUnkOuter,
1519         DWORD dwClsContext,
1520         REFIID iid,
1521         LPVOID *ppv)
1522 {
1523         HRESULT hres;
1524         LPCLASSFACTORY lpclf = 0;
1525
1526   /*
1527    * Sanity check
1528    */
1529   if (ppv==0)
1530     return E_POINTER;
1531
1532   /*
1533    * Initialize the "out" parameter
1534    */
1535   *ppv = 0;
1536
1537   /*
1538    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1539    * Rather than create a class factory, we can just check for it here
1540    */
1541   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1542     if (StdGlobalInterfaceTableInstance == NULL) 
1543       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1544     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1545     if (hres) return hres;
1546     
1547     TRACE("Retrieved GIT (%p)\n", *ppv);
1548     return S_OK;
1549   }
1550   
1551   /*
1552    * Get a class factory to construct the object we want.
1553    */
1554   hres = CoGetClassObject(rclsid,
1555                           dwClsContext,
1556                           NULL,
1557                           &IID_IClassFactory,
1558                           (LPVOID)&lpclf);
1559
1560   if (FAILED(hres)) {
1561     FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1562           debugstr_guid(rclsid),hres);
1563     return hres;
1564   }
1565
1566   /*
1567    * Create the object and don't forget to release the factory
1568    */
1569         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1570         IClassFactory_Release(lpclf);
1571         if(FAILED(hres))
1572           FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1573                 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1574
1575         return hres;
1576 }
1577
1578 /***********************************************************************
1579  *           CoCreateInstanceEx [OLE32.@]
1580  */
1581 HRESULT WINAPI CoCreateInstanceEx(
1582   REFCLSID      rclsid,
1583   LPUNKNOWN     pUnkOuter,
1584   DWORD         dwClsContext,
1585   COSERVERINFO* pServerInfo,
1586   ULONG         cmq,
1587   MULTI_QI*     pResults)
1588 {
1589   IUnknown* pUnk = NULL;
1590   HRESULT   hr;
1591   ULONG     index;
1592   int       successCount = 0;
1593
1594   /*
1595    * Sanity check
1596    */
1597   if ( (cmq==0) || (pResults==NULL))
1598     return E_INVALIDARG;
1599
1600   if (pServerInfo!=NULL)
1601     FIXME("() non-NULL pServerInfo not supported!\n");
1602
1603   /*
1604    * Initialize all the "out" parameters.
1605    */
1606   for (index = 0; index < cmq; index++)
1607   {
1608     pResults[index].pItf = NULL;
1609     pResults[index].hr   = E_NOINTERFACE;
1610   }
1611
1612   /*
1613    * Get the object and get its IUnknown pointer.
1614    */
1615   hr = CoCreateInstance(rclsid,
1616                         pUnkOuter,
1617                         dwClsContext,
1618                         &IID_IUnknown,
1619                         (VOID**)&pUnk);
1620
1621   if (hr)
1622     return hr;
1623
1624   /*
1625    * Then, query for all the interfaces requested.
1626    */
1627   for (index = 0; index < cmq; index++)
1628   {
1629     pResults[index].hr = IUnknown_QueryInterface(pUnk,
1630                                                  pResults[index].pIID,
1631                                                  (VOID**)&(pResults[index].pItf));
1632
1633     if (pResults[index].hr == S_OK)
1634       successCount++;
1635   }
1636
1637   /*
1638    * Release our temporary unknown pointer.
1639    */
1640   IUnknown_Release(pUnk);
1641
1642   if (successCount == 0)
1643     return E_NOINTERFACE;
1644
1645   if (successCount!=cmq)
1646     return CO_S_NOTALLINTERFACES;
1647
1648   return S_OK;
1649 }
1650
1651 /***********************************************************************
1652  *           CoLoadLibrary (OLE32.@)
1653  */
1654 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1655 {
1656     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1657
1658     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1659 }
1660
1661 /***********************************************************************
1662  *           CoFreeLibrary [OLE32.@]
1663  *
1664  * NOTES: don't believe the documentation
1665  */
1666 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1667 {
1668     FreeLibrary(hLibrary);
1669 }
1670
1671
1672 /***********************************************************************
1673  *           CoFreeAllLibraries [OLE32.@]
1674  *
1675  * NOTES: don't believe the documentation
1676  */
1677 void WINAPI CoFreeAllLibraries(void)
1678 {
1679     /* NOP */
1680 }
1681
1682
1683 /***********************************************************************
1684  *           CoFreeUnusedLibraries [COMPOBJ.17]
1685  *           CoFreeUnusedLibraries [OLE32.@]
1686  *
1687  * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1688  * through the main apartment's thread to call DllCanUnloadNow
1689  */
1690 void WINAPI CoFreeUnusedLibraries(void)
1691 {
1692     COMPOBJ_DllList_FreeUnused(0);
1693 }
1694
1695 /***********************************************************************
1696  *           CoFileTimeNow [COMPOBJ.82]
1697  *           CoFileTimeNow [OLE32.@]
1698  *
1699  * RETURNS
1700  *      the current system time in lpFileTime
1701  */
1702 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1703 {
1704     GetSystemTimeAsFileTime( lpFileTime );
1705     return S_OK;
1706 }
1707
1708 /***********************************************************************
1709  *           CoLoadLibrary (OLE32.@)
1710  */
1711 static void COM_RevokeAllClasses()
1712 {
1713   EnterCriticalSection( &csRegisteredClassList );
1714
1715   while (firstRegisteredClass!=0)
1716   {
1717     CoRevokeClassObject(firstRegisteredClass->dwCookie);
1718   }
1719
1720   LeaveCriticalSection( &csRegisteredClassList );
1721 }
1722
1723 /****************************************************************************
1724  *  COM External Lock methods implementation
1725  *
1726  *  This api provides a linked list to managed external references to
1727  *  COM objects.
1728  *
1729  *  The public interface consists of three calls:
1730  *      COM_ExternalLockAddRef
1731  *      COM_ExternalLockRelease
1732  *      COM_ExternalLockFreeList
1733  */
1734
1735 #define EL_END_OF_LIST 0
1736 #define EL_NOT_FOUND   0
1737
1738 /*
1739  * Declaration of the static structure that manage the
1740  * external lock to COM  objects.
1741  */
1742 typedef struct COM_ExternalLock     COM_ExternalLock;
1743 typedef struct COM_ExternalLockList COM_ExternalLockList;
1744
1745 struct COM_ExternalLock
1746 {
1747   IUnknown         *pUnk;     /* IUnknown referenced */
1748   ULONG            uRefCount; /* external lock counter to IUnknown object*/
1749   COM_ExternalLock *next;     /* Pointer to next element in list */
1750 };
1751
1752 struct COM_ExternalLockList
1753 {
1754   COM_ExternalLock *head;     /* head of list */
1755 };
1756
1757 /*
1758  * Declaration and initialization of the static structure that manages
1759  * the external lock to COM objects.
1760  */
1761 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1762
1763 /*
1764  * Private methods used to managed the linked list
1765  */
1766
1767
1768 static COM_ExternalLock* COM_ExternalLockLocate(
1769   COM_ExternalLock *element,
1770   IUnknown         *pUnk);
1771
1772 /****************************************************************************
1773  * Internal - Insert a new IUnknown* to the linked list
1774  */
1775 static BOOL COM_ExternalLockInsert(
1776   IUnknown *pUnk)
1777 {
1778   COM_ExternalLock *newLock      = NULL;
1779   COM_ExternalLock *previousHead = NULL;
1780
1781   /*
1782    * Allocate space for the new storage object
1783    */
1784   newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1785
1786   if (newLock!=NULL) {
1787     if ( elList.head == EL_END_OF_LIST ) {
1788       elList.head = newLock;    /* The list is empty */
1789     } else {
1790       /* insert does it at the head */
1791       previousHead  = elList.head;
1792       elList.head = newLock;
1793     }
1794
1795     /* Set new list item data member */
1796     newLock->pUnk      = pUnk;
1797     newLock->uRefCount = 1;
1798     newLock->next      = previousHead;
1799
1800     return TRUE;
1801   }
1802   return FALSE;
1803 }
1804
1805 /****************************************************************************
1806  * Internal - Method that removes an item from the linked list.
1807  */
1808 static void COM_ExternalLockDelete(
1809   COM_ExternalLock *itemList)
1810 {
1811   COM_ExternalLock *current = elList.head;
1812
1813   if ( current == itemList ) {
1814     /* this section handles the deletion of the first node */
1815     elList.head = itemList->next;
1816     HeapFree( GetProcessHeap(), 0, itemList);
1817   } else {
1818     do {
1819       if ( current->next == itemList ){   /* We found the item to free  */
1820         current->next = itemList->next;  /* readjust the list pointers */
1821         HeapFree( GetProcessHeap(), 0, itemList);
1822         break;
1823       }
1824
1825       /* Skip to the next item */
1826       current = current->next;
1827
1828     } while ( current != EL_END_OF_LIST );
1829   }
1830 }
1831
1832 /****************************************************************************
1833  * Internal - Recursivity agent for IUnknownExternalLockList_Find
1834  *
1835  * NOTES: how long can the list be ?? (recursive!!!)
1836  */
1837 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1838 {
1839   if ( element == EL_END_OF_LIST )
1840     return EL_NOT_FOUND;
1841   else if ( element->pUnk == pUnk )    /* We found it */
1842     return element;
1843   else                                 /* Not the right guy, keep on looking */
1844     return COM_ExternalLockLocate( element->next, pUnk);
1845 }
1846
1847 /****************************************************************************
1848  * Public - Method that increments the count for a IUnknown* in the linked
1849  * list.  The item is inserted if not already in the list.
1850  */
1851 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1852 {
1853   COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1854
1855   /*
1856    * Add an external lock to the object. If it was already externally
1857    * locked, just increase the reference count. If it was not.
1858    * add the item to the list.
1859    */
1860   if ( externalLock == EL_NOT_FOUND )
1861     COM_ExternalLockInsert(pUnk);
1862   else
1863     externalLock->uRefCount++;
1864
1865   /*
1866    * Add an internal lock to the object
1867    */
1868   IUnknown_AddRef(pUnk);
1869 }
1870
1871 /****************************************************************************
1872  * Public - Method that decrements the count for a IUnknown* in the linked
1873  * list.  The item is removed from the list if its count end up at zero or if
1874  * bRelAll is TRUE.
1875  */
1876 static void COM_ExternalLockRelease(
1877   IUnknown *pUnk,
1878   BOOL   bRelAll)
1879 {
1880   COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1881
1882   if ( externalLock != EL_NOT_FOUND ) {
1883     do {
1884       externalLock->uRefCount--;  /* release external locks      */
1885       IUnknown_Release(pUnk);     /* release local locks as well */
1886
1887       if ( bRelAll == FALSE ) break;  /* perform single release */
1888
1889     } while ( externalLock->uRefCount > 0 );
1890
1891     if ( externalLock->uRefCount == 0 )  /* get rid of the list entry */
1892       COM_ExternalLockDelete(externalLock);
1893   }
1894 }
1895 /****************************************************************************
1896  * Public - Method that frees the content of the list.
1897  */
1898 static void COM_ExternalLockFreeList()
1899 {
1900   COM_ExternalLock *head;
1901
1902   head = elList.head;                 /* grab it by the head             */
1903   while ( head != EL_END_OF_LIST ) {
1904     COM_ExternalLockDelete(head);     /* get rid of the head stuff       */
1905     head = elList.head;               /* get the new head...             */
1906   }
1907 }
1908
1909 /****************************************************************************
1910  * Public - Method that dump the content of the list.
1911  */
1912 void COM_ExternalLockDump()
1913 {
1914   COM_ExternalLock *current = elList.head;
1915
1916   DPRINTF("\nExternal lock list contains:\n");
1917
1918   while ( current != EL_END_OF_LIST ) {
1919     DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1920
1921     /* Skip to the next item */
1922     current = current->next;
1923   }
1924 }
1925
1926 /******************************************************************************
1927  *              CoLockObjectExternal    [OLE32.@]
1928  */
1929 HRESULT WINAPI CoLockObjectExternal(
1930     LPUNKNOWN pUnk,             /* [in] object to be locked */
1931     BOOL fLock,         /* [in] do lock */
1932     BOOL fLastUnlockReleases) /* [in] unlock all */
1933 {
1934
1935         if (fLock) {
1936             /*
1937              * Increment the external lock coutner, COM_ExternalLockAddRef also
1938              * increment the object's internal lock counter.
1939              */
1940             COM_ExternalLockAddRef( pUnk);
1941         } else {
1942             /*
1943              * Decrement the external lock coutner, COM_ExternalLockRelease also
1944              * decrement the object's internal lock counter.
1945              */
1946             COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1947         }
1948
1949         return S_OK;
1950 }
1951
1952 /***********************************************************************
1953  *           CoInitializeWOW (OLE32.@)
1954  */
1955 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1956     FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1957     return 0;
1958 }
1959
1960 static int nStatCounter = 0;     /* global */
1961 static HMODULE hOleAut32 = 0;    /* global */
1962
1963 /***********************************************************************
1964  *           CoGetState [OLE32.@]
1965  *
1966  * NOTES: might be incomplete
1967  */
1968 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1969 {
1970         APARTMENT * apt = COM_CurrentInfo();
1971
1972         FIXME("\n");
1973
1974         if(apt && apt->state) {
1975             IUnknown_AddRef(apt->state);
1976             *ppv = apt->state;
1977             FIXME("-- %p\n", *ppv);
1978             return S_OK;
1979         }
1980         *ppv = NULL;
1981         return E_FAIL;
1982
1983 }
1984
1985 /***********************************************************************
1986  *           CoSetState [OLE32.@]
1987  *
1988  * NOTES: FIXME: protect this with a crst
1989  */
1990 HRESULT WINAPI CoSetState(IUnknown * pv)
1991 {
1992     APARTMENT * apt = COM_CurrentInfo();
1993
1994     if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1995
1996         FIXME("(%p),stub!\n", pv);
1997
1998         if (pv) {
1999             IUnknown_AddRef(pv);
2000             nStatCounter++;
2001             if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
2002         }
2003
2004         if (apt->state) {
2005             TRACE("-- release %p now\n", apt->state);
2006             IUnknown_Release(apt->state);
2007             nStatCounter--;
2008             if (!nStatCounter) FreeLibrary(hOleAut32);
2009         }
2010         apt->state = pv;
2011         return S_OK;
2012 }
2013
2014
2015 /******************************************************************************
2016  *              OleGetAutoConvert        [OLE32.@]
2017  */
2018 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2019 {
2020     HKEY hkey = 0;
2021     char buf[200];
2022     WCHAR wbuf[200];
2023     DWORD len;
2024     HRESULT res = S_OK;
2025
2026     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2027     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2028     {
2029         res = REGDB_E_CLASSNOTREG;
2030         goto done;
2031     }
2032     len = 200;
2033     /* we can just query for the default value of AutoConvertTo key like that,
2034        without opening the AutoConvertTo key and querying for NULL (default) */
2035     if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2036     {
2037         res = REGDB_E_KEYMISSING;
2038         goto done;
2039     }
2040     MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2041     CLSIDFromString(wbuf,pClsidNew);
2042 done:
2043     if (hkey) RegCloseKey(hkey);
2044     return res;
2045 }
2046
2047 /******************************************************************************
2048  *              OleSetAutoConvert        [OLE32.@]
2049  */
2050 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2051 {
2052     HKEY hkey = 0;
2053     char buf[200], szClsidNew[200];
2054     HRESULT res = S_OK;
2055
2056     TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2057     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2058     WINE_StringFromCLSID(clsidNew, szClsidNew);
2059     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2060     {
2061         res = REGDB_E_CLASSNOTREG;
2062         goto done;
2063     }
2064     if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2065     {
2066         res = REGDB_E_WRITEREGDB;
2067         goto done;
2068     }
2069
2070 done:
2071     if (hkey) RegCloseKey(hkey);
2072     return res;
2073 }
2074
2075 /******************************************************************************
2076  *              OleDoAutoConvert        [OLE32.@]
2077  */
2078 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2079 {
2080     FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2081     return E_NOTIMPL;
2082 }
2083
2084 /******************************************************************************
2085  *              CoTreatAsClass        [OLE32.@]
2086  *
2087  * Sets TreatAs value of a class
2088  */
2089 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2090 {
2091     HKEY hkey = 0;
2092     char buf[47];
2093     char szClsidNew[39];
2094     HRESULT res = S_OK;
2095     char auto_treat_as[39];
2096     LONG auto_treat_as_size = sizeof(auto_treat_as);
2097     CLSID id;
2098
2099     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2100     WINE_StringFromCLSID(clsidNew, szClsidNew);
2101     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2102     {
2103         res = REGDB_E_CLASSNOTREG;
2104         goto done;
2105     }
2106     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2107     {
2108        if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2109            !__CLSIDFromStringA(auto_treat_as, &id))
2110        {
2111            if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2112            {
2113                res = REGDB_E_WRITEREGDB;
2114                goto done;
2115            }
2116        }
2117        else
2118        {
2119            RegDeleteKeyA(hkey, "TreatAs");
2120            goto done;
2121        }
2122     }
2123     else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2124     {
2125        res = REGDB_E_WRITEREGDB;
2126         goto done;
2127     }
2128
2129 done:
2130     if (hkey) RegCloseKey(hkey);
2131     return res;
2132 }
2133
2134 /******************************************************************************
2135  *              CoGetTreatAsClass        [OLE32.@]
2136  *
2137  * Reads the TreatAs value from a class.
2138  */
2139 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2140 {
2141     HKEY hkey = 0;
2142     char buf[200], szClsidNew[200];
2143     HRESULT res = S_OK;
2144     LONG len = sizeof(szClsidNew);
2145
2146     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2147     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2148     memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2149
2150     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2151     {
2152         res = REGDB_E_CLASSNOTREG;
2153         goto done;
2154     }
2155     if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2156     {
2157         res = S_FALSE;
2158         goto done;
2159     }
2160     res = __CLSIDFromStringA(szClsidNew,clsidNew);
2161     if (FAILED(res))
2162         FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2163 done:
2164     if (hkey) RegCloseKey(hkey);
2165     return res;
2166     
2167 }
2168
2169 /***********************************************************************
2170  *           IsEqualGUID [OLE32.@]
2171  *
2172  * Compares two Unique Identifiers.
2173  *
2174  * RETURNS
2175  *      TRUE if equal
2176  */
2177 #undef IsEqualGUID
2178 BOOL WINAPI IsEqualGUID(
2179      REFGUID rguid1, /* [in] unique id 1 */
2180      REFGUID rguid2  /* [in] unique id 2 */
2181      )
2182 {
2183     return !memcmp(rguid1,rguid2,sizeof(GUID));
2184 }
2185
2186 /***********************************************************************
2187  *           CoInitializeSecurity [OLE32.@]
2188  */
2189 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2190                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2191                                     void* pReserved1, DWORD dwAuthnLevel,
2192                                     DWORD dwImpLevel, void* pReserved2,
2193                                     DWORD dwCapabilities, void* pReserved3)
2194 {
2195   FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2196         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2197         dwCapabilities, pReserved3);
2198   return S_OK;
2199 }