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
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
46 #include "wine/unicode.h"
48 #include "ole32_main.h"
49 #include "compobj_private.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
55 typedef LPCSTR LPCOLESTR16;
57 /****************************************************************************
58 * This section defines variables internal to the COM module.
60 * TODO: Most of these things will have to be made thread-safe.
62 HINSTANCE COMPOBJ_hInstance32 = 0;
64 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
65 static void COM_RevokeAllClasses();
66 static void COM_ExternalLockFreeList();
68 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
72 static CRITICAL_SECTION csApartment;
73 static CRITICAL_SECTION_DEBUG critsect_debug =
76 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
77 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
79 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
82 * This lock count counts the number of times CoInitialize is called. It is
83 * decreased every time CoUninitialize is called. When it hits 0, the COM
86 static LONG s_COMLockCount = 0;
89 * This linked list contains the list of registered class objects. These
90 * are mostly used to register the factories for out-of-proc servers of OLE
93 * TODO: Make this data structure aware of inter-process communication. This
94 * means that parts of this will be exported to the Wine Server.
96 typedef struct tagRegisteredClass
98 CLSID classIdentifier;
99 LPUNKNOWN classObject;
103 HANDLE hThread; /* only for localserver */
104 struct tagRegisteredClass* nextClass;
107 static RegisteredClass* firstRegisteredClass = NULL;
109 static CRITICAL_SECTION csRegisteredClassList;
110 static CRITICAL_SECTION_DEBUG class_cs_debug =
112 0, 0, &csRegisteredClassList,
113 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
114 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
116 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
118 /*****************************************************************************
119 * This section contains OpenDllList definitions
121 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
122 * other functions that do LoadLibrary _without_ giving back a HMODULE.
123 * Without this list these handles would never be freed.
125 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
126 * next unload-call but not before 600 sec.
129 typedef struct tagOpenDll {
131 struct tagOpenDll *next;
134 static OpenDll *openDllList = NULL; /* linked list of open dlls */
136 static CRITICAL_SECTION csOpenDllList;
137 static CRITICAL_SECTION_DEBUG dll_cs_debug =
139 0, 0, &csOpenDllList,
140 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
141 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
143 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
145 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
146 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
148 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
149 static void COMPOBJ_DllList_FreeUnused(int Timeout);
151 void COMPOBJ_InitProcess( void )
155 /* Dispatching to the correct thread in an apartment is done through
156 * window messages rather than RPC transports. When an interface is
157 * marshalled into another apartment in the same process, a window of the
158 * following class is created. The *caller* of CoMarshalInterface (ie the
159 * application) is responsible for pumping the message loop in that thread.
160 * The WM_USER messages which point to the RPCs are then dispatched to
161 * COM_AptWndProc by the user's code.
163 memset(&wclass, 0, sizeof(wclass));
164 wclass.lpfnWndProc = &COM_AptWndProc;
165 wclass.hInstance = OLE32_hInstance;
166 wclass.lpszClassName = aptWinClass;
167 RegisterClassA(&wclass);
170 void COMPOBJ_UninitProcess( void )
172 UnregisterClassA(aptWinClass, OLE32_hInstance);
175 /******************************************************************************
180 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
181 with free threaded (ie thread safe) COM objects. There is only ever one MTA
182 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
184 static void COM_InitMTA(void)
186 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
187 within a network. That is, two different MTAs on different machines will have
190 This method of generating an OXID is therefore wrong as it doesn't work across
191 a network, but for local RPC only it's OK. We can distinguish between MTAs and
192 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
194 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
195 InitializeCriticalSection(&MTA.cs);
198 static void COM_UninitMTA(void)
200 DeleteCriticalSection(&MTA.cs);
204 /* creates an apartment structure which stores OLE thread-local
205 * information. Call with COINIT_UNINITIALIZED to create an apartment
206 * that will be initialized with a model later. Note: do not call
207 * with COINIT_UNINITIALIZED if the apartment has already been initialized
208 * with a different COINIT value */
209 APARTMENT* COM_CreateApartment(DWORD model)
212 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
216 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
217 apt->tid = GetCurrentThreadId();
218 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
219 GetCurrentProcess(), &apt->thread,
220 THREAD_ALL_ACCESS, FALSE, 0);
223 apt = NtCurrentTeb()->ReservedForOle;
226 if (model & COINIT_APARTMENTTHREADED) {
227 /* FIXME: how does windoze create OXIDs? */
228 apt->oxid = MTA.oxid | GetCurrentThreadId();
229 apt->win = CreateWindowA(aptWinClass, NULL, 0,
231 0, 0, OLE32_hInstance, NULL);
232 InitializeCriticalSection(&apt->cs);
234 else if (!(model & COINIT_UNINITIALIZED)) {
236 apt->oxid = MTA.oxid;
238 EnterCriticalSection(&csApartment);
241 if (apts) apts->prev = apt;
245 LeaveCriticalSection(&csApartment);
246 NtCurrentTeb()->ReservedForOle = apt;
250 static void COM_DestroyApartment(APARTMENT *apt)
252 EnterCriticalSection(&csApartment);
253 if (apt->prev) apt->prev->next = apt->next;
254 if (apt->next) apt->next->prev = apt->prev;
255 if (apts == apt) apts = apt->next;
256 apt->prev = NULL; apt->next = NULL;
257 LeaveCriticalSection(&csApartment);
258 if (apt->model & COINIT_APARTMENTTHREADED) {
259 if (apt->win) DestroyWindow(apt->win);
260 DeleteCriticalSection(&apt->cs);
262 CloseHandle(apt->thread);
263 HeapFree(GetProcessHeap(), 0, apt);
266 /* The given OXID must be local to this process: you cannot use apartment
267 windows to send RPCs to other processes */
268 HWND COM_GetApartmentWin(OXID oxid)
273 EnterCriticalSection(&csApartment);
275 while (apt && apt->oxid != oxid) apt = apt->next;
276 if (apt) win = apt->win;
277 LeaveCriticalSection(&csApartment);
281 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
282 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
284 return DefWindowProcA(hWnd, msg, wParam, lParam);
287 /*****************************************************************************
288 * This section contains OpenDllList implemantation
291 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
298 EnterCriticalSection( &csOpenDllList );
300 if (openDllList == NULL) {
301 /* empty list -- add first node */
302 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
303 openDllList->hLibrary=hLibrary;
304 openDllList->next = NULL;
306 /* search for this dll */
308 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
309 if (ptr->hLibrary == hLibrary) {
315 /* dll not found, add it */
317 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
318 openDllList->hLibrary = hLibrary;
319 openDllList->next = tmp;
323 LeaveCriticalSection( &csOpenDllList );
326 static void COMPOBJ_DllList_FreeUnused(int Timeout)
328 OpenDll *curr, *next, *prev = NULL;
329 typedef HRESULT(*DllCanUnloadNowFunc)(void);
330 DllCanUnloadNowFunc DllCanUnloadNow;
334 EnterCriticalSection( &csOpenDllList );
336 for (curr = openDllList; curr != NULL; ) {
337 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
339 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
342 TRACE("freeing %p\n", curr->hLibrary);
343 FreeLibrary(curr->hLibrary);
345 HeapFree(GetProcessHeap(), 0, curr);
346 if (curr == openDllList) {
359 LeaveCriticalSection( &csOpenDllList );
362 /******************************************************************************
363 * CoBuildVersion [COMPOBJ.1]
364 * CoBuildVersion [OLE32.@]
367 * Current build version, hiword is majornumber, loword is minornumber
369 DWORD WINAPI CoBuildVersion(void)
371 TRACE("Returning version %d, build %d.\n", rmm, rup);
372 return (rmm<<16)+rup;
375 /******************************************************************************
376 * CoInitialize [OLE32.@]
378 * Initializes the COM libraries.
382 HRESULT WINAPI CoInitialize(
383 LPVOID lpReserved /* [in] pointer to win32 malloc interface
384 (obsolete, should be NULL) */
388 * Just delegate to the newer method.
390 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
393 /******************************************************************************
394 * CoInitializeEx [OLE32.@]
396 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
397 * used for memory management is obsolete.
400 * S_OK if successful,
401 * S_FALSE if this function was called already.
402 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
405 HRESULT WINAPI CoInitializeEx(
406 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
407 (obsolete, should be NULL) */
408 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
414 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
416 if (lpReserved!=NULL)
418 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
421 apt = NtCurrentTeb()->ReservedForOle;
422 if (apt && !(apt->model == COINIT_UNINITIALIZED))
424 if (dwCoInit != apt->model)
426 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
427 code then we are probably using the wrong threading model to implement that API. */
428 WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
429 return RPC_E_CHANGED_MODE;
437 * Check the lock count. If this is the first time going through the initialize
438 * process, we have to initialize the libraries.
440 * And crank-up that lock count.
442 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
445 * Initialize the various COM libraries and data structures.
447 TRACE("() - Initializing the COM libraries\n");
451 RunningObjectTableImpl_Initialize();
454 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
456 InterlockedIncrement(&apt->inits);
457 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
462 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
463 pending RPCs are ignored. Non-COM messages are discarded at this point.
465 void COM_FlushMessageQueue(void)
468 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
470 if (!apt || !apt->win) return;
472 TRACE("Flushing STA message queue\n");
474 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
475 if (message.hwnd != apt->win) continue;
476 TranslateMessage(&message);
477 DispatchMessageA(&message);
481 /***********************************************************************
482 * CoUninitialize [OLE32.@]
484 * This method will release the COM libraries.
486 * See the windows documentation for more details.
488 void WINAPI CoUninitialize(void)
495 apt = NtCurrentTeb()->ReservedForOle;
497 if (InterlockedDecrement(&apt->inits)==0) {
498 NtCurrentTeb()->ReservedForOle = NULL;
499 COM_DestroyApartment(apt);
504 * Decrease the reference count.
505 * If we are back to 0 locks on the COM library, make sure we free
506 * all the associated data structures.
508 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
511 TRACE("() - Releasing the COM libraries\n");
513 RunningObjectTableImpl_UnInitialize();
515 /* Release the references to the registered class objects */
516 COM_RevokeAllClasses();
518 /* This will free the loaded COM Dlls */
519 CoFreeAllLibraries();
521 /* This will free list of external references to COM objects */
522 COM_ExternalLockFreeList();
524 /* This ensures we deal with any pending RPCs */
525 COM_FlushMessageQueue();
529 else if (lCOMRefCnt<1) {
530 ERR( "CoUninitialize() - not CoInitialized.\n" );
531 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
535 /******************************************************************************
536 * CoDisconnectObject [COMPOBJ.15]
537 * CoDisconnectObject [OLE32.@]
539 * Disconnects all connections to this object from remote processes. Dispatches
540 * pending RPCs while blocking new RPCs from occurring, and then calls
541 * IMarshal::DisconnectObject on the given object.
543 * Typically called when the object server is forced to shut down, for instance by
546 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
548 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
552 /******************************************************************************
553 * CoCreateGuid[OLE32.@]
556 HRESULT WINAPI CoCreateGuid(
557 GUID *pguid /* [out] points to the GUID to initialize */
559 return UuidCreate(pguid);
562 /******************************************************************************
563 * CLSIDFromString [OLE32.@]
564 * IIDFromString [OLE32.@]
565 * Converts a unique identifier from its string representation into
569 * If idstr is not a valid CLSID string then it gets treated as a ProgID
574 HRESULT WINAPI __CLSIDFromStringA(
575 LPCSTR idstr, /* [in] string representation of guid */
576 CLSID *id) /* [out] GUID converted from string */
578 const BYTE *s = (BYTE *) idstr;
583 s = "{00000000-0000-0000-0000-000000000000}";
584 else { /* validate the CLSID string */
587 return CO_E_CLASSSTRING;
589 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
590 return CO_E_CLASSSTRING;
592 for (i=1; i<37; i++) {
593 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
594 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
595 ((s[i] >= 'a') && (s[i] <= 'f')) ||
596 ((s[i] >= 'A') && (s[i] <= 'F'))))
597 return CO_E_CLASSSTRING;
601 TRACE("%s -> %p\n", s, id);
603 /* quick lookup table */
604 memset(table, 0, 256);
606 for (i = 0; i < 10; i++) {
609 for (i = 0; i < 6; i++) {
610 table['A' + i] = i+10;
611 table['a' + i] = i+10;
614 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
616 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
617 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
618 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
619 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
621 /* these are just sequential bytes */
622 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
623 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
624 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
625 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
626 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
627 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
628 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
629 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
634 /*****************************************************************************/
636 HRESULT WINAPI CLSIDFromString(
637 LPOLESTR idstr, /* [in] string representation of GUID */
638 CLSID *id ) /* [out] GUID represented by above string */
643 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
644 return CO_E_CLASSSTRING;
647 ret = __CLSIDFromStringA(xid,id);
648 if(ret != S_OK) { /* It appears a ProgID is also valid */
649 ret = CLSIDFromProgID(idstr, id);
654 /******************************************************************************
655 * WINE_StringFromCLSID [Internal]
656 * Converts a GUID into the respective string representation.
661 * the string representation and HRESULT
663 HRESULT WINE_StringFromCLSID(
664 const CLSID *id, /* [in] GUID to be converted */
665 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
667 static const char *hex = "0123456789ABCDEF";
672 { ERR("called with id=Null\n");
677 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
678 id->Data1, id->Data2, id->Data3,
679 id->Data4[0], id->Data4[1]);
683 for (i = 2; i < 8; i++) {
684 *s++ = hex[id->Data4[i]>>4];
685 *s++ = hex[id->Data4[i] & 0xf];
691 TRACE("%p->%s\n", id, idstr);
697 /******************************************************************************
698 * StringFromCLSID [OLE32.@]
699 * StringFromIID [OLE32.@]
700 * Converts a GUID into the respective string representation.
701 * The target string is allocated using the OLE IMalloc.
703 * the string representation and HRESULT
705 HRESULT WINAPI StringFromCLSID(
706 REFCLSID id, /* [in] the GUID to be converted */
707 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
713 if ((ret=CoGetMalloc(0,&mllc)))
716 ret=WINE_StringFromCLSID(id,buf);
718 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
719 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
720 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
725 /******************************************************************************
726 * StringFromGUID2 [COMPOBJ.76]
727 * StringFromGUID2 [OLE32.@]
729 * Converts a global unique identifier into a string of an API-
730 * specified fixed format. (The usual {.....} stuff.)
733 * The (UNICODE) string representation of the GUID in 'str'
734 * The length of the resulting string, 0 if there was any problem.
737 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
741 if (WINE_StringFromCLSID(id,xguid))
743 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
746 /******************************************************************************
747 * ProgIDFromCLSID [OLE32.@]
748 * Converts a class id into the respective Program ID. (By using a registry lookup)
749 * RETURNS S_OK on success
750 * riid associated with the progid
753 HRESULT WINAPI ProgIDFromCLSID(
754 REFCLSID clsid, /* [in] class id as found in registry */
755 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
758 char strCLSID[50], *buf, *buf2;
764 WINE_StringFromCLSID(clsid, strCLSID);
766 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
767 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
768 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
769 ret = REGDB_E_CLASSNOTREG;
771 HeapFree(GetProcessHeap(), 0, buf);
775 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
777 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
778 ret = REGDB_E_CLASSNOTREG;
782 if (CoGetMalloc(0,&mllc))
786 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
787 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
788 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
791 HeapFree(GetProcessHeap(), 0, buf2);
798 /******************************************************************************
799 * CLSIDFromProgID [COMPOBJ.61]
800 * Converts a program id into the respective GUID. (By using a registry lookup)
802 * riid associated with the progid
804 HRESULT WINAPI CLSIDFromProgID16(
805 LPCOLESTR16 progid, /* [in] program id as found in registry */
806 LPCLSID riid /* [out] associated CLSID */
813 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
814 sprintf(buf,"%s\\CLSID",progid);
815 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
816 HeapFree(GetProcessHeap(),0,buf);
817 return CO_E_CLASSSTRING;
819 HeapFree(GetProcessHeap(),0,buf);
820 buf2len = sizeof(buf2);
821 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
823 return CO_E_CLASSSTRING;
826 return __CLSIDFromStringA(buf2,riid);
829 /******************************************************************************
830 * CLSIDFromProgID [OLE32.@]
831 * Converts a program id into the respective GUID. (By using a registry lookup)
833 * riid associated with the progid
835 HRESULT WINAPI CLSIDFromProgID(
836 LPCOLESTR progid, /* [in] program id as found in registry */
837 LPCLSID riid ) /* [out] associated CLSID */
839 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
841 DWORD buf2len = sizeof(buf2);
844 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
845 strcpyW( buf, progid );
846 strcatW( buf, clsidW );
847 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
849 HeapFree(GetProcessHeap(),0,buf);
850 return CO_E_CLASSSTRING;
852 HeapFree(GetProcessHeap(),0,buf);
854 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
857 return CO_E_CLASSSTRING;
860 return __CLSIDFromStringA(buf2,riid);
865 /*****************************************************************************
866 * CoGetPSClsid [OLE32.@]
868 * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
869 * for the specified interface.
871 * The standard marshaller activates the object with the CLSID returned and uses the
872 * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
873 * the proxies and stubs for a given object.
875 * CoGetPSClsid determines this CLSID by searching the
876 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
877 * and any interface id registered by CoRegisterPSClsid within the current process.
879 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
881 HRESULT WINAPI CoGetPSClsid(
882 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
883 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
889 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
891 /* Get the input iid as a string */
892 WINE_StringFromCLSID(riid, buf2);
893 /* Allocate memory for the registry key we will construct.
894 (length of iid string plus constant length of static text */
895 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
898 return (E_OUTOFMEMORY);
901 /* Construct the registry key we want */
902 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
905 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
907 WARN("No PSFactoryBuffer object is registered for this IID\n");
908 HeapFree(GetProcessHeap(),0,buf);
909 return (E_INVALIDARG);
911 HeapFree(GetProcessHeap(),0,buf);
913 /* ... Once we have the key, query the registry to get the
914 value of CLSID as a string, and convert it into a
915 proper CLSID structure to be passed back to the app */
916 buf2len = sizeof(buf2);
917 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
924 /* We have the CLSid we want back from the registry as a string, so
925 lets convert it into a CLSID structure */
926 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
930 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
936 /***********************************************************************
937 * WriteClassStm (OLE32.@)
939 * This function write a CLSID on stream
941 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
943 TRACE("(%p,%p)\n",pStm,rclsid);
948 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
951 /***********************************************************************
952 * ReadClassStm (OLE32.@)
954 * This function read a CLSID from a stream
956 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
961 TRACE("(%p,%p)\n",pStm,pclsid);
966 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
971 if (nbByte != sizeof(CLSID))
979 * COM_GetRegisteredClassObject
981 * This internal method is used to scan the registered class list to
982 * find a class object.
985 * rclsid Class ID of the class to find.
986 * dwClsContext Class context to match.
987 * ppv [out] returns a pointer to the class object. Complying
988 * to normal COM usage, this method will increase the
989 * reference count on this object.
991 static HRESULT COM_GetRegisteredClassObject(
996 HRESULT hr = S_FALSE;
997 RegisteredClass* curClass;
999 EnterCriticalSection( &csRegisteredClassList );
1007 * Iterate through the whole list and try to match the class ID.
1009 curClass = firstRegisteredClass;
1011 while (curClass != 0)
1014 * Check if we have a match on the class ID.
1016 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1019 * Since we don't do out-of process or DCOM just right away, let's ignore the
1024 * We have a match, return the pointer to the class object.
1026 *ppUnk = curClass->classObject;
1028 IUnknown_AddRef(curClass->classObject);
1035 * Step to the next class in the list.
1037 curClass = curClass->nextClass;
1041 LeaveCriticalSection( &csRegisteredClassList );
1043 * If we get to here, we haven't found our class.
1049 _LocalServerThread(LPVOID param) {
1052 RegisteredClass *newClass = (RegisteredClass*)param;
1056 unsigned char *buffer;
1058 IClassFactory *classfac;
1059 LARGE_INTEGER seekto;
1060 ULARGE_INTEGER newpos;
1063 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1064 strcpy(pipefn,PIPEPREF);
1065 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1067 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1068 if (hres) return hres;
1070 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1072 FIXME("Failed to create stream on hglobal.\n");
1075 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1077 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1080 hres = IStream_Stat(pStm,&ststg,0);
1081 if (hres) return hres;
1083 buflen = ststg.cbSize.u.LowPart;
1084 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1085 seekto.u.LowPart = 0;
1086 seekto.u.HighPart = 0;
1087 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1089 FIXME("IStream_Seek failed, %lx\n",hres);
1092 hres = IStream_Read(pStm,buffer,buflen,&res);
1094 FIXME("Stream Read failed, %lx\n",hres);
1097 IStream_Release(pStm);
1099 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1100 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1101 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1102 if (hPipe == INVALID_HANDLE_VALUE) {
1103 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1107 if (!ConnectNamedPipe(hPipe,NULL)) {
1108 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1111 WriteFile(hPipe,buffer,buflen,&res,NULL);
1112 FlushFileBuffers(hPipe);
1113 DisconnectNamedPipe(hPipe);
1119 /******************************************************************************
1120 * CoRegisterClassObject [OLE32.@]
1122 * This method will register the class object for a given class ID. Servers housed
1123 * in EXE files use this method instead of exporting DllGetClassObject to allow other
1124 * code to connect to their objects.
1126 * When a class object (an object which implements IClassFactory) is registered in
1127 * this way, a new thread is started which listens for connections on a named pipe
1128 * specific to the registered CLSID. When something else connects to it, it writes
1129 * out the marshalled IClassFactory interface to the pipe. The code on the other end
1130 * uses this buffer to unmarshal the class factory, and can then call methods on it.
1132 * In Windows, such objects are registered with the RPC endpoint mapper, not with
1133 * a unique named pipe.
1135 * See the Windows documentation for more details.
1137 HRESULT WINAPI CoRegisterClassObject(
1140 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1141 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1142 LPDWORD lpdwRegister
1145 RegisteredClass* newClass;
1146 LPUNKNOWN foundObject;
1149 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1150 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1152 if ( (lpdwRegister==0) || (pUnk==0) )
1153 return E_INVALIDARG;
1158 * First, check if the class is already registered.
1159 * If it is, this should cause an error.
1161 * MSDN claims that multiple interface registrations are legal, but we can't do that with
1162 * our current implementation.
1164 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1166 IUnknown_Release(foundObject);
1167 return CO_E_OBJISREG;
1170 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1171 if ( newClass == NULL )
1172 return E_OUTOFMEMORY;
1174 EnterCriticalSection( &csRegisteredClassList );
1176 newClass->classIdentifier = *rclsid;
1177 newClass->runContext = dwClsContext;
1178 newClass->connectFlags = flags;
1180 * Use the address of the chain node as the cookie since we are sure it's
1183 newClass->dwCookie = (DWORD)newClass;
1184 newClass->nextClass = firstRegisteredClass;
1187 * Since we're making a copy of the object pointer, we have to increase its
1190 newClass->classObject = pUnk;
1191 IUnknown_AddRef(newClass->classObject);
1193 firstRegisteredClass = newClass;
1194 LeaveCriticalSection( &csRegisteredClassList );
1196 *lpdwRegister = newClass->dwCookie;
1198 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1202 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1207 /***********************************************************************
1208 * CoRevokeClassObject [OLE32.@]
1210 * This method will remove a class object from the class registry
1212 * See the Windows documentation for more details.
1214 HRESULT WINAPI CoRevokeClassObject(
1217 HRESULT hr = E_INVALIDARG;
1218 RegisteredClass** prevClassLink;
1219 RegisteredClass* curClass;
1221 TRACE("(%08lx)\n",dwRegister);
1223 EnterCriticalSection( &csRegisteredClassList );
1226 * Iterate through the whole list and try to match the cookie.
1228 curClass = firstRegisteredClass;
1229 prevClassLink = &firstRegisteredClass;
1231 while (curClass != 0)
1234 * Check if we have a match on the cookie.
1236 if (curClass->dwCookie == dwRegister)
1239 * Remove the class from the chain.
1241 *prevClassLink = curClass->nextClass;
1244 * Release the reference to the class object.
1246 IUnknown_Release(curClass->classObject);
1249 * Free the memory used by the chain node.
1251 HeapFree(GetProcessHeap(), 0, curClass);
1258 * Step to the next class in the list.
1260 prevClassLink = &(curClass->nextClass);
1261 curClass = curClass->nextClass;
1265 LeaveCriticalSection( &csRegisteredClassList );
1267 * If we get to here, we haven't found our class.
1272 /***********************************************************************
1273 * compobj_RegReadPath [internal]
1275 * Reads a registry value and expands it when necessary
1277 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1283 DWORD dwLength = dstlen;
1285 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1286 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1287 if (keytype == REG_EXPAND_SZ) {
1288 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1290 strncpy(dst, src, dstlen);
1298 /***********************************************************************
1299 * CoGetClassObject [COMPOBJ.7]
1300 * CoGetClassObject [OLE32.@]
1302 * FIXME. If request allows of several options and there is a failure
1303 * with one (other than not being registered) do we try the
1304 * others or return failure? (E.g. inprocess is registered but
1305 * the DLL is not found but the server version works)
1307 HRESULT WINAPI CoGetClassObject(
1308 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1309 REFIID iid, LPVOID *ppv
1311 LPUNKNOWN regClassObject;
1312 HRESULT hres = E_UNEXPECTED;
1315 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1316 DllGetClassObjectFunc DllGetClassObject;
1318 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1320 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1323 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1324 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1328 * First, try and see if we can't match the class ID with one of the
1329 * registered classes.
1331 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1334 * Get the required interface from the retrieved pointer.
1336 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1339 * Since QI got another reference on the pointer, we want to release the
1340 * one we already have. If QI was unsuccessful, this will release the object. This
1341 * is good since we are not returning it in the "out" parameter.
1343 IUnknown_Release(regClassObject);
1348 /* first try: in-process */
1349 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1350 char keyname[MAX_PATH];
1351 char dllpath[MAX_PATH+1];
1353 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1355 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1356 /* failure: CLSID is not found in registry */
1357 WARN("class %s not registered inproc\n", xclsid);
1358 hres = REGDB_E_CLASSNOTREG;
1360 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1361 /* failure: DLL could not be loaded */
1362 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1363 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1364 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1365 /* failure: the dll did not export DllGetClassObject */
1366 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1367 FreeLibrary( hLibrary );
1368 hres = CO_E_DLLNOTFOUND;
1370 /* OK: get the ClassObject */
1371 COMPOBJ_DLLList_Add( hLibrary );
1372 return DllGetClassObject(rclsid, iid, ppv);
1377 /* Next try out of process */
1378 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1380 return create_marshalled_proxy(rclsid,iid,ppv);
1383 /* Finally try remote: this requires networked DCOM (a lot of work) */
1384 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1386 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1387 hres = E_NOINTERFACE;
1392 /***********************************************************************
1393 * CoResumeClassObjects (OLE32.@)
1395 * Resumes classobjects registered with REGCLS suspended
1397 HRESULT WINAPI CoResumeClassObjects(void)
1403 /***********************************************************************
1404 * GetClassFile (OLE32.@)
1406 * This function supplies the CLSID associated with the given filename.
1408 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1412 int nbElm, length, i;
1414 LPOLESTR *pathDec=0,absFile=0,progId=0;
1416 static const WCHAR bkslashW[] = {'\\',0};
1417 static const WCHAR dotW[] = {'.',0};
1419 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1421 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1422 if((StgIsStorageFile(filePathName))==S_OK){
1424 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1427 res=ReadClassStg(pstg,pclsid);
1429 IStorage_Release(pstg);
1433 /* if the file is not a storage object then attemps to match various bits in the file against a
1434 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1437 for(i=0;i<nFileTypes;i++)
1439 for(i=0;j<nPatternsForType;j++){
1444 pat=ReadPatternFromRegistry(i,j);
1445 hFile=CreateFileW(filePathName,,,,,,hFile);
1446 SetFilePosition(hFile,pat.offset);
1447 ReadFile(hFile,buf,pat.size,NULL,NULL);
1448 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1450 *pclsid=ReadCLSIDFromRegistry(i);
1456 /* if the above strategies fail then search for the extension key in the registry */
1458 /* get the last element (absolute file) in the path name */
1459 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1460 absFile=pathDec[nbElm-1];
1462 /* failed if the path represente a directory and not an absolute file name*/
1463 if (!lstrcmpW(absFile, bkslashW))
1464 return MK_E_INVALIDEXTENSION;
1466 /* get the extension of the file */
1468 length=lstrlenW(absFile);
1469 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1472 if (!extension || !lstrcmpW(extension, dotW))
1473 return MK_E_INVALIDEXTENSION;
1475 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1477 /* get the progId associated to the extension */
1478 progId = CoTaskMemAlloc(sizeProgId);
1479 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1481 if (res==ERROR_SUCCESS)
1482 /* return the clsid associated to the progId */
1483 res= CLSIDFromProgID(progId,pclsid);
1485 for(i=0; pathDec[i]!=NULL;i++)
1486 CoTaskMemFree(pathDec[i]);
1487 CoTaskMemFree(pathDec);
1489 CoTaskMemFree(progId);
1491 if (res==ERROR_SUCCESS)
1494 return MK_E_INVALIDEXTENSION;
1496 /***********************************************************************
1497 * CoCreateInstance [COMPOBJ.13]
1498 * CoCreateInstance [OLE32.@]
1500 HRESULT WINAPI CoCreateInstance(
1502 LPUNKNOWN pUnkOuter,
1508 LPCLASSFACTORY lpclf = 0;
1517 * Initialize the "out" parameter
1522 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1523 * Rather than create a class factory, we can just check for it here
1525 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1526 if (StdGlobalInterfaceTableInstance == NULL)
1527 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1528 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1529 if (hres) return hres;
1531 TRACE("Retrieved GIT (%p)\n", *ppv);
1536 * Get a class factory to construct the object we want.
1538 hres = CoGetClassObject(rclsid,
1545 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1546 debugstr_guid(rclsid),hres);
1551 * Create the object and don't forget to release the factory
1553 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1554 IClassFactory_Release(lpclf);
1556 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1557 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1562 /***********************************************************************
1563 * CoCreateInstanceEx [OLE32.@]
1565 HRESULT WINAPI CoCreateInstanceEx(
1567 LPUNKNOWN pUnkOuter,
1569 COSERVERINFO* pServerInfo,
1573 IUnknown* pUnk = NULL;
1576 int successCount = 0;
1581 if ( (cmq==0) || (pResults==NULL))
1582 return E_INVALIDARG;
1584 if (pServerInfo!=NULL)
1585 FIXME("() non-NULL pServerInfo not supported!\n");
1588 * Initialize all the "out" parameters.
1590 for (index = 0; index < cmq; index++)
1592 pResults[index].pItf = NULL;
1593 pResults[index].hr = E_NOINTERFACE;
1597 * Get the object and get its IUnknown pointer.
1599 hr = CoCreateInstance(rclsid,
1609 * Then, query for all the interfaces requested.
1611 for (index = 0; index < cmq; index++)
1613 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1614 pResults[index].pIID,
1615 (VOID**)&(pResults[index].pItf));
1617 if (pResults[index].hr == S_OK)
1622 * Release our temporary unknown pointer.
1624 IUnknown_Release(pUnk);
1626 if (successCount == 0)
1627 return E_NOINTERFACE;
1629 if (successCount!=cmq)
1630 return CO_S_NOTALLINTERFACES;
1635 /***********************************************************************
1636 * CoLoadLibrary (OLE32.@)
1638 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1640 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1642 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1645 /***********************************************************************
1646 * CoFreeLibrary [OLE32.@]
1648 * NOTES: don't believe the documentation
1650 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1652 FreeLibrary(hLibrary);
1656 /***********************************************************************
1657 * CoFreeAllLibraries [OLE32.@]
1659 * NOTES: don't believe the documentation
1661 void WINAPI CoFreeAllLibraries(void)
1667 /***********************************************************************
1668 * CoFreeUnusedLibraries [COMPOBJ.17]
1669 * CoFreeUnusedLibraries [OLE32.@]
1671 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1672 * through the main apartment's thread to call DllCanUnloadNow
1674 void WINAPI CoFreeUnusedLibraries(void)
1676 COMPOBJ_DllList_FreeUnused(0);
1679 /***********************************************************************
1680 * CoFileTimeNow [COMPOBJ.82]
1681 * CoFileTimeNow [OLE32.@]
1684 * the current system time in lpFileTime
1686 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1688 GetSystemTimeAsFileTime( lpFileTime );
1692 /***********************************************************************
1693 * CoLoadLibrary (OLE32.@)
1695 static void COM_RevokeAllClasses()
1697 EnterCriticalSection( &csRegisteredClassList );
1699 while (firstRegisteredClass!=0)
1701 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1704 LeaveCriticalSection( &csRegisteredClassList );
1707 /****************************************************************************
1708 * COM External Lock methods implementation
1710 * This api provides a linked list to managed external references to
1713 * The public interface consists of three calls:
1714 * COM_ExternalLockAddRef
1715 * COM_ExternalLockRelease
1716 * COM_ExternalLockFreeList
1719 #define EL_END_OF_LIST 0
1720 #define EL_NOT_FOUND 0
1723 * Declaration of the static structure that manage the
1724 * external lock to COM objects.
1726 typedef struct COM_ExternalLock COM_ExternalLock;
1727 typedef struct COM_ExternalLockList COM_ExternalLockList;
1729 struct COM_ExternalLock
1731 IUnknown *pUnk; /* IUnknown referenced */
1732 ULONG uRefCount; /* external lock counter to IUnknown object*/
1733 COM_ExternalLock *next; /* Pointer to next element in list */
1736 struct COM_ExternalLockList
1738 COM_ExternalLock *head; /* head of list */
1742 * Declaration and initialization of the static structure that manages
1743 * the external lock to COM objects.
1745 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1748 * Private methods used to managed the linked list
1752 static COM_ExternalLock* COM_ExternalLockLocate(
1753 COM_ExternalLock *element,
1756 /****************************************************************************
1757 * Internal - Insert a new IUnknown* to the linked list
1759 static BOOL COM_ExternalLockInsert(
1762 COM_ExternalLock *newLock = NULL;
1763 COM_ExternalLock *previousHead = NULL;
1766 * Allocate space for the new storage object
1768 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1770 if (newLock!=NULL) {
1771 if ( elList.head == EL_END_OF_LIST ) {
1772 elList.head = newLock; /* The list is empty */
1774 /* insert does it at the head */
1775 previousHead = elList.head;
1776 elList.head = newLock;
1779 /* Set new list item data member */
1780 newLock->pUnk = pUnk;
1781 newLock->uRefCount = 1;
1782 newLock->next = previousHead;
1789 /****************************************************************************
1790 * Internal - Method that removes an item from the linked list.
1792 static void COM_ExternalLockDelete(
1793 COM_ExternalLock *itemList)
1795 COM_ExternalLock *current = elList.head;
1797 if ( current == itemList ) {
1798 /* this section handles the deletion of the first node */
1799 elList.head = itemList->next;
1800 HeapFree( GetProcessHeap(), 0, itemList);
1803 if ( current->next == itemList ){ /* We found the item to free */
1804 current->next = itemList->next; /* readjust the list pointers */
1805 HeapFree( GetProcessHeap(), 0, itemList);
1809 /* Skip to the next item */
1810 current = current->next;
1812 } while ( current != EL_END_OF_LIST );
1816 /****************************************************************************
1817 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1819 * NOTES: how long can the list be ?? (recursive!!!)
1821 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1823 if ( element == EL_END_OF_LIST )
1824 return EL_NOT_FOUND;
1825 else if ( element->pUnk == pUnk ) /* We found it */
1827 else /* Not the right guy, keep on looking */
1828 return COM_ExternalLockLocate( element->next, pUnk);
1831 /****************************************************************************
1832 * Public - Method that increments the count for a IUnknown* in the linked
1833 * list. The item is inserted if not already in the list.
1835 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1837 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1840 * Add an external lock to the object. If it was already externally
1841 * locked, just increase the reference count. If it was not.
1842 * add the item to the list.
1844 if ( externalLock == EL_NOT_FOUND )
1845 COM_ExternalLockInsert(pUnk);
1847 externalLock->uRefCount++;
1850 * Add an internal lock to the object
1852 IUnknown_AddRef(pUnk);
1855 /****************************************************************************
1856 * Public - Method that decrements the count for a IUnknown* in the linked
1857 * list. The item is removed from the list if its count end up at zero or if
1860 static void COM_ExternalLockRelease(
1864 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1866 if ( externalLock != EL_NOT_FOUND ) {
1868 externalLock->uRefCount--; /* release external locks */
1869 IUnknown_Release(pUnk); /* release local locks as well */
1871 if ( bRelAll == FALSE ) break; /* perform single release */
1873 } while ( externalLock->uRefCount > 0 );
1875 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1876 COM_ExternalLockDelete(externalLock);
1879 /****************************************************************************
1880 * Public - Method that frees the content of the list.
1882 static void COM_ExternalLockFreeList()
1884 COM_ExternalLock *head;
1886 head = elList.head; /* grab it by the head */
1887 while ( head != EL_END_OF_LIST ) {
1888 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1889 head = elList.head; /* get the new head... */
1893 /****************************************************************************
1894 * Public - Method that dump the content of the list.
1896 void COM_ExternalLockDump()
1898 COM_ExternalLock *current = elList.head;
1900 DPRINTF("\nExternal lock list contains:\n");
1902 while ( current != EL_END_OF_LIST ) {
1903 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1905 /* Skip to the next item */
1906 current = current->next;
1910 /******************************************************************************
1911 * CoLockObjectExternal [OLE32.@]
1913 HRESULT WINAPI CoLockObjectExternal(
1914 LPUNKNOWN pUnk, /* [in] object to be locked */
1915 BOOL fLock, /* [in] do lock */
1916 BOOL fLastUnlockReleases) /* [in] unlock all */
1921 * Increment the external lock coutner, COM_ExternalLockAddRef also
1922 * increment the object's internal lock counter.
1924 COM_ExternalLockAddRef( pUnk);
1927 * Decrement the external lock coutner, COM_ExternalLockRelease also
1928 * decrement the object's internal lock counter.
1930 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1936 /***********************************************************************
1937 * CoInitializeWOW (OLE32.@)
1939 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1940 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1944 static int nStatCounter = 0; /* global */
1945 static HMODULE hOleAut32 = 0; /* global */
1947 /***********************************************************************
1948 * CoGetState [OLE32.@]
1950 * NOTES: might be incomplete
1952 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1954 APARTMENT * apt = COM_CurrentInfo();
1958 if(apt && apt->state) {
1959 IUnknown_AddRef(apt->state);
1961 FIXME("-- %p\n", *ppv);
1969 /***********************************************************************
1970 * CoSetState [OLE32.@]
1972 * NOTES: FIXME: protect this with a crst
1974 HRESULT WINAPI CoSetState(IUnknown * pv)
1976 APARTMENT * apt = COM_CurrentInfo();
1978 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1980 FIXME("(%p),stub!\n", pv);
1983 IUnknown_AddRef(pv);
1985 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1989 TRACE("-- release %p now\n", apt->state);
1990 IUnknown_Release(apt->state);
1992 if (!nStatCounter) FreeLibrary(hOleAut32);
1999 /******************************************************************************
2000 * OleGetAutoConvert [OLE32.@]
2002 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2010 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2011 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2013 res = REGDB_E_CLASSNOTREG;
2017 /* we can just query for the default value of AutoConvertTo key like that,
2018 without opening the AutoConvertTo key and querying for NULL (default) */
2019 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2021 res = REGDB_E_KEYMISSING;
2024 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2025 CLSIDFromString(wbuf,pClsidNew);
2027 if (hkey) RegCloseKey(hkey);
2031 /******************************************************************************
2032 * OleSetAutoConvert [OLE32.@]
2034 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2037 char buf[200], szClsidNew[200];
2040 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2041 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2042 WINE_StringFromCLSID(clsidNew, szClsidNew);
2043 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2045 res = REGDB_E_CLASSNOTREG;
2048 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2050 res = REGDB_E_WRITEREGDB;
2055 if (hkey) RegCloseKey(hkey);
2059 /******************************************************************************
2060 * OleDoAutoConvert [OLE32.@]
2062 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2064 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2068 /******************************************************************************
2069 * CoTreatAsClass [OLE32.@]
2071 * Sets TreatAs value of a class
2073 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2077 char szClsidNew[39];
2079 char auto_treat_as[39];
2080 LONG auto_treat_as_size = sizeof(auto_treat_as);
2083 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2084 WINE_StringFromCLSID(clsidNew, szClsidNew);
2085 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2087 res = REGDB_E_CLASSNOTREG;
2090 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2092 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2093 !__CLSIDFromStringA(auto_treat_as, &id))
2095 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2097 res = REGDB_E_WRITEREGDB;
2103 RegDeleteKeyA(hkey, "TreatAs");
2107 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2109 res = REGDB_E_WRITEREGDB;
2114 if (hkey) RegCloseKey(hkey);
2118 /******************************************************************************
2119 * CoGetTreatAsClass [OLE32.@]
2121 * Reads the TreatAs value from a class.
2123 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2126 char buf[200], szClsidNew[200];
2128 LONG len = sizeof(szClsidNew);
2130 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2131 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2132 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2134 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2136 res = REGDB_E_CLASSNOTREG;
2139 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2144 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2146 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2148 if (hkey) RegCloseKey(hkey);
2153 /***********************************************************************
2154 * IsEqualGUID [OLE32.@]
2156 * Compares two Unique Identifiers.
2162 BOOL WINAPI IsEqualGUID(
2163 REFGUID rguid1, /* [in] unique id 1 */
2164 REFGUID rguid2 /* [in] unique id 2 */
2167 return !memcmp(rguid1,rguid2,sizeof(GUID));
2170 /***********************************************************************
2171 * CoInitializeSecurity [OLE32.@]
2173 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2174 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2175 void* pReserved1, DWORD dwAuthnLevel,
2176 DWORD dwImpLevel, void* pReserved2,
2177 DWORD dwCapabilities, void* pReserved3)
2179 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2180 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2181 dwCapabilities, pReserved3);