Authors: Robert Shearman <rob@codeweavers.com>, Mike Hearn <mh@codeweavers.com>
[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     /* Release the references to the registered class objects */
516     COM_RevokeAllClasses();
517
518     /* This will free the loaded COM Dlls  */
519     CoFreeAllLibraries();
520
521     /* This will free list of external references to COM objects */
522     COM_ExternalLockFreeList();
523
524     /* This ensures we deal with any pending RPCs */
525     COM_FlushMessageQueue();
526
527     COM_UninitMTA();
528   }
529   else if (lCOMRefCnt<1) {
530     ERR( "CoUninitialize() - not CoInitialized.\n" );
531     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
532   }
533 }
534
535 /******************************************************************************
536  *              CoDisconnectObject      [COMPOBJ.15]
537  *              CoDisconnectObject      [OLE32.@]
538  *
539  * Disconnects all connections to this object from remote processes. Dispatches
540  * pending RPCs while blocking new RPCs from occurring, and then calls
541  * IMarshal::DisconnectObject on the given object.
542  *
543  * Typically called when the object server is forced to shut down, for instance by
544  * the user.
545  */
546 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
547 {
548     FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
549     return S_OK;
550 }
551
552 /******************************************************************************
553  *              CoCreateGuid[OLE32.@]
554  *
555  */
556 HRESULT WINAPI CoCreateGuid(
557         GUID *pguid /* [out] points to the GUID to initialize */
558 ) {
559     return UuidCreate(pguid);
560 }
561
562 /******************************************************************************
563  *              CLSIDFromString [OLE32.@]
564  *              IIDFromString   [OLE32.@]
565  * Converts a unique identifier from its string representation into
566  * the GUID struct.
567  *
568  * UNDOCUMENTED
569  *      If idstr is not a valid CLSID string then it gets treated as a ProgID
570  *
571  * RETURNS
572  *      the converted GUID
573  */
574 HRESULT WINAPI __CLSIDFromStringA(
575         LPCSTR idstr,           /* [in] string representation of guid */
576         CLSID *id)              /* [out] GUID converted from string */
577 {
578   const BYTE *s = (BYTE *) idstr;
579   int   i;
580   BYTE table[256];
581
582   if (!s)
583           s = "{00000000-0000-0000-0000-000000000000}";
584   else {  /* validate the CLSID string */
585
586       if (strlen(s) != 38)
587           return CO_E_CLASSSTRING;
588
589       if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
590           return CO_E_CLASSSTRING;
591
592       for (i=1; i<37; i++) {
593           if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
594           if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
595                 ((s[i] >= 'a') && (s[i] <= 'f'))  ||
596                 ((s[i] >= 'A') && (s[i] <= 'F'))))
597               return CO_E_CLASSSTRING;
598       }
599   }
600
601   TRACE("%s -> %p\n", s, id);
602
603   /* quick lookup table */
604   memset(table, 0, 256);
605
606   for (i = 0; i < 10; i++) {
607     table['0' + i] = i;
608   }
609   for (i = 0; i < 6; i++) {
610     table['A' + i] = i+10;
611     table['a' + i] = i+10;
612   }
613
614   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
615
616   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
617                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
618   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
619   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
620
621   /* these are just sequential bytes */
622   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
623   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
624   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
625   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
626   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
627   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
628   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
629   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
630
631   return S_OK;
632 }
633
634 /*****************************************************************************/
635
636 HRESULT WINAPI CLSIDFromString(
637         LPOLESTR idstr,         /* [in] string representation of GUID */
638         CLSID *id )             /* [out] GUID represented by above string */
639 {
640     char xid[40];
641     HRESULT ret;
642
643     if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
644         return CO_E_CLASSSTRING;
645
646
647     ret = __CLSIDFromStringA(xid,id);
648     if(ret != S_OK) { /* It appears a ProgID is also valid */
649         ret = CLSIDFromProgID(idstr, id);
650     }
651     return ret;
652 }
653
654 /******************************************************************************
655  *              WINE_StringFromCLSID    [Internal]
656  * Converts a GUID into the respective string representation.
657  *
658  * NOTES
659  *
660  * RETURNS
661  *      the string representation and HRESULT
662  */
663 HRESULT WINE_StringFromCLSID(
664         const CLSID *id,        /* [in] GUID to be converted */
665         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
666 ) {
667   static const char *hex = "0123456789ABCDEF";
668   char *s;
669   int   i;
670
671   if (!id)
672         { ERR("called with id=Null\n");
673           *idstr = 0x00;
674           return E_FAIL;
675         }
676
677   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
678           id->Data1, id->Data2, id->Data3,
679           id->Data4[0], id->Data4[1]);
680   s = &idstr[25];
681
682   /* 6 hex bytes */
683   for (i = 2; i < 8; i++) {
684     *s++ = hex[id->Data4[i]>>4];
685     *s++ = hex[id->Data4[i] & 0xf];
686   }
687
688   *s++ = '}';
689   *s++ = '\0';
690
691   TRACE("%p->%s\n", id, idstr);
692
693   return S_OK;
694 }
695
696
697 /******************************************************************************
698  *              StringFromCLSID [OLE32.@]
699  *              StringFromIID   [OLE32.@]
700  * Converts a GUID into the respective string representation.
701  * The target string is allocated using the OLE IMalloc.
702  * RETURNS
703  *      the string representation and HRESULT
704  */
705 HRESULT WINAPI StringFromCLSID(
706         REFCLSID id,            /* [in] the GUID to be converted */
707         LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
708 ) {
709         char            buf[80];
710         HRESULT       ret;
711         LPMALLOC        mllc;
712
713         if ((ret=CoGetMalloc(0,&mllc)))
714                 return ret;
715
716         ret=WINE_StringFromCLSID(id,buf);
717         if (!ret) {
718             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
719             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
720             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
721         }
722         return ret;
723 }
724
725 /******************************************************************************
726  *              StringFromGUID2 [COMPOBJ.76]
727  *              StringFromGUID2 [OLE32.@]
728  *
729  * Converts a global unique identifier into a string of an API-
730  * specified fixed format. (The usual {.....} stuff.)
731  *
732  * RETURNS
733  *      The (UNICODE) string representation of the GUID in 'str'
734  *      The length of the resulting string, 0 if there was any problem.
735  */
736 INT WINAPI
737 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
738 {
739   char          xguid[80];
740
741   if (WINE_StringFromCLSID(id,xguid))
742         return 0;
743   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
744 }
745
746 /******************************************************************************
747  * ProgIDFromCLSID [OLE32.@]
748  * Converts a class id into the respective Program ID. (By using a registry lookup)
749  * RETURNS S_OK on success
750  * riid associated with the progid
751  */
752
753 HRESULT WINAPI ProgIDFromCLSID(
754   REFCLSID clsid, /* [in] class id as found in registry */
755   LPOLESTR *lplpszProgID/* [out] associated Prog ID */
756 )
757 {
758   char     strCLSID[50], *buf, *buf2;
759   DWORD    buf2len;
760   HKEY     xhkey;
761   LPMALLOC mllc;
762   HRESULT  ret = S_OK;
763
764   WINE_StringFromCLSID(clsid, strCLSID);
765
766   buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
767   sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
768   if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
769     ret = REGDB_E_CLASSNOTREG;
770
771   HeapFree(GetProcessHeap(), 0, buf);
772
773   if (ret == S_OK)
774   {
775     buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
776     buf2len = 255;
777     if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
778       ret = REGDB_E_CLASSNOTREG;
779
780     if (ret == S_OK)
781     {
782       if (CoGetMalloc(0,&mllc))
783         ret = E_OUTOFMEMORY;
784       else
785       {
786           DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
787           *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
788           MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
789       }
790     }
791     HeapFree(GetProcessHeap(), 0, buf2);
792   }
793
794   RegCloseKey(xhkey);
795   return ret;
796 }
797
798 /******************************************************************************
799  *              CLSIDFromProgID [COMPOBJ.61]
800  * Converts a program id into the respective GUID. (By using a registry lookup)
801  * RETURNS
802  *      riid associated with the progid
803  */
804 HRESULT WINAPI CLSIDFromProgID16(
805         LPCOLESTR16 progid,     /* [in] program id as found in registry */
806         LPCLSID riid            /* [out] associated CLSID */
807 ) {
808         char    *buf,buf2[80];
809         DWORD   buf2len;
810         HRESULT err;
811         HKEY    xhkey;
812
813         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
814         sprintf(buf,"%s\\CLSID",progid);
815         if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
816                 HeapFree(GetProcessHeap(),0,buf);
817                 return CO_E_CLASSSTRING;
818         }
819         HeapFree(GetProcessHeap(),0,buf);
820         buf2len = sizeof(buf2);
821         if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
822                 RegCloseKey(xhkey);
823                 return CO_E_CLASSSTRING;
824         }
825         RegCloseKey(xhkey);
826         return __CLSIDFromStringA(buf2,riid);
827 }
828
829 /******************************************************************************
830  *              CLSIDFromProgID [OLE32.@]
831  * Converts a program id into the respective GUID. (By using a registry lookup)
832  * RETURNS
833  *      riid associated with the progid
834  */
835 HRESULT WINAPI CLSIDFromProgID(
836         LPCOLESTR progid,       /* [in] program id as found in registry */
837         LPCLSID riid )          /* [out] associated CLSID */
838 {
839     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
840     char buf2[80];
841     DWORD buf2len = sizeof(buf2);
842     HKEY xhkey;
843
844     WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
845     strcpyW( buf, progid );
846     strcatW( buf, clsidW );
847     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
848     {
849         HeapFree(GetProcessHeap(),0,buf);
850         return CO_E_CLASSSTRING;
851     }
852     HeapFree(GetProcessHeap(),0,buf);
853
854     if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
855     {
856         RegCloseKey(xhkey);
857         return CO_E_CLASSSTRING;
858     }
859     RegCloseKey(xhkey);
860     return __CLSIDFromStringA(buf2,riid);
861 }
862
863
864
865 /*****************************************************************************
866  *             CoGetPSClsid [OLE32.@]
867  *
868  * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
869  * for the specified interface.
870  *
871  * The standard marshaller activates the object with the CLSID returned and uses the
872  * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
873  * the proxies and stubs for a given object.
874  *
875  * CoGetPSClsid determines this CLSID by searching the
876  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
877  * and any interface id registered by CoRegisterPSClsid within the current process.
878  *
879  * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
880  */
881 HRESULT WINAPI CoGetPSClsid(
882           REFIID riid,     /* [in]  Interface whose proxy/stub CLSID is to be returned */
883           CLSID *pclsid )    /* [out] Where to store returned proxy/stub CLSID */
884 {
885     char *buf, buf2[40];
886     DWORD buf2len;
887     HKEY xhkey;
888
889     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
890
891     /* Get the input iid as a string */
892     WINE_StringFromCLSID(riid, buf2);
893     /* Allocate memory for the registry key we will construct.
894        (length of iid string plus constant length of static text */
895     buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
896     if (buf == NULL)
897     {
898        return (E_OUTOFMEMORY);
899     }
900
901     /* Construct the registry key we want */
902     sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
903
904     /* Open the key.. */
905     if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
906     {
907        WARN("No PSFactoryBuffer object is registered for this IID\n");
908        HeapFree(GetProcessHeap(),0,buf);
909        return (E_INVALIDARG);
910     }
911     HeapFree(GetProcessHeap(),0,buf);
912
913     /* ... Once we have the key, query the registry to get the
914        value of CLSID as a string, and convert it into a
915        proper CLSID structure to be passed back to the app */
916     buf2len = sizeof(buf2);
917     if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
918     {
919        RegCloseKey(xhkey);
920        return E_INVALIDARG;
921     }
922     RegCloseKey(xhkey);
923
924     /* We have the CLSid we want back from the registry as a string, so
925        lets convert it into a CLSID structure */
926     if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
927        return E_INVALIDARG;
928     }
929
930     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
931     return (S_OK);
932 }
933
934
935
936 /***********************************************************************
937  *              WriteClassStm (OLE32.@)
938  *
939  * This function write a CLSID on stream
940  */
941 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
942 {
943     TRACE("(%p,%p)\n",pStm,rclsid);
944
945     if (rclsid==NULL)
946         return E_INVALIDARG;
947
948     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
949 }
950
951 /***********************************************************************
952  *              ReadClassStm (OLE32.@)
953  *
954  * This function read a CLSID from a stream
955  */
956 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
957 {
958     ULONG nbByte;
959     HRESULT res;
960
961     TRACE("(%p,%p)\n",pStm,pclsid);
962
963     if (pclsid==NULL)
964         return E_INVALIDARG;
965
966     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
967
968     if (FAILED(res))
969         return res;
970
971     if (nbByte != sizeof(CLSID))
972         return S_FALSE;
973     else
974         return S_OK;
975 }
976
977
978 /***
979  * COM_GetRegisteredClassObject
980  *
981  * This internal method is used to scan the registered class list to
982  * find a class object.
983  *
984  * Params:
985  *   rclsid        Class ID of the class to find.
986  *   dwClsContext  Class context to match.
987  *   ppv           [out] returns a pointer to the class object. Complying
988  *                 to normal COM usage, this method will increase the
989  *                 reference count on this object.
990  */
991 static HRESULT COM_GetRegisteredClassObject(
992         REFCLSID    rclsid,
993         DWORD       dwClsContext,
994         LPUNKNOWN*  ppUnk)
995 {
996   HRESULT hr = S_FALSE;
997   RegisteredClass* curClass;
998
999   EnterCriticalSection( &csRegisteredClassList );
1000
1001   /*
1002    * Sanity check
1003    */
1004   assert(ppUnk!=0);
1005
1006   /*
1007    * Iterate through the whole list and try to match the class ID.
1008    */
1009   curClass = firstRegisteredClass;
1010
1011   while (curClass != 0)
1012   {
1013     /*
1014      * Check if we have a match on the class ID.
1015      */
1016     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1017     {
1018       /*
1019        * Since we don't do out-of process or DCOM just right away, let's ignore the
1020        * class context.
1021        */
1022
1023       /*
1024        * We have a match, return the pointer to the class object.
1025        */
1026       *ppUnk = curClass->classObject;
1027
1028       IUnknown_AddRef(curClass->classObject);
1029
1030       hr = S_OK;
1031       goto end;
1032     }
1033
1034     /*
1035      * Step to the next class in the list.
1036      */
1037     curClass = curClass->nextClass;
1038   }
1039
1040 end:
1041   LeaveCriticalSection( &csRegisteredClassList );
1042   /*
1043    * If we get to here, we haven't found our class.
1044    */
1045   return hr;
1046 }
1047
1048 static DWORD WINAPI
1049 _LocalServerThread(LPVOID param) {
1050     HANDLE              hPipe;
1051     char                pipefn[200];
1052     RegisteredClass *newClass = (RegisteredClass*)param;
1053     HRESULT             hres;
1054     IStream             *pStm;
1055     STATSTG             ststg;
1056     unsigned char       *buffer;
1057     int                 buflen;
1058     IClassFactory       *classfac;
1059     LARGE_INTEGER       seekto;
1060     ULARGE_INTEGER      newpos;
1061     ULONG               res;
1062
1063     TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1064     strcpy(pipefn,PIPEPREF);
1065     WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1066
1067     hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1068     if (hres) return hres;
1069
1070     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1071     if (hres) {
1072         FIXME("Failed to create stream on hglobal.\n");
1073         return hres;
1074     }
1075     hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1076     if (hres) {
1077         FIXME("CoMarshalInterface failed, %lx!\n",hres);
1078         return hres;
1079     }
1080     hres = IStream_Stat(pStm,&ststg,0);
1081     if (hres) return hres;
1082
1083     buflen = ststg.cbSize.u.LowPart;
1084     buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1085     seekto.u.LowPart = 0;
1086     seekto.u.HighPart = 0;
1087     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1088     if (hres) {
1089         FIXME("IStream_Seek failed, %lx\n",hres);
1090         return hres;
1091     }
1092     hres = IStream_Read(pStm,buffer,buflen,&res);
1093     if (hres) {
1094         FIXME("Stream Read failed, %lx\n",hres);
1095         return hres;
1096     }
1097     IStream_Release(pStm);
1098
1099     hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1100                PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1101                4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1102     if (hPipe == INVALID_HANDLE_VALUE) {
1103         FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1104         return 1;
1105     }
1106     while (1) {
1107         if (!ConnectNamedPipe(hPipe,NULL)) {
1108             ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1109             break;
1110         }
1111         WriteFile(hPipe,buffer,buflen,&res,NULL);
1112         FlushFileBuffers(hPipe);
1113         DisconnectNamedPipe(hPipe);
1114     }
1115     CloseHandle(hPipe);
1116     return 0;
1117 }
1118
1119 /******************************************************************************
1120  *              CoRegisterClassObject   [OLE32.@]
1121  *
1122  * This method will register the class object for a given class ID. Servers housed
1123  * in EXE files use this method instead of exporting DllGetClassObject to allow other
1124  * code to connect to their objects.
1125  *
1126  * When a class object (an object which implements IClassFactory) is registered in
1127  * this way, a new thread is started which listens for connections on a named pipe
1128  * specific to the registered CLSID. When something else connects to it, it writes
1129  * out the marshalled IClassFactory interface to the pipe. The code on the other end
1130  * uses this buffer to unmarshal the class factory, and can then call methods on it.
1131  *
1132  * In Windows, such objects are registered with the RPC endpoint mapper, not with
1133  * a unique named pipe.
1134  *
1135  * See the Windows documentation for more details.
1136  */
1137 HRESULT WINAPI CoRegisterClassObject(
1138         REFCLSID rclsid,
1139         LPUNKNOWN pUnk,
1140         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1141         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
1142         LPDWORD lpdwRegister
1143 )
1144 {
1145   RegisteredClass* newClass;
1146   LPUNKNOWN        foundObject;
1147   HRESULT          hr;
1148
1149   TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1150         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1151
1152   if ( (lpdwRegister==0) || (pUnk==0) )
1153     return E_INVALIDARG;
1154
1155   *lpdwRegister = 0;
1156
1157   /*
1158    * First, check if the class is already registered.
1159    * If it is, this should cause an error.
1160    *
1161    * MSDN claims that multiple interface registrations are legal, but we can't do that with
1162    * our current implementation.
1163    */
1164   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1165   if (hr == S_OK) {
1166     IUnknown_Release(foundObject);
1167     return CO_E_OBJISREG;
1168   }
1169
1170   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1171   if ( newClass == NULL )
1172     return E_OUTOFMEMORY;
1173
1174   EnterCriticalSection( &csRegisteredClassList );
1175
1176   newClass->classIdentifier = *rclsid;
1177   newClass->runContext      = dwClsContext;
1178   newClass->connectFlags    = flags;
1179   /*
1180    * Use the address of the chain node as the cookie since we are sure it's
1181    * unique.
1182    */
1183   newClass->dwCookie        = (DWORD)newClass;
1184   newClass->nextClass       = firstRegisteredClass;
1185
1186   /*
1187    * Since we're making a copy of the object pointer, we have to increase its
1188    * reference count.
1189    */
1190   newClass->classObject     = pUnk;
1191   IUnknown_AddRef(newClass->classObject);
1192
1193   firstRegisteredClass = newClass;
1194   LeaveCriticalSection( &csRegisteredClassList );
1195
1196   *lpdwRegister = newClass->dwCookie;
1197
1198   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1199       DWORD tid;
1200
1201       STUBMGR_Start();
1202       newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1203   }
1204   return S_OK;
1205 }
1206
1207 /***********************************************************************
1208  *           CoRevokeClassObject [OLE32.@]
1209  *
1210  * This method will remove a class object from the class registry
1211  *
1212  * See the Windows documentation for more details.
1213  */
1214 HRESULT WINAPI CoRevokeClassObject(
1215         DWORD dwRegister)
1216 {
1217   HRESULT hr = E_INVALIDARG;
1218   RegisteredClass** prevClassLink;
1219   RegisteredClass*  curClass;
1220
1221   TRACE("(%08lx)\n",dwRegister);
1222
1223   EnterCriticalSection( &csRegisteredClassList );
1224
1225   /*
1226    * Iterate through the whole list and try to match the cookie.
1227    */
1228   curClass      = firstRegisteredClass;
1229   prevClassLink = &firstRegisteredClass;
1230
1231   while (curClass != 0)
1232   {
1233     /*
1234      * Check if we have a match on the cookie.
1235      */
1236     if (curClass->dwCookie == dwRegister)
1237     {
1238       /*
1239        * Remove the class from the chain.
1240        */
1241       *prevClassLink = curClass->nextClass;
1242
1243       /*
1244        * Release the reference to the class object.
1245        */
1246       IUnknown_Release(curClass->classObject);
1247
1248       /*
1249        * Free the memory used by the chain node.
1250        */
1251       HeapFree(GetProcessHeap(), 0, curClass);
1252
1253       hr = S_OK;
1254       goto end;
1255     }
1256
1257     /*
1258      * Step to the next class in the list.
1259      */
1260     prevClassLink = &(curClass->nextClass);
1261     curClass      = curClass->nextClass;
1262   }
1263
1264 end:
1265   LeaveCriticalSection( &csRegisteredClassList );
1266   /*
1267    * If we get to here, we haven't found our class.
1268    */
1269   return hr;
1270 }
1271
1272 /***********************************************************************
1273  *      compobj_RegReadPath     [internal]
1274  *
1275  *      Reads a registry value and expands it when necessary
1276  */
1277 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1278 {
1279         HRESULT hres;
1280         HKEY key;
1281         DWORD keytype;
1282         char src[MAX_PATH];
1283         DWORD dwLength = dstlen;
1284
1285         if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1286           if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1287             if (keytype == REG_EXPAND_SZ) {
1288               if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1289             } else {
1290               strncpy(dst, src, dstlen);
1291             }
1292           }
1293           RegCloseKey (key);
1294         }
1295         return hres;
1296 }
1297
1298 /***********************************************************************
1299  *           CoGetClassObject [COMPOBJ.7]
1300  *           CoGetClassObject [OLE32.@]
1301  *
1302  * FIXME.  If request allows of several options and there is a failure
1303  *         with one (other than not being registered) do we try the
1304  *         others or return failure?  (E.g. inprocess is registered but
1305  *         the DLL is not found but the server version works)
1306  */
1307 HRESULT WINAPI CoGetClassObject(
1308     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1309     REFIID iid, LPVOID *ppv
1310 ) {
1311     LPUNKNOWN   regClassObject;
1312     HRESULT     hres = E_UNEXPECTED;
1313     char        xclsid[80];
1314     HINSTANCE hLibrary;
1315     typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1316     DllGetClassObjectFunc DllGetClassObject;
1317
1318     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1319
1320     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1321
1322     if (pServerInfo) {
1323         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1324         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1325     }
1326
1327     /*
1328      * First, try and see if we can't match the class ID with one of the
1329      * registered classes.
1330      */
1331     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1332     {
1333       /*
1334        * Get the required interface from the retrieved pointer.
1335        */
1336       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1337
1338       /*
1339        * Since QI got another reference on the pointer, we want to release the
1340        * one we already have. If QI was unsuccessful, this will release the object. This
1341        * is good since we are not returning it in the "out" parameter.
1342        */
1343       IUnknown_Release(regClassObject);
1344
1345       return hres;
1346     }
1347
1348     /* first try: in-process */
1349     if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1350         char keyname[MAX_PATH];
1351         char dllpath[MAX_PATH+1];
1352
1353         sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1354
1355         if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1356             /* failure: CLSID is not found in registry */
1357            WARN("class %s not registered inproc\n", xclsid);
1358             hres = REGDB_E_CLASSNOTREG;
1359         } else {
1360           if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1361             /* failure: DLL could not be loaded */
1362             ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1363             hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1364           } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1365             /* failure: the dll did not export DllGetClassObject */
1366             ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1367             FreeLibrary( hLibrary );
1368             hres = CO_E_DLLNOTFOUND;
1369           } else {
1370             /* OK: get the ClassObject */
1371             COMPOBJ_DLLList_Add( hLibrary );
1372             return DllGetClassObject(rclsid, iid, ppv);
1373           }
1374         }
1375     }
1376
1377     /* Next try out of process */
1378     if (CLSCTX_LOCAL_SERVER & dwClsContext)
1379     {
1380         return create_marshalled_proxy(rclsid,iid,ppv);
1381     }
1382
1383     /* Finally try remote: this requires networked DCOM (a lot of work) */
1384     if (CLSCTX_REMOTE_SERVER & dwClsContext)
1385     {
1386         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1387         hres = E_NOINTERFACE;
1388     }
1389
1390     return hres;
1391 }
1392 /***********************************************************************
1393  *        CoResumeClassObjects (OLE32.@)
1394  *
1395  * Resumes classobjects registered with REGCLS suspended
1396  */
1397 HRESULT WINAPI CoResumeClassObjects(void)
1398 {
1399        FIXME("stub\n");
1400         return S_OK;
1401 }
1402
1403 /***********************************************************************
1404  *        GetClassFile (OLE32.@)
1405  *
1406  * This function supplies the CLSID associated with the given filename.
1407  */
1408 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1409 {
1410     IStorage *pstg=0;
1411     HRESULT res;
1412     int nbElm, length, i;
1413     LONG sizeProgId;
1414     LPOLESTR *pathDec=0,absFile=0,progId=0;
1415     LPWSTR extension;
1416     static const WCHAR bkslashW[] = {'\\',0};
1417     static const WCHAR dotW[] = {'.',0};
1418
1419     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1420
1421     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1422     if((StgIsStorageFile(filePathName))==S_OK){
1423
1424         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1425
1426         if (SUCCEEDED(res))
1427             res=ReadClassStg(pstg,pclsid);
1428
1429         IStorage_Release(pstg);
1430
1431         return res;
1432     }
1433     /* if the file is not a storage object then attemps to match various bits in the file against a
1434        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1435        this case
1436
1437      for(i=0;i<nFileTypes;i++)
1438
1439         for(i=0;j<nPatternsForType;j++){
1440
1441             PATTERN pat;
1442             HANDLE  hFile;
1443
1444             pat=ReadPatternFromRegistry(i,j);
1445             hFile=CreateFileW(filePathName,,,,,,hFile);
1446             SetFilePosition(hFile,pat.offset);
1447             ReadFile(hFile,buf,pat.size,NULL,NULL);
1448             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1449
1450                 *pclsid=ReadCLSIDFromRegistry(i);
1451                 return S_OK;
1452             }
1453         }
1454      */
1455
1456     /* if the above strategies fail then search for the extension key in the registry */
1457
1458     /* get the last element (absolute file) in the path name */
1459     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1460     absFile=pathDec[nbElm-1];
1461
1462     /* failed if the path represente a directory and not an absolute file name*/
1463     if (!lstrcmpW(absFile, bkslashW))
1464         return MK_E_INVALIDEXTENSION;
1465
1466     /* get the extension of the file */
1467     extension = NULL;
1468     length=lstrlenW(absFile);
1469     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1470         /* nothing */;
1471
1472     if (!extension || !lstrcmpW(extension, dotW))
1473         return MK_E_INVALIDEXTENSION;
1474
1475     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1476
1477     /* get the progId associated to the extension */
1478     progId = CoTaskMemAlloc(sizeProgId);
1479     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1480
1481     if (res==ERROR_SUCCESS)
1482         /* return the clsid associated to the progId */
1483         res= CLSIDFromProgID(progId,pclsid);
1484
1485     for(i=0; pathDec[i]!=NULL;i++)
1486         CoTaskMemFree(pathDec[i]);
1487     CoTaskMemFree(pathDec);
1488
1489     CoTaskMemFree(progId);
1490
1491     if (res==ERROR_SUCCESS)
1492         return res;
1493
1494     return MK_E_INVALIDEXTENSION;
1495 }
1496 /***********************************************************************
1497  *           CoCreateInstance [COMPOBJ.13]
1498  *           CoCreateInstance [OLE32.@]
1499  */
1500 HRESULT WINAPI CoCreateInstance(
1501         REFCLSID rclsid,
1502         LPUNKNOWN pUnkOuter,
1503         DWORD dwClsContext,
1504         REFIID iid,
1505         LPVOID *ppv)
1506 {
1507         HRESULT hres;
1508         LPCLASSFACTORY lpclf = 0;
1509
1510   /*
1511    * Sanity check
1512    */
1513   if (ppv==0)
1514     return E_POINTER;
1515
1516   /*
1517    * Initialize the "out" parameter
1518    */
1519   *ppv = 0;
1520
1521   /*
1522    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1523    * Rather than create a class factory, we can just check for it here
1524    */
1525   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1526     if (StdGlobalInterfaceTableInstance == NULL) 
1527       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1528     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1529     if (hres) return hres;
1530     
1531     TRACE("Retrieved GIT (%p)\n", *ppv);
1532     return S_OK;
1533   }
1534   
1535   /*
1536    * Get a class factory to construct the object we want.
1537    */
1538   hres = CoGetClassObject(rclsid,
1539                           dwClsContext,
1540                           NULL,
1541                           &IID_IClassFactory,
1542                           (LPVOID)&lpclf);
1543
1544   if (FAILED(hres)) {
1545     FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1546           debugstr_guid(rclsid),hres);
1547     return hres;
1548   }
1549
1550   /*
1551    * Create the object and don't forget to release the factory
1552    */
1553         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1554         IClassFactory_Release(lpclf);
1555         if(FAILED(hres))
1556           FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1557                 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1558
1559         return hres;
1560 }
1561
1562 /***********************************************************************
1563  *           CoCreateInstanceEx [OLE32.@]
1564  */
1565 HRESULT WINAPI CoCreateInstanceEx(
1566   REFCLSID      rclsid,
1567   LPUNKNOWN     pUnkOuter,
1568   DWORD         dwClsContext,
1569   COSERVERINFO* pServerInfo,
1570   ULONG         cmq,
1571   MULTI_QI*     pResults)
1572 {
1573   IUnknown* pUnk = NULL;
1574   HRESULT   hr;
1575   ULONG     index;
1576   int       successCount = 0;
1577
1578   /*
1579    * Sanity check
1580    */
1581   if ( (cmq==0) || (pResults==NULL))
1582     return E_INVALIDARG;
1583
1584   if (pServerInfo!=NULL)
1585     FIXME("() non-NULL pServerInfo not supported!\n");
1586
1587   /*
1588    * Initialize all the "out" parameters.
1589    */
1590   for (index = 0; index < cmq; index++)
1591   {
1592     pResults[index].pItf = NULL;
1593     pResults[index].hr   = E_NOINTERFACE;
1594   }
1595
1596   /*
1597    * Get the object and get its IUnknown pointer.
1598    */
1599   hr = CoCreateInstance(rclsid,
1600                         pUnkOuter,
1601                         dwClsContext,
1602                         &IID_IUnknown,
1603                         (VOID**)&pUnk);
1604
1605   if (hr)
1606     return hr;
1607
1608   /*
1609    * Then, query for all the interfaces requested.
1610    */
1611   for (index = 0; index < cmq; index++)
1612   {
1613     pResults[index].hr = IUnknown_QueryInterface(pUnk,
1614                                                  pResults[index].pIID,
1615                                                  (VOID**)&(pResults[index].pItf));
1616
1617     if (pResults[index].hr == S_OK)
1618       successCount++;
1619   }
1620
1621   /*
1622    * Release our temporary unknown pointer.
1623    */
1624   IUnknown_Release(pUnk);
1625
1626   if (successCount == 0)
1627     return E_NOINTERFACE;
1628
1629   if (successCount!=cmq)
1630     return CO_S_NOTALLINTERFACES;
1631
1632   return S_OK;
1633 }
1634
1635 /***********************************************************************
1636  *           CoLoadLibrary (OLE32.@)
1637  */
1638 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1639 {
1640     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1641
1642     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1643 }
1644
1645 /***********************************************************************
1646  *           CoFreeLibrary [OLE32.@]
1647  *
1648  * NOTES: don't believe the documentation
1649  */
1650 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1651 {
1652     FreeLibrary(hLibrary);
1653 }
1654
1655
1656 /***********************************************************************
1657  *           CoFreeAllLibraries [OLE32.@]
1658  *
1659  * NOTES: don't believe the documentation
1660  */
1661 void WINAPI CoFreeAllLibraries(void)
1662 {
1663     /* NOP */
1664 }
1665
1666
1667 /***********************************************************************
1668  *           CoFreeUnusedLibraries [COMPOBJ.17]
1669  *           CoFreeUnusedLibraries [OLE32.@]
1670  *
1671  * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1672  * through the main apartment's thread to call DllCanUnloadNow
1673  */
1674 void WINAPI CoFreeUnusedLibraries(void)
1675 {
1676     COMPOBJ_DllList_FreeUnused(0);
1677 }
1678
1679 /***********************************************************************
1680  *           CoFileTimeNow [COMPOBJ.82]
1681  *           CoFileTimeNow [OLE32.@]
1682  *
1683  * RETURNS
1684  *      the current system time in lpFileTime
1685  */
1686 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1687 {
1688     GetSystemTimeAsFileTime( lpFileTime );
1689     return S_OK;
1690 }
1691
1692 /***********************************************************************
1693  *           CoLoadLibrary (OLE32.@)
1694  */
1695 static void COM_RevokeAllClasses()
1696 {
1697   EnterCriticalSection( &csRegisteredClassList );
1698
1699   while (firstRegisteredClass!=0)
1700   {
1701     CoRevokeClassObject(firstRegisteredClass->dwCookie);
1702   }
1703
1704   LeaveCriticalSection( &csRegisteredClassList );
1705 }
1706
1707 /****************************************************************************
1708  *  COM External Lock methods implementation
1709  *
1710  *  This api provides a linked list to managed external references to
1711  *  COM objects.
1712  *
1713  *  The public interface consists of three calls:
1714  *      COM_ExternalLockAddRef
1715  *      COM_ExternalLockRelease
1716  *      COM_ExternalLockFreeList
1717  */
1718
1719 #define EL_END_OF_LIST 0
1720 #define EL_NOT_FOUND   0
1721
1722 /*
1723  * Declaration of the static structure that manage the
1724  * external lock to COM  objects.
1725  */
1726 typedef struct COM_ExternalLock     COM_ExternalLock;
1727 typedef struct COM_ExternalLockList COM_ExternalLockList;
1728
1729 struct COM_ExternalLock
1730 {
1731   IUnknown         *pUnk;     /* IUnknown referenced */
1732   ULONG            uRefCount; /* external lock counter to IUnknown object*/
1733   COM_ExternalLock *next;     /* Pointer to next element in list */
1734 };
1735
1736 struct COM_ExternalLockList
1737 {
1738   COM_ExternalLock *head;     /* head of list */
1739 };
1740
1741 /*
1742  * Declaration and initialization of the static structure that manages
1743  * the external lock to COM objects.
1744  */
1745 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1746
1747 /*
1748  * Private methods used to managed the linked list
1749  */
1750
1751
1752 static COM_ExternalLock* COM_ExternalLockLocate(
1753   COM_ExternalLock *element,
1754   IUnknown         *pUnk);
1755
1756 /****************************************************************************
1757  * Internal - Insert a new IUnknown* to the linked list
1758  */
1759 static BOOL COM_ExternalLockInsert(
1760   IUnknown *pUnk)
1761 {
1762   COM_ExternalLock *newLock      = NULL;
1763   COM_ExternalLock *previousHead = NULL;
1764
1765   /*
1766    * Allocate space for the new storage object
1767    */
1768   newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1769
1770   if (newLock!=NULL) {
1771     if ( elList.head == EL_END_OF_LIST ) {
1772       elList.head = newLock;    /* The list is empty */
1773     } else {
1774       /* insert does it at the head */
1775       previousHead  = elList.head;
1776       elList.head = newLock;
1777     }
1778
1779     /* Set new list item data member */
1780     newLock->pUnk      = pUnk;
1781     newLock->uRefCount = 1;
1782     newLock->next      = previousHead;
1783
1784     return TRUE;
1785   }
1786   return FALSE;
1787 }
1788
1789 /****************************************************************************
1790  * Internal - Method that removes an item from the linked list.
1791  */
1792 static void COM_ExternalLockDelete(
1793   COM_ExternalLock *itemList)
1794 {
1795   COM_ExternalLock *current = elList.head;
1796
1797   if ( current == itemList ) {
1798     /* this section handles the deletion of the first node */
1799     elList.head = itemList->next;
1800     HeapFree( GetProcessHeap(), 0, itemList);
1801   } else {
1802     do {
1803       if ( current->next == itemList ){   /* We found the item to free  */
1804         current->next = itemList->next;  /* readjust the list pointers */
1805         HeapFree( GetProcessHeap(), 0, itemList);
1806         break;
1807       }
1808
1809       /* Skip to the next item */
1810       current = current->next;
1811
1812     } while ( current != EL_END_OF_LIST );
1813   }
1814 }
1815
1816 /****************************************************************************
1817  * Internal - Recursivity agent for IUnknownExternalLockList_Find
1818  *
1819  * NOTES: how long can the list be ?? (recursive!!!)
1820  */
1821 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1822 {
1823   if ( element == EL_END_OF_LIST )
1824     return EL_NOT_FOUND;
1825   else if ( element->pUnk == pUnk )    /* We found it */
1826     return element;
1827   else                                 /* Not the right guy, keep on looking */
1828     return COM_ExternalLockLocate( element->next, pUnk);
1829 }
1830
1831 /****************************************************************************
1832  * Public - Method that increments the count for a IUnknown* in the linked
1833  * list.  The item is inserted if not already in the list.
1834  */
1835 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1836 {
1837   COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1838
1839   /*
1840    * Add an external lock to the object. If it was already externally
1841    * locked, just increase the reference count. If it was not.
1842    * add the item to the list.
1843    */
1844   if ( externalLock == EL_NOT_FOUND )
1845     COM_ExternalLockInsert(pUnk);
1846   else
1847     externalLock->uRefCount++;
1848
1849   /*
1850    * Add an internal lock to the object
1851    */
1852   IUnknown_AddRef(pUnk);
1853 }
1854
1855 /****************************************************************************
1856  * Public - Method that decrements the count for a IUnknown* in the linked
1857  * list.  The item is removed from the list if its count end up at zero or if
1858  * bRelAll is TRUE.
1859  */
1860 static void COM_ExternalLockRelease(
1861   IUnknown *pUnk,
1862   BOOL   bRelAll)
1863 {
1864   COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1865
1866   if ( externalLock != EL_NOT_FOUND ) {
1867     do {
1868       externalLock->uRefCount--;  /* release external locks      */
1869       IUnknown_Release(pUnk);     /* release local locks as well */
1870
1871       if ( bRelAll == FALSE ) break;  /* perform single release */
1872
1873     } while ( externalLock->uRefCount > 0 );
1874
1875     if ( externalLock->uRefCount == 0 )  /* get rid of the list entry */
1876       COM_ExternalLockDelete(externalLock);
1877   }
1878 }
1879 /****************************************************************************
1880  * Public - Method that frees the content of the list.
1881  */
1882 static void COM_ExternalLockFreeList()
1883 {
1884   COM_ExternalLock *head;
1885
1886   head = elList.head;                 /* grab it by the head             */
1887   while ( head != EL_END_OF_LIST ) {
1888     COM_ExternalLockDelete(head);     /* get rid of the head stuff       */
1889     head = elList.head;               /* get the new head...             */
1890   }
1891 }
1892
1893 /****************************************************************************
1894  * Public - Method that dump the content of the list.
1895  */
1896 void COM_ExternalLockDump()
1897 {
1898   COM_ExternalLock *current = elList.head;
1899
1900   DPRINTF("\nExternal lock list contains:\n");
1901
1902   while ( current != EL_END_OF_LIST ) {
1903     DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1904
1905     /* Skip to the next item */
1906     current = current->next;
1907   }
1908 }
1909
1910 /******************************************************************************
1911  *              CoLockObjectExternal    [OLE32.@]
1912  */
1913 HRESULT WINAPI CoLockObjectExternal(
1914     LPUNKNOWN pUnk,             /* [in] object to be locked */
1915     BOOL fLock,         /* [in] do lock */
1916     BOOL fLastUnlockReleases) /* [in] unlock all */
1917 {
1918
1919         if (fLock) {
1920             /*
1921              * Increment the external lock coutner, COM_ExternalLockAddRef also
1922              * increment the object's internal lock counter.
1923              */
1924             COM_ExternalLockAddRef( pUnk);
1925         } else {
1926             /*
1927              * Decrement the external lock coutner, COM_ExternalLockRelease also
1928              * decrement the object's internal lock counter.
1929              */
1930             COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1931         }
1932
1933         return S_OK;
1934 }
1935
1936 /***********************************************************************
1937  *           CoInitializeWOW (OLE32.@)
1938  */
1939 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1940     FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1941     return 0;
1942 }
1943
1944 static int nStatCounter = 0;     /* global */
1945 static HMODULE hOleAut32 = 0;    /* global */
1946
1947 /***********************************************************************
1948  *           CoGetState [OLE32.@]
1949  *
1950  * NOTES: might be incomplete
1951  */
1952 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1953 {
1954         APARTMENT * apt = COM_CurrentInfo();
1955
1956         FIXME("\n");
1957
1958         if(apt && apt->state) {
1959             IUnknown_AddRef(apt->state);
1960             *ppv = apt->state;
1961             FIXME("-- %p\n", *ppv);
1962             return S_OK;
1963         }
1964         *ppv = NULL;
1965         return E_FAIL;
1966
1967 }
1968
1969 /***********************************************************************
1970  *           CoSetState [OLE32.@]
1971  *
1972  * NOTES: FIXME: protect this with a crst
1973  */
1974 HRESULT WINAPI CoSetState(IUnknown * pv)
1975 {
1976     APARTMENT * apt = COM_CurrentInfo();
1977
1978     if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1979
1980         FIXME("(%p),stub!\n", pv);
1981
1982         if (pv) {
1983             IUnknown_AddRef(pv);
1984             nStatCounter++;
1985             if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1986         }
1987
1988         if (apt->state) {
1989             TRACE("-- release %p now\n", apt->state);
1990             IUnknown_Release(apt->state);
1991             nStatCounter--;
1992             if (!nStatCounter) FreeLibrary(hOleAut32);
1993         }
1994         apt->state = pv;
1995         return S_OK;
1996 }
1997
1998
1999 /******************************************************************************
2000  *              OleGetAutoConvert        [OLE32.@]
2001  */
2002 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2003 {
2004     HKEY hkey = 0;
2005     char buf[200];
2006     WCHAR wbuf[200];
2007     DWORD len;
2008     HRESULT res = S_OK;
2009
2010     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2011     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2012     {
2013         res = REGDB_E_CLASSNOTREG;
2014         goto done;
2015     }
2016     len = 200;
2017     /* we can just query for the default value of AutoConvertTo key like that,
2018        without opening the AutoConvertTo key and querying for NULL (default) */
2019     if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2020     {
2021         res = REGDB_E_KEYMISSING;
2022         goto done;
2023     }
2024     MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2025     CLSIDFromString(wbuf,pClsidNew);
2026 done:
2027     if (hkey) RegCloseKey(hkey);
2028     return res;
2029 }
2030
2031 /******************************************************************************
2032  *              OleSetAutoConvert        [OLE32.@]
2033  */
2034 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2035 {
2036     HKEY hkey = 0;
2037     char buf[200], szClsidNew[200];
2038     HRESULT res = S_OK;
2039
2040     TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2041     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2042     WINE_StringFromCLSID(clsidNew, szClsidNew);
2043     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2044     {
2045         res = REGDB_E_CLASSNOTREG;
2046         goto done;
2047     }
2048     if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2049     {
2050         res = REGDB_E_WRITEREGDB;
2051         goto done;
2052     }
2053
2054 done:
2055     if (hkey) RegCloseKey(hkey);
2056     return res;
2057 }
2058
2059 /******************************************************************************
2060  *              OleDoAutoConvert        [OLE32.@]
2061  */
2062 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2063 {
2064     FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2065     return E_NOTIMPL;
2066 }
2067
2068 /******************************************************************************
2069  *              CoTreatAsClass        [OLE32.@]
2070  *
2071  * Sets TreatAs value of a class
2072  */
2073 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2074 {
2075     HKEY hkey = 0;
2076     char buf[47];
2077     char szClsidNew[39];
2078     HRESULT res = S_OK;
2079     char auto_treat_as[39];
2080     LONG auto_treat_as_size = sizeof(auto_treat_as);
2081     CLSID id;
2082
2083     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2084     WINE_StringFromCLSID(clsidNew, szClsidNew);
2085     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2086     {
2087         res = REGDB_E_CLASSNOTREG;
2088         goto done;
2089     }
2090     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2091     {
2092        if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2093            !__CLSIDFromStringA(auto_treat_as, &id))
2094        {
2095            if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2096            {
2097                res = REGDB_E_WRITEREGDB;
2098                goto done;
2099            }
2100        }
2101        else
2102        {
2103            RegDeleteKeyA(hkey, "TreatAs");
2104            goto done;
2105        }
2106     }
2107     else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2108     {
2109        res = REGDB_E_WRITEREGDB;
2110         goto done;
2111     }
2112
2113 done:
2114     if (hkey) RegCloseKey(hkey);
2115     return res;
2116 }
2117
2118 /******************************************************************************
2119  *              CoGetTreatAsClass        [OLE32.@]
2120  *
2121  * Reads the TreatAs value from a class.
2122  */
2123 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2124 {
2125     HKEY hkey = 0;
2126     char buf[200], szClsidNew[200];
2127     HRESULT res = S_OK;
2128     LONG len = sizeof(szClsidNew);
2129
2130     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2131     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2132     memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2133
2134     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2135     {
2136         res = REGDB_E_CLASSNOTREG;
2137         goto done;
2138     }
2139     if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2140     {
2141         res = S_FALSE;
2142         goto done;
2143     }
2144     res = __CLSIDFromStringA(szClsidNew,clsidNew);
2145     if (FAILED(res))
2146         FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2147 done:
2148     if (hkey) RegCloseKey(hkey);
2149     return res;
2150     
2151 }
2152
2153 /***********************************************************************
2154  *           IsEqualGUID [OLE32.@]
2155  *
2156  * Compares two Unique Identifiers.
2157  *
2158  * RETURNS
2159  *      TRUE if equal
2160  */
2161 #undef IsEqualGUID
2162 BOOL WINAPI IsEqualGUID(
2163      REFGUID rguid1, /* [in] unique id 1 */
2164      REFGUID rguid2  /* [in] unique id 2 */
2165      )
2166 {
2167     return !memcmp(rguid1,rguid2,sizeof(GUID));
2168 }
2169
2170 /***********************************************************************
2171  *           CoInitializeSecurity [OLE32.@]
2172  */
2173 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2174                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2175                                     void* pReserved1, DWORD dwAuthnLevel,
2176                                     DWORD dwImpLevel, void* pReserved2,
2177                                     DWORD dwCapabilities, void* pReserved3)
2178 {
2179   FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2180         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2181         dwCapabilities, pReserved3);
2182   return S_OK;
2183 }