Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / ole32 / compobj.c
blobcfcc6febaef655c83d142f80ca71c7e80ca79d18
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winuser.h"
38 #include "objbase.h"
39 #include "ole2.h"
40 #include "ole2ver.h"
41 #include "rpc.h"
42 #include "winerror.h"
43 #include "winreg.h"
44 #include "wownt32.h"
45 #include "wine/unicode.h"
46 #include "objbase.h"
47 #include "ole32_main.h"
48 #include "compobj_private.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54 /****************************************************************************
55 * This section defines variables internal to the COM module.
57 * TODO: Most of these things will have to be made thread-safe.
59 HINSTANCE COMPOBJ_hInstance32 = 0;
61 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
62 static void COM_RevokeAllClasses();
63 static void COM_ExternalLockFreeList();
65 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
67 APARTMENT MTA, *apts;
69 static CRITICAL_SECTION csApartment;
70 static CRITICAL_SECTION_DEBUG critsect_debug =
72 0, 0, &csApartment,
73 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
74 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
76 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
79 * This lock count counts the number of times CoInitialize is called. It is
80 * decreased every time CoUninitialize is called. When it hits 0, the COM
81 * libraries are freed
83 static LONG s_COMLockCount = 0;
86 * This linked list contains the list of registered class objects. These
87 * are mostly used to register the factories for out-of-proc servers of OLE
88 * objects.
90 * TODO: Make this data structure aware of inter-process communication. This
91 * means that parts of this will be exported to the Wine Server.
93 typedef struct tagRegisteredClass
95 CLSID classIdentifier;
96 LPUNKNOWN classObject;
97 DWORD runContext;
98 DWORD connectFlags;
99 DWORD dwCookie;
100 HANDLE hThread; /* only for localserver */
101 struct tagRegisteredClass* nextClass;
102 } RegisteredClass;
104 static RegisteredClass* firstRegisteredClass = NULL;
106 static CRITICAL_SECTION csRegisteredClassList;
107 static CRITICAL_SECTION_DEBUG class_cs_debug =
109 0, 0, &csRegisteredClassList,
110 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
111 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
113 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
115 /*****************************************************************************
116 * This section contains OpenDllList definitions
118 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
119 * other functions what do LoadLibrary _without_ giving back a HMODULE.
120 * Without this list these handles would be freed never.
122 * FIXME: a DLL what says OK whenn asked for unloading is unloaded in the
123 * next unload-call but not before 600 sec.
126 typedef struct tagOpenDll {
127 HINSTANCE hLibrary;
128 struct tagOpenDll *next;
129 } OpenDll;
131 static OpenDll *openDllList = NULL; /* linked list of open dlls */
133 static CRITICAL_SECTION csOpenDllList;
134 static CRITICAL_SECTION_DEBUG dll_cs_debug =
136 0, 0, &csOpenDllList,
137 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
138 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
140 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
142 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
143 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
145 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
146 static void COMPOBJ_DllList_FreeUnused(int Timeout);
149 /******************************************************************************
150 * Initialize/Unitialize threading stuff.
152 void COMPOBJ_InitProcess( void )
154 WNDCLASSA wclass;
156 memset(&wclass, 0, sizeof(wclass));
157 wclass.lpfnWndProc = &COM_AptWndProc;
158 wclass.hInstance = OLE32_hInstance;
159 wclass.lpszClassName = aptWinClass;
160 RegisterClassA(&wclass);
163 void COMPOBJ_UninitProcess( void )
165 UnregisterClassA(aptWinClass, OLE32_hInstance);
168 /******************************************************************************
169 * Manage apartments.
171 static void COM_InitMTA(void)
173 /* FIXME: how does windoze create OXIDs?
174 * this method will only work for local RPC */
175 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
176 InitializeCriticalSection(&MTA.cs);
179 static void COM_UninitMTA(void)
181 DeleteCriticalSection(&MTA.cs);
182 MTA.oxid = 0;
185 static APARTMENT* COM_CreateApartment(DWORD model)
187 APARTMENT *apt;
189 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
190 apt->model = model;
191 apt->tid = GetCurrentThreadId();
192 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
193 GetCurrentProcess(), &apt->thread,
194 THREAD_ALL_ACCESS, FALSE, 0);
195 if (model & COINIT_APARTMENTTHREADED) {
196 /* FIXME: how does windoze create OXIDs? */
197 apt->oxid = MTA.oxid | GetCurrentThreadId();
198 apt->win = CreateWindowA(aptWinClass, NULL, 0,
199 0, 0, 0, 0,
200 0, 0, OLE32_hInstance, NULL);
201 InitializeCriticalSection(&apt->cs);
203 else {
204 apt->parent = &MTA;
205 apt->oxid = MTA.oxid;
207 EnterCriticalSection(&csApartment);
208 if (apts) apts->prev = apt;
209 apt->next = apts;
210 apts = apt;
211 LeaveCriticalSection(&csApartment);
212 NtCurrentTeb()->ReservedForOle = apt;
213 return apt;
216 static void COM_DestroyApartment(APARTMENT *apt)
218 EnterCriticalSection(&csApartment);
219 if (apt->prev) apt->prev->next = apt->next;
220 if (apt->next) apt->next->prev = apt->prev;
221 if (apts == apt) apts = apt->next;
222 apt->prev = NULL; apt->next = NULL;
223 LeaveCriticalSection(&csApartment);
224 if (apt->model & COINIT_APARTMENTTHREADED) {
225 if (apt->win) DestroyWindow(apt->win);
226 DeleteCriticalSection(&apt->cs);
228 CloseHandle(apt->thread);
229 HeapFree(GetProcessHeap(), 0, apt);
232 HWND COM_GetApartmentWin(OXID oxid)
234 APARTMENT *apt;
235 HWND win = 0;
237 EnterCriticalSection(&csApartment);
238 apt = apts;
239 while (apt && apt->oxid != oxid) apt = apt->next;
240 if (apt) win = apt->win;
241 LeaveCriticalSection(&csApartment);
242 return win;
245 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
247 return DefWindowProcA(hWnd, msg, wParam, lParam);
250 /*****************************************************************************
251 * This section contains OpenDllList implemantation
254 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
256 OpenDll *ptr;
257 OpenDll *tmp;
259 TRACE("\n");
261 EnterCriticalSection( &csOpenDllList );
263 if (openDllList == NULL) {
264 /* empty list -- add first node */
265 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
266 openDllList->hLibrary=hLibrary;
267 openDllList->next = NULL;
268 } else {
269 /* search for this dll */
270 int found = FALSE;
271 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
272 if (ptr->hLibrary == hLibrary) {
273 found = TRUE;
274 break;
277 if (!found) {
278 /* dll not found, add it */
279 tmp = openDllList;
280 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
281 openDllList->hLibrary = hLibrary;
282 openDllList->next = tmp;
286 LeaveCriticalSection( &csOpenDllList );
289 static void COMPOBJ_DllList_FreeUnused(int Timeout)
291 OpenDll *curr, *next, *prev = NULL;
292 typedef HRESULT(*DllCanUnloadNowFunc)(void);
293 DllCanUnloadNowFunc DllCanUnloadNow;
295 TRACE("\n");
297 EnterCriticalSection( &csOpenDllList );
299 for (curr = openDllList; curr != NULL; ) {
300 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
302 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
303 next = curr->next;
305 TRACE("freeing %p\n", curr->hLibrary);
306 FreeLibrary(curr->hLibrary);
308 HeapFree(GetProcessHeap(), 0, curr);
309 if (curr == openDllList) {
310 openDllList = next;
311 } else {
312 prev->next = next;
315 curr = next;
316 } else {
317 prev = curr;
318 curr = curr->next;
322 LeaveCriticalSection( &csOpenDllList );
325 /******************************************************************************
326 * CoBuildVersion [COMPOBJ.1]
327 * CoBuildVersion [OLE32.4]
329 * RETURNS
330 * Current build version, hiword is majornumber, loword is minornumber
332 DWORD WINAPI CoBuildVersion(void)
334 TRACE("Returning version %d, build %d.\n", rmm, rup);
335 return (rmm<<16)+rup;
338 /******************************************************************************
339 * CoInitialize [OLE32.26]
341 * Initializes the COM libraries.
343 * See CoInitializeEx
345 HRESULT WINAPI CoInitialize(
346 LPVOID lpReserved /* [in] pointer to win32 malloc interface
347 (obsolete, should be NULL) */
351 * Just delegate to the newer method.
353 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
356 /******************************************************************************
357 * CoInitializeEx [OLE32.163]
359 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
360 * used for memory management is obsolete.
362 * RETURNS
363 * S_OK if successful,
364 * S_FALSE if this function was called already.
365 * RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
366 * threading model.
368 HRESULT WINAPI CoInitializeEx(
369 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
370 (obsolete, should be NULL) */
371 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
374 HRESULT hr = S_OK;
375 APARTMENT *apt;
377 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
379 if (lpReserved!=NULL)
381 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
384 apt = NtCurrentTeb()->ReservedForOle;
385 if (apt && dwCoInit != apt->model) return RPC_E_CHANGED_MODE;
386 hr = apt ? S_FALSE : S_OK;
389 * Check the lock count. If this is the first time going through the initialize
390 * process, we have to initialize the libraries.
392 * And crank-up that lock count.
394 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
397 * Initialize the various COM libraries and data structures.
399 TRACE("() - Initializing the COM libraries\n");
401 COM_InitMTA();
403 RunningObjectTableImpl_Initialize();
406 if (!apt) apt = COM_CreateApartment(dwCoInit);
408 InterlockedIncrement(&apt->inits);
409 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
411 return hr;
414 /***********************************************************************
415 * CoUninitialize [OLE32.47]
417 * This method will release the COM libraries.
419 * See the windows documentation for more details.
421 void WINAPI CoUninitialize(void)
423 LONG lCOMRefCnt;
424 APARTMENT *apt;
426 TRACE("()\n");
428 apt = NtCurrentTeb()->ReservedForOle;
429 if (!apt) return;
430 if (InterlockedDecrement(&apt->inits)==0) {
431 NtCurrentTeb()->ReservedForOle = NULL;
432 COM_DestroyApartment(apt);
433 apt = NULL;
437 * Decrease the reference count.
438 * If we are back to 0 locks on the COM library, make sure we free
439 * all the associated data structures.
441 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
442 if (lCOMRefCnt==1)
445 * Release the various COM libraries and data structures.
447 TRACE("() - Releasing the COM libraries\n");
449 RunningObjectTableImpl_UnInitialize();
451 * Release the references to the registered class objects.
453 COM_RevokeAllClasses();
456 * This will free the loaded COM Dlls.
458 CoFreeAllLibraries();
461 * This will free list of external references to COM objects.
463 COM_ExternalLockFreeList();
465 COM_UninitMTA();
467 else if (lCOMRefCnt<1) {
468 ERR( "CoUninitialize() - not CoInitialized.\n" );
469 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
473 /******************************************************************************
474 * CoDisconnectObject [COMPOBJ.15]
475 * CoDisconnectObject [OLE32.8]
477 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
479 TRACE("(%p, %lx)\n",lpUnk,reserved);
480 return S_OK;
483 /******************************************************************************
484 * CoCreateGuid[OLE32.6]
487 HRESULT WINAPI CoCreateGuid(
488 GUID *pguid /* [out] points to the GUID to initialize */
490 return UuidCreate(pguid);
493 /******************************************************************************
494 * CLSIDFromString [OLE32.3]
495 * IIDFromString [OLE32.74]
496 * Converts a unique identifier from its string representation into
497 * the GUID struct.
499 * UNDOCUMENTED
500 * If idstr is not a valid CLSID string then it gets treated as a ProgID
502 * RETURNS
503 * the converted GUID
505 HRESULT WINAPI __CLSIDFromStringA(
506 LPCSTR idstr, /* [in] string representation of guid */
507 CLSID *id) /* [out] GUID converted from string */
509 BYTE *s = (BYTE *) idstr;
510 int i;
511 BYTE table[256];
513 if (!s)
514 s = "{00000000-0000-0000-0000-000000000000}";
515 else { /* validate the CLSID string */
517 if (strlen(s) != 38)
518 return CO_E_CLASSSTRING;
520 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
521 return CO_E_CLASSSTRING;
523 for (i=1; i<37; i++) {
524 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
525 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
526 ((s[i] >= 'a') && (s[i] <= 'f')) ||
527 ((s[i] >= 'A') && (s[i] <= 'F'))))
528 return CO_E_CLASSSTRING;
532 TRACE("%s -> %p\n", s, id);
534 /* quick lookup table */
535 memset(table, 0, 256);
537 for (i = 0; i < 10; i++) {
538 table['0' + i] = i;
540 for (i = 0; i < 6; i++) {
541 table['A' + i] = i+10;
542 table['a' + i] = i+10;
545 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
547 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
548 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
549 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
550 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
552 /* these are just sequential bytes */
553 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
554 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
555 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
556 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
557 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
558 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
559 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
560 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
562 return S_OK;
565 /*****************************************************************************/
567 HRESULT WINAPI CLSIDFromString(
568 LPCOLESTR idstr, /* [in] string representation of GUID */
569 CLSID *id ) /* [out] GUID represented by above string */
571 char xid[40];
572 HRESULT ret;
574 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
575 return CO_E_CLASSSTRING;
578 ret = __CLSIDFromStringA(xid,id);
579 if(ret != S_OK) { /* It appears a ProgID is also valid */
580 ret = CLSIDFromProgID(idstr, id);
582 return ret;
585 /******************************************************************************
586 * WINE_StringFromCLSID [Internal]
587 * Converts a GUID into the respective string representation.
589 * NOTES
591 * RETURNS
592 * the string representation and HRESULT
594 HRESULT WINE_StringFromCLSID(
595 const CLSID *id, /* [in] GUID to be converted */
596 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
598 static const char *hex = "0123456789ABCDEF";
599 char *s;
600 int i;
602 if (!id)
603 { ERR("called with id=Null\n");
604 *idstr = 0x00;
605 return E_FAIL;
608 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
609 id->Data1, id->Data2, id->Data3,
610 id->Data4[0], id->Data4[1]);
611 s = &idstr[25];
613 /* 6 hex bytes */
614 for (i = 2; i < 8; i++) {
615 *s++ = hex[id->Data4[i]>>4];
616 *s++ = hex[id->Data4[i] & 0xf];
619 *s++ = '}';
620 *s++ = '\0';
622 TRACE("%p->%s\n", id, idstr);
624 return S_OK;
628 /******************************************************************************
629 * StringFromCLSID [OLE32.151]
630 * StringFromIID [OLE32.153]
631 * Converts a GUID into the respective string representation.
632 * The target string is allocated using the OLE IMalloc.
633 * RETURNS
634 * the string representation and HRESULT
636 HRESULT WINAPI StringFromCLSID(
637 REFCLSID id, /* [in] the GUID to be converted */
638 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
640 char buf[80];
641 HRESULT ret;
642 LPMALLOC mllc;
644 if ((ret=CoGetMalloc(0,&mllc)))
645 return ret;
647 ret=WINE_StringFromCLSID(id,buf);
648 if (!ret) {
649 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
650 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
651 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
653 return ret;
656 /******************************************************************************
657 * StringFromGUID2 [COMPOBJ.76]
658 * StringFromGUID2 [OLE32.152]
660 * Converts a global unique identifier into a string of an API-
661 * specified fixed format. (The usual {.....} stuff.)
663 * RETURNS
664 * The (UNICODE) string representation of the GUID in 'str'
665 * The length of the resulting string, 0 if there was any problem.
667 INT WINAPI
668 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
670 char xguid[80];
672 if (WINE_StringFromCLSID(id,xguid))
673 return 0;
674 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
677 /******************************************************************************
678 * ProgIDFromCLSID [OLE32.133]
679 * Converts a class id into the respective Program ID. (By using a registry lookup)
680 * RETURNS S_OK on success
681 * riid associated with the progid
684 HRESULT WINAPI ProgIDFromCLSID(
685 REFCLSID clsid, /* [in] class id as found in registry */
686 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
689 char strCLSID[50], *buf, *buf2;
690 DWORD buf2len;
691 HKEY xhkey;
692 LPMALLOC mllc;
693 HRESULT ret = S_OK;
695 WINE_StringFromCLSID(clsid, strCLSID);
697 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
698 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
699 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
700 ret = REGDB_E_CLASSNOTREG;
702 HeapFree(GetProcessHeap(), 0, buf);
704 if (ret == S_OK)
706 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
707 buf2len = 255;
708 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
709 ret = REGDB_E_CLASSNOTREG;
711 if (ret == S_OK)
713 if (CoGetMalloc(0,&mllc))
714 ret = E_OUTOFMEMORY;
715 else
717 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
718 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
719 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
722 HeapFree(GetProcessHeap(), 0, buf2);
725 RegCloseKey(xhkey);
726 return ret;
729 /******************************************************************************
730 * CLSIDFromProgID [COMPOBJ.61]
731 * Converts a program id into the respective GUID. (By using a registry lookup)
732 * RETURNS
733 * riid associated with the progid
735 HRESULT WINAPI CLSIDFromProgID16(
736 LPCOLESTR16 progid, /* [in] program id as found in registry */
737 LPCLSID riid /* [out] associated CLSID */
739 char *buf,buf2[80];
740 DWORD buf2len;
741 HRESULT err;
742 HKEY xhkey;
744 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
745 sprintf(buf,"%s\\CLSID",progid);
746 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
747 HeapFree(GetProcessHeap(),0,buf);
748 return CO_E_CLASSSTRING;
750 HeapFree(GetProcessHeap(),0,buf);
751 buf2len = sizeof(buf2);
752 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
753 RegCloseKey(xhkey);
754 return CO_E_CLASSSTRING;
756 RegCloseKey(xhkey);
757 return __CLSIDFromStringA(buf2,riid);
760 /******************************************************************************
761 * CLSIDFromProgID [OLE32.2]
762 * Converts a program id into the respective GUID. (By using a registry lookup)
763 * RETURNS
764 * riid associated with the progid
766 HRESULT WINAPI CLSIDFromProgID(
767 LPCOLESTR progid, /* [in] program id as found in registry */
768 LPCLSID riid ) /* [out] associated CLSID */
770 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
771 char buf2[80];
772 DWORD buf2len = sizeof(buf2);
773 HKEY xhkey;
775 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
776 strcpyW( buf, progid );
777 strcatW( buf, clsidW );
778 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
780 HeapFree(GetProcessHeap(),0,buf);
781 return CO_E_CLASSSTRING;
783 HeapFree(GetProcessHeap(),0,buf);
785 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
787 RegCloseKey(xhkey);
788 return CO_E_CLASSSTRING;
790 RegCloseKey(xhkey);
791 return __CLSIDFromStringA(buf2,riid);
796 /*****************************************************************************
797 * CoGetPSClsid [OLE32.22]
799 * This function returns the CLSID of the DLL that implements the proxy and stub
800 * for the specified interface.
802 * It determines this by searching the
803 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
804 * and any interface id registered by CoRegisterPSClsid within the current process.
806 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
808 HRESULT WINAPI CoGetPSClsid(
809 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
810 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
812 char *buf, buf2[40];
813 DWORD buf2len;
814 HKEY xhkey;
816 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
818 /* Get the input iid as a string */
819 WINE_StringFromCLSID(riid, buf2);
820 /* Allocate memory for the registry key we will construct.
821 (length of iid string plus constant length of static text */
822 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
823 if (buf == NULL)
825 return (E_OUTOFMEMORY);
828 /* Construct the registry key we want */
829 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
831 /* Open the key.. */
832 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
834 HeapFree(GetProcessHeap(),0,buf);
835 return (E_INVALIDARG);
837 HeapFree(GetProcessHeap(),0,buf);
839 /* ... Once we have the key, query the registry to get the
840 value of CLSID as a string, and convert it into a
841 proper CLSID structure to be passed back to the app */
842 buf2len = sizeof(buf2);
843 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
845 RegCloseKey(xhkey);
846 return E_INVALIDARG;
848 RegCloseKey(xhkey);
850 /* We have the CLSid we want back from the registry as a string, so
851 lets convert it into a CLSID structure */
852 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
853 return E_INVALIDARG;
856 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
857 return (S_OK);
862 /***********************************************************************
863 * WriteClassStm (OLE32.159)
865 * This function write a CLSID on stream
867 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
869 TRACE("(%p,%p)\n",pStm,rclsid);
871 if (rclsid==NULL)
872 return E_INVALIDARG;
874 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
877 /***********************************************************************
878 * ReadClassStm (OLE32.135)
880 * This function read a CLSID from a stream
882 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
884 ULONG nbByte;
885 HRESULT res;
887 TRACE("(%p,%p)\n",pStm,pclsid);
889 if (pclsid==NULL)
890 return E_INVALIDARG;
892 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
894 if (FAILED(res))
895 return res;
897 if (nbByte != sizeof(CLSID))
898 return S_FALSE;
899 else
900 return S_OK;
904 /***
905 * COM_GetRegisteredClassObject
907 * This internal method is used to scan the registered class list to
908 * find a class object.
910 * Params:
911 * rclsid Class ID of the class to find.
912 * dwClsContext Class context to match.
913 * ppv [out] returns a pointer to the class object. Complying
914 * to normal COM usage, this method will increase the
915 * reference count on this object.
917 static HRESULT COM_GetRegisteredClassObject(
918 REFCLSID rclsid,
919 DWORD dwClsContext,
920 LPUNKNOWN* ppUnk)
922 HRESULT hr = S_FALSE;
923 RegisteredClass* curClass;
925 EnterCriticalSection( &csRegisteredClassList );
928 * Sanity check
930 assert(ppUnk!=0);
933 * Iterate through the whole list and try to match the class ID.
935 curClass = firstRegisteredClass;
937 while (curClass != 0)
940 * Check if we have a match on the class ID.
942 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
945 * Since we don't do out-of process or DCOM just right away, let's ignore the
946 * class context.
950 * We have a match, return the pointer to the class object.
952 *ppUnk = curClass->classObject;
954 IUnknown_AddRef(curClass->classObject);
956 hr = S_OK;
957 goto end;
961 * Step to the next class in the list.
963 curClass = curClass->nextClass;
966 end:
967 LeaveCriticalSection( &csRegisteredClassList );
969 * If we get to here, we haven't found our class.
971 return hr;
974 static DWORD WINAPI
975 _LocalServerThread(LPVOID param) {
976 HANDLE hPipe;
977 char pipefn[200];
978 RegisteredClass *newClass = (RegisteredClass*)param;
979 HRESULT hres;
980 IStream *pStm;
981 STATSTG ststg;
982 unsigned char *buffer;
983 int buflen;
984 IClassFactory *classfac;
985 LARGE_INTEGER seekto;
986 ULARGE_INTEGER newpos;
987 ULONG res;
989 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
990 strcpy(pipefn,PIPEPREF);
991 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
993 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
994 if (hres) return hres;
996 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
997 if (hres) {
998 FIXME("Failed to create stream on hglobal.\n");
999 return hres;
1001 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1002 if (hres) {
1003 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1004 return hres;
1006 hres = IStream_Stat(pStm,&ststg,0);
1007 if (hres) return hres;
1009 buflen = ststg.cbSize.s.LowPart;
1010 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1011 seekto.s.LowPart = 0;
1012 seekto.s.HighPart = 0;
1013 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1014 if (hres) {
1015 FIXME("IStream_Seek failed, %lx\n",hres);
1016 return hres;
1018 hres = IStream_Read(pStm,buffer,buflen,&res);
1019 if (hres) {
1020 FIXME("Stream Read failed, %lx\n",hres);
1021 return hres;
1023 IStream_Release(pStm);
1025 while (1) {
1026 hPipe = CreateNamedPipeA(
1027 pipefn,
1028 PIPE_ACCESS_DUPLEX,
1029 PIPE_TYPE_BYTE|PIPE_WAIT,
1030 PIPE_UNLIMITED_INSTANCES,
1031 4096,
1032 4096,
1033 NMPWAIT_USE_DEFAULT_WAIT,
1034 NULL
1036 if (hPipe == INVALID_HANDLE_VALUE) {
1037 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1038 return 1;
1040 if (!ConnectNamedPipe(hPipe,NULL)) {
1041 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1042 CloseHandle(hPipe);
1043 continue;
1045 WriteFile(hPipe,buffer,buflen,&res,NULL);
1046 CloseHandle(hPipe);
1048 return 0;
1051 /******************************************************************************
1052 * CoRegisterClassObject [OLE32.36]
1054 * This method will register the class object for a given class ID.
1056 * See the Windows documentation for more details.
1058 HRESULT WINAPI CoRegisterClassObject(
1059 REFCLSID rclsid,
1060 LPUNKNOWN pUnk,
1061 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1062 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1063 LPDWORD lpdwRegister
1066 RegisteredClass* newClass;
1067 LPUNKNOWN foundObject;
1068 HRESULT hr;
1070 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1071 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1073 if ( (lpdwRegister==0) || (pUnk==0) )
1074 return E_INVALIDARG;
1076 *lpdwRegister = 0;
1079 * First, check if the class is already registered.
1080 * If it is, this should cause an error.
1082 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1083 if (hr == S_OK) {
1084 IUnknown_Release(foundObject);
1085 return CO_E_OBJISREG;
1088 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1089 if ( newClass == NULL )
1090 return E_OUTOFMEMORY;
1092 EnterCriticalSection( &csRegisteredClassList );
1094 newClass->classIdentifier = *rclsid;
1095 newClass->runContext = dwClsContext;
1096 newClass->connectFlags = flags;
1098 * Use the address of the chain node as the cookie since we are sure it's
1099 * unique.
1101 newClass->dwCookie = (DWORD)newClass;
1102 newClass->nextClass = firstRegisteredClass;
1105 * Since we're making a copy of the object pointer, we have to increase its
1106 * reference count.
1108 newClass->classObject = pUnk;
1109 IUnknown_AddRef(newClass->classObject);
1111 firstRegisteredClass = newClass;
1112 LeaveCriticalSection( &csRegisteredClassList );
1114 *lpdwRegister = newClass->dwCookie;
1116 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1117 DWORD tid;
1119 STUBMGR_Start();
1120 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1122 return S_OK;
1125 /***********************************************************************
1126 * CoRevokeClassObject [OLE32.40]
1128 * This method will remove a class object from the class registry
1130 * See the Windows documentation for more details.
1132 HRESULT WINAPI CoRevokeClassObject(
1133 DWORD dwRegister)
1135 HRESULT hr = E_INVALIDARG;
1136 RegisteredClass** prevClassLink;
1137 RegisteredClass* curClass;
1139 TRACE("(%08lx)\n",dwRegister);
1141 EnterCriticalSection( &csRegisteredClassList );
1144 * Iterate through the whole list and try to match the cookie.
1146 curClass = firstRegisteredClass;
1147 prevClassLink = &firstRegisteredClass;
1149 while (curClass != 0)
1152 * Check if we have a match on the cookie.
1154 if (curClass->dwCookie == dwRegister)
1157 * Remove the class from the chain.
1159 *prevClassLink = curClass->nextClass;
1162 * Release the reference to the class object.
1164 IUnknown_Release(curClass->classObject);
1167 * Free the memory used by the chain node.
1169 HeapFree(GetProcessHeap(), 0, curClass);
1171 hr = S_OK;
1172 goto end;
1176 * Step to the next class in the list.
1178 prevClassLink = &(curClass->nextClass);
1179 curClass = curClass->nextClass;
1182 end:
1183 LeaveCriticalSection( &csRegisteredClassList );
1185 * If we get to here, we haven't found our class.
1187 return hr;
1190 /***********************************************************************
1191 * compobj_RegReadPath [internal]
1193 * Reads a registry value and expands it when nessesary
1195 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1197 HRESULT hres;
1198 HKEY key;
1199 DWORD keytype;
1200 char src[MAX_PATH];
1201 DWORD dwLength = dstlen;
1203 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1204 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1205 if (keytype == REG_EXPAND_SZ) {
1206 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1207 } else {
1208 strncpy(dst, src, dstlen);
1211 RegCloseKey (key);
1213 return hres;
1216 /***********************************************************************
1217 * CoGetClassObject [COMPOBJ.7]
1218 * CoGetClassObject [OLE32.16]
1220 * FIXME. If request allows of several options and there is a failure
1221 * with one (other than not being registered) do we try the
1222 * others or return failure? (E.g. inprocess is registered but
1223 * the DLL is not found but the server version works)
1225 HRESULT WINAPI CoGetClassObject(
1226 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1227 REFIID iid, LPVOID *ppv
1229 LPUNKNOWN regClassObject;
1230 HRESULT hres = E_UNEXPECTED;
1231 char xclsid[80];
1232 HINSTANCE hLibrary;
1233 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1234 DllGetClassObjectFunc DllGetClassObject;
1236 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1238 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1240 if (pServerInfo) {
1241 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1242 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1246 * First, try and see if we can't match the class ID with one of the
1247 * registered classes.
1249 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1252 * Get the required interface from the retrieved pointer.
1254 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1257 * Since QI got another reference on the pointer, we want to release the
1258 * one we already have. If QI was unsuccessful, this will release the object. This
1259 * is good since we are not returning it in the "out" parameter.
1261 IUnknown_Release(regClassObject);
1263 return hres;
1266 /* first try: in-process */
1267 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1268 char keyname[MAX_PATH];
1269 char dllpath[MAX_PATH+1];
1271 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1273 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1274 /* failure: CLSID is not found in registry */
1275 WARN("class %s not registred\n", xclsid);
1276 hres = REGDB_E_CLASSNOTREG;
1277 } else {
1278 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1279 /* failure: DLL could not be loaded */
1280 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1281 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1282 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1283 /* failure: the dll did not export DllGetClassObject */
1284 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1285 FreeLibrary( hLibrary );
1286 hres = CO_E_DLLNOTFOUND;
1287 } else {
1288 /* OK: get the ClassObject */
1289 COMPOBJ_DLLList_Add( hLibrary );
1290 return DllGetClassObject(rclsid, iid, ppv);
1295 /* Next try out of process */
1296 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1298 return create_marshalled_proxy(rclsid,iid,ppv);
1301 /* Finally try remote */
1302 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1304 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1305 hres = E_NOINTERFACE;
1308 return hres;
1310 /***********************************************************************
1311 * CoResumeClassObjects (OLE32.173)
1313 * Resumes classobjects registered with REGCLS suspended
1315 HRESULT WINAPI CoResumeClassObjects(void)
1317 FIXME("\n");
1318 return S_OK;
1321 /***********************************************************************
1322 * GetClassFile (OLE32.67)
1324 * This function supplies the CLSID associated with the given filename.
1326 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1328 IStorage *pstg=0;
1329 HRESULT res;
1330 int nbElm, length, i;
1331 LONG sizeProgId;
1332 LPOLESTR *pathDec=0,absFile=0,progId=0;
1333 LPWSTR extension;
1334 static const WCHAR bkslashW[] = {'\\',0};
1335 static const WCHAR dotW[] = {'.',0};
1337 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1339 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1340 if((StgIsStorageFile(filePathName))==S_OK){
1342 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1344 if (SUCCEEDED(res))
1345 res=ReadClassStg(pstg,pclsid);
1347 IStorage_Release(pstg);
1349 return res;
1351 /* if the file is not a storage object then attemps to match various bits in the file against a
1352 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1353 this case
1355 for(i=0;i<nFileTypes;i++)
1357 for(i=0;j<nPatternsForType;j++){
1359 PATTERN pat;
1360 HANDLE hFile;
1362 pat=ReadPatternFromRegistry(i,j);
1363 hFile=CreateFileW(filePathName,,,,,,hFile);
1364 SetFilePosition(hFile,pat.offset);
1365 ReadFile(hFile,buf,pat.size,NULL,NULL);
1366 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1368 *pclsid=ReadCLSIDFromRegistry(i);
1369 return S_OK;
1374 /* if the obove strategies fail then search for the extension key in the registry */
1376 /* get the last element (absolute file) in the path name */
1377 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1378 absFile=pathDec[nbElm-1];
1380 /* failed if the path represente a directory and not an absolute file name*/
1381 if (!lstrcmpW(absFile, bkslashW))
1382 return MK_E_INVALIDEXTENSION;
1384 /* get the extension of the file */
1385 extension = NULL;
1386 length=lstrlenW(absFile);
1387 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1388 /* nothing */;
1390 if (!extension || !lstrcmpW(extension, dotW))
1391 return MK_E_INVALIDEXTENSION;
1393 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1395 /* get the progId associated to the extension */
1396 progId = CoTaskMemAlloc(sizeProgId);
1397 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1399 if (res==ERROR_SUCCESS)
1400 /* return the clsid associated to the progId */
1401 res= CLSIDFromProgID(progId,pclsid);
1403 for(i=0; pathDec[i]!=NULL;i++)
1404 CoTaskMemFree(pathDec[i]);
1405 CoTaskMemFree(pathDec);
1407 CoTaskMemFree(progId);
1409 if (res==ERROR_SUCCESS)
1410 return res;
1412 return MK_E_INVALIDEXTENSION;
1414 /***********************************************************************
1415 * CoCreateInstance [COMPOBJ.13]
1416 * CoCreateInstance [OLE32.7]
1418 HRESULT WINAPI CoCreateInstance(
1419 REFCLSID rclsid,
1420 LPUNKNOWN pUnkOuter,
1421 DWORD dwClsContext,
1422 REFIID iid,
1423 LPVOID *ppv)
1425 HRESULT hres;
1426 LPCLASSFACTORY lpclf = 0;
1429 * Sanity check
1431 if (ppv==0)
1432 return E_POINTER;
1435 * Initialize the "out" parameter
1437 *ppv = 0;
1440 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1441 * Rather than create a class factory, we can just check for it here
1443 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1444 if (StdGlobalInterfaceTableInstance == NULL)
1445 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1446 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1447 if (hres) return hres;
1449 TRACE("Retrieved GIT (%p)\n", *ppv);
1450 return S_OK;
1454 * Get a class factory to construct the object we want.
1456 hres = CoGetClassObject(rclsid,
1457 dwClsContext,
1458 NULL,
1459 &IID_IClassFactory,
1460 (LPVOID)&lpclf);
1462 if (FAILED(hres)) {
1463 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1464 debugstr_guid(rclsid),hres);
1465 return hres;
1469 * Create the object and don't forget to release the factory
1471 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1472 IClassFactory_Release(lpclf);
1473 if(FAILED(hres))
1474 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1475 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1477 return hres;
1480 /***********************************************************************
1481 * CoCreateInstanceEx [OLE32.165]
1483 HRESULT WINAPI CoCreateInstanceEx(
1484 REFCLSID rclsid,
1485 LPUNKNOWN pUnkOuter,
1486 DWORD dwClsContext,
1487 COSERVERINFO* pServerInfo,
1488 ULONG cmq,
1489 MULTI_QI* pResults)
1491 IUnknown* pUnk = NULL;
1492 HRESULT hr;
1493 ULONG index;
1494 int successCount = 0;
1497 * Sanity check
1499 if ( (cmq==0) || (pResults==NULL))
1500 return E_INVALIDARG;
1502 if (pServerInfo!=NULL)
1503 FIXME("() non-NULL pServerInfo not supported!\n");
1506 * Initialize all the "out" parameters.
1508 for (index = 0; index < cmq; index++)
1510 pResults[index].pItf = NULL;
1511 pResults[index].hr = E_NOINTERFACE;
1515 * Get the object and get its IUnknown pointer.
1517 hr = CoCreateInstance(rclsid,
1518 pUnkOuter,
1519 dwClsContext,
1520 &IID_IUnknown,
1521 (VOID**)&pUnk);
1523 if (hr)
1524 return hr;
1527 * Then, query for all the interfaces requested.
1529 for (index = 0; index < cmq; index++)
1531 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1532 pResults[index].pIID,
1533 (VOID**)&(pResults[index].pItf));
1535 if (pResults[index].hr == S_OK)
1536 successCount++;
1540 * Release our temporary unknown pointer.
1542 IUnknown_Release(pUnk);
1544 if (successCount == 0)
1545 return E_NOINTERFACE;
1547 if (successCount!=cmq)
1548 return CO_S_NOTALLINTERFACES;
1550 return S_OK;
1553 /***********************************************************************
1554 * CoLoadLibrary (OLE32.30)
1556 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1558 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1560 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1563 /***********************************************************************
1564 * CoFreeLibrary [OLE32.13]
1566 * NOTES: don't belive the docu
1568 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1570 FreeLibrary(hLibrary);
1574 /***********************************************************************
1575 * CoFreeAllLibraries [OLE32.12]
1577 * NOTES: don't belive the docu
1579 void WINAPI CoFreeAllLibraries(void)
1581 /* NOP */
1585 /***********************************************************************
1586 * CoFreeUnusedLibraries [COMPOBJ.17]
1587 * CoFreeUnusedLibraries [OLE32.14]
1589 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1590 * through the main apartment's thread to call DllCanUnloadNow
1592 void WINAPI CoFreeUnusedLibraries(void)
1594 COMPOBJ_DllList_FreeUnused(0);
1597 /***********************************************************************
1598 * CoFileTimeNow [COMPOBJ.82]
1599 * CoFileTimeNow [OLE32.10]
1601 * RETURNS
1602 * the current system time in lpFileTime
1604 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1606 GetSystemTimeAsFileTime( lpFileTime );
1607 return S_OK;
1610 /***********************************************************************
1611 * CoLoadLibrary (OLE32.30)
1613 static void COM_RevokeAllClasses()
1615 EnterCriticalSection( &csRegisteredClassList );
1617 while (firstRegisteredClass!=0)
1619 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1622 LeaveCriticalSection( &csRegisteredClassList );
1625 /****************************************************************************
1626 * COM External Lock methods implementation
1628 * This api provides a linked list to managed external references to
1629 * COM objects.
1631 * The public interface consists of three calls:
1632 * COM_ExternalLockAddRef
1633 * COM_ExternalLockRelease
1634 * COM_ExternalLockFreeList
1637 #define EL_END_OF_LIST 0
1638 #define EL_NOT_FOUND 0
1641 * Declaration of the static structure that manage the
1642 * external lock to COM objects.
1644 typedef struct COM_ExternalLock COM_ExternalLock;
1645 typedef struct COM_ExternalLockList COM_ExternalLockList;
1647 struct COM_ExternalLock
1649 IUnknown *pUnk; /* IUnknown referenced */
1650 ULONG uRefCount; /* external lock counter to IUnknown object*/
1651 COM_ExternalLock *next; /* Pointer to next element in list */
1654 struct COM_ExternalLockList
1656 COM_ExternalLock *head; /* head of list */
1660 * Declaration and initialization of the static structure that manages
1661 * the external lock to COM objects.
1663 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1666 * Private methods used to managed the linked list
1670 static COM_ExternalLock* COM_ExternalLockLocate(
1671 COM_ExternalLock *element,
1672 IUnknown *pUnk);
1674 /****************************************************************************
1675 * Internal - Insert a new IUnknown* to the linked list
1677 static BOOL COM_ExternalLockInsert(
1678 IUnknown *pUnk)
1680 COM_ExternalLock *newLock = NULL;
1681 COM_ExternalLock *previousHead = NULL;
1684 * Allocate space for the new storage object
1686 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1688 if (newLock!=NULL) {
1689 if ( elList.head == EL_END_OF_LIST ) {
1690 elList.head = newLock; /* The list is empty */
1691 } else {
1692 /* insert does it at the head */
1693 previousHead = elList.head;
1694 elList.head = newLock;
1697 /* Set new list item data member */
1698 newLock->pUnk = pUnk;
1699 newLock->uRefCount = 1;
1700 newLock->next = previousHead;
1702 return TRUE;
1704 return FALSE;
1707 /****************************************************************************
1708 * Internal - Method that removes an item from the linked list.
1710 static void COM_ExternalLockDelete(
1711 COM_ExternalLock *itemList)
1713 COM_ExternalLock *current = elList.head;
1715 if ( current == itemList ) {
1716 /* this section handles the deletion of the first node */
1717 elList.head = itemList->next;
1718 HeapFree( GetProcessHeap(), 0, itemList);
1719 } else {
1720 do {
1721 if ( current->next == itemList ){ /* We found the item to free */
1722 current->next = itemList->next; /* readjust the list pointers */
1723 HeapFree( GetProcessHeap(), 0, itemList);
1724 break;
1727 /* Skip to the next item */
1728 current = current->next;
1730 } while ( current != EL_END_OF_LIST );
1734 /****************************************************************************
1735 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1737 * NOTES: how long can the list be ?? (recursive!!!)
1739 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1741 if ( element == EL_END_OF_LIST )
1742 return EL_NOT_FOUND;
1743 else if ( element->pUnk == pUnk ) /* We found it */
1744 return element;
1745 else /* Not the right guy, keep on looking */
1746 return COM_ExternalLockLocate( element->next, pUnk);
1749 /****************************************************************************
1750 * Public - Method that increments the count for a IUnknown* in the linked
1751 * list. The item is inserted if not already in the list.
1753 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1755 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1758 * Add an external lock to the object. If it was already externally
1759 * locked, just increase the reference count. If it was not.
1760 * add the item to the list.
1762 if ( externalLock == EL_NOT_FOUND )
1763 COM_ExternalLockInsert(pUnk);
1764 else
1765 externalLock->uRefCount++;
1768 * Add an internal lock to the object
1770 IUnknown_AddRef(pUnk);
1773 /****************************************************************************
1774 * Public - Method that decrements the count for a IUnknown* in the linked
1775 * list. The item is removed from the list if its count end up at zero or if
1776 * bRelAll is TRUE.
1778 static void COM_ExternalLockRelease(
1779 IUnknown *pUnk,
1780 BOOL bRelAll)
1782 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1784 if ( externalLock != EL_NOT_FOUND ) {
1785 do {
1786 externalLock->uRefCount--; /* release external locks */
1787 IUnknown_Release(pUnk); /* release local locks as well */
1789 if ( bRelAll == FALSE ) break; /* perform single release */
1791 } while ( externalLock->uRefCount > 0 );
1793 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1794 COM_ExternalLockDelete(externalLock);
1797 /****************************************************************************
1798 * Public - Method that frees the content of the list.
1800 static void COM_ExternalLockFreeList()
1802 COM_ExternalLock *head;
1804 head = elList.head; /* grab it by the head */
1805 while ( head != EL_END_OF_LIST ) {
1806 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1807 head = elList.head; /* get the new head... */
1811 /****************************************************************************
1812 * Public - Method that dump the content of the list.
1814 void COM_ExternalLockDump()
1816 COM_ExternalLock *current = elList.head;
1818 DPRINTF("\nExternal lock list contains:\n");
1820 while ( current != EL_END_OF_LIST ) {
1821 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1823 /* Skip to the next item */
1824 current = current->next;
1828 /******************************************************************************
1829 * CoLockObjectExternal [OLE32.31]
1831 HRESULT WINAPI CoLockObjectExternal(
1832 LPUNKNOWN pUnk, /* [in] object to be locked */
1833 BOOL fLock, /* [in] do lock */
1834 BOOL fLastUnlockReleases) /* [in] unlock all */
1837 if (fLock) {
1839 * Increment the external lock coutner, COM_ExternalLockAddRef also
1840 * increment the object's internal lock counter.
1842 COM_ExternalLockAddRef( pUnk);
1843 } else {
1845 * Decrement the external lock coutner, COM_ExternalLockRelease also
1846 * decrement the object's internal lock counter.
1848 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1851 return S_OK;
1854 /***********************************************************************
1855 * CoInitializeWOW (OLE32.27)
1857 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1858 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1859 return 0;
1862 static IUnknown * pUnkState = 0; /* FIXME: thread local */
1863 static int nStatCounter = 0; /* global */
1864 static HMODULE hOleAut32 = 0; /* global */
1866 /***********************************************************************
1867 * CoGetState [OLE32.24]
1869 * NOTES: might be incomplete
1871 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1873 FIXME("\n");
1875 if(pUnkState) {
1876 IUnknown_AddRef(pUnkState);
1877 *ppv = pUnkState;
1878 FIXME("-- %p\n", *ppv);
1879 return S_OK;
1881 *ppv = NULL;
1882 return E_FAIL;
1886 /***********************************************************************
1887 * CoSetState [OLE32.42]
1889 * NOTES: FIXME: protect this with a crst
1891 HRESULT WINAPI CoSetState(IUnknown * pv)
1893 FIXME("(%p),stub!\n", pv);
1895 if (pv) {
1896 IUnknown_AddRef(pv);
1897 nStatCounter++;
1898 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1901 if (pUnkState) {
1902 TRACE("-- release %p now\n", pUnkState);
1903 IUnknown_Release(pUnkState);
1904 nStatCounter--;
1905 if (!nStatCounter) FreeLibrary(hOleAut32);
1907 pUnkState = pv;
1908 return S_OK;
1912 /******************************************************************************
1913 * OleGetAutoConvert [OLE32.104]
1915 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
1917 HKEY hkey = 0;
1918 char buf[200];
1919 WCHAR wbuf[200];
1920 DWORD len;
1921 HRESULT res = S_OK;
1923 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1924 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1926 res = REGDB_E_CLASSNOTREG;
1927 goto done;
1929 len = 200;
1930 /* we can just query for the default value of AutoConvertTo key like that,
1931 without opening the AutoConvertTo key and querying for NULL (default) */
1932 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
1934 res = REGDB_E_KEYMISSING;
1935 goto done;
1937 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
1938 CLSIDFromString(wbuf,pClsidNew);
1939 done:
1940 if (hkey) RegCloseKey(hkey);
1941 return res;
1944 /******************************************************************************
1945 * OleSetAutoConvert [OLE32.126]
1947 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
1949 HKEY hkey = 0;
1950 char buf[200], szClsidNew[200];
1951 HRESULT res = S_OK;
1953 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1954 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1955 WINE_StringFromCLSID(clsidNew, szClsidNew);
1956 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1958 res = REGDB_E_CLASSNOTREG;
1959 goto done;
1961 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
1963 res = REGDB_E_WRITEREGDB;
1964 goto done;
1967 done:
1968 if (hkey) RegCloseKey(hkey);
1969 return res;
1972 /******************************************************************************
1973 * OleDoAutoConvert [OLE32.100]
1975 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
1977 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
1978 return E_NOTIMPL;
1981 /******************************************************************************
1982 * CoTreatAsClass [OLE32.46]
1984 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
1986 HKEY hkey = 0;
1987 char buf[200], szClsidNew[200];
1988 HRESULT res = S_OK;
1990 FIXME("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
1991 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1992 WINE_StringFromCLSID(clsidNew, szClsidNew);
1993 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1995 res = REGDB_E_CLASSNOTREG;
1996 goto done;
1998 if (RegSetValueA(hkey, "AutoTreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2000 res = REGDB_E_WRITEREGDB;
2001 goto done;
2004 done:
2005 if (hkey) RegCloseKey(hkey);
2006 return res;
2009 /******************************************************************************
2010 * CoGetTreatAsClass [OLE32.25]
2012 * Reads the TreatAs value from a class.
2014 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2016 HKEY hkey = 0;
2017 char buf[200], szClsidNew[200];
2018 HRESULT res = S_OK;
2019 LONG len = sizeof(szClsidNew);
2021 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2022 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2023 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2025 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2027 res = REGDB_E_CLASSNOTREG;
2028 goto done;
2030 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2032 res = S_FALSE;
2033 goto done;
2035 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2036 if (FAILED(res))
2037 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2038 done:
2039 if (hkey) RegCloseKey(hkey);
2040 return res;
2044 /***********************************************************************
2045 * IsEqualGUID [OLE32.76]
2047 * Compares two Unique Identifiers.
2049 * RETURNS
2050 * TRUE if equal
2052 #undef IsEqualGUID
2053 BOOL WINAPI IsEqualGUID(
2054 REFGUID rguid1, /* [in] unique id 1 */
2055 REFGUID rguid2 /* [in] unique id 2 */
2058 return !memcmp(rguid1,rguid2,sizeof(GUID));
2061 /***********************************************************************
2062 * CoInitializeSecurity [OLE32.164]
2064 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2065 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2066 void* pReserved1, DWORD dwAuthnLevel,
2067 DWORD dwImpLevel, void* pReserved2,
2068 DWORD dwCapabilities, void* pReserved3)
2070 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2071 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2072 dwCapabilities, pReserved3);
2073 return S_OK;