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