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