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