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
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Once that's done, replace wine_marshal_id with STDOBJREF
33 * - Rewrite the CoLockObjectExternal code, it does totally the wrong
34 * thing currently (should be controlling the stub manager)
36 * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
38 * - Implement the service control manager (in rpcss) to keep track
39 * of registered class objects: ISCM::ServerRegisterClsid et al
40 * - Implement the OXID resolver so we don't need magic pipe names for
41 * clients and servers to meet up
42 * - Flip our marshalling on top of the RPC runtime transport API,
43 * so we no longer use named pipes to communicate
44 * - Rework threading so re-entrant calls don't need to be sent on
46 * - Implement RPC thread affinity (should fix InstallShield painting
49 * - Implement IRemUnknown and marshalling for it, then use that for
50 * reffing/unreffing the stub manager from a proxy instead of our
51 * current hack of simply reffing the stub manager once when it's
53 * - Implement table marshalling, then use it to let us do the final
54 * rework of the threading
56 * - Make our custom marshalling use NDR to be wire compatible with
71 #define NONAMELESSUNION
72 #define NONAMELESSSTRUCT
84 #include "wine/unicode.h"
86 #include "ole32_main.h"
87 #include "compobj_private.h"
89 #include "wine/debug.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(ole);
93 typedef LPCSTR LPCOLESTR16;
95 /****************************************************************************
96 * This section defines variables internal to the COM module.
98 * TODO: Most of these things will have to be made thread-safe.
101 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
102 static void COM_RevokeAllClasses(void);
103 static void COM_ExternalLockFreeList(void);
105 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
107 APARTMENT *MTA; /* protected by csApartment */
108 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
110 static CRITICAL_SECTION csApartment;
111 static CRITICAL_SECTION_DEBUG critsect_debug =
114 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
115 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
117 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
120 * This lock count counts the number of times CoInitialize is called. It is
121 * decreased every time CoUninitialize is called. When it hits 0, the COM
122 * libraries are freed
124 static LONG s_COMLockCount = 0;
127 * This linked list contains the list of registered class objects. These
128 * are mostly used to register the factories for out-of-proc servers of OLE
131 * TODO: Make this data structure aware of inter-process communication. This
132 * means that parts of this will be exported to the Wine Server.
134 typedef struct tagRegisteredClass
136 CLSID classIdentifier;
137 LPUNKNOWN classObject;
141 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
142 struct tagRegisteredClass* nextClass;
145 static RegisteredClass* firstRegisteredClass = NULL;
147 static CRITICAL_SECTION csRegisteredClassList;
148 static CRITICAL_SECTION_DEBUG class_cs_debug =
150 0, 0, &csRegisteredClassList,
151 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
152 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
154 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
156 /*****************************************************************************
157 * This section contains OpenDllList definitions
159 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
160 * other functions that do LoadLibrary _without_ giving back a HMODULE.
161 * Without this list these handles would never be freed.
163 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
164 * next unload-call but not before 600 sec.
167 typedef struct tagOpenDll {
169 struct tagOpenDll *next;
172 static OpenDll *openDllList = NULL; /* linked list of open dlls */
174 static CRITICAL_SECTION csOpenDllList;
175 static CRITICAL_SECTION_DEBUG dll_cs_debug =
177 0, 0, &csOpenDllList,
178 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
179 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
181 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
183 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
184 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
187 static void COMPOBJ_DllList_FreeUnused(int Timeout);
189 void COMPOBJ_InitProcess( void )
193 /* Dispatching to the correct thread in an apartment is done through
194 * window messages rather than RPC transports. When an interface is
195 * marshalled into another apartment in the same process, a window of the
196 * following class is created. The *caller* of CoMarshalInterface (ie the
197 * application) is responsible for pumping the message loop in that thread.
198 * The WM_USER messages which point to the RPCs are then dispatched to
199 * COM_AptWndProc by the user's code from the apartment in which the interface
202 memset(&wclass, 0, sizeof(wclass));
203 wclass.lpfnWndProc = &COM_AptWndProc;
204 wclass.hInstance = OLE32_hInstance;
205 wclass.lpszClassName = aptWinClass;
206 RegisterClassA(&wclass);
209 void COMPOBJ_UninitProcess( void )
211 UnregisterClassA(aptWinClass, OLE32_hInstance);
214 /******************************************************************************
218 /* creates an apartment structure which stores OLE apartment-local
220 APARTMENT* COM_CreateApartment(DWORD model)
222 APARTMENT *apt = COM_CurrentApt();
226 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
227 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
230 EnterCriticalSection(&csApartment);
231 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
233 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
235 COM_ApartmentAddRef(apt);
237 LeaveCriticalSection(&csApartment);
239 COM_CurrentInfo()->apt = apt;
243 TRACE("creating new apartment, model=%ld\n", model);
245 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
246 apt->tid = GetCurrentThreadId();
247 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
248 GetCurrentProcess(), &apt->thread,
249 THREAD_ALL_ACCESS, FALSE, 0);
251 list_init(&apt->proxies);
252 list_init(&apt->stubmgrs);
255 InitializeCriticalSection(&apt->cs);
259 if (model & COINIT_APARTMENTTHREADED)
261 /* FIXME: should be randomly generated by in an RPC call to rpcss */
262 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
263 apt->win = CreateWindowA(aptWinClass, NULL, 0,
265 0, 0, OLE32_hInstance, NULL);
269 /* FIXME: should be randomly generated by in an RPC call to rpcss */
270 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
277 LeaveCriticalSection(&csApartment);
279 COM_CurrentInfo()->apt = apt;
285 DWORD COM_ApartmentAddRef(struct apartment *apt)
287 return InterlockedIncrement(&apt->refs);
290 DWORD COM_ApartmentRelease(struct apartment *apt)
294 EnterCriticalSection(&csApartment);
296 ret = InterlockedDecrement(&apt->refs);
297 /* destruction stuff that needs to happen under csApartment CS */
300 if (apt == MTA) MTA = NULL;
301 list_remove(&apt->entry);
304 LeaveCriticalSection(&csApartment);
308 struct list *cursor, *cursor2;
310 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
312 MARSHAL_Disconnect_Proxies(apt);
314 if (apt->win) DestroyWindow(apt->win);
316 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
318 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
319 /* release the implicit reference given by the fact that the
320 * stub has external references (it must do since it is in the
321 * stub manager list in the apartment and all non-apartment users
322 * must have a ref on the apartment and so it cannot be destroyed).
324 stub_manager_int_release(stubmgr);
327 /* if this assert fires, then another thread took a reference to a
328 * stub manager without taking a reference to the containing
329 * apartment, which it must do. */
330 assert(list_empty(&apt->stubmgrs));
332 if (apt->filter) IUnknown_Release(apt->filter);
334 DeleteCriticalSection(&apt->cs);
335 CloseHandle(apt->thread);
336 HeapFree(GetProcessHeap(), 0, apt);
342 /* The given OXID must be local to this process: you cannot use
343 * apartment windows to send RPCs to other processes. This all needs
346 * The ref parameter is here mostly to ensure people remember that
347 * they get one, you should normally take a ref for thread safety.
349 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
351 APARTMENT *result = NULL;
354 EnterCriticalSection(&csApartment);
355 LIST_FOR_EACH( cursor, &apts )
357 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
358 if (apt->oxid == oxid)
361 if (ref) COM_ApartmentAddRef(result);
365 LeaveCriticalSection(&csApartment);
370 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
374 apt = COM_ApartmentFromOXID(oxid, ref);
375 if (!apt) return NULL;
380 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
381 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
383 return DefWindowProcA(hWnd, msg, wParam, lParam);
386 /*****************************************************************************
387 * This section contains OpenDllList implemantation
390 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
397 EnterCriticalSection( &csOpenDllList );
399 if (openDllList == NULL) {
400 /* empty list -- add first node */
401 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
402 openDllList->hLibrary=hLibrary;
403 openDllList->next = NULL;
405 /* search for this dll */
407 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
408 if (ptr->hLibrary == hLibrary) {
414 /* dll not found, add it */
416 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
417 openDllList->hLibrary = hLibrary;
418 openDllList->next = tmp;
422 LeaveCriticalSection( &csOpenDllList );
425 static void COMPOBJ_DllList_FreeUnused(int Timeout)
427 OpenDll *curr, *next, *prev = NULL;
428 typedef HRESULT(*DllCanUnloadNowFunc)(void);
429 DllCanUnloadNowFunc DllCanUnloadNow;
433 EnterCriticalSection( &csOpenDllList );
435 for (curr = openDllList; curr != NULL; ) {
436 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
438 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
441 TRACE("freeing %p\n", curr->hLibrary);
442 FreeLibrary(curr->hLibrary);
444 HeapFree(GetProcessHeap(), 0, curr);
445 if (curr == openDllList) {
458 LeaveCriticalSection( &csOpenDllList );
461 /******************************************************************************
462 * CoBuildVersion [COMPOBJ.1]
463 * CoBuildVersion [OLE32.@]
466 * Current build version, hiword is majornumber, loword is minornumber
468 DWORD WINAPI CoBuildVersion(void)
470 TRACE("Returning version %d, build %d.\n", rmm, rup);
471 return (rmm<<16)+rup;
474 /******************************************************************************
475 * CoInitialize [OLE32.@]
477 * Initializes the COM libraries by calling CoInitializeEx with
478 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
483 HRESULT WINAPI CoInitialize(
484 LPVOID lpReserved /* [in] pointer to win32 malloc interface
485 (obsolete, should be NULL) */
489 * Just delegate to the newer method.
491 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
494 /******************************************************************************
495 * CoInitializeEx [OLE32.@]
497 * Initializes the COM libraries. The behavior used to set the win32
498 * IMalloc used for memory management is obsolete. If
499 * COINIT_APARTMENTTHREADED is specified this thread enters a new STA
500 * (single threaded apartment), otherwise COINIT_MULTITHREADED should
501 * be specified which indicates that the thread will enter the MTA.
503 * Currently STA threading is only partly implemented.
506 * S_OK if successful,
507 * S_FALSE if this function was called already.
508 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
514 HRESULT WINAPI CoInitializeEx(
515 LPVOID lpReserved, /* [in] pointer to win32 malloc interface (obsolete, should be NULL) */
516 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
522 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
524 if (lpReserved!=NULL)
526 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
530 * Check the lock count. If this is the first time going through the initialize
531 * process, we have to initialize the libraries.
533 * And crank-up that lock count.
535 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
538 * Initialize the various COM libraries and data structures.
540 TRACE("() - Initializing the COM libraries\n");
542 /* we may need to defer this until after apartment initialisation */
543 RunningObjectTableImpl_Initialize();
546 if (!(apt = COM_CurrentInfo()->apt))
548 apt = COM_CreateApartment(dwCoInit);
549 if (!apt) return E_OUTOFMEMORY;
551 else if (dwCoInit != apt->model)
553 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
554 code then we are probably using the wrong threading model to implement that API. */
555 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
556 COM_ApartmentRelease(apt);
557 return RPC_E_CHANGED_MODE;
562 COM_CurrentInfo()->inits++;
567 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
568 pending RPCs are ignored. Non-COM messages are discarded at this point.
570 void COM_FlushMessageQueue(void)
573 APARTMENT *apt = COM_CurrentApt();
575 if (!apt || !apt->win) return;
577 TRACE("Flushing STA message queue\n");
579 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
581 if (message.hwnd != apt->win)
583 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
587 TranslateMessage(&message);
588 DispatchMessageA(&message);
592 /***********************************************************************
593 * CoUninitialize [OLE32.@]
595 * This method will decrement the refcount on the COM libraries,
596 * potentially unloading them. The current thread leaves the apartment
597 * it's currently in. If not in an apartment, the routine does
600 * If COM is to be shut down, any outstanding proxies are
601 * disconnected, all registered class objects are unregistered and the
602 * message queue for the thread is flushed (if native does
603 * this or not is unknown).
608 void WINAPI CoUninitialize(void)
610 struct oletls * info = COM_CurrentInfo();
615 /* will only happen on OOM */
621 ERR("Mismatched CoUninitialize\n");
627 COM_ApartmentRelease(info->apt);
632 * Decrease the reference count.
633 * If we are back to 0 locks on the COM library, make sure we free
634 * all the associated data structures.
636 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
639 TRACE("() - Releasing the COM libraries\n");
641 RunningObjectTableImpl_UnInitialize();
643 /* Release the references to the registered class objects */
644 COM_RevokeAllClasses();
646 /* This will free the loaded COM Dlls */
647 CoFreeAllLibraries();
649 /* This will free list of external references to COM objects */
650 COM_ExternalLockFreeList();
652 /* This ensures we deal with any pending RPCs */
653 COM_FlushMessageQueue();
655 else if (lCOMRefCnt<1) {
656 ERR( "CoUninitialize() - not CoInitialized.\n" );
657 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
661 /******************************************************************************
662 * CoDisconnectObject [COMPOBJ.15]
663 * CoDisconnectObject [OLE32.@]
665 * Disconnects all connections to this object from remote processes. Dispatches
666 * pending RPCs while blocking new RPCs from occurring, and then calls
667 * IMarshal::DisconnectObject on the given object.
669 * Typically called when the object server is forced to shut down, for instance by
672 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
674 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
678 /******************************************************************************
679 * CoCreateGuid[OLE32.@]
681 * Simply forwards to UuidCreate in RPCRT4.
687 HRESULT WINAPI CoCreateGuid(
688 GUID *pguid /* [out] points to the GUID to initialize */
690 return UuidCreate(pguid);
693 /******************************************************************************
694 * CLSIDFromString [OLE32.@]
695 * IIDFromString [OLE32.@]
697 * Converts a unique identifier from its string representation into
700 * In Windows, if idstr is not a valid CLSID string then it gets
701 * treated as a ProgID. Wine currently doesn't do this. If idstr is
702 * NULL it's treated as an all-zero GUID.
706 * CO_E_CLASSSTRING if idstr is not a valid CLSID
708 HRESULT WINAPI __CLSIDFromStringA(
709 LPCSTR idstr, /* [in] string representation of guid */
710 CLSID *id) /* [out] GUID converted from string */
712 const BYTE *s = (const BYTE *) idstr;
717 s = "{00000000-0000-0000-0000-000000000000}";
718 else { /* validate the CLSID string */
721 return CO_E_CLASSSTRING;
723 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
724 return CO_E_CLASSSTRING;
726 for (i=1; i<37; i++) {
727 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
728 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
729 ((s[i] >= 'a') && (s[i] <= 'f')) ||
730 ((s[i] >= 'A') && (s[i] <= 'F'))))
731 return CO_E_CLASSSTRING;
735 TRACE("%s -> %p\n", s, id);
737 /* quick lookup table */
738 memset(table, 0, 256);
740 for (i = 0; i < 10; i++) {
743 for (i = 0; i < 6; i++) {
744 table['A' + i] = i+10;
745 table['a' + i] = i+10;
748 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
750 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
751 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
752 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
753 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
755 /* these are just sequential bytes */
756 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
757 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
758 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
759 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
760 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
761 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
762 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
763 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
768 /*****************************************************************************/
770 HRESULT WINAPI CLSIDFromString(
771 LPOLESTR idstr, /* [in] string representation of GUID */
772 CLSID *id ) /* [out] GUID represented by above string */
777 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
778 return CO_E_CLASSSTRING;
781 ret = __CLSIDFromStringA(xid,id);
782 if(ret != S_OK) { /* It appears a ProgID is also valid */
783 ret = CLSIDFromProgID(idstr, id);
788 /* Converts a GUID into the respective string representation. */
789 HRESULT WINE_StringFromCLSID(
790 const CLSID *id, /* [in] GUID to be converted */
791 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
793 static const char *hex = "0123456789ABCDEF";
798 { ERR("called with id=Null\n");
803 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
804 id->Data1, id->Data2, id->Data3,
805 id->Data4[0], id->Data4[1]);
809 for (i = 2; i < 8; i++) {
810 *s++ = hex[id->Data4[i]>>4];
811 *s++ = hex[id->Data4[i] & 0xf];
817 TRACE("%p->%s\n", id, idstr);
823 /******************************************************************************
824 * StringFromCLSID [OLE32.@]
825 * StringFromIID [OLE32.@]
827 * Converts a GUID into the respective string representation.
828 * The target string is allocated using the OLE IMalloc.
834 HRESULT WINAPI StringFromCLSID(
835 REFCLSID id, /* [in] the GUID to be converted */
836 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
842 if ((ret = CoGetMalloc(0,&mllc)))
845 ret=WINE_StringFromCLSID(id,buf);
847 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
848 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
849 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
854 /******************************************************************************
855 * StringFromGUID2 [COMPOBJ.76]
856 * StringFromGUID2 [OLE32.@]
858 * Modified version of StringFromCLSID that allows you to specify max
862 * The length of the resulting string, 0 if there was any problem.
864 INT WINAPI StringFromGUID2(
865 REFGUID id, /* [in] GUID to convert to string */
866 LPOLESTR str, /* [out] Unicode buffer to hold result */
871 if (WINE_StringFromCLSID(id,xguid))
873 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
876 /******************************************************************************
877 * ProgIDFromCLSID [OLE32.@]
879 * Converts a class id into the respective Program ID. (By using a
885 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
887 HRESULT WINAPI ProgIDFromCLSID(
888 REFCLSID clsid, /* [in] class id as found in registry */
889 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
892 char strCLSID[50], *buf, *buf2;
898 WINE_StringFromCLSID(clsid, strCLSID);
900 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
901 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
902 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
903 ret = REGDB_E_CLASSNOTREG;
905 HeapFree(GetProcessHeap(), 0, buf);
909 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
911 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
912 ret = REGDB_E_CLASSNOTREG;
916 if (CoGetMalloc(0,&mllc))
920 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
921 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
922 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
925 HeapFree(GetProcessHeap(), 0, buf2);
932 HRESULT WINAPI CLSIDFromProgID16(
933 LPCOLESTR16 progid, /* [in] program id as found in registry */
934 LPCLSID riid /* [out] associated CLSID */
941 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
942 sprintf(buf,"%s\\CLSID",progid);
943 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
944 HeapFree(GetProcessHeap(),0,buf);
945 return CO_E_CLASSSTRING;
947 HeapFree(GetProcessHeap(),0,buf);
948 buf2len = sizeof(buf2);
949 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
951 return CO_E_CLASSSTRING;
954 return __CLSIDFromStringA(buf2,riid);
957 /******************************************************************************
958 * CLSIDFromProgID [COMPOBJ.61]
960 * Converts a program id into the respective GUID. (By using a
965 * CO_E_CLASSSTRING if the given ProgID cannot be found
967 HRESULT WINAPI CLSIDFromProgID(
968 LPCOLESTR progid, /* [in] Unicode program id as found in registry */
969 LPCLSID riid ) /* [out] associated CLSID */
971 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
973 DWORD buf2len = sizeof(buf2);
976 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
977 strcpyW( buf, progid );
978 strcatW( buf, clsidW );
979 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
981 HeapFree(GetProcessHeap(),0,buf);
982 return CO_E_CLASSSTRING;
984 HeapFree(GetProcessHeap(),0,buf);
986 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
989 return CO_E_CLASSSTRING;
992 return __CLSIDFromStringA(buf2,riid);
997 /*****************************************************************************
998 * CoGetPSClsid [OLE32.@]
1000 * This function returns the CLSID of the proxy/stub factory that
1001 * implements IPSFactoryBuffer for the specified interface.
1003 * The standard marshaller activates the object with the CLSID
1004 * returned and uses the CreateProxy and CreateStub methods on its
1005 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1008 * CoGetPSClsid determines this CLSID by searching the
1009 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1010 * in the registry and any interface id registered by
1011 * CoRegisterPSClsid within the current process.
1013 * FIXME: We only search the registry, not ids registered with
1014 * CoRegisterPSClsid.
1019 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1021 HRESULT WINAPI CoGetPSClsid(
1022 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
1023 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
1025 char *buf, buf2[40];
1029 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1031 /* Get the input iid as a string */
1032 WINE_StringFromCLSID(riid, buf2);
1033 /* Allocate memory for the registry key we will construct.
1034 (length of iid string plus constant length of static text */
1035 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1038 return (E_OUTOFMEMORY);
1041 /* Construct the registry key we want */
1042 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1044 /* Open the key.. */
1045 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1047 WARN("No PSFactoryBuffer object is registered for this IID\n");
1048 HeapFree(GetProcessHeap(),0,buf);
1049 return (E_INVALIDARG);
1051 HeapFree(GetProcessHeap(),0,buf);
1053 /* ... Once we have the key, query the registry to get the
1054 value of CLSID as a string, and convert it into a
1055 proper CLSID structure to be passed back to the app */
1056 buf2len = sizeof(buf2);
1057 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1060 return E_INVALIDARG;
1064 /* We have the CLSid we want back from the registry as a string, so
1065 lets convert it into a CLSID structure */
1066 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1067 return E_INVALIDARG;
1070 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1076 /***********************************************************************
1077 * WriteClassStm (OLE32.@)
1079 * This function write a CLSID on stream
1081 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1083 TRACE("(%p,%p)\n",pStm,rclsid);
1086 return E_INVALIDARG;
1088 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1091 /***********************************************************************
1092 * ReadClassStm (OLE32.@)
1094 * This function read a CLSID from a stream
1096 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1101 TRACE("(%p,%p)\n",pStm,pclsid);
1104 return E_INVALIDARG;
1106 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1111 if (nbByte != sizeof(CLSID))
1119 * COM_GetRegisteredClassObject
1121 * This internal method is used to scan the registered class list to
1122 * find a class object.
1125 * rclsid Class ID of the class to find.
1126 * dwClsContext Class context to match.
1127 * ppv [out] returns a pointer to the class object. Complying
1128 * to normal COM usage, this method will increase the
1129 * reference count on this object.
1131 static HRESULT COM_GetRegisteredClassObject(
1136 HRESULT hr = S_FALSE;
1137 RegisteredClass* curClass;
1139 EnterCriticalSection( &csRegisteredClassList );
1147 * Iterate through the whole list and try to match the class ID.
1149 curClass = firstRegisteredClass;
1151 while (curClass != 0)
1154 * Check if we have a match on the class ID.
1156 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1159 * Since we don't do out-of process or DCOM just right away, let's ignore the
1164 * We have a match, return the pointer to the class object.
1166 *ppUnk = curClass->classObject;
1168 IUnknown_AddRef(curClass->classObject);
1175 * Step to the next class in the list.
1177 curClass = curClass->nextClass;
1181 LeaveCriticalSection( &csRegisteredClassList );
1183 * If we get to here, we haven't found our class.
1188 /******************************************************************************
1189 * CoRegisterClassObject [OLE32.@]
1191 * Registers the class object for a given class ID. Servers housed in EXE
1192 * files use this method instead of exporting DllGetClassObject to allow
1193 * other code to connect to their objects.
1197 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1198 * CO_E_OBJISREG if the object is already registered. We should not return this.
1201 * CoRevokeClassObject, CoGetClassObject
1204 * MSDN claims that multiple interface registrations are legal, but we
1205 * can't do that with our current implementation.
1207 HRESULT WINAPI CoRegisterClassObject(
1208 REFCLSID rclsid, /* [in] CLSID of the object to register */
1209 LPUNKNOWN pUnk, /* [in] IUnknown of the object */
1210 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1211 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1212 LPDWORD lpdwRegister) /* [out] A unique cookie that can be passed to CoRevokeClassObject */
1214 RegisteredClass* newClass;
1215 LPUNKNOWN foundObject;
1218 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1219 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1221 if ( (lpdwRegister==0) || (pUnk==0) )
1222 return E_INVALIDARG;
1224 if (!COM_CurrentApt())
1226 ERR("COM was not initialized\n");
1227 return CO_E_NOTINITIALIZED;
1233 * First, check if the class is already registered.
1234 * If it is, this should cause an error.
1236 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1238 IUnknown_Release(foundObject);
1239 return CO_E_OBJISREG;
1242 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1243 if ( newClass == NULL )
1244 return E_OUTOFMEMORY;
1246 EnterCriticalSection( &csRegisteredClassList );
1248 newClass->classIdentifier = *rclsid;
1249 newClass->runContext = dwClsContext;
1250 newClass->connectFlags = flags;
1252 * Use the address of the chain node as the cookie since we are sure it's
1253 * unique. FIXME: not on 64-bit platforms.
1255 newClass->dwCookie = (DWORD)newClass;
1256 newClass->nextClass = firstRegisteredClass;
1259 * Since we're making a copy of the object pointer, we have to increase its
1262 newClass->classObject = pUnk;
1263 IUnknown_AddRef(newClass->classObject);
1265 firstRegisteredClass = newClass;
1266 LeaveCriticalSection( &csRegisteredClassList );
1268 *lpdwRegister = newClass->dwCookie;
1270 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1271 IClassFactory *classfac;
1273 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1274 (LPVOID*)&classfac);
1277 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1279 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1280 IUnknown_Release(classfac);
1283 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1284 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1285 MSHLFLAGS_TABLESTRONG);
1287 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1288 IUnknown_Release(classfac);
1292 IUnknown_Release(classfac);
1294 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1299 /***********************************************************************
1300 * CoRevokeClassObject [OLE32.@]
1302 * This method will remove a class object from the class registry
1304 * See the Windows documentation for more details.
1306 HRESULT WINAPI CoRevokeClassObject(
1309 HRESULT hr = E_INVALIDARG;
1310 RegisteredClass** prevClassLink;
1311 RegisteredClass* curClass;
1313 TRACE("(%08lx)\n",dwRegister);
1315 EnterCriticalSection( &csRegisteredClassList );
1318 * Iterate through the whole list and try to match the cookie.
1320 curClass = firstRegisteredClass;
1321 prevClassLink = &firstRegisteredClass;
1323 while (curClass != 0)
1326 * Check if we have a match on the cookie.
1328 if (curClass->dwCookie == dwRegister)
1331 * Remove the class from the chain.
1333 *prevClassLink = curClass->nextClass;
1336 * Release the reference to the class object.
1338 IUnknown_Release(curClass->classObject);
1340 if (curClass->pMarshaledData)
1343 memset(&zero, 0, sizeof(zero));
1344 /* FIXME: stop local server thread */
1345 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1346 CoReleaseMarshalData(curClass->pMarshaledData);
1350 * Free the memory used by the chain node.
1352 HeapFree(GetProcessHeap(), 0, curClass);
1359 * Step to the next class in the list.
1361 prevClassLink = &(curClass->nextClass);
1362 curClass = curClass->nextClass;
1366 LeaveCriticalSection( &csRegisteredClassList );
1368 * If we get to here, we haven't found our class.
1373 /***********************************************************************
1374 * compobj_RegReadPath [internal]
1376 * Reads a registry value and expands it when necessary
1378 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1384 DWORD dwLength = dstlen;
1386 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1387 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1388 if (keytype == REG_EXPAND_SZ) {
1389 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1391 lstrcpynA(dst, src, dstlen);
1399 /***********************************************************************
1400 * CoGetClassObject [COMPOBJ.7]
1401 * CoGetClassObject [OLE32.@]
1403 * FIXME. If request allows of several options and there is a failure
1404 * with one (other than not being registered) do we try the
1405 * others or return failure? (E.g. inprocess is registered but
1406 * the DLL is not found but the server version works)
1408 HRESULT WINAPI CoGetClassObject(
1409 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1410 REFIID iid, LPVOID *ppv
1412 LPUNKNOWN regClassObject;
1413 HRESULT hres = E_UNEXPECTED;
1416 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1417 DllGetClassObjectFunc DllGetClassObject;
1419 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1421 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1424 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1425 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1429 * First, try and see if we can't match the class ID with one of the
1430 * registered classes.
1432 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1435 * Get the required interface from the retrieved pointer.
1437 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1440 * Since QI got another reference on the pointer, we want to release the
1441 * one we already have. If QI was unsuccessful, this will release the object. This
1442 * is good since we are not returning it in the "out" parameter.
1444 IUnknown_Release(regClassObject);
1449 /* first try: in-process */
1450 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1451 char keyname[MAX_PATH];
1452 char dllpath[MAX_PATH+1];
1454 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1456 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1457 /* failure: CLSID is not found in registry */
1458 WARN("class %s not registered inproc\n", xclsid);
1459 hres = REGDB_E_CLASSNOTREG;
1461 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1462 /* failure: DLL could not be loaded */
1463 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1464 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1465 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1466 /* failure: the dll did not export DllGetClassObject */
1467 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1468 FreeLibrary( hLibrary );
1469 hres = CO_E_DLLNOTFOUND;
1471 /* OK: get the ClassObject */
1472 COMPOBJ_DLLList_Add( hLibrary );
1473 return DllGetClassObject(rclsid, iid, ppv);
1478 /* Next try out of process */
1479 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1481 return create_marshalled_proxy(rclsid,iid,ppv);
1484 /* Finally try remote: this requires networked DCOM (a lot of work) */
1485 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1487 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1488 hres = E_NOINTERFACE;
1493 /***********************************************************************
1494 * CoResumeClassObjects (OLE32.@)
1496 * Resumes classobjects registered with REGCLS suspended
1498 HRESULT WINAPI CoResumeClassObjects(void)
1504 /***********************************************************************
1505 * GetClassFile (OLE32.@)
1507 * This function supplies the CLSID associated with the given filename.
1509 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1513 int nbElm, length, i;
1515 LPOLESTR *pathDec=0,absFile=0,progId=0;
1517 static const WCHAR bkslashW[] = {'\\',0};
1518 static const WCHAR dotW[] = {'.',0};
1520 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1522 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1523 if((StgIsStorageFile(filePathName))==S_OK){
1525 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1528 res=ReadClassStg(pstg,pclsid);
1530 IStorage_Release(pstg);
1534 /* if the file is not a storage object then attemps to match various bits in the file against a
1535 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1538 for(i=0;i<nFileTypes;i++)
1540 for(i=0;j<nPatternsForType;j++){
1545 pat=ReadPatternFromRegistry(i,j);
1546 hFile=CreateFileW(filePathName,,,,,,hFile);
1547 SetFilePosition(hFile,pat.offset);
1548 ReadFile(hFile,buf,pat.size,&r,NULL);
1549 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1551 *pclsid=ReadCLSIDFromRegistry(i);
1557 /* if the above strategies fail then search for the extension key in the registry */
1559 /* get the last element (absolute file) in the path name */
1560 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1561 absFile=pathDec[nbElm-1];
1563 /* failed if the path represente a directory and not an absolute file name*/
1564 if (!lstrcmpW(absFile, bkslashW))
1565 return MK_E_INVALIDEXTENSION;
1567 /* get the extension of the file */
1569 length=lstrlenW(absFile);
1570 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1573 if (!extension || !lstrcmpW(extension, dotW))
1574 return MK_E_INVALIDEXTENSION;
1576 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1578 /* get the progId associated to the extension */
1579 progId = CoTaskMemAlloc(sizeProgId);
1580 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1582 if (res==ERROR_SUCCESS)
1583 /* return the clsid associated to the progId */
1584 res= CLSIDFromProgID(progId,pclsid);
1586 for(i=0; pathDec[i]!=NULL;i++)
1587 CoTaskMemFree(pathDec[i]);
1588 CoTaskMemFree(pathDec);
1590 CoTaskMemFree(progId);
1592 if (res==ERROR_SUCCESS)
1595 return MK_E_INVALIDEXTENSION;
1597 /***********************************************************************
1598 * CoCreateInstance [COMPOBJ.13]
1599 * CoCreateInstance [OLE32.@]
1601 HRESULT WINAPI CoCreateInstance(
1603 LPUNKNOWN pUnkOuter,
1609 LPCLASSFACTORY lpclf = 0;
1611 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1620 * Initialize the "out" parameter
1625 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1626 * Rather than create a class factory, we can just check for it here
1628 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1629 if (StdGlobalInterfaceTableInstance == NULL)
1630 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1631 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1632 if (hres) return hres;
1634 TRACE("Retrieved GIT (%p)\n", *ppv);
1639 * Get a class factory to construct the object we want.
1641 hres = CoGetClassObject(rclsid,
1648 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1649 debugstr_guid(rclsid),hres);
1654 * Create the object and don't forget to release the factory
1656 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1657 IClassFactory_Release(lpclf);
1659 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1660 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1665 /***********************************************************************
1666 * CoCreateInstanceEx [OLE32.@]
1668 HRESULT WINAPI CoCreateInstanceEx(
1670 LPUNKNOWN pUnkOuter,
1672 COSERVERINFO* pServerInfo,
1676 IUnknown* pUnk = NULL;
1679 ULONG successCount = 0;
1684 if ( (cmq==0) || (pResults==NULL))
1685 return E_INVALIDARG;
1687 if (pServerInfo!=NULL)
1688 FIXME("() non-NULL pServerInfo not supported!\n");
1691 * Initialize all the "out" parameters.
1693 for (index = 0; index < cmq; index++)
1695 pResults[index].pItf = NULL;
1696 pResults[index].hr = E_NOINTERFACE;
1700 * Get the object and get its IUnknown pointer.
1702 hr = CoCreateInstance(rclsid,
1712 * Then, query for all the interfaces requested.
1714 for (index = 0; index < cmq; index++)
1716 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1717 pResults[index].pIID,
1718 (VOID**)&(pResults[index].pItf));
1720 if (pResults[index].hr == S_OK)
1725 * Release our temporary unknown pointer.
1727 IUnknown_Release(pUnk);
1729 if (successCount == 0)
1730 return E_NOINTERFACE;
1732 if (successCount!=cmq)
1733 return CO_S_NOTALLINTERFACES;
1738 /***********************************************************************
1739 * CoLoadLibrary (OLE32.@)
1741 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1743 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1745 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1748 /***********************************************************************
1749 * CoFreeLibrary [OLE32.@]
1751 * NOTES: don't believe the documentation
1753 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1755 FreeLibrary(hLibrary);
1759 /***********************************************************************
1760 * CoFreeAllLibraries [OLE32.@]
1762 * NOTES: don't believe the documentation
1764 void WINAPI CoFreeAllLibraries(void)
1770 /***********************************************************************
1771 * CoFreeUnusedLibraries [COMPOBJ.17]
1772 * CoFreeUnusedLibraries [OLE32.@]
1774 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1775 * through the main apartment's thread to call DllCanUnloadNow
1777 void WINAPI CoFreeUnusedLibraries(void)
1779 COMPOBJ_DllList_FreeUnused(0);
1782 /***********************************************************************
1783 * CoFileTimeNow [COMPOBJ.82]
1784 * CoFileTimeNow [OLE32.@]
1787 * the current system time in lpFileTime
1789 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1791 GetSystemTimeAsFileTime( lpFileTime );
1795 /***********************************************************************
1796 * CoLoadLibrary (OLE32.@)
1798 static void COM_RevokeAllClasses()
1800 EnterCriticalSection( &csRegisteredClassList );
1802 while (firstRegisteredClass!=0)
1804 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1807 LeaveCriticalSection( &csRegisteredClassList );
1810 /****************************************************************************
1811 * COM External Lock methods implementation
1813 * This api provides a linked list to managed external references to
1816 * The public interface consists of three calls:
1817 * COM_ExternalLockAddRef
1818 * COM_ExternalLockRelease
1819 * COM_ExternalLockFreeList
1822 #define EL_END_OF_LIST 0
1823 #define EL_NOT_FOUND 0
1826 * Declaration of the static structure that manage the
1827 * external lock to COM objects.
1829 typedef struct COM_ExternalLock COM_ExternalLock;
1830 typedef struct COM_ExternalLockList COM_ExternalLockList;
1832 struct COM_ExternalLock
1834 IUnknown *pUnk; /* IUnknown referenced */
1835 ULONG uRefCount; /* external lock counter to IUnknown object*/
1836 COM_ExternalLock *next; /* Pointer to next element in list */
1839 struct COM_ExternalLockList
1841 COM_ExternalLock *head; /* head of list */
1845 * Declaration and initialization of the static structure that manages
1846 * the external lock to COM objects.
1848 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1851 * Private methods used to managed the linked list
1855 static COM_ExternalLock* COM_ExternalLockLocate(
1856 COM_ExternalLock *element,
1859 /****************************************************************************
1860 * Internal - Insert a new IUnknown* to the linked list
1862 static BOOL COM_ExternalLockInsert(
1865 COM_ExternalLock *newLock = NULL;
1866 COM_ExternalLock *previousHead = NULL;
1869 * Allocate space for the new storage object
1871 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1873 if (newLock!=NULL) {
1874 if ( elList.head == EL_END_OF_LIST ) {
1875 elList.head = newLock; /* The list is empty */
1877 /* insert does it at the head */
1878 previousHead = elList.head;
1879 elList.head = newLock;
1882 /* Set new list item data member */
1883 newLock->pUnk = pUnk;
1884 newLock->uRefCount = 1;
1885 newLock->next = previousHead;
1892 /****************************************************************************
1893 * Internal - Method that removes an item from the linked list.
1895 static void COM_ExternalLockDelete(
1896 COM_ExternalLock *itemList)
1898 COM_ExternalLock *current = elList.head;
1900 if ( current == itemList ) {
1901 /* this section handles the deletion of the first node */
1902 elList.head = itemList->next;
1903 HeapFree( GetProcessHeap(), 0, itemList);
1906 if ( current->next == itemList ){ /* We found the item to free */
1907 current->next = itemList->next; /* readjust the list pointers */
1908 HeapFree( GetProcessHeap(), 0, itemList);
1912 /* Skip to the next item */
1913 current = current->next;
1915 } while ( current != EL_END_OF_LIST );
1919 /****************************************************************************
1920 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1922 * NOTES: how long can the list be ?? (recursive!!!)
1924 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1926 if ( element == EL_END_OF_LIST )
1927 return EL_NOT_FOUND;
1928 else if ( element->pUnk == pUnk ) /* We found it */
1930 else /* Not the right guy, keep on looking */
1931 return COM_ExternalLockLocate( element->next, pUnk);
1934 /****************************************************************************
1935 * Public - Method that increments the count for a IUnknown* in the linked
1936 * list. The item is inserted if not already in the list.
1938 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1940 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1943 * Add an external lock to the object. If it was already externally
1944 * locked, just increase the reference count. If it was not.
1945 * add the item to the list.
1947 if ( externalLock == EL_NOT_FOUND )
1948 COM_ExternalLockInsert(pUnk);
1950 externalLock->uRefCount++;
1953 * Add an internal lock to the object
1955 IUnknown_AddRef(pUnk);
1958 /****************************************************************************
1959 * Public - Method that decrements the count for a IUnknown* in the linked
1960 * list. The item is removed from the list if its count end up at zero or if
1963 static void COM_ExternalLockRelease(
1967 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1969 if ( externalLock != EL_NOT_FOUND ) {
1971 externalLock->uRefCount--; /* release external locks */
1972 IUnknown_Release(pUnk); /* release local locks as well */
1974 if ( bRelAll == FALSE ) break; /* perform single release */
1976 } while ( externalLock->uRefCount > 0 );
1978 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1979 COM_ExternalLockDelete(externalLock);
1982 /****************************************************************************
1983 * Public - Method that frees the content of the list.
1985 static void COM_ExternalLockFreeList()
1987 COM_ExternalLock *head;
1989 head = elList.head; /* grab it by the head */
1990 while ( head != EL_END_OF_LIST ) {
1991 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1992 head = elList.head; /* get the new head... */
1996 /****************************************************************************
1997 * Public - Method that dump the content of the list.
1999 void COM_ExternalLockDump()
2001 COM_ExternalLock *current = elList.head;
2003 DPRINTF("\nExternal lock list contains:\n");
2005 while ( current != EL_END_OF_LIST ) {
2006 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2008 /* Skip to the next item */
2009 current = current->next;
2013 /******************************************************************************
2014 * CoLockObjectExternal [OLE32.@]
2016 HRESULT WINAPI CoLockObjectExternal(
2017 LPUNKNOWN pUnk, /* [in] object to be locked */
2018 BOOL fLock, /* [in] do lock */
2019 BOOL fLastUnlockReleases) /* [in] unlock all */
2021 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2022 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2026 * Increment the external lock coutner, COM_ExternalLockAddRef also
2027 * increment the object's internal lock counter.
2029 COM_ExternalLockAddRef( pUnk);
2032 * Decrement the external lock coutner, COM_ExternalLockRelease also
2033 * decrement the object's internal lock counter.
2035 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2041 /***********************************************************************
2042 * CoInitializeWOW (OLE32.@)
2044 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
2045 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2049 /***********************************************************************
2050 * CoGetState [OLE32.@]
2052 * Retrieves the thread state object previously stored by CoSetState().
2055 * ppv [I] Address where pointer to object will be stored.
2059 * Failure: E_OUTOFMEMORY.
2062 * Crashes on all invalid ppv addresses, including NULL.
2063 * If the function returns a non-NULL object then the caller must release its
2064 * reference on the object when the object is no longer required.
2069 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2071 struct oletls *info = COM_CurrentInfo();
2072 if (!info) return E_OUTOFMEMORY;
2078 IUnknown_AddRef(info->state);
2080 TRACE("apt->state=%p\n", info->state);
2086 /***********************************************************************
2087 * CoSetState [OLE32.@]
2089 * Sets the thread state object.
2092 * pv [I] Pointer to state object to be stored.
2095 * The system keeps a reference on the object while the object stored.
2099 * Failure: E_OUTOFMEMORY.
2101 HRESULT WINAPI CoSetState(IUnknown * pv)
2103 struct oletls *info = COM_CurrentInfo();
2104 if (!info) return E_OUTOFMEMORY;
2106 if (pv) IUnknown_AddRef(pv);
2110 TRACE("-- release %p now\n", info->state);
2111 IUnknown_Release(info->state);
2120 /******************************************************************************
2121 * OleGetAutoConvert [OLE32.@]
2123 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2131 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2132 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2134 res = REGDB_E_CLASSNOTREG;
2138 /* we can just query for the default value of AutoConvertTo key like that,
2139 without opening the AutoConvertTo key and querying for NULL (default) */
2140 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2142 res = REGDB_E_KEYMISSING;
2145 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2146 CLSIDFromString(wbuf,pClsidNew);
2148 if (hkey) RegCloseKey(hkey);
2152 /******************************************************************************
2153 * OleSetAutoConvert [OLE32.@]
2155 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2158 char buf[200], szClsidNew[200];
2161 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2162 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2163 WINE_StringFromCLSID(clsidNew, szClsidNew);
2164 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2166 res = REGDB_E_CLASSNOTREG;
2169 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2171 res = REGDB_E_WRITEREGDB;
2176 if (hkey) RegCloseKey(hkey);
2180 /******************************************************************************
2181 * OleDoAutoConvert [OLE32.@]
2183 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2185 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2189 /******************************************************************************
2190 * CoTreatAsClass [OLE32.@]
2192 * Sets TreatAs value of a class
2194 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2198 char szClsidNew[39];
2200 char auto_treat_as[39];
2201 LONG auto_treat_as_size = sizeof(auto_treat_as);
2204 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2205 WINE_StringFromCLSID(clsidNew, szClsidNew);
2206 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2208 res = REGDB_E_CLASSNOTREG;
2211 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2213 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2214 !__CLSIDFromStringA(auto_treat_as, &id))
2216 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2218 res = REGDB_E_WRITEREGDB;
2224 RegDeleteKeyA(hkey, "TreatAs");
2228 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2230 res = REGDB_E_WRITEREGDB;
2235 if (hkey) RegCloseKey(hkey);
2239 /******************************************************************************
2240 * CoGetTreatAsClass [OLE32.@]
2242 * Reads the TreatAs value from a class.
2244 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2247 char buf[200], szClsidNew[200];
2249 LONG len = sizeof(szClsidNew);
2251 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2252 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2253 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2255 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2257 res = REGDB_E_CLASSNOTREG;
2260 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2265 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2267 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2269 if (hkey) RegCloseKey(hkey);
2274 /***********************************************************************
2275 * IsEqualGUID [OLE32.@]
2277 * Compares two Unique Identifiers.
2283 BOOL WINAPI IsEqualGUID(
2284 REFGUID rguid1, /* [in] unique id 1 */
2285 REFGUID rguid2 /* [in] unique id 2 */
2288 return !memcmp(rguid1,rguid2,sizeof(GUID));
2291 /***********************************************************************
2292 * CoInitializeSecurity [OLE32.@]
2294 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2295 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2296 void* pReserved1, DWORD dwAuthnLevel,
2297 DWORD dwImpLevel, void* pReserved2,
2298 DWORD dwCapabilities, void* pReserved3)
2300 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2301 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2302 dwCapabilities, pReserved3);
2306 /***********************************************************************
2307 * CoSuspendClassObjects [OLE32.@]
2309 HRESULT WINAPI CoSuspendClassObjects(void)
2315 /***********************************************************************
2316 * CoAddRefServerProcess [OLE32.@]
2318 ULONG WINAPI CoAddRefServerProcess(void)
2324 /***********************************************************************
2325 * CoReleaseServerProcess [OLE32.@]
2327 ULONG WINAPI CoReleaseServerProcess(void)