4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
50 #include "ole32_main.h"
51 #include "compobj_private.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(ole);
57 typedef LPCSTR LPCOLESTR16;
59 /****************************************************************************
60 * This section defines variables internal to the COM module.
62 * TODO: Most of these things will have to be made thread-safe.
64 HINSTANCE COMPOBJ_hInstance32 = 0;
66 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
67 static void COM_RevokeAllClasses();
68 static void COM_ExternalLockFreeList();
70 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
74 static CRITICAL_SECTION csApartment;
75 static CRITICAL_SECTION_DEBUG critsect_debug =
78 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
79 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
81 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
84 * This lock count counts the number of times CoInitialize is called. It is
85 * decreased every time CoUninitialize is called. When it hits 0, the COM
88 static LONG s_COMLockCount = 0;
91 * This linked list contains the list of registered class objects. These
92 * are mostly used to register the factories for out-of-proc servers of OLE
95 * TODO: Make this data structure aware of inter-process communication. This
96 * means that parts of this will be exported to the Wine Server.
98 typedef struct tagRegisteredClass
100 CLSID classIdentifier;
101 LPUNKNOWN classObject;
105 HANDLE hThread; /* only for localserver */
106 struct tagRegisteredClass* nextClass;
109 static RegisteredClass* firstRegisteredClass = NULL;
111 static CRITICAL_SECTION csRegisteredClassList;
112 static CRITICAL_SECTION_DEBUG class_cs_debug =
114 0, 0, &csRegisteredClassList,
115 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
116 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
118 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
120 /*****************************************************************************
121 * This section contains OpenDllList definitions
123 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
124 * other functions that do LoadLibrary _without_ giving back a HMODULE.
125 * Without this list these handles would never be freed.
127 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
128 * next unload-call but not before 600 sec.
131 typedef struct tagOpenDll {
133 struct tagOpenDll *next;
136 static OpenDll *openDllList = NULL; /* linked list of open dlls */
138 static CRITICAL_SECTION csOpenDllList;
139 static CRITICAL_SECTION_DEBUG dll_cs_debug =
141 0, 0, &csOpenDllList,
142 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
143 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
145 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
147 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
148 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
150 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
151 static void COMPOBJ_DllList_FreeUnused(int Timeout);
153 void COMPOBJ_InitProcess( void )
157 /* Dispatching to the correct thread in an apartment is done through
158 * window messages rather than RPC transports. When an interface is
159 * marshalled into another apartment in the same process, a window of the
160 * following class is created. The *caller* of CoMarshalInterface (ie the
161 * application) is responsible for pumping the message loop in that thread.
162 * The WM_USER messages which point to the RPCs are then dispatched to
163 * COM_AptWndProc by the user's code.
165 memset(&wclass, 0, sizeof(wclass));
166 wclass.lpfnWndProc = &COM_AptWndProc;
167 wclass.hInstance = OLE32_hInstance;
168 wclass.lpszClassName = aptWinClass;
169 RegisterClassA(&wclass);
172 void COMPOBJ_UninitProcess( void )
174 UnregisterClassA(aptWinClass, OLE32_hInstance);
177 /******************************************************************************
182 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
183 with free threaded (ie thread safe) COM objects. There is only ever one MTA
184 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
186 static void COM_InitMTA(void)
188 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
189 within a network. That is, two different MTAs on different machines will have
192 This method of generating an OXID is therefore wrong as it doesn't work across
193 a network, but for local RPC only it's OK. We can distinguish between MTAs and
194 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
196 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
197 InitializeCriticalSection(&MTA.cs);
200 static void COM_UninitMTA(void)
202 DeleteCriticalSection(&MTA.cs);
206 /* creates an apartment structure which stores OLE thread-local
207 * information. Call with COINIT_UNINITIALIZED to create an apartment
208 * that will be initialized with a model later. Note: do not call
209 * with COINIT_UNINITIALIZED if the apartment has already been initialized
210 * with a different COINIT value */
211 APARTMENT* COM_CreateApartment(DWORD model)
214 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
218 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
219 apt->tid = GetCurrentThreadId();
220 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
221 GetCurrentProcess(), &apt->thread,
222 THREAD_ALL_ACCESS, FALSE, 0);
225 apt = NtCurrentTeb()->ReservedForOle;
228 if (model & COINIT_APARTMENTTHREADED) {
229 /* FIXME: how does windoze create OXIDs? */
230 apt->oxid = MTA.oxid | GetCurrentThreadId();
231 apt->win = CreateWindowA(aptWinClass, NULL, 0,
233 0, 0, OLE32_hInstance, NULL);
234 InitializeCriticalSection(&apt->cs);
236 else if (!(model & COINIT_UNINITIALIZED)) {
238 apt->oxid = MTA.oxid;
240 EnterCriticalSection(&csApartment);
243 if (apts) apts->prev = apt;
247 LeaveCriticalSection(&csApartment);
248 NtCurrentTeb()->ReservedForOle = apt;
252 static void COM_DestroyApartment(APARTMENT *apt)
254 EnterCriticalSection(&csApartment);
255 if (apt->prev) apt->prev->next = apt->next;
256 if (apt->next) apt->next->prev = apt->prev;
257 if (apts == apt) apts = apt->next;
258 apt->prev = NULL; apt->next = NULL;
259 LeaveCriticalSection(&csApartment);
260 if (apt->model & COINIT_APARTMENTTHREADED) {
261 if (apt->win) DestroyWindow(apt->win);
262 DeleteCriticalSection(&apt->cs);
264 CloseHandle(apt->thread);
265 HeapFree(GetProcessHeap(), 0, apt);
268 /* The given OXID must be local to this process: you cannot use apartment
269 windows to send RPCs to other processes */
270 HWND COM_GetApartmentWin(OXID oxid)
275 EnterCriticalSection(&csApartment);
277 while (apt && apt->oxid != oxid) apt = apt->next;
278 if (apt) win = apt->win;
279 LeaveCriticalSection(&csApartment);
283 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
284 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
286 return DefWindowProcA(hWnd, msg, wParam, lParam);
289 /*****************************************************************************
290 * This section contains OpenDllList implemantation
293 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
300 EnterCriticalSection( &csOpenDllList );
302 if (openDllList == NULL) {
303 /* empty list -- add first node */
304 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
305 openDllList->hLibrary=hLibrary;
306 openDllList->next = NULL;
308 /* search for this dll */
310 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
311 if (ptr->hLibrary == hLibrary) {
317 /* dll not found, add it */
319 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
320 openDllList->hLibrary = hLibrary;
321 openDllList->next = tmp;
325 LeaveCriticalSection( &csOpenDllList );
328 static void COMPOBJ_DllList_FreeUnused(int Timeout)
330 OpenDll *curr, *next, *prev = NULL;
331 typedef HRESULT(*DllCanUnloadNowFunc)(void);
332 DllCanUnloadNowFunc DllCanUnloadNow;
336 EnterCriticalSection( &csOpenDllList );
338 for (curr = openDllList; curr != NULL; ) {
339 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
341 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
344 TRACE("freeing %p\n", curr->hLibrary);
345 FreeLibrary(curr->hLibrary);
347 HeapFree(GetProcessHeap(), 0, curr);
348 if (curr == openDllList) {
361 LeaveCriticalSection( &csOpenDllList );
364 /******************************************************************************
365 * CoBuildVersion [COMPOBJ.1]
366 * CoBuildVersion [OLE32.@]
369 * Current build version, hiword is majornumber, loword is minornumber
371 DWORD WINAPI CoBuildVersion(void)
373 TRACE("Returning version %d, build %d.\n", rmm, rup);
374 return (rmm<<16)+rup;
377 /******************************************************************************
378 * CoInitialize [OLE32.@]
380 * Initializes the COM libraries.
384 HRESULT WINAPI CoInitialize(
385 LPVOID lpReserved /* [in] pointer to win32 malloc interface
386 (obsolete, should be NULL) */
390 * Just delegate to the newer method.
392 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
395 /******************************************************************************
396 * CoInitializeEx [OLE32.@]
398 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
399 * used for memory management is obsolete.
402 * S_OK if successful,
403 * S_FALSE if this function was called already.
404 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
407 HRESULT WINAPI CoInitializeEx(
408 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
409 (obsolete, should be NULL) */
410 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
416 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
418 if (lpReserved!=NULL)
420 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
423 apt = NtCurrentTeb()->ReservedForOle;
424 if (apt && !(apt->model == COINIT_UNINITIALIZED))
426 if (dwCoInit != apt->model)
428 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
429 code then we are probably using the wrong threading model to implement that API. */
430 WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
431 return RPC_E_CHANGED_MODE;
439 * Check the lock count. If this is the first time going through the initialize
440 * process, we have to initialize the libraries.
442 * And crank-up that lock count.
444 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
447 * Initialize the various COM libraries and data structures.
449 TRACE("() - Initializing the COM libraries\n");
453 RunningObjectTableImpl_Initialize();
456 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
458 InterlockedIncrement(&apt->inits);
459 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
464 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
465 pending RPCs are ignored. Non-COM messages are discarded at this point.
467 void COM_FlushMessageQueue(void)
470 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
472 if (!apt || !apt->win) return;
474 TRACE("Flushing STA message queue\n");
476 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
477 if (message.hwnd != apt->win) continue;
478 TranslateMessage(&message);
479 DispatchMessageA(&message);
483 /***********************************************************************
484 * CoUninitialize [OLE32.@]
486 * This method will release the COM libraries.
488 * See the windows documentation for more details.
490 void WINAPI CoUninitialize(void)
497 apt = NtCurrentTeb()->ReservedForOle;
499 if (InterlockedDecrement(&apt->inits)==0) {
500 NtCurrentTeb()->ReservedForOle = NULL;
501 COM_DestroyApartment(apt);
506 * Decrease the reference count.
507 * If we are back to 0 locks on the COM library, make sure we free
508 * all the associated data structures.
510 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
513 TRACE("() - Releasing the COM libraries\n");
515 RunningObjectTableImpl_UnInitialize();
517 /* disconnect proxies to release the corresponding stubs.
518 * It is confirmed in "Essential COM" in the sub-chapter on
519 * "Lifecycle Management and Marshalling" that the native version also
520 * does some kind of proxy cleanup in this function.
521 * FIXME: does it just disconnect or completely destroy the proxies?
522 * FIXME: should this be in the apartment destructor? */
523 MARSHAL_Disconnect_Proxies();
525 /* Release the references to the registered class objects */
526 COM_RevokeAllClasses();
528 /* This will free the loaded COM Dlls */
529 CoFreeAllLibraries();
531 /* This will free list of external references to COM objects */
532 COM_ExternalLockFreeList();
534 /* This ensures we deal with any pending RPCs */
535 COM_FlushMessageQueue();
539 else if (lCOMRefCnt<1) {
540 ERR( "CoUninitialize() - not CoInitialized.\n" );
541 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
545 /******************************************************************************
546 * CoDisconnectObject [COMPOBJ.15]
547 * CoDisconnectObject [OLE32.@]
549 * Disconnects all connections to this object from remote processes. Dispatches
550 * pending RPCs while blocking new RPCs from occurring, and then calls
551 * IMarshal::DisconnectObject on the given object.
553 * Typically called when the object server is forced to shut down, for instance by
556 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
558 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
562 /******************************************************************************
563 * CoCreateGuid[OLE32.@]
566 HRESULT WINAPI CoCreateGuid(
567 GUID *pguid /* [out] points to the GUID to initialize */
569 return UuidCreate(pguid);
572 /******************************************************************************
573 * CLSIDFromString [OLE32.@]
574 * IIDFromString [OLE32.@]
575 * Converts a unique identifier from its string representation into
579 * If idstr is not a valid CLSID string then it gets treated as a ProgID
584 HRESULT WINAPI __CLSIDFromStringA(
585 LPCSTR idstr, /* [in] string representation of guid */
586 CLSID *id) /* [out] GUID converted from string */
588 const BYTE *s = (BYTE *) idstr;
593 s = "{00000000-0000-0000-0000-000000000000}";
594 else { /* validate the CLSID string */
597 return CO_E_CLASSSTRING;
599 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
600 return CO_E_CLASSSTRING;
602 for (i=1; i<37; i++) {
603 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
604 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
605 ((s[i] >= 'a') && (s[i] <= 'f')) ||
606 ((s[i] >= 'A') && (s[i] <= 'F'))))
607 return CO_E_CLASSSTRING;
611 TRACE("%s -> %p\n", s, id);
613 /* quick lookup table */
614 memset(table, 0, 256);
616 for (i = 0; i < 10; i++) {
619 for (i = 0; i < 6; i++) {
620 table['A' + i] = i+10;
621 table['a' + i] = i+10;
624 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
626 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
627 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
628 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
629 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
631 /* these are just sequential bytes */
632 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
633 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
634 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
635 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
636 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
637 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
638 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
639 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
644 /*****************************************************************************/
646 HRESULT WINAPI CLSIDFromString(
647 LPOLESTR idstr, /* [in] string representation of GUID */
648 CLSID *id ) /* [out] GUID represented by above string */
653 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
654 return CO_E_CLASSSTRING;
657 ret = __CLSIDFromStringA(xid,id);
658 if(ret != S_OK) { /* It appears a ProgID is also valid */
659 ret = CLSIDFromProgID(idstr, id);
664 /******************************************************************************
665 * WINE_StringFromCLSID [Internal]
666 * Converts a GUID into the respective string representation.
671 * the string representation and HRESULT
673 HRESULT WINE_StringFromCLSID(
674 const CLSID *id, /* [in] GUID to be converted */
675 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
677 static const char *hex = "0123456789ABCDEF";
682 { ERR("called with id=Null\n");
687 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
688 id->Data1, id->Data2, id->Data3,
689 id->Data4[0], id->Data4[1]);
693 for (i = 2; i < 8; i++) {
694 *s++ = hex[id->Data4[i]>>4];
695 *s++ = hex[id->Data4[i] & 0xf];
701 TRACE("%p->%s\n", id, idstr);
707 /******************************************************************************
708 * StringFromCLSID [OLE32.@]
709 * StringFromIID [OLE32.@]
710 * Converts a GUID into the respective string representation.
711 * The target string is allocated using the OLE IMalloc.
713 * the string representation and HRESULT
715 HRESULT WINAPI StringFromCLSID(
716 REFCLSID id, /* [in] the GUID to be converted */
717 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
723 if ((ret=CoGetMalloc(0,&mllc)))
726 ret=WINE_StringFromCLSID(id,buf);
728 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
729 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
730 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
735 /******************************************************************************
736 * StringFromGUID2 [COMPOBJ.76]
737 * StringFromGUID2 [OLE32.@]
739 * Converts a global unique identifier into a string of an API-
740 * specified fixed format. (The usual {.....} stuff.)
743 * The (UNICODE) string representation of the GUID in 'str'
744 * The length of the resulting string, 0 if there was any problem.
747 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
751 if (WINE_StringFromCLSID(id,xguid))
753 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
756 /******************************************************************************
757 * ProgIDFromCLSID [OLE32.@]
758 * Converts a class id into the respective Program ID. (By using a registry lookup)
759 * RETURNS S_OK on success
760 * riid associated with the progid
763 HRESULT WINAPI ProgIDFromCLSID(
764 REFCLSID clsid, /* [in] class id as found in registry */
765 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
768 char strCLSID[50], *buf, *buf2;
774 WINE_StringFromCLSID(clsid, strCLSID);
776 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
777 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
778 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
779 ret = REGDB_E_CLASSNOTREG;
781 HeapFree(GetProcessHeap(), 0, buf);
785 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
787 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
788 ret = REGDB_E_CLASSNOTREG;
792 if (CoGetMalloc(0,&mllc))
796 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
797 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
798 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
801 HeapFree(GetProcessHeap(), 0, buf2);
808 /******************************************************************************
809 * CLSIDFromProgID [COMPOBJ.61]
810 * Converts a program id into the respective GUID. (By using a registry lookup)
812 * riid associated with the progid
814 HRESULT WINAPI CLSIDFromProgID16(
815 LPCOLESTR16 progid, /* [in] program id as found in registry */
816 LPCLSID riid /* [out] associated CLSID */
823 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
824 sprintf(buf,"%s\\CLSID",progid);
825 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
826 HeapFree(GetProcessHeap(),0,buf);
827 return CO_E_CLASSSTRING;
829 HeapFree(GetProcessHeap(),0,buf);
830 buf2len = sizeof(buf2);
831 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
833 return CO_E_CLASSSTRING;
836 return __CLSIDFromStringA(buf2,riid);
839 /******************************************************************************
840 * CLSIDFromProgID [OLE32.@]
841 * Converts a program id into the respective GUID. (By using a registry lookup)
843 * riid associated with the progid
845 HRESULT WINAPI CLSIDFromProgID(
846 LPCOLESTR progid, /* [in] program id as found in registry */
847 LPCLSID riid ) /* [out] associated CLSID */
849 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
851 DWORD buf2len = sizeof(buf2);
854 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
855 strcpyW( buf, progid );
856 strcatW( buf, clsidW );
857 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
859 HeapFree(GetProcessHeap(),0,buf);
860 return CO_E_CLASSSTRING;
862 HeapFree(GetProcessHeap(),0,buf);
864 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
867 return CO_E_CLASSSTRING;
870 return __CLSIDFromStringA(buf2,riid);
875 /*****************************************************************************
876 * CoGetPSClsid [OLE32.@]
878 * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
879 * for the specified interface.
881 * The standard marshaller activates the object with the CLSID returned and uses the
882 * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
883 * the proxies and stubs for a given object.
885 * CoGetPSClsid determines this CLSID by searching the
886 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
887 * and any interface id registered by CoRegisterPSClsid within the current process.
889 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
891 HRESULT WINAPI CoGetPSClsid(
892 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
893 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
899 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
901 /* Get the input iid as a string */
902 WINE_StringFromCLSID(riid, buf2);
903 /* Allocate memory for the registry key we will construct.
904 (length of iid string plus constant length of static text */
905 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
908 return (E_OUTOFMEMORY);
911 /* Construct the registry key we want */
912 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
915 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
917 WARN("No PSFactoryBuffer object is registered for this IID\n");
918 HeapFree(GetProcessHeap(),0,buf);
919 return (E_INVALIDARG);
921 HeapFree(GetProcessHeap(),0,buf);
923 /* ... Once we have the key, query the registry to get the
924 value of CLSID as a string, and convert it into a
925 proper CLSID structure to be passed back to the app */
926 buf2len = sizeof(buf2);
927 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
934 /* We have the CLSid we want back from the registry as a string, so
935 lets convert it into a CLSID structure */
936 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
940 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
946 /***********************************************************************
947 * WriteClassStm (OLE32.@)
949 * This function write a CLSID on stream
951 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
953 TRACE("(%p,%p)\n",pStm,rclsid);
958 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
961 /***********************************************************************
962 * ReadClassStm (OLE32.@)
964 * This function read a CLSID from a stream
966 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
971 TRACE("(%p,%p)\n",pStm,pclsid);
976 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
981 if (nbByte != sizeof(CLSID))
989 * COM_GetRegisteredClassObject
991 * This internal method is used to scan the registered class list to
992 * find a class object.
995 * rclsid Class ID of the class to find.
996 * dwClsContext Class context to match.
997 * ppv [out] returns a pointer to the class object. Complying
998 * to normal COM usage, this method will increase the
999 * reference count on this object.
1001 static HRESULT COM_GetRegisteredClassObject(
1006 HRESULT hr = S_FALSE;
1007 RegisteredClass* curClass;
1009 EnterCriticalSection( &csRegisteredClassList );
1017 * Iterate through the whole list and try to match the class ID.
1019 curClass = firstRegisteredClass;
1021 while (curClass != 0)
1024 * Check if we have a match on the class ID.
1026 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1029 * Since we don't do out-of process or DCOM just right away, let's ignore the
1034 * We have a match, return the pointer to the class object.
1036 *ppUnk = curClass->classObject;
1038 IUnknown_AddRef(curClass->classObject);
1045 * Step to the next class in the list.
1047 curClass = curClass->nextClass;
1051 LeaveCriticalSection( &csRegisteredClassList );
1053 * If we get to here, we haven't found our class.
1059 _LocalServerThread(LPVOID param) {
1062 RegisteredClass *newClass = (RegisteredClass*)param;
1066 unsigned char *buffer;
1068 IClassFactory *classfac;
1069 LARGE_INTEGER seekto;
1070 ULARGE_INTEGER newpos;
1073 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1075 strcpy(pipefn,PIPEPREF);
1076 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1078 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1079 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1080 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1081 if (hPipe == INVALID_HANDLE_VALUE) {
1082 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1086 if (!ConnectNamedPipe(hPipe,NULL)) {
1087 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1091 TRACE("marshalling IClassFactory to client\n");
1093 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1094 if (hres) return hres;
1096 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1098 FIXME("Failed to create stream on hglobal.\n");
1101 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1103 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1107 IUnknown_Release(classfac); /* is this right? */
1109 hres = IStream_Stat(pStm,&ststg,0);
1110 if (hres) return hres;
1112 buflen = ststg.cbSize.u.LowPart;
1113 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1114 seekto.u.LowPart = 0;
1115 seekto.u.HighPart = 0;
1116 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1118 FIXME("IStream_Seek failed, %lx\n",hres);
1122 hres = IStream_Read(pStm,buffer,buflen,&res);
1124 FIXME("Stream Read failed, %lx\n",hres);
1128 IStream_Release(pStm);
1130 WriteFile(hPipe,buffer,buflen,&res,NULL);
1131 FlushFileBuffers(hPipe);
1132 DisconnectNamedPipe(hPipe);
1134 TRACE("done marshalling IClassFactory\n");
1140 /******************************************************************************
1141 * CoRegisterClassObject [OLE32.@]
1143 * This method will register the class object for a given class ID. Servers housed
1144 * in EXE files use this method instead of exporting DllGetClassObject to allow other
1145 * code to connect to their objects.
1147 * When a class object (an object which implements IClassFactory) is registered in
1148 * this way, a new thread is started which listens for connections on a named pipe
1149 * specific to the registered CLSID. When something else connects to it, it writes
1150 * out the marshalled IClassFactory interface to the pipe. The code on the other end
1151 * uses this buffer to unmarshal the class factory, and can then call methods on it.
1153 * In Windows, such objects are registered with the RPC endpoint mapper, not with
1154 * a unique named pipe.
1156 * See the Windows documentation for more details.
1158 HRESULT WINAPI CoRegisterClassObject(
1161 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1162 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1163 LPDWORD lpdwRegister
1166 RegisteredClass* newClass;
1167 LPUNKNOWN foundObject;
1170 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1171 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1173 if ( (lpdwRegister==0) || (pUnk==0) )
1174 return E_INVALIDARG;
1179 * First, check if the class is already registered.
1180 * If it is, this should cause an error.
1182 * MSDN claims that multiple interface registrations are legal, but we can't do that with
1183 * our current implementation.
1185 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1187 IUnknown_Release(foundObject);
1188 return CO_E_OBJISREG;
1191 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1192 if ( newClass == NULL )
1193 return E_OUTOFMEMORY;
1195 EnterCriticalSection( &csRegisteredClassList );
1197 newClass->classIdentifier = *rclsid;
1198 newClass->runContext = dwClsContext;
1199 newClass->connectFlags = flags;
1201 * Use the address of the chain node as the cookie since we are sure it's
1204 newClass->dwCookie = (DWORD)newClass;
1205 newClass->nextClass = firstRegisteredClass;
1208 * Since we're making a copy of the object pointer, we have to increase its
1211 newClass->classObject = pUnk;
1212 IUnknown_AddRef(newClass->classObject);
1214 firstRegisteredClass = newClass;
1215 LeaveCriticalSection( &csRegisteredClassList );
1217 *lpdwRegister = newClass->dwCookie;
1219 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1223 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1228 /***********************************************************************
1229 * CoRevokeClassObject [OLE32.@]
1231 * This method will remove a class object from the class registry
1233 * See the Windows documentation for more details.
1235 HRESULT WINAPI CoRevokeClassObject(
1238 HRESULT hr = E_INVALIDARG;
1239 RegisteredClass** prevClassLink;
1240 RegisteredClass* curClass;
1242 TRACE("(%08lx)\n",dwRegister);
1244 EnterCriticalSection( &csRegisteredClassList );
1247 * Iterate through the whole list and try to match the cookie.
1249 curClass = firstRegisteredClass;
1250 prevClassLink = &firstRegisteredClass;
1252 while (curClass != 0)
1255 * Check if we have a match on the cookie.
1257 if (curClass->dwCookie == dwRegister)
1260 * Remove the class from the chain.
1262 *prevClassLink = curClass->nextClass;
1265 * Release the reference to the class object.
1267 IUnknown_Release(curClass->classObject);
1270 * Free the memory used by the chain node.
1272 HeapFree(GetProcessHeap(), 0, curClass);
1279 * Step to the next class in the list.
1281 prevClassLink = &(curClass->nextClass);
1282 curClass = curClass->nextClass;
1286 LeaveCriticalSection( &csRegisteredClassList );
1288 * If we get to here, we haven't found our class.
1293 /***********************************************************************
1294 * compobj_RegReadPath [internal]
1296 * Reads a registry value and expands it when necessary
1298 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1304 DWORD dwLength = dstlen;
1306 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1307 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1308 if (keytype == REG_EXPAND_SZ) {
1309 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1311 lstrcpynA(dst, src, dstlen);
1319 /***********************************************************************
1320 * CoGetClassObject [COMPOBJ.7]
1321 * CoGetClassObject [OLE32.@]
1323 * FIXME. If request allows of several options and there is a failure
1324 * with one (other than not being registered) do we try the
1325 * others or return failure? (E.g. inprocess is registered but
1326 * the DLL is not found but the server version works)
1328 HRESULT WINAPI CoGetClassObject(
1329 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1330 REFIID iid, LPVOID *ppv
1332 LPUNKNOWN regClassObject;
1333 HRESULT hres = E_UNEXPECTED;
1336 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1337 DllGetClassObjectFunc DllGetClassObject;
1339 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1341 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1344 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1345 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1349 * First, try and see if we can't match the class ID with one of the
1350 * registered classes.
1352 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1355 * Get the required interface from the retrieved pointer.
1357 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1360 * Since QI got another reference on the pointer, we want to release the
1361 * one we already have. If QI was unsuccessful, this will release the object. This
1362 * is good since we are not returning it in the "out" parameter.
1364 IUnknown_Release(regClassObject);
1369 /* first try: in-process */
1370 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1371 char keyname[MAX_PATH];
1372 char dllpath[MAX_PATH+1];
1374 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1376 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1377 /* failure: CLSID is not found in registry */
1378 WARN("class %s not registered inproc\n", xclsid);
1379 hres = REGDB_E_CLASSNOTREG;
1381 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1382 /* failure: DLL could not be loaded */
1383 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1384 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1385 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1386 /* failure: the dll did not export DllGetClassObject */
1387 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1388 FreeLibrary( hLibrary );
1389 hres = CO_E_DLLNOTFOUND;
1391 /* OK: get the ClassObject */
1392 COMPOBJ_DLLList_Add( hLibrary );
1393 return DllGetClassObject(rclsid, iid, ppv);
1398 /* Next try out of process */
1399 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1401 return create_marshalled_proxy(rclsid,iid,ppv);
1404 /* Finally try remote: this requires networked DCOM (a lot of work) */
1405 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1407 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1408 hres = E_NOINTERFACE;
1413 /***********************************************************************
1414 * CoResumeClassObjects (OLE32.@)
1416 * Resumes classobjects registered with REGCLS suspended
1418 HRESULT WINAPI CoResumeClassObjects(void)
1424 /***********************************************************************
1425 * GetClassFile (OLE32.@)
1427 * This function supplies the CLSID associated with the given filename.
1429 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1433 int nbElm, length, i;
1435 LPOLESTR *pathDec=0,absFile=0,progId=0;
1437 static const WCHAR bkslashW[] = {'\\',0};
1438 static const WCHAR dotW[] = {'.',0};
1440 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1442 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1443 if((StgIsStorageFile(filePathName))==S_OK){
1445 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1448 res=ReadClassStg(pstg,pclsid);
1450 IStorage_Release(pstg);
1454 /* if the file is not a storage object then attemps to match various bits in the file against a
1455 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1458 for(i=0;i<nFileTypes;i++)
1460 for(i=0;j<nPatternsForType;j++){
1465 pat=ReadPatternFromRegistry(i,j);
1466 hFile=CreateFileW(filePathName,,,,,,hFile);
1467 SetFilePosition(hFile,pat.offset);
1468 ReadFile(hFile,buf,pat.size,NULL,NULL);
1469 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1471 *pclsid=ReadCLSIDFromRegistry(i);
1477 /* if the above strategies fail then search for the extension key in the registry */
1479 /* get the last element (absolute file) in the path name */
1480 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1481 absFile=pathDec[nbElm-1];
1483 /* failed if the path represente a directory and not an absolute file name*/
1484 if (!lstrcmpW(absFile, bkslashW))
1485 return MK_E_INVALIDEXTENSION;
1487 /* get the extension of the file */
1489 length=lstrlenW(absFile);
1490 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1493 if (!extension || !lstrcmpW(extension, dotW))
1494 return MK_E_INVALIDEXTENSION;
1496 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1498 /* get the progId associated to the extension */
1499 progId = CoTaskMemAlloc(sizeProgId);
1500 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1502 if (res==ERROR_SUCCESS)
1503 /* return the clsid associated to the progId */
1504 res= CLSIDFromProgID(progId,pclsid);
1506 for(i=0; pathDec[i]!=NULL;i++)
1507 CoTaskMemFree(pathDec[i]);
1508 CoTaskMemFree(pathDec);
1510 CoTaskMemFree(progId);
1512 if (res==ERROR_SUCCESS)
1515 return MK_E_INVALIDEXTENSION;
1517 /***********************************************************************
1518 * CoCreateInstance [COMPOBJ.13]
1519 * CoCreateInstance [OLE32.@]
1521 HRESULT WINAPI CoCreateInstance(
1523 LPUNKNOWN pUnkOuter,
1529 LPCLASSFACTORY lpclf = 0;
1538 * Initialize the "out" parameter
1543 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1544 * Rather than create a class factory, we can just check for it here
1546 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1547 if (StdGlobalInterfaceTableInstance == NULL)
1548 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1549 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1550 if (hres) return hres;
1552 TRACE("Retrieved GIT (%p)\n", *ppv);
1557 * Get a class factory to construct the object we want.
1559 hres = CoGetClassObject(rclsid,
1566 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1567 debugstr_guid(rclsid),hres);
1572 * Create the object and don't forget to release the factory
1574 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1575 IClassFactory_Release(lpclf);
1577 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1578 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1583 /***********************************************************************
1584 * CoCreateInstanceEx [OLE32.@]
1586 HRESULT WINAPI CoCreateInstanceEx(
1588 LPUNKNOWN pUnkOuter,
1590 COSERVERINFO* pServerInfo,
1594 IUnknown* pUnk = NULL;
1597 ULONG successCount = 0;
1602 if ( (cmq==0) || (pResults==NULL))
1603 return E_INVALIDARG;
1605 if (pServerInfo!=NULL)
1606 FIXME("() non-NULL pServerInfo not supported!\n");
1609 * Initialize all the "out" parameters.
1611 for (index = 0; index < cmq; index++)
1613 pResults[index].pItf = NULL;
1614 pResults[index].hr = E_NOINTERFACE;
1618 * Get the object and get its IUnknown pointer.
1620 hr = CoCreateInstance(rclsid,
1630 * Then, query for all the interfaces requested.
1632 for (index = 0; index < cmq; index++)
1634 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1635 pResults[index].pIID,
1636 (VOID**)&(pResults[index].pItf));
1638 if (pResults[index].hr == S_OK)
1643 * Release our temporary unknown pointer.
1645 IUnknown_Release(pUnk);
1647 if (successCount == 0)
1648 return E_NOINTERFACE;
1650 if (successCount!=cmq)
1651 return CO_S_NOTALLINTERFACES;
1656 /***********************************************************************
1657 * CoLoadLibrary (OLE32.@)
1659 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1661 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1663 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1666 /***********************************************************************
1667 * CoFreeLibrary [OLE32.@]
1669 * NOTES: don't believe the documentation
1671 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1673 FreeLibrary(hLibrary);
1677 /***********************************************************************
1678 * CoFreeAllLibraries [OLE32.@]
1680 * NOTES: don't believe the documentation
1682 void WINAPI CoFreeAllLibraries(void)
1688 /***********************************************************************
1689 * CoFreeUnusedLibraries [COMPOBJ.17]
1690 * CoFreeUnusedLibraries [OLE32.@]
1692 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1693 * through the main apartment's thread to call DllCanUnloadNow
1695 void WINAPI CoFreeUnusedLibraries(void)
1697 COMPOBJ_DllList_FreeUnused(0);
1700 /***********************************************************************
1701 * CoFileTimeNow [COMPOBJ.82]
1702 * CoFileTimeNow [OLE32.@]
1705 * the current system time in lpFileTime
1707 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1709 GetSystemTimeAsFileTime( lpFileTime );
1713 /***********************************************************************
1714 * CoLoadLibrary (OLE32.@)
1716 static void COM_RevokeAllClasses()
1718 EnterCriticalSection( &csRegisteredClassList );
1720 while (firstRegisteredClass!=0)
1722 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1725 LeaveCriticalSection( &csRegisteredClassList );
1728 /****************************************************************************
1729 * COM External Lock methods implementation
1731 * This api provides a linked list to managed external references to
1734 * The public interface consists of three calls:
1735 * COM_ExternalLockAddRef
1736 * COM_ExternalLockRelease
1737 * COM_ExternalLockFreeList
1740 #define EL_END_OF_LIST 0
1741 #define EL_NOT_FOUND 0
1744 * Declaration of the static structure that manage the
1745 * external lock to COM objects.
1747 typedef struct COM_ExternalLock COM_ExternalLock;
1748 typedef struct COM_ExternalLockList COM_ExternalLockList;
1750 struct COM_ExternalLock
1752 IUnknown *pUnk; /* IUnknown referenced */
1753 ULONG uRefCount; /* external lock counter to IUnknown object*/
1754 COM_ExternalLock *next; /* Pointer to next element in list */
1757 struct COM_ExternalLockList
1759 COM_ExternalLock *head; /* head of list */
1763 * Declaration and initialization of the static structure that manages
1764 * the external lock to COM objects.
1766 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1769 * Private methods used to managed the linked list
1773 static COM_ExternalLock* COM_ExternalLockLocate(
1774 COM_ExternalLock *element,
1777 /****************************************************************************
1778 * Internal - Insert a new IUnknown* to the linked list
1780 static BOOL COM_ExternalLockInsert(
1783 COM_ExternalLock *newLock = NULL;
1784 COM_ExternalLock *previousHead = NULL;
1787 * Allocate space for the new storage object
1789 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1791 if (newLock!=NULL) {
1792 if ( elList.head == EL_END_OF_LIST ) {
1793 elList.head = newLock; /* The list is empty */
1795 /* insert does it at the head */
1796 previousHead = elList.head;
1797 elList.head = newLock;
1800 /* Set new list item data member */
1801 newLock->pUnk = pUnk;
1802 newLock->uRefCount = 1;
1803 newLock->next = previousHead;
1810 /****************************************************************************
1811 * Internal - Method that removes an item from the linked list.
1813 static void COM_ExternalLockDelete(
1814 COM_ExternalLock *itemList)
1816 COM_ExternalLock *current = elList.head;
1818 if ( current == itemList ) {
1819 /* this section handles the deletion of the first node */
1820 elList.head = itemList->next;
1821 HeapFree( GetProcessHeap(), 0, itemList);
1824 if ( current->next == itemList ){ /* We found the item to free */
1825 current->next = itemList->next; /* readjust the list pointers */
1826 HeapFree( GetProcessHeap(), 0, itemList);
1830 /* Skip to the next item */
1831 current = current->next;
1833 } while ( current != EL_END_OF_LIST );
1837 /****************************************************************************
1838 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1840 * NOTES: how long can the list be ?? (recursive!!!)
1842 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1844 if ( element == EL_END_OF_LIST )
1845 return EL_NOT_FOUND;
1846 else if ( element->pUnk == pUnk ) /* We found it */
1848 else /* Not the right guy, keep on looking */
1849 return COM_ExternalLockLocate( element->next, pUnk);
1852 /****************************************************************************
1853 * Public - Method that increments the count for a IUnknown* in the linked
1854 * list. The item is inserted if not already in the list.
1856 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1858 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1861 * Add an external lock to the object. If it was already externally
1862 * locked, just increase the reference count. If it was not.
1863 * add the item to the list.
1865 if ( externalLock == EL_NOT_FOUND )
1866 COM_ExternalLockInsert(pUnk);
1868 externalLock->uRefCount++;
1871 * Add an internal lock to the object
1873 IUnknown_AddRef(pUnk);
1876 /****************************************************************************
1877 * Public - Method that decrements the count for a IUnknown* in the linked
1878 * list. The item is removed from the list if its count end up at zero or if
1881 static void COM_ExternalLockRelease(
1885 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1887 if ( externalLock != EL_NOT_FOUND ) {
1889 externalLock->uRefCount--; /* release external locks */
1890 IUnknown_Release(pUnk); /* release local locks as well */
1892 if ( bRelAll == FALSE ) break; /* perform single release */
1894 } while ( externalLock->uRefCount > 0 );
1896 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1897 COM_ExternalLockDelete(externalLock);
1900 /****************************************************************************
1901 * Public - Method that frees the content of the list.
1903 static void COM_ExternalLockFreeList()
1905 COM_ExternalLock *head;
1907 head = elList.head; /* grab it by the head */
1908 while ( head != EL_END_OF_LIST ) {
1909 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1910 head = elList.head; /* get the new head... */
1914 /****************************************************************************
1915 * Public - Method that dump the content of the list.
1917 void COM_ExternalLockDump()
1919 COM_ExternalLock *current = elList.head;
1921 DPRINTF("\nExternal lock list contains:\n");
1923 while ( current != EL_END_OF_LIST ) {
1924 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1926 /* Skip to the next item */
1927 current = current->next;
1931 /******************************************************************************
1932 * CoLockObjectExternal [OLE32.@]
1934 HRESULT WINAPI CoLockObjectExternal(
1935 LPUNKNOWN pUnk, /* [in] object to be locked */
1936 BOOL fLock, /* [in] do lock */
1937 BOOL fLastUnlockReleases) /* [in] unlock all */
1942 * Increment the external lock coutner, COM_ExternalLockAddRef also
1943 * increment the object's internal lock counter.
1945 COM_ExternalLockAddRef( pUnk);
1948 * Decrement the external lock coutner, COM_ExternalLockRelease also
1949 * decrement the object's internal lock counter.
1951 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1957 /***********************************************************************
1958 * CoInitializeWOW (OLE32.@)
1960 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1961 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1965 /***********************************************************************
1966 * CoGetState [OLE32.@]
1968 * NOTES: might be incomplete
1970 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1972 APARTMENT * apt = COM_CurrentInfo();
1976 if(apt && apt->state) {
1977 IUnknown_AddRef(apt->state);
1979 FIXME("-- %p\n", *ppv);
1987 /***********************************************************************
1988 * CoSetState [OLE32.@]
1991 HRESULT WINAPI CoSetState(IUnknown * pv)
1993 APARTMENT * apt = COM_CurrentInfo();
1995 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1997 FIXME("(%p),stub!\n", pv);
2000 IUnknown_AddRef(pv);
2004 TRACE("-- release %p now\n", apt->state);
2005 IUnknown_Release(apt->state);
2012 /******************************************************************************
2013 * OleGetAutoConvert [OLE32.@]
2015 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2023 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2024 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2026 res = REGDB_E_CLASSNOTREG;
2030 /* we can just query for the default value of AutoConvertTo key like that,
2031 without opening the AutoConvertTo key and querying for NULL (default) */
2032 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2034 res = REGDB_E_KEYMISSING;
2037 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2038 CLSIDFromString(wbuf,pClsidNew);
2040 if (hkey) RegCloseKey(hkey);
2044 /******************************************************************************
2045 * OleSetAutoConvert [OLE32.@]
2047 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2050 char buf[200], szClsidNew[200];
2053 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2054 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2055 WINE_StringFromCLSID(clsidNew, szClsidNew);
2056 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2058 res = REGDB_E_CLASSNOTREG;
2061 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2063 res = REGDB_E_WRITEREGDB;
2068 if (hkey) RegCloseKey(hkey);
2072 /******************************************************************************
2073 * OleDoAutoConvert [OLE32.@]
2075 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2077 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2081 /******************************************************************************
2082 * CoTreatAsClass [OLE32.@]
2084 * Sets TreatAs value of a class
2086 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2090 char szClsidNew[39];
2092 char auto_treat_as[39];
2093 LONG auto_treat_as_size = sizeof(auto_treat_as);
2096 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2097 WINE_StringFromCLSID(clsidNew, szClsidNew);
2098 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2100 res = REGDB_E_CLASSNOTREG;
2103 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2105 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2106 !__CLSIDFromStringA(auto_treat_as, &id))
2108 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2110 res = REGDB_E_WRITEREGDB;
2116 RegDeleteKeyA(hkey, "TreatAs");
2120 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2122 res = REGDB_E_WRITEREGDB;
2127 if (hkey) RegCloseKey(hkey);
2131 /******************************************************************************
2132 * CoGetTreatAsClass [OLE32.@]
2134 * Reads the TreatAs value from a class.
2136 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2139 char buf[200], szClsidNew[200];
2141 LONG len = sizeof(szClsidNew);
2143 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2144 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2145 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2147 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2149 res = REGDB_E_CLASSNOTREG;
2152 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2157 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2159 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2161 if (hkey) RegCloseKey(hkey);
2166 /***********************************************************************
2167 * IsEqualGUID [OLE32.@]
2169 * Compares two Unique Identifiers.
2175 BOOL WINAPI IsEqualGUID(
2176 REFGUID rguid1, /* [in] unique id 1 */
2177 REFGUID rguid2 /* [in] unique id 2 */
2180 return !memcmp(rguid1,rguid2,sizeof(GUID));
2183 /***********************************************************************
2184 * CoInitializeSecurity [OLE32.@]
2186 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2187 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2188 void* pReserved1, DWORD dwAuthnLevel,
2189 DWORD dwImpLevel, void* pReserved2,
2190 DWORD dwCapabilities, void* pReserved3)
2192 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2193 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2194 dwCapabilities, pReserved3);
2198 /***********************************************************************
2199 * CoSuspendClassObjects [OLE32.@]
2201 HRESULT WINAPI CoSuspendClassObjects(void)