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
25 * TODO list: (items bunched together depend on each other)
27 * - Switch wine_marshal_id to use IPIDs not IIDs
28 * - Once that's done, replace wine_marshal_id with STDOBJREF
30 * - Rewrite the CoLockObjectExternal code, it does totally the wrong
31 * thing currently (should be controlling the stub manager)
33 * - Implement the service control manager (in rpcss) to keep track
34 * of registered class objects: ISCM::ServerRegisterClsid et al
35 * - Implement the OXID resolver so we don't need magic pipe names for
36 * clients and servers to meet up
37 * - Flip our marshalling on top of the RPC runtime transport API,
38 * so we no longer use named pipes to communicate
39 * - Rework threading so re-entrant calls don't need to be sent on
41 * - Implement RPC thread affinity (should fix InstallShield painting
44 * - Implement IRemUnknown and marshalling for it, then use that for
45 * reffing/unreffing the stub manager from a proxy instead of our
46 * current hack of simply reffing the stub manager once when it's
48 * - Implement table marshalling, then use it to let us do the final
49 * rework of the threading
51 * - Make our custom marshalling use NDR to be wire compatible with
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
79 #include "wine/unicode.h"
81 #include "ole32_main.h"
82 #include "compobj_private.h"
84 #include "wine/debug.h"
86 WINE_DEFAULT_DEBUG_CHANNEL(ole);
88 typedef LPCSTR LPCOLESTR16;
90 /****************************************************************************
91 * This section defines variables internal to the COM module.
93 * TODO: Most of these things will have to be made thread-safe.
96 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
97 static void COM_RevokeAllClasses(void);
98 static void COM_ExternalLockFreeList(void);
100 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
102 APARTMENT MTA, *apts;
104 static CRITICAL_SECTION csApartment;
105 static CRITICAL_SECTION_DEBUG critsect_debug =
108 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
109 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
111 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
114 * This lock count counts the number of times CoInitialize is called. It is
115 * decreased every time CoUninitialize is called. When it hits 0, the COM
116 * libraries are freed
118 static LONG s_COMLockCount = 0;
121 * This linked list contains the list of registered class objects. These
122 * are mostly used to register the factories for out-of-proc servers of OLE
125 * TODO: Make this data structure aware of inter-process communication. This
126 * means that parts of this will be exported to the Wine Server.
128 typedef struct tagRegisteredClass
130 CLSID classIdentifier;
131 LPUNKNOWN classObject;
135 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
136 struct tagRegisteredClass* nextClass;
139 static RegisteredClass* firstRegisteredClass = NULL;
141 static CRITICAL_SECTION csRegisteredClassList;
142 static CRITICAL_SECTION_DEBUG class_cs_debug =
144 0, 0, &csRegisteredClassList,
145 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
146 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
148 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
150 /*****************************************************************************
151 * This section contains OpenDllList definitions
153 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
154 * other functions that do LoadLibrary _without_ giving back a HMODULE.
155 * Without this list these handles would never be freed.
157 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
158 * next unload-call but not before 600 sec.
161 typedef struct tagOpenDll {
163 struct tagOpenDll *next;
166 static OpenDll *openDllList = NULL; /* linked list of open dlls */
168 static CRITICAL_SECTION csOpenDllList;
169 static CRITICAL_SECTION_DEBUG dll_cs_debug =
171 0, 0, &csOpenDllList,
172 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
173 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
175 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
177 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
178 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
180 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
181 static void COMPOBJ_DllList_FreeUnused(int Timeout);
183 void COMPOBJ_InitProcess( void )
187 /* Dispatching to the correct thread in an apartment is done through
188 * window messages rather than RPC transports. When an interface is
189 * marshalled into another apartment in the same process, a window of the
190 * following class is created. The *caller* of CoMarshalInterface (ie the
191 * application) is responsible for pumping the message loop in that thread.
192 * The WM_USER messages which point to the RPCs are then dispatched to
193 * COM_AptWndProc by the user's code from the apartment in which the interface
196 memset(&wclass, 0, sizeof(wclass));
197 wclass.lpfnWndProc = &COM_AptWndProc;
198 wclass.hInstance = OLE32_hInstance;
199 wclass.lpszClassName = aptWinClass;
200 RegisterClassA(&wclass);
203 void COMPOBJ_UninitProcess( void )
205 UnregisterClassA(aptWinClass, OLE32_hInstance);
208 /******************************************************************************
213 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
214 with free threaded (ie thread safe) COM objects. There is only ever one MTA
215 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
217 static void COM_InitMTA(void)
219 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
220 within a network. That is, two different MTAs on different machines will have
223 This method of generating an OXID is therefore wrong as it doesn't work across
224 a network, but for local RPC only it's OK. We can distinguish between MTAs and
225 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
227 The algorithm Microsoft use is currently unknown.
229 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
230 InitializeCriticalSection(&MTA.cs);
233 static void COM_UninitMTA(void)
235 DeleteCriticalSection(&MTA.cs);
239 /* creates an apartment structure which stores OLE thread-local
240 * information. Call with COINIT_UNINITIALIZED to create an apartment
241 * that will be initialized with a model later. Note: do not call
242 * with COINIT_UNINITIALIZED if the apartment has already been initialized
243 * with a different COINIT value */
244 APARTMENT* COM_CreateApartment(DWORD model)
247 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
251 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
252 apt->tid = GetCurrentThreadId();
253 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
254 GetCurrentProcess(), &apt->thread,
255 THREAD_ALL_ACCESS, FALSE, 0);
258 apt = NtCurrentTeb()->ReservedForOle;
260 list_init(&apt->proxies);
261 list_init(&apt->stubmgrs);
265 if (model & COINIT_APARTMENTTHREADED) {
266 /* FIXME: how does windoze create OXIDs? */
267 apt->oxid = MTA.oxid | GetCurrentThreadId();
268 apt->win = CreateWindowA(aptWinClass, NULL, 0,
270 0, 0, OLE32_hInstance, NULL);
271 InitializeCriticalSection(&apt->cs);
273 else if (!(model & COINIT_UNINITIALIZED)) {
275 apt->oxid = MTA.oxid;
277 EnterCriticalSection(&csApartment);
280 if (apts) apts->prev = apt;
284 LeaveCriticalSection(&csApartment);
285 NtCurrentTeb()->ReservedForOle = apt;
289 static void COM_DestroyApartment(APARTMENT *apt)
291 EnterCriticalSection(&csApartment);
292 if (apt->prev) apt->prev->next = apt->next;
293 if (apt->next) apt->next->prev = apt->prev;
294 if (apts == apt) apts = apt->next;
295 apt->prev = NULL; apt->next = NULL;
296 LeaveCriticalSection(&csApartment);
297 if (apt->model & COINIT_APARTMENTTHREADED) {
298 /* disconnect proxies to release the corresponding stubs.
299 * It is confirmed in "Essential COM" in the sub-chapter on
300 * "Lifecycle Management and Marshalling" that the native version also
301 * disconnects proxies in this function. */
302 /* FIXME: this should also be called for MTA destruction, but that
303 * requires restructuring how apartments work slightly. */
304 MARSHAL_Disconnect_Proxies(apt);
306 if (apt->win) DestroyWindow(apt->win);
307 DeleteCriticalSection(&apt->cs);
309 CloseHandle(apt->thread);
310 HeapFree(GetProcessHeap(), 0, apt);
313 /* The given OXID must be local to this process: you cannot use apartment
314 windows to send RPCs to other processes. This all needs to move to rpcrt4 */
316 APARTMENT *COM_ApartmentFromOXID(OXID oxid)
318 APARTMENT *apt = NULL;
320 EnterCriticalSection(&csApartment);
322 while (apt && apt->oxid != oxid) apt = apt->next;
323 LeaveCriticalSection(&csApartment);
328 HWND COM_GetApartmentWin(OXID oxid)
330 APARTMENT *apt = COM_ApartmentFromOXID(oxid);
332 return apt ? apt->win : NULL;
335 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
336 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
338 return DefWindowProcA(hWnd, msg, wParam, lParam);
341 /*****************************************************************************
342 * This section contains OpenDllList implemantation
345 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
352 EnterCriticalSection( &csOpenDllList );
354 if (openDllList == NULL) {
355 /* empty list -- add first node */
356 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
357 openDllList->hLibrary=hLibrary;
358 openDllList->next = NULL;
360 /* search for this dll */
362 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
363 if (ptr->hLibrary == hLibrary) {
369 /* dll not found, add it */
371 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
372 openDllList->hLibrary = hLibrary;
373 openDllList->next = tmp;
377 LeaveCriticalSection( &csOpenDllList );
380 static void COMPOBJ_DllList_FreeUnused(int Timeout)
382 OpenDll *curr, *next, *prev = NULL;
383 typedef HRESULT(*DllCanUnloadNowFunc)(void);
384 DllCanUnloadNowFunc DllCanUnloadNow;
388 EnterCriticalSection( &csOpenDllList );
390 for (curr = openDllList; curr != NULL; ) {
391 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
393 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
396 TRACE("freeing %p\n", curr->hLibrary);
397 FreeLibrary(curr->hLibrary);
399 HeapFree(GetProcessHeap(), 0, curr);
400 if (curr == openDllList) {
413 LeaveCriticalSection( &csOpenDllList );
416 /******************************************************************************
417 * CoBuildVersion [COMPOBJ.1]
418 * CoBuildVersion [OLE32.@]
421 * Current build version, hiword is majornumber, loword is minornumber
423 DWORD WINAPI CoBuildVersion(void)
425 TRACE("Returning version %d, build %d.\n", rmm, rup);
426 return (rmm<<16)+rup;
429 /******************************************************************************
430 * CoInitialize [OLE32.@]
432 * Initializes the COM libraries by calling CoInitializeEx with
433 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
438 HRESULT WINAPI CoInitialize(
439 LPVOID lpReserved /* [in] pointer to win32 malloc interface
440 (obsolete, should be NULL) */
444 * Just delegate to the newer method.
446 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
449 /******************************************************************************
450 * CoInitializeEx [OLE32.@]
452 * Initializes the COM libraries. The behavior used to set the win32
453 * IMalloc used for memory management is obsolete. If
454 * COINIT_APARTMENTTHREADED is specified this thread enters a new STA
455 * (single threaded apartment), otherwise COINIT_MULTITHREADED should
456 * be specified which indicates that the thread will enter the MTA.
458 * Currently STA threading is only partly implemented.
461 * S_OK if successful,
462 * S_FALSE if this function was called already.
463 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
469 HRESULT WINAPI CoInitializeEx(
470 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
471 (obsolete, should be NULL) */
472 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
478 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
480 if (lpReserved!=NULL)
482 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
485 apt = NtCurrentTeb()->ReservedForOle;
486 if (apt && !(apt->model == COINIT_UNINITIALIZED))
488 if (dwCoInit != apt->model)
490 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
491 code then we are probably using the wrong threading model to implement that API. */
492 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
493 return RPC_E_CHANGED_MODE;
501 * Check the lock count. If this is the first time going through the initialize
502 * process, we have to initialize the libraries.
504 * And crank-up that lock count.
506 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
509 * Initialize the various COM libraries and data structures.
511 TRACE("() - Initializing the COM libraries\n");
515 RunningObjectTableImpl_Initialize();
518 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
520 InterlockedIncrement(&apt->inits);
521 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
526 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
527 pending RPCs are ignored. Non-COM messages are discarded at this point.
529 void COM_FlushMessageQueue(void)
532 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
534 if (!apt || !apt->win) return;
536 TRACE("Flushing STA message queue\n");
538 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
539 if (message.hwnd != apt->win) continue;
540 TranslateMessage(&message);
541 DispatchMessageA(&message);
545 /***********************************************************************
546 * CoUninitialize [OLE32.@]
548 * This method will decrement the refcount on the COM libraries,
549 * potentially unloading them. The current thread leaves the apartment
550 * it's currently in. If not in an apartment, the routine does
553 * If COM is to be shut down, any outstanding proxies are
554 * disconnected, all registered class objects are unregistered and the
555 * message queue for the thread is flushed (if native does
556 * this or not is unknown).
561 void WINAPI CoUninitialize(void)
568 apt = NtCurrentTeb()->ReservedForOle;
570 if (InterlockedDecrement(&apt->inits)==0) {
571 NtCurrentTeb()->ReservedForOle = NULL;
572 COM_DestroyApartment(apt);
577 * Decrease the reference count.
578 * If we are back to 0 locks on the COM library, make sure we free
579 * all the associated data structures.
581 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
584 TRACE("() - Releasing the COM libraries\n");
586 RunningObjectTableImpl_UnInitialize();
588 /* Release the references to the registered class objects */
589 COM_RevokeAllClasses();
591 /* This will free the loaded COM Dlls */
592 CoFreeAllLibraries();
594 /* This will free list of external references to COM objects */
595 COM_ExternalLockFreeList();
597 /* This ensures we deal with any pending RPCs */
598 COM_FlushMessageQueue();
602 else if (lCOMRefCnt<1) {
603 ERR( "CoUninitialize() - not CoInitialized.\n" );
604 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
608 /******************************************************************************
609 * CoDisconnectObject [COMPOBJ.15]
610 * CoDisconnectObject [OLE32.@]
612 * Disconnects all connections to this object from remote processes. Dispatches
613 * pending RPCs while blocking new RPCs from occurring, and then calls
614 * IMarshal::DisconnectObject on the given object.
616 * Typically called when the object server is forced to shut down, for instance by
619 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
621 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
625 /******************************************************************************
626 * CoCreateGuid[OLE32.@]
628 * Simply forwards to UuidCreate in RPCRT4.
634 HRESULT WINAPI CoCreateGuid(
635 GUID *pguid /* [out] points to the GUID to initialize */
637 return UuidCreate(pguid);
640 /******************************************************************************
641 * CLSIDFromString [OLE32.@]
642 * IIDFromString [OLE32.@]
644 * Converts a unique identifier from its string representation into
647 * In Windows, if idstr is not a valid CLSID string then it gets
648 * treated as a ProgID. Wine currently doesn't do this. If idstr is
649 * NULL it's treated as an all-zero GUID.
653 * CO_E_CLASSSTRING if idstr is not a valid CLSID
655 HRESULT WINAPI __CLSIDFromStringA(
656 LPCSTR idstr, /* [in] string representation of guid */
657 CLSID *id) /* [out] GUID converted from string */
659 const BYTE *s = (const BYTE *) idstr;
664 s = "{00000000-0000-0000-0000-000000000000}";
665 else { /* validate the CLSID string */
668 return CO_E_CLASSSTRING;
670 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
671 return CO_E_CLASSSTRING;
673 for (i=1; i<37; i++) {
674 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
675 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
676 ((s[i] >= 'a') && (s[i] <= 'f')) ||
677 ((s[i] >= 'A') && (s[i] <= 'F'))))
678 return CO_E_CLASSSTRING;
682 TRACE("%s -> %p\n", s, id);
684 /* quick lookup table */
685 memset(table, 0, 256);
687 for (i = 0; i < 10; i++) {
690 for (i = 0; i < 6; i++) {
691 table['A' + i] = i+10;
692 table['a' + i] = i+10;
695 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
697 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
698 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
699 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
700 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
702 /* these are just sequential bytes */
703 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
704 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
705 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
706 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
707 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
708 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
709 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
710 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
715 /*****************************************************************************/
717 HRESULT WINAPI CLSIDFromString(
718 LPOLESTR idstr, /* [in] string representation of GUID */
719 CLSID *id ) /* [out] GUID represented by above string */
724 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
725 return CO_E_CLASSSTRING;
728 ret = __CLSIDFromStringA(xid,id);
729 if(ret != S_OK) { /* It appears a ProgID is also valid */
730 ret = CLSIDFromProgID(idstr, id);
735 /* Converts a GUID into the respective string representation. */
736 HRESULT WINE_StringFromCLSID(
737 const CLSID *id, /* [in] GUID to be converted */
738 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
740 static const char *hex = "0123456789ABCDEF";
745 { ERR("called with id=Null\n");
750 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
751 id->Data1, id->Data2, id->Data3,
752 id->Data4[0], id->Data4[1]);
756 for (i = 2; i < 8; i++) {
757 *s++ = hex[id->Data4[i]>>4];
758 *s++ = hex[id->Data4[i] & 0xf];
764 TRACE("%p->%s\n", id, idstr);
770 /******************************************************************************
771 * StringFromCLSID [OLE32.@]
772 * StringFromIID [OLE32.@]
774 * Converts a GUID into the respective string representation.
775 * The target string is allocated using the OLE IMalloc.
781 HRESULT WINAPI StringFromCLSID(
782 REFCLSID id, /* [in] the GUID to be converted */
783 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
789 if ((ret = CoGetMalloc(0,&mllc)))
792 ret=WINE_StringFromCLSID(id,buf);
794 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
795 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
796 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
801 /******************************************************************************
802 * StringFromGUID2 [COMPOBJ.76]
803 * StringFromGUID2 [OLE32.@]
805 * Modified version of StringFromCLSID that allows you to specify max
809 * The length of the resulting string, 0 if there was any problem.
811 INT WINAPI StringFromGUID2(
812 REFGUID id, /* [in] GUID to convert to string */
813 LPOLESTR str, /* [out] Unicode buffer to hold result */
818 if (WINE_StringFromCLSID(id,xguid))
820 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
823 /******************************************************************************
824 * ProgIDFromCLSID [OLE32.@]
826 * Converts a class id into the respective Program ID. (By using a
832 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
834 HRESULT WINAPI ProgIDFromCLSID(
835 REFCLSID clsid, /* [in] class id as found in registry */
836 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
839 char strCLSID[50], *buf, *buf2;
845 WINE_StringFromCLSID(clsid, strCLSID);
847 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
848 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
849 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
850 ret = REGDB_E_CLASSNOTREG;
852 HeapFree(GetProcessHeap(), 0, buf);
856 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
858 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
859 ret = REGDB_E_CLASSNOTREG;
863 if (CoGetMalloc(0,&mllc))
867 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
868 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
869 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
872 HeapFree(GetProcessHeap(), 0, buf2);
879 HRESULT WINAPI CLSIDFromProgID16(
880 LPCOLESTR16 progid, /* [in] program id as found in registry */
881 LPCLSID riid /* [out] associated CLSID */
888 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
889 sprintf(buf,"%s\\CLSID",progid);
890 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
891 HeapFree(GetProcessHeap(),0,buf);
892 return CO_E_CLASSSTRING;
894 HeapFree(GetProcessHeap(),0,buf);
895 buf2len = sizeof(buf2);
896 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
898 return CO_E_CLASSSTRING;
901 return __CLSIDFromStringA(buf2,riid);
904 /******************************************************************************
905 * CLSIDFromProgID [COMPOBJ.61]
907 * Converts a program id into the respective GUID. (By using a
912 * CO_E_CLASSSTRING if the given ProgID cannot be found
914 HRESULT WINAPI CLSIDFromProgID(
915 LPCOLESTR progid, /* [in] Unicode program id as found in registry */
916 LPCLSID riid ) /* [out] associated CLSID */
918 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
920 DWORD buf2len = sizeof(buf2);
923 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
924 strcpyW( buf, progid );
925 strcatW( buf, clsidW );
926 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
928 HeapFree(GetProcessHeap(),0,buf);
929 return CO_E_CLASSSTRING;
931 HeapFree(GetProcessHeap(),0,buf);
933 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
936 return CO_E_CLASSSTRING;
939 return __CLSIDFromStringA(buf2,riid);
944 /*****************************************************************************
945 * CoGetPSClsid [OLE32.@]
947 * This function returns the CLSID of the proxy/stub factory that
948 * implements IPSFactoryBuffer for the specified interface.
950 * The standard marshaller activates the object with the CLSID
951 * returned and uses the CreateProxy and CreateStub methods on its
952 * IPSFactoryBuffer interface to construct the proxies and stubs for a
955 * CoGetPSClsid determines this CLSID by searching the
956 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
957 * in the registry and any interface id registered by
958 * CoRegisterPSClsid within the current process.
960 * FIXME: We only search the registry, not ids registered with
966 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
968 HRESULT WINAPI CoGetPSClsid(
969 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
970 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
976 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
978 /* Get the input iid as a string */
979 WINE_StringFromCLSID(riid, buf2);
980 /* Allocate memory for the registry key we will construct.
981 (length of iid string plus constant length of static text */
982 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
985 return (E_OUTOFMEMORY);
988 /* Construct the registry key we want */
989 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
992 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
994 WARN("No PSFactoryBuffer object is registered for this IID\n");
995 HeapFree(GetProcessHeap(),0,buf);
996 return (E_INVALIDARG);
998 HeapFree(GetProcessHeap(),0,buf);
1000 /* ... Once we have the key, query the registry to get the
1001 value of CLSID as a string, and convert it into a
1002 proper CLSID structure to be passed back to the app */
1003 buf2len = sizeof(buf2);
1004 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1007 return E_INVALIDARG;
1011 /* We have the CLSid we want back from the registry as a string, so
1012 lets convert it into a CLSID structure */
1013 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1014 return E_INVALIDARG;
1017 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1023 /***********************************************************************
1024 * WriteClassStm (OLE32.@)
1026 * This function write a CLSID on stream
1028 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1030 TRACE("(%p,%p)\n",pStm,rclsid);
1033 return E_INVALIDARG;
1035 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1038 /***********************************************************************
1039 * ReadClassStm (OLE32.@)
1041 * This function read a CLSID from a stream
1043 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1048 TRACE("(%p,%p)\n",pStm,pclsid);
1051 return E_INVALIDARG;
1053 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1058 if (nbByte != sizeof(CLSID))
1066 * COM_GetRegisteredClassObject
1068 * This internal method is used to scan the registered class list to
1069 * find a class object.
1072 * rclsid Class ID of the class to find.
1073 * dwClsContext Class context to match.
1074 * ppv [out] returns a pointer to the class object. Complying
1075 * to normal COM usage, this method will increase the
1076 * reference count on this object.
1078 static HRESULT COM_GetRegisteredClassObject(
1083 HRESULT hr = S_FALSE;
1084 RegisteredClass* curClass;
1086 EnterCriticalSection( &csRegisteredClassList );
1094 * Iterate through the whole list and try to match the class ID.
1096 curClass = firstRegisteredClass;
1098 while (curClass != 0)
1101 * Check if we have a match on the class ID.
1103 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1106 * Since we don't do out-of process or DCOM just right away, let's ignore the
1111 * We have a match, return the pointer to the class object.
1113 *ppUnk = curClass->classObject;
1115 IUnknown_AddRef(curClass->classObject);
1122 * Step to the next class in the list.
1124 curClass = curClass->nextClass;
1128 LeaveCriticalSection( &csRegisteredClassList );
1130 * If we get to here, we haven't found our class.
1135 /******************************************************************************
1136 * CoRegisterClassObject [OLE32.@]
1138 * Registers the class object for a given class ID. Servers housed in EXE
1139 * files use this method instead of exporting DllGetClassObject to allow
1140 * other code to connect to their objects.
1144 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1145 * CO_E_OBJISREG if the object is already registered. We should not return this.
1148 * CoRevokeClassObject, CoGetClassObject
1151 * MSDN claims that multiple interface registrations are legal, but we
1152 * can't do that with our current implementation.
1154 HRESULT WINAPI CoRegisterClassObject(
1155 REFCLSID rclsid, /* [in] CLSID of the object to register */
1156 LPUNKNOWN pUnk, /* [in] IUnknown of the object */
1157 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1158 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1159 LPDWORD lpdwRegister) /* [out] A unique cookie that can be passed to CoRevokeClassObject */
1161 RegisteredClass* newClass;
1162 LPUNKNOWN foundObject;
1165 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1166 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1168 if ( (lpdwRegister==0) || (pUnk==0) )
1169 return E_INVALIDARG;
1171 if (!COM_CurrentApt())
1173 ERR("COM was not initialized\n");
1174 return CO_E_NOTINITIALIZED;
1180 * First, check if the class is already registered.
1181 * If it is, this should cause an error.
1183 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1185 IUnknown_Release(foundObject);
1186 return CO_E_OBJISREG;
1189 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1190 if ( newClass == NULL )
1191 return E_OUTOFMEMORY;
1193 EnterCriticalSection( &csRegisteredClassList );
1195 newClass->classIdentifier = *rclsid;
1196 newClass->runContext = dwClsContext;
1197 newClass->connectFlags = flags;
1199 * Use the address of the chain node as the cookie since we are sure it's
1200 * unique. FIXME: not on 64-bit platforms.
1202 newClass->dwCookie = (DWORD)newClass;
1203 newClass->nextClass = firstRegisteredClass;
1206 * Since we're making a copy of the object pointer, we have to increase its
1209 newClass->classObject = pUnk;
1210 IUnknown_AddRef(newClass->classObject);
1212 firstRegisteredClass = newClass;
1213 LeaveCriticalSection( &csRegisteredClassList );
1215 *lpdwRegister = newClass->dwCookie;
1217 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1218 IClassFactory *classfac;
1220 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1221 (LPVOID*)&classfac);
1224 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1226 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1227 IUnknown_Release(classfac);
1230 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1231 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1232 MSHLFLAGS_TABLESTRONG);
1234 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1235 IUnknown_Release(classfac);
1239 IUnknown_Release(classfac);
1241 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1246 /***********************************************************************
1247 * CoRevokeClassObject [OLE32.@]
1249 * This method will remove a class object from the class registry
1251 * See the Windows documentation for more details.
1253 HRESULT WINAPI CoRevokeClassObject(
1256 HRESULT hr = E_INVALIDARG;
1257 RegisteredClass** prevClassLink;
1258 RegisteredClass* curClass;
1260 TRACE("(%08lx)\n",dwRegister);
1262 EnterCriticalSection( &csRegisteredClassList );
1265 * Iterate through the whole list and try to match the cookie.
1267 curClass = firstRegisteredClass;
1268 prevClassLink = &firstRegisteredClass;
1270 while (curClass != 0)
1273 * Check if we have a match on the cookie.
1275 if (curClass->dwCookie == dwRegister)
1278 * Remove the class from the chain.
1280 *prevClassLink = curClass->nextClass;
1283 * Release the reference to the class object.
1285 IUnknown_Release(curClass->classObject);
1287 if (curClass->pMarshaledData)
1290 memset(&zero, 0, sizeof(zero));
1291 /* FIXME: stop local server thread */
1292 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1293 CoReleaseMarshalData(curClass->pMarshaledData);
1297 * Free the memory used by the chain node.
1299 HeapFree(GetProcessHeap(), 0, curClass);
1306 * Step to the next class in the list.
1308 prevClassLink = &(curClass->nextClass);
1309 curClass = curClass->nextClass;
1313 LeaveCriticalSection( &csRegisteredClassList );
1315 * If we get to here, we haven't found our class.
1320 /***********************************************************************
1321 * compobj_RegReadPath [internal]
1323 * Reads a registry value and expands it when necessary
1325 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1331 DWORD dwLength = dstlen;
1333 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1334 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1335 if (keytype == REG_EXPAND_SZ) {
1336 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1338 lstrcpynA(dst, src, dstlen);
1346 /***********************************************************************
1347 * CoGetClassObject [COMPOBJ.7]
1348 * CoGetClassObject [OLE32.@]
1350 * FIXME. If request allows of several options and there is a failure
1351 * with one (other than not being registered) do we try the
1352 * others or return failure? (E.g. inprocess is registered but
1353 * the DLL is not found but the server version works)
1355 HRESULT WINAPI CoGetClassObject(
1356 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1357 REFIID iid, LPVOID *ppv
1359 LPUNKNOWN regClassObject;
1360 HRESULT hres = E_UNEXPECTED;
1363 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1364 DllGetClassObjectFunc DllGetClassObject;
1366 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1368 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1371 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1372 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1376 * First, try and see if we can't match the class ID with one of the
1377 * registered classes.
1379 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1382 * Get the required interface from the retrieved pointer.
1384 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1387 * Since QI got another reference on the pointer, we want to release the
1388 * one we already have. If QI was unsuccessful, this will release the object. This
1389 * is good since we are not returning it in the "out" parameter.
1391 IUnknown_Release(regClassObject);
1396 /* first try: in-process */
1397 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1398 char keyname[MAX_PATH];
1399 char dllpath[MAX_PATH+1];
1401 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1403 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1404 /* failure: CLSID is not found in registry */
1405 WARN("class %s not registered inproc\n", xclsid);
1406 hres = REGDB_E_CLASSNOTREG;
1408 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1409 /* failure: DLL could not be loaded */
1410 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1411 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1412 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1413 /* failure: the dll did not export DllGetClassObject */
1414 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1415 FreeLibrary( hLibrary );
1416 hres = CO_E_DLLNOTFOUND;
1418 /* OK: get the ClassObject */
1419 COMPOBJ_DLLList_Add( hLibrary );
1420 return DllGetClassObject(rclsid, iid, ppv);
1425 /* Next try out of process */
1426 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1428 return create_marshalled_proxy(rclsid,iid,ppv);
1431 /* Finally try remote: this requires networked DCOM (a lot of work) */
1432 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1434 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1435 hres = E_NOINTERFACE;
1440 /***********************************************************************
1441 * CoResumeClassObjects (OLE32.@)
1443 * Resumes classobjects registered with REGCLS suspended
1445 HRESULT WINAPI CoResumeClassObjects(void)
1451 /***********************************************************************
1452 * GetClassFile (OLE32.@)
1454 * This function supplies the CLSID associated with the given filename.
1456 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1460 int nbElm, length, i;
1462 LPOLESTR *pathDec=0,absFile=0,progId=0;
1464 static const WCHAR bkslashW[] = {'\\',0};
1465 static const WCHAR dotW[] = {'.',0};
1467 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1469 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1470 if((StgIsStorageFile(filePathName))==S_OK){
1472 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1475 res=ReadClassStg(pstg,pclsid);
1477 IStorage_Release(pstg);
1481 /* if the file is not a storage object then attemps to match various bits in the file against a
1482 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1485 for(i=0;i<nFileTypes;i++)
1487 for(i=0;j<nPatternsForType;j++){
1492 pat=ReadPatternFromRegistry(i,j);
1493 hFile=CreateFileW(filePathName,,,,,,hFile);
1494 SetFilePosition(hFile,pat.offset);
1495 ReadFile(hFile,buf,pat.size,&r,NULL);
1496 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1498 *pclsid=ReadCLSIDFromRegistry(i);
1504 /* if the above strategies fail then search for the extension key in the registry */
1506 /* get the last element (absolute file) in the path name */
1507 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1508 absFile=pathDec[nbElm-1];
1510 /* failed if the path represente a directory and not an absolute file name*/
1511 if (!lstrcmpW(absFile, bkslashW))
1512 return MK_E_INVALIDEXTENSION;
1514 /* get the extension of the file */
1516 length=lstrlenW(absFile);
1517 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1520 if (!extension || !lstrcmpW(extension, dotW))
1521 return MK_E_INVALIDEXTENSION;
1523 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1525 /* get the progId associated to the extension */
1526 progId = CoTaskMemAlloc(sizeProgId);
1527 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1529 if (res==ERROR_SUCCESS)
1530 /* return the clsid associated to the progId */
1531 res= CLSIDFromProgID(progId,pclsid);
1533 for(i=0; pathDec[i]!=NULL;i++)
1534 CoTaskMemFree(pathDec[i]);
1535 CoTaskMemFree(pathDec);
1537 CoTaskMemFree(progId);
1539 if (res==ERROR_SUCCESS)
1542 return MK_E_INVALIDEXTENSION;
1544 /***********************************************************************
1545 * CoCreateInstance [COMPOBJ.13]
1546 * CoCreateInstance [OLE32.@]
1548 HRESULT WINAPI CoCreateInstance(
1550 LPUNKNOWN pUnkOuter,
1556 LPCLASSFACTORY lpclf = 0;
1558 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1567 * Initialize the "out" parameter
1572 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1573 * Rather than create a class factory, we can just check for it here
1575 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1576 if (StdGlobalInterfaceTableInstance == NULL)
1577 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1578 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1579 if (hres) return hres;
1581 TRACE("Retrieved GIT (%p)\n", *ppv);
1586 * Get a class factory to construct the object we want.
1588 hres = CoGetClassObject(rclsid,
1595 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1596 debugstr_guid(rclsid),hres);
1601 * Create the object and don't forget to release the factory
1603 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1604 IClassFactory_Release(lpclf);
1606 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1607 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1612 /***********************************************************************
1613 * CoCreateInstanceEx [OLE32.@]
1615 HRESULT WINAPI CoCreateInstanceEx(
1617 LPUNKNOWN pUnkOuter,
1619 COSERVERINFO* pServerInfo,
1623 IUnknown* pUnk = NULL;
1626 ULONG successCount = 0;
1631 if ( (cmq==0) || (pResults==NULL))
1632 return E_INVALIDARG;
1634 if (pServerInfo!=NULL)
1635 FIXME("() non-NULL pServerInfo not supported!\n");
1638 * Initialize all the "out" parameters.
1640 for (index = 0; index < cmq; index++)
1642 pResults[index].pItf = NULL;
1643 pResults[index].hr = E_NOINTERFACE;
1647 * Get the object and get its IUnknown pointer.
1649 hr = CoCreateInstance(rclsid,
1659 * Then, query for all the interfaces requested.
1661 for (index = 0; index < cmq; index++)
1663 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1664 pResults[index].pIID,
1665 (VOID**)&(pResults[index].pItf));
1667 if (pResults[index].hr == S_OK)
1672 * Release our temporary unknown pointer.
1674 IUnknown_Release(pUnk);
1676 if (successCount == 0)
1677 return E_NOINTERFACE;
1679 if (successCount!=cmq)
1680 return CO_S_NOTALLINTERFACES;
1685 /***********************************************************************
1686 * CoLoadLibrary (OLE32.@)
1688 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1690 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1692 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1695 /***********************************************************************
1696 * CoFreeLibrary [OLE32.@]
1698 * NOTES: don't believe the documentation
1700 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1702 FreeLibrary(hLibrary);
1706 /***********************************************************************
1707 * CoFreeAllLibraries [OLE32.@]
1709 * NOTES: don't believe the documentation
1711 void WINAPI CoFreeAllLibraries(void)
1717 /***********************************************************************
1718 * CoFreeUnusedLibraries [COMPOBJ.17]
1719 * CoFreeUnusedLibraries [OLE32.@]
1721 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1722 * through the main apartment's thread to call DllCanUnloadNow
1724 void WINAPI CoFreeUnusedLibraries(void)
1726 COMPOBJ_DllList_FreeUnused(0);
1729 /***********************************************************************
1730 * CoFileTimeNow [COMPOBJ.82]
1731 * CoFileTimeNow [OLE32.@]
1734 * the current system time in lpFileTime
1736 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1738 GetSystemTimeAsFileTime( lpFileTime );
1742 /***********************************************************************
1743 * CoLoadLibrary (OLE32.@)
1745 static void COM_RevokeAllClasses()
1747 EnterCriticalSection( &csRegisteredClassList );
1749 while (firstRegisteredClass!=0)
1751 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1754 LeaveCriticalSection( &csRegisteredClassList );
1757 /****************************************************************************
1758 * COM External Lock methods implementation
1760 * This api provides a linked list to managed external references to
1763 * The public interface consists of three calls:
1764 * COM_ExternalLockAddRef
1765 * COM_ExternalLockRelease
1766 * COM_ExternalLockFreeList
1769 #define EL_END_OF_LIST 0
1770 #define EL_NOT_FOUND 0
1773 * Declaration of the static structure that manage the
1774 * external lock to COM objects.
1776 typedef struct COM_ExternalLock COM_ExternalLock;
1777 typedef struct COM_ExternalLockList COM_ExternalLockList;
1779 struct COM_ExternalLock
1781 IUnknown *pUnk; /* IUnknown referenced */
1782 ULONG uRefCount; /* external lock counter to IUnknown object*/
1783 COM_ExternalLock *next; /* Pointer to next element in list */
1786 struct COM_ExternalLockList
1788 COM_ExternalLock *head; /* head of list */
1792 * Declaration and initialization of the static structure that manages
1793 * the external lock to COM objects.
1795 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1798 * Private methods used to managed the linked list
1802 static COM_ExternalLock* COM_ExternalLockLocate(
1803 COM_ExternalLock *element,
1806 /****************************************************************************
1807 * Internal - Insert a new IUnknown* to the linked list
1809 static BOOL COM_ExternalLockInsert(
1812 COM_ExternalLock *newLock = NULL;
1813 COM_ExternalLock *previousHead = NULL;
1816 * Allocate space for the new storage object
1818 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1820 if (newLock!=NULL) {
1821 if ( elList.head == EL_END_OF_LIST ) {
1822 elList.head = newLock; /* The list is empty */
1824 /* insert does it at the head */
1825 previousHead = elList.head;
1826 elList.head = newLock;
1829 /* Set new list item data member */
1830 newLock->pUnk = pUnk;
1831 newLock->uRefCount = 1;
1832 newLock->next = previousHead;
1839 /****************************************************************************
1840 * Internal - Method that removes an item from the linked list.
1842 static void COM_ExternalLockDelete(
1843 COM_ExternalLock *itemList)
1845 COM_ExternalLock *current = elList.head;
1847 if ( current == itemList ) {
1848 /* this section handles the deletion of the first node */
1849 elList.head = itemList->next;
1850 HeapFree( GetProcessHeap(), 0, itemList);
1853 if ( current->next == itemList ){ /* We found the item to free */
1854 current->next = itemList->next; /* readjust the list pointers */
1855 HeapFree( GetProcessHeap(), 0, itemList);
1859 /* Skip to the next item */
1860 current = current->next;
1862 } while ( current != EL_END_OF_LIST );
1866 /****************************************************************************
1867 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1869 * NOTES: how long can the list be ?? (recursive!!!)
1871 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1873 if ( element == EL_END_OF_LIST )
1874 return EL_NOT_FOUND;
1875 else if ( element->pUnk == pUnk ) /* We found it */
1877 else /* Not the right guy, keep on looking */
1878 return COM_ExternalLockLocate( element->next, pUnk);
1881 /****************************************************************************
1882 * Public - Method that increments the count for a IUnknown* in the linked
1883 * list. The item is inserted if not already in the list.
1885 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1887 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1890 * Add an external lock to the object. If it was already externally
1891 * locked, just increase the reference count. If it was not.
1892 * add the item to the list.
1894 if ( externalLock == EL_NOT_FOUND )
1895 COM_ExternalLockInsert(pUnk);
1897 externalLock->uRefCount++;
1900 * Add an internal lock to the object
1902 IUnknown_AddRef(pUnk);
1905 /****************************************************************************
1906 * Public - Method that decrements the count for a IUnknown* in the linked
1907 * list. The item is removed from the list if its count end up at zero or if
1910 static void COM_ExternalLockRelease(
1914 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1916 if ( externalLock != EL_NOT_FOUND ) {
1918 externalLock->uRefCount--; /* release external locks */
1919 IUnknown_Release(pUnk); /* release local locks as well */
1921 if ( bRelAll == FALSE ) break; /* perform single release */
1923 } while ( externalLock->uRefCount > 0 );
1925 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1926 COM_ExternalLockDelete(externalLock);
1929 /****************************************************************************
1930 * Public - Method that frees the content of the list.
1932 static void COM_ExternalLockFreeList()
1934 COM_ExternalLock *head;
1936 head = elList.head; /* grab it by the head */
1937 while ( head != EL_END_OF_LIST ) {
1938 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1939 head = elList.head; /* get the new head... */
1943 /****************************************************************************
1944 * Public - Method that dump the content of the list.
1946 void COM_ExternalLockDump()
1948 COM_ExternalLock *current = elList.head;
1950 DPRINTF("\nExternal lock list contains:\n");
1952 while ( current != EL_END_OF_LIST ) {
1953 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1955 /* Skip to the next item */
1956 current = current->next;
1960 /******************************************************************************
1961 * CoLockObjectExternal [OLE32.@]
1963 HRESULT WINAPI CoLockObjectExternal(
1964 LPUNKNOWN pUnk, /* [in] object to be locked */
1965 BOOL fLock, /* [in] do lock */
1966 BOOL fLastUnlockReleases) /* [in] unlock all */
1968 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
1969 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
1973 * Increment the external lock coutner, COM_ExternalLockAddRef also
1974 * increment the object's internal lock counter.
1976 COM_ExternalLockAddRef( pUnk);
1979 * Decrement the external lock coutner, COM_ExternalLockRelease also
1980 * decrement the object's internal lock counter.
1982 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1988 /***********************************************************************
1989 * CoInitializeWOW (OLE32.@)
1991 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1992 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1996 /***********************************************************************
1997 * CoGetState [OLE32.@]
1999 * NOTES: might be incomplete
2001 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2003 APARTMENT * apt = COM_CurrentInfo();
2007 if(apt && apt->state) {
2008 IUnknown_AddRef(apt->state);
2010 FIXME("-- %p\n", *ppv);
2018 /***********************************************************************
2019 * CoSetState [OLE32.@]
2022 HRESULT WINAPI CoSetState(IUnknown * pv)
2024 APARTMENT * apt = COM_CurrentInfo();
2026 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
2028 FIXME("(%p),stub!\n", pv);
2031 IUnknown_AddRef(pv);
2035 TRACE("-- release %p now\n", apt->state);
2036 IUnknown_Release(apt->state);
2043 /******************************************************************************
2044 * OleGetAutoConvert [OLE32.@]
2046 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2054 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2055 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2057 res = REGDB_E_CLASSNOTREG;
2061 /* we can just query for the default value of AutoConvertTo key like that,
2062 without opening the AutoConvertTo key and querying for NULL (default) */
2063 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2065 res = REGDB_E_KEYMISSING;
2068 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2069 CLSIDFromString(wbuf,pClsidNew);
2071 if (hkey) RegCloseKey(hkey);
2075 /******************************************************************************
2076 * OleSetAutoConvert [OLE32.@]
2078 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2081 char buf[200], szClsidNew[200];
2084 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2085 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2086 WINE_StringFromCLSID(clsidNew, szClsidNew);
2087 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2089 res = REGDB_E_CLASSNOTREG;
2092 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2094 res = REGDB_E_WRITEREGDB;
2099 if (hkey) RegCloseKey(hkey);
2103 /******************************************************************************
2104 * OleDoAutoConvert [OLE32.@]
2106 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2108 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2112 /******************************************************************************
2113 * CoTreatAsClass [OLE32.@]
2115 * Sets TreatAs value of a class
2117 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2121 char szClsidNew[39];
2123 char auto_treat_as[39];
2124 LONG auto_treat_as_size = sizeof(auto_treat_as);
2127 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2128 WINE_StringFromCLSID(clsidNew, szClsidNew);
2129 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2131 res = REGDB_E_CLASSNOTREG;
2134 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2136 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2137 !__CLSIDFromStringA(auto_treat_as, &id))
2139 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2141 res = REGDB_E_WRITEREGDB;
2147 RegDeleteKeyA(hkey, "TreatAs");
2151 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2153 res = REGDB_E_WRITEREGDB;
2158 if (hkey) RegCloseKey(hkey);
2162 /******************************************************************************
2163 * CoGetTreatAsClass [OLE32.@]
2165 * Reads the TreatAs value from a class.
2167 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2170 char buf[200], szClsidNew[200];
2172 LONG len = sizeof(szClsidNew);
2174 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2175 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2176 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2178 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2180 res = REGDB_E_CLASSNOTREG;
2183 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2188 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2190 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2192 if (hkey) RegCloseKey(hkey);
2197 /***********************************************************************
2198 * IsEqualGUID [OLE32.@]
2200 * Compares two Unique Identifiers.
2206 BOOL WINAPI IsEqualGUID(
2207 REFGUID rguid1, /* [in] unique id 1 */
2208 REFGUID rguid2 /* [in] unique id 2 */
2211 return !memcmp(rguid1,rguid2,sizeof(GUID));
2214 /***********************************************************************
2215 * CoInitializeSecurity [OLE32.@]
2217 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2218 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2219 void* pReserved1, DWORD dwAuthnLevel,
2220 DWORD dwImpLevel, void* pReserved2,
2221 DWORD dwCapabilities, void* pReserved3)
2223 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2224 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2225 dwCapabilities, pReserved3);
2229 /***********************************************************************
2230 * CoSuspendClassObjects [OLE32.@]
2232 HRESULT WINAPI CoSuspendClassObjects(void)
2238 /***********************************************************************
2239 * CoAddRefServerProcess [OLE32.@]
2241 ULONG WINAPI CoAddRefServerProcess(void)
2247 /***********************************************************************
2248 * CoReleaseServerProcess [OLE32.@]
2250 ULONG WINAPI CoReleaseServerProcess(void)