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