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