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