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 * - Implement the service control manager (in rpcss) to keep track
32 * of registered class objects: ISCM::ServerRegisterClsid et al
33 * - Implement the OXID resolver so we don't need magic endpoint names for
34 * clients and servers to meet up
36 * - Pump the message loop during RPC calls.
37 * - Call IMessageFilter functions.
39 * - Make all ole interface marshaling use NDR to be wire compatible with
41 * - Use & interpret ORPCTHIS & ORPCTHAT.
54 #define NONAMELESSUNION
55 #define NONAMELESSSTRUCT
67 #include "wine/unicode.h"
69 #include "compobj_private.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(ole);
75 typedef LPCSTR LPCOLESTR16;
77 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
79 /****************************************************************************
80 * This section defines variables internal to the COM module.
82 * TODO: Most of these things will have to be made thread-safe.
85 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
86 static void COM_RevokeAllClasses(void);
88 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
90 APARTMENT *MTA; /* protected by csApartment */
91 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
93 static CRITICAL_SECTION csApartment;
94 static CRITICAL_SECTION_DEBUG critsect_debug =
97 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
98 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
100 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
103 * This lock count counts the number of times CoInitialize is called. It is
104 * decreased every time CoUninitialize is called. When it hits 0, the COM
105 * libraries are freed
107 static LONG s_COMLockCount = 0;
110 * This linked list contains the list of registered class objects. These
111 * are mostly used to register the factories for out-of-proc servers of OLE
114 * TODO: Make this data structure aware of inter-process communication. This
115 * means that parts of this will be exported to the Wine Server.
117 typedef struct tagRegisteredClass
119 CLSID classIdentifier;
120 LPUNKNOWN classObject;
124 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
125 struct tagRegisteredClass* nextClass;
128 static RegisteredClass* firstRegisteredClass = NULL;
130 static CRITICAL_SECTION csRegisteredClassList;
131 static CRITICAL_SECTION_DEBUG class_cs_debug =
133 0, 0, &csRegisteredClassList,
134 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
135 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
137 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
139 /*****************************************************************************
140 * This section contains OpenDllList definitions
142 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
143 * other functions that do LoadLibrary _without_ giving back a HMODULE.
144 * Without this list these handles would never be freed.
146 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
147 * next unload-call but not before 600 sec.
150 typedef struct tagOpenDll {
152 struct tagOpenDll *next;
155 static OpenDll *openDllList = NULL; /* linked list of open dlls */
157 static CRITICAL_SECTION csOpenDllList;
158 static CRITICAL_SECTION_DEBUG dll_cs_debug =
160 0, 0, &csOpenDllList,
161 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
162 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
164 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
166 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
167 '0','x','#','#','#','#','#','#','#','#',' ',0};
168 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
170 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
171 static void COMPOBJ_DllList_FreeUnused(int Timeout);
173 static void COMPOBJ_InitProcess( void )
177 /* Dispatching to the correct thread in an apartment is done through
178 * window messages rather than RPC transports. When an interface is
179 * marshalled into another apartment in the same process, a window of the
180 * following class is created. The *caller* of CoMarshalInterface (ie the
181 * application) is responsible for pumping the message loop in that thread.
182 * The WM_USER messages which point to the RPCs are then dispatched to
183 * COM_AptWndProc by the user's code from the apartment in which the interface
186 memset(&wclass, 0, sizeof(wclass));
187 wclass.lpfnWndProc = apartment_wndproc;
188 wclass.hInstance = OLE32_hInstance;
189 wclass.lpszClassName = wszAptWinClass;
190 RegisterClassW(&wclass);
193 static void COMPOBJ_UninitProcess( void )
195 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
198 static void COM_TlsDestroy()
200 struct oletls *info = NtCurrentTeb()->ReservedForOle;
203 if (info->apt) apartment_release(info->apt);
204 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
205 if (info->state) IUnknown_Release(info->state);
206 HeapFree(GetProcessHeap(), 0, info);
207 NtCurrentTeb()->ReservedForOle = NULL;
211 /******************************************************************************
215 /* allocates memory and fills in the necessary fields for a new apartment
217 static APARTMENT *apartment_construct(DWORD model)
221 TRACE("creating new apartment, model=%ld\n", model);
223 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
224 apt->tid = GetCurrentThreadId();
225 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
226 GetCurrentProcess(), &apt->thread,
227 THREAD_ALL_ACCESS, FALSE, 0);
229 list_init(&apt->proxies);
230 list_init(&apt->stubmgrs);
233 apt->remunk_exported = FALSE;
235 InitializeCriticalSection(&apt->cs);
236 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
240 if (model & COINIT_APARTMENTTHREADED)
242 /* FIXME: should be randomly generated by in an RPC call to rpcss */
243 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
244 apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
246 0, 0, OLE32_hInstance, NULL);
250 /* FIXME: should be randomly generated by in an RPC call to rpcss */
251 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
254 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
256 /* the locking here is not currently needed for the MTA case, but it
257 * doesn't hurt and makes the code simpler */
258 EnterCriticalSection(&csApartment);
259 list_add_head(&apts, &apt->entry);
260 LeaveCriticalSection(&csApartment);
265 /* gets and existing apartment if one exists or otherwise creates an apartment
266 * structure which stores OLE apartment-local information and stores a pointer
267 * to it in the thread-local storage */
268 static APARTMENT *apartment_get_or_create(DWORD model)
270 APARTMENT *apt = COM_CurrentApt();
274 if (model & COINIT_APARTMENTTHREADED)
276 apt = apartment_construct(model);
277 COM_CurrentInfo()->apt = apt;
281 EnterCriticalSection(&csApartment);
283 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
284 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
288 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
289 apartment_addref(MTA);
292 MTA = apartment_construct(model);
295 COM_CurrentInfo()->apt = apt;
297 LeaveCriticalSection(&csApartment);
304 DWORD apartment_addref(struct apartment *apt)
306 DWORD refs = InterlockedIncrement(&apt->refs);
307 TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
311 DWORD apartment_release(struct apartment *apt)
315 EnterCriticalSection(&csApartment);
317 ret = InterlockedDecrement(&apt->refs);
318 TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
319 /* destruction stuff that needs to happen under csApartment CS */
322 if (apt == MTA) MTA = NULL;
323 list_remove(&apt->entry);
326 LeaveCriticalSection(&csApartment);
330 struct list *cursor, *cursor2;
332 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
334 /* no locking is needed for this apartment, because no other thread
335 * can access it at this point */
337 apartment_disconnectproxies(apt);
339 if (apt->win) DestroyWindow(apt->win);
341 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
343 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
344 /* release the implicit reference given by the fact that the
345 * stub has external references (it must do since it is in the
346 * stub manager list in the apartment and all non-apartment users
347 * must have a ref on the apartment and so it cannot be destroyed).
349 stub_manager_int_release(stubmgr);
352 /* if this assert fires, then another thread took a reference to a
353 * stub manager without taking a reference to the containing
354 * apartment, which it must do. */
355 assert(list_empty(&apt->stubmgrs));
357 if (apt->filter) IUnknown_Release(apt->filter);
359 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
360 DeleteCriticalSection(&apt->cs);
361 CloseHandle(apt->thread);
363 HeapFree(GetProcessHeap(), 0, apt);
369 /* The given OXID must be local to this process:
371 * The ref parameter is here mostly to ensure people remember that
372 * they get one, you should normally take a ref for thread safety.
374 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
376 APARTMENT *result = NULL;
379 EnterCriticalSection(&csApartment);
380 LIST_FOR_EACH( cursor, &apts )
382 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
383 if (apt->oxid == oxid)
386 if (ref) apartment_addref(result);
390 LeaveCriticalSection(&csApartment);
395 /* gets the apartment which has a given creator thread ID. The caller must
396 * release the reference from the apartment as soon as the apartment pointer
397 * is no longer required. */
398 APARTMENT *apartment_findfromtid(DWORD tid)
400 APARTMENT *result = NULL;
403 EnterCriticalSection(&csApartment);
404 LIST_FOR_EACH( cursor, &apts )
406 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
410 apartment_addref(result);
414 LeaveCriticalSection(&csApartment);
419 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
424 return RPC_ExecuteCall((struct dispatch_params *)lParam);
426 return DefWindowProcW(hWnd, msg, wParam, lParam);
430 /*****************************************************************************
431 * This section contains OpenDllList implemantation
434 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
441 EnterCriticalSection( &csOpenDllList );
443 if (openDllList == NULL) {
444 /* empty list -- add first node */
445 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
446 openDllList->hLibrary=hLibrary;
447 openDllList->next = NULL;
449 /* search for this dll */
451 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
452 if (ptr->hLibrary == hLibrary) {
458 /* dll not found, add it */
460 openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
461 openDllList->hLibrary = hLibrary;
462 openDllList->next = tmp;
466 LeaveCriticalSection( &csOpenDllList );
469 static void COMPOBJ_DllList_FreeUnused(int Timeout)
471 OpenDll *curr, *next, *prev = NULL;
472 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
473 DllCanUnloadNowFunc DllCanUnloadNow;
477 EnterCriticalSection( &csOpenDllList );
479 for (curr = openDllList; curr != NULL; ) {
480 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
482 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
485 TRACE("freeing %p\n", curr->hLibrary);
486 FreeLibrary(curr->hLibrary);
488 HeapFree(GetProcessHeap(), 0, curr);
489 if (curr == openDllList) {
502 LeaveCriticalSection( &csOpenDllList );
505 /******************************************************************************
506 * CoBuildVersion [OLE32.@]
507 * CoBuildVersion [COMPOBJ.1]
509 * Gets the build version of the DLL.
514 * Current build version, hiword is majornumber, loword is minornumber
516 DWORD WINAPI CoBuildVersion(void)
518 TRACE("Returning version %d, build %d.\n", rmm, rup);
519 return (rmm<<16)+rup;
522 /******************************************************************************
523 * CoInitialize [OLE32.@]
525 * Initializes the COM libraries by calling CoInitializeEx with
526 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
529 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
532 * Success: S_OK if not already initialized, S_FALSE otherwise.
533 * Failure: HRESULT code.
538 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
541 * Just delegate to the newer method.
543 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
546 /******************************************************************************
547 * CoInitializeEx [OLE32.@]
549 * Initializes the COM libraries.
552 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
553 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
556 * S_OK if successful,
557 * S_FALSE if this function was called already.
558 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
563 * The behavior used to set the IMalloc used for memory management is
565 * The dwCoInit parameter must specify of of the following apartment
567 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
568 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
569 * The parameter may also specify zero or more of the following flags:
570 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
571 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
576 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
581 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
583 if (lpReserved!=NULL)
585 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
589 * Check the lock count. If this is the first time going through the initialize
590 * process, we have to initialize the libraries.
592 * And crank-up that lock count.
594 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
597 * Initialize the various COM libraries and data structures.
599 TRACE("() - Initializing the COM libraries\n");
601 /* we may need to defer this until after apartment initialisation */
602 RunningObjectTableImpl_Initialize();
605 if (!(apt = COM_CurrentInfo()->apt))
607 apt = apartment_get_or_create(dwCoInit);
608 if (!apt) return E_OUTOFMEMORY;
610 else if (dwCoInit != apt->model)
612 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
613 code then we are probably using the wrong threading model to implement that API. */
614 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
615 return RPC_E_CHANGED_MODE;
620 COM_CurrentInfo()->inits++;
625 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
626 pending RPCs are ignored. Non-COM messages are discarded at this point.
628 static void COM_FlushMessageQueue(void)
631 APARTMENT *apt = COM_CurrentApt();
633 if (!apt || !apt->win) return;
635 TRACE("Flushing STA message queue\n");
637 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
639 if (message.hwnd != apt->win)
641 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
645 TranslateMessage(&message);
646 DispatchMessageA(&message);
650 /***********************************************************************
651 * CoUninitialize [OLE32.@]
653 * This method will decrement the refcount on the current apartment, freeing
654 * the resources associated with it if it is the last thread in the apartment.
655 * If the last apartment is freed, the function will additionally release
656 * any COM resources associated with the process.
666 void WINAPI CoUninitialize(void)
668 struct oletls * info = COM_CurrentInfo();
673 /* will only happen on OOM */
679 ERR("Mismatched CoUninitialize\n");
685 apartment_release(info->apt);
690 * Decrease the reference count.
691 * If we are back to 0 locks on the COM library, make sure we free
692 * all the associated data structures.
694 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
697 TRACE("() - Releasing the COM libraries\n");
699 RunningObjectTableImpl_UnInitialize();
701 /* Release the references to the registered class objects */
702 COM_RevokeAllClasses();
704 /* This will free the loaded COM Dlls */
705 CoFreeAllLibraries();
707 /* This ensures we deal with any pending RPCs */
708 COM_FlushMessageQueue();
710 else if (lCOMRefCnt<1) {
711 ERR( "CoUninitialize() - not CoInitialized.\n" );
712 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
716 /******************************************************************************
717 * CoDisconnectObject [OLE32.@]
718 * CoDisconnectObject [COMPOBJ.15]
720 * Disconnects all connections to this object from remote processes. Dispatches
721 * pending RPCs while blocking new RPCs from occurring, and then calls
722 * IMarshal::DisconnectObject on the given object.
724 * Typically called when the object server is forced to shut down, for instance by
728 * lpUnk [I] The object whose stub should be disconnected.
729 * reserved [I] Reserved. Should be set to 0.
733 * Failure: HRESULT code.
736 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
738 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
744 TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
746 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
749 hr = IMarshal_DisconnectObject(marshal, reserved);
750 IMarshal_Release(marshal);
754 apt = COM_CurrentApt();
756 return CO_E_NOTINITIALIZED;
758 apartment_disconnectobject(apt, lpUnk);
760 /* Note: native is pretty broken here because it just silently
761 * fails, without returning an appropriate error code if the object was
762 * not found, making apps think that the object was disconnected, when
763 * it actually wasn't */
768 /******************************************************************************
769 * CoCreateGuid [OLE32.@]
771 * Simply forwards to UuidCreate in RPCRT4.
774 * pguid [O] Points to the GUID to initialize.
778 * Failure: HRESULT code.
783 HRESULT WINAPI CoCreateGuid(GUID *pguid)
785 return UuidCreate(pguid);
788 /******************************************************************************
789 * CLSIDFromString [OLE32.@]
790 * IIDFromString [OLE32.@]
792 * Converts a unique identifier from its string representation into
796 * idstr [I] The string representation of the GUID.
797 * id [O] GUID converted from the string.
801 * CO_E_CLASSSTRING if idstr is not a valid CLSID
805 * In Windows, if idstr is not a valid CLSID string then it gets
806 * treated as a ProgID. Wine currently doesn't do this. If idstr is
807 * NULL it's treated as an all-zero GUID.
812 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
814 const BYTE *s = (const BYTE *) idstr;
819 s = "{00000000-0000-0000-0000-000000000000}";
820 else { /* validate the CLSID string */
823 return CO_E_CLASSSTRING;
825 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
826 return CO_E_CLASSSTRING;
828 for (i=1; i<37; i++) {
829 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
830 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
831 ((s[i] >= 'a') && (s[i] <= 'f')) ||
832 ((s[i] >= 'A') && (s[i] <= 'F'))))
833 return CO_E_CLASSSTRING;
837 TRACE("%s -> %p\n", s, id);
839 /* quick lookup table */
840 memset(table, 0, 256);
842 for (i = 0; i < 10; i++) {
845 for (i = 0; i < 6; i++) {
846 table['A' + i] = i+10;
847 table['a' + i] = i+10;
850 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
852 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
853 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
854 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
855 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
857 /* these are just sequential bytes */
858 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
859 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
860 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
861 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
862 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
863 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
864 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
865 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
870 /*****************************************************************************/
872 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
877 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
878 return CO_E_CLASSSTRING;
881 ret = __CLSIDFromStringA(xid,id);
882 if(ret != S_OK) { /* It appears a ProgID is also valid */
883 ret = CLSIDFromProgID(idstr, id);
888 /* Converts a GUID into the respective string representation. */
889 HRESULT WINE_StringFromCLSID(
890 const CLSID *id, /* [in] GUID to be converted */
891 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
893 static const char *hex = "0123456789ABCDEF";
898 { ERR("called with id=Null\n");
903 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
904 id->Data1, id->Data2, id->Data3,
905 id->Data4[0], id->Data4[1]);
909 for (i = 2; i < 8; i++) {
910 *s++ = hex[id->Data4[i]>>4];
911 *s++ = hex[id->Data4[i] & 0xf];
917 TRACE("%p->%s\n", id, idstr);
923 /******************************************************************************
924 * StringFromCLSID [OLE32.@]
925 * StringFromIID [OLE32.@]
927 * Converts a GUID into the respective string representation.
928 * The target string is allocated using the OLE IMalloc.
931 * id [I] the GUID to be converted.
932 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
939 * StringFromGUID2, CLSIDFromString
941 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
947 if ((ret = CoGetMalloc(0,&mllc)))
950 ret=WINE_StringFromCLSID(id,buf);
952 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
953 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
954 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
959 /******************************************************************************
960 * StringFromGUID2 [OLE32.@]
961 * StringFromGUID2 [COMPOBJ.76]
963 * Modified version of StringFromCLSID that allows you to specify max
967 * id [I] GUID to convert to string.
968 * str [O] Buffer where the result will be stored.
969 * cmax [I] Size of the buffer in characters.
972 * Success: The length of the resulting string in characters.
975 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
979 if (WINE_StringFromCLSID(id,xguid))
981 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
984 /******************************************************************************
985 * ProgIDFromCLSID [OLE32.@]
987 * Converts a class id into the respective program ID.
990 * clsid [I] Class ID, as found in registry.
991 * lplpszProgID [O] Associated ProgID.
996 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
998 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1000 char strCLSID[50], *buf, *buf2;
1006 WINE_StringFromCLSID(clsid, strCLSID);
1008 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
1009 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
1010 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1011 ret = REGDB_E_CLASSNOTREG;
1013 HeapFree(GetProcessHeap(), 0, buf);
1017 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1019 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1020 ret = REGDB_E_CLASSNOTREG;
1024 if (CoGetMalloc(0,&mllc))
1025 ret = E_OUTOFMEMORY;
1028 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1029 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1030 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1033 HeapFree(GetProcessHeap(), 0, buf2);
1040 /******************************************************************************
1041 * CLSIDFromProgID [COMPOBJ.61]
1043 * Converts a program ID into the respective GUID.
1046 * progid [I] program id as found in registry
1047 * riid [O] associated CLSID
1051 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1053 HRESULT WINAPI CLSIDFromProgID16(LPCOLESTR16 progid, LPCLSID riid)
1060 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1061 sprintf(buf,"%s\\CLSID",progid);
1062 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1063 HeapFree(GetProcessHeap(),0,buf);
1064 return CO_E_CLASSSTRING;
1066 HeapFree(GetProcessHeap(),0,buf);
1067 buf2len = sizeof(buf2);
1068 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1070 return CO_E_CLASSSTRING;
1073 return __CLSIDFromStringA(buf2,riid);
1076 /******************************************************************************
1077 * CLSIDFromProgID [OLE32.@]
1079 * Converts a program id into the respective GUID.
1082 * progid [I] Unicode program ID, as found in registry.
1083 * riid [O] Associated CLSID.
1087 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1089 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1091 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1093 DWORD buf2len = sizeof(buf2);
1096 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1097 strcpyW( buf, progid );
1098 strcatW( buf, clsidW );
1099 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1101 HeapFree(GetProcessHeap(),0,buf);
1102 return CO_E_CLASSSTRING;
1104 HeapFree(GetProcessHeap(),0,buf);
1106 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1109 return CO_E_CLASSSTRING;
1112 return __CLSIDFromStringA(buf2,riid);
1117 /*****************************************************************************
1118 * CoGetPSClsid [OLE32.@]
1120 * Retrieves the CLSID of the proxy/stub factory that implements
1121 * IPSFactoryBuffer for the specified interface.
1124 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1125 * pclsid [O] Where to store returned proxy/stub CLSID.
1130 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1134 * The standard marshaller activates the object with the CLSID
1135 * returned and uses the CreateProxy and CreateStub methods on its
1136 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1139 * CoGetPSClsid determines this CLSID by searching the
1140 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1141 * in the registry and any interface id registered by
1142 * CoRegisterPSClsid within the current process.
1146 * We only search the registry, not ids registered with
1147 * CoRegisterPSClsid.
1148 * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but
1149 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1150 * considered a bug in native unless an application depends on this (unlikely).
1152 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1154 char *buf, buf2[40];
1158 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1160 /* Get the input iid as a string */
1161 WINE_StringFromCLSID(riid, buf2);
1162 /* Allocate memory for the registry key we will construct.
1163 (length of iid string plus constant length of static text */
1164 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1166 return E_OUTOFMEMORY;
1168 /* Construct the registry key we want */
1169 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1171 /* Open the key.. */
1172 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1174 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1175 HeapFree(GetProcessHeap(),0,buf);
1176 return REGDB_E_IIDNOTREG;
1178 HeapFree(GetProcessHeap(),0,buf);
1180 /* ... Once we have the key, query the registry to get the
1181 value of CLSID as a string, and convert it into a
1182 proper CLSID structure to be passed back to the app */
1183 buf2len = sizeof(buf2);
1184 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1187 return REGDB_E_IIDNOTREG;
1191 /* We have the CLSid we want back from the registry as a string, so
1192 lets convert it into a CLSID structure */
1193 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1194 return REGDB_E_IIDNOTREG;
1196 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1202 /***********************************************************************
1203 * WriteClassStm (OLE32.@)
1205 * Writes a CLSID to a stream.
1208 * pStm [I] Stream to write to.
1209 * rclsid [I] CLSID to write.
1213 * Failure: HRESULT code.
1215 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1217 TRACE("(%p,%p)\n",pStm,rclsid);
1220 return E_INVALIDARG;
1222 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1225 /***********************************************************************
1226 * ReadClassStm (OLE32.@)
1228 * Reads a CLSID from a stream.
1231 * pStm [I] Stream to read from.
1232 * rclsid [O] CLSID to read.
1236 * Failure: HRESULT code.
1238 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1243 TRACE("(%p,%p)\n",pStm,pclsid);
1246 return E_INVALIDARG;
1248 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1253 if (nbByte != sizeof(CLSID))
1261 * COM_GetRegisteredClassObject
1263 * This internal method is used to scan the registered class list to
1264 * find a class object.
1267 * rclsid Class ID of the class to find.
1268 * dwClsContext Class context to match.
1269 * ppv [out] returns a pointer to the class object. Complying
1270 * to normal COM usage, this method will increase the
1271 * reference count on this object.
1273 static HRESULT COM_GetRegisteredClassObject(
1278 HRESULT hr = S_FALSE;
1279 RegisteredClass* curClass;
1281 EnterCriticalSection( &csRegisteredClassList );
1289 * Iterate through the whole list and try to match the class ID.
1291 curClass = firstRegisteredClass;
1293 while (curClass != 0)
1296 * Check if we have a match on the class ID.
1298 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1301 * Since we don't do out-of process or DCOM just right away, let's ignore the
1306 * We have a match, return the pointer to the class object.
1308 *ppUnk = curClass->classObject;
1310 IUnknown_AddRef(curClass->classObject);
1317 * Step to the next class in the list.
1319 curClass = curClass->nextClass;
1323 LeaveCriticalSection( &csRegisteredClassList );
1325 * If we get to here, we haven't found our class.
1330 /******************************************************************************
1331 * CoRegisterClassObject [OLE32.@]
1333 * Registers the class object for a given class ID. Servers housed in EXE
1334 * files use this method instead of exporting DllGetClassObject to allow
1335 * other code to connect to their objects.
1338 * rclsid [I] CLSID of the object to register.
1339 * pUnk [I] IUnknown of the object.
1340 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1341 * flags [I] REGCLS flags indicating how connections are made.
1342 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1346 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1347 * CO_E_OBJISREG if the object is already registered. We should not return this.
1350 * CoRevokeClassObject, CoGetClassObject
1353 * MSDN claims that multiple interface registrations are legal, but we
1354 * can't do that with our current implementation.
1356 HRESULT WINAPI CoRegisterClassObject(
1361 LPDWORD lpdwRegister)
1363 RegisteredClass* newClass;
1364 LPUNKNOWN foundObject;
1367 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1368 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1370 if ( (lpdwRegister==0) || (pUnk==0) )
1371 return E_INVALIDARG;
1373 if (!COM_CurrentApt())
1375 ERR("COM was not initialized\n");
1376 return CO_E_NOTINITIALIZED;
1382 * First, check if the class is already registered.
1383 * If it is, this should cause an error.
1385 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1387 IUnknown_Release(foundObject);
1388 return CO_E_OBJISREG;
1391 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1392 if ( newClass == NULL )
1393 return E_OUTOFMEMORY;
1395 EnterCriticalSection( &csRegisteredClassList );
1397 newClass->classIdentifier = *rclsid;
1398 newClass->runContext = dwClsContext;
1399 newClass->connectFlags = flags;
1401 * Use the address of the chain node as the cookie since we are sure it's
1402 * unique. FIXME: not on 64-bit platforms.
1404 newClass->dwCookie = (DWORD)newClass;
1405 newClass->nextClass = firstRegisteredClass;
1408 * Since we're making a copy of the object pointer, we have to increase its
1411 newClass->classObject = pUnk;
1412 IUnknown_AddRef(newClass->classObject);
1414 firstRegisteredClass = newClass;
1415 LeaveCriticalSection( &csRegisteredClassList );
1417 *lpdwRegister = newClass->dwCookie;
1419 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1420 IClassFactory *classfac;
1422 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1423 (LPVOID*)&classfac);
1426 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1428 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1429 IUnknown_Release(classfac);
1432 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1433 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1434 MSHLFLAGS_TABLESTRONG);
1436 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1437 IUnknown_Release(classfac);
1441 IUnknown_Release(classfac);
1443 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1448 /***********************************************************************
1449 * CoRevokeClassObject [OLE32.@]
1451 * Removes a class object from the class registry.
1454 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1458 * Failure: HRESULT code.
1461 * CoRegisterClassObject
1463 HRESULT WINAPI CoRevokeClassObject(
1466 HRESULT hr = E_INVALIDARG;
1467 RegisteredClass** prevClassLink;
1468 RegisteredClass* curClass;
1470 TRACE("(%08lx)\n",dwRegister);
1472 EnterCriticalSection( &csRegisteredClassList );
1475 * Iterate through the whole list and try to match the cookie.
1477 curClass = firstRegisteredClass;
1478 prevClassLink = &firstRegisteredClass;
1480 while (curClass != 0)
1483 * Check if we have a match on the cookie.
1485 if (curClass->dwCookie == dwRegister)
1488 * Remove the class from the chain.
1490 *prevClassLink = curClass->nextClass;
1493 * Release the reference to the class object.
1495 IUnknown_Release(curClass->classObject);
1497 if (curClass->pMarshaledData)
1500 memset(&zero, 0, sizeof(zero));
1501 /* FIXME: stop local server thread */
1502 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1503 CoReleaseMarshalData(curClass->pMarshaledData);
1507 * Free the memory used by the chain node.
1509 HeapFree(GetProcessHeap(), 0, curClass);
1516 * Step to the next class in the list.
1518 prevClassLink = &(curClass->nextClass);
1519 curClass = curClass->nextClass;
1523 LeaveCriticalSection( &csRegisteredClassList );
1525 * If we get to here, we haven't found our class.
1530 /***********************************************************************
1531 * compobj_RegReadPath [internal]
1533 * Reads a registry value and expands it when necessary
1536 compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1542 DWORD dwLength = dstlen;
1544 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1545 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1546 if (keytype == REG_EXPAND_SZ) {
1547 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1549 lstrcpynA(dst, src, dstlen);
1557 /***********************************************************************
1558 * CoGetClassObject [COMPOBJ.7]
1559 * CoGetClassObject [OLE32.@]
1561 * FIXME. If request allows of several options and there is a failure
1562 * with one (other than not being registered) do we try the
1563 * others or return failure? (E.g. inprocess is registered but
1564 * the DLL is not found but the server version works)
1566 HRESULT WINAPI CoGetClassObject(
1567 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1568 REFIID iid, LPVOID *ppv
1570 LPUNKNOWN regClassObject;
1571 HRESULT hres = E_UNEXPECTED;
1574 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1575 DllGetClassObjectFunc DllGetClassObject;
1577 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1579 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1582 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1583 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1587 * First, try and see if we can't match the class ID with one of the
1588 * registered classes.
1590 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1593 * Get the required interface from the retrieved pointer.
1595 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1598 * Since QI got another reference on the pointer, we want to release the
1599 * one we already have. If QI was unsuccessful, this will release the object. This
1600 * is good since we are not returning it in the "out" parameter.
1602 IUnknown_Release(regClassObject);
1607 /* first try: in-process */
1608 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1609 char keyname[MAX_PATH];
1610 char dllpath[MAX_PATH+1];
1612 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1614 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1615 /* failure: CLSID is not found in registry */
1616 WARN("class %s not registered inproc\n", xclsid);
1617 hres = REGDB_E_CLASSNOTREG;
1619 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1620 /* failure: DLL could not be loaded */
1621 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1622 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1623 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1624 /* failure: the dll did not export DllGetClassObject */
1625 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1626 FreeLibrary( hLibrary );
1627 hres = CO_E_DLLNOTFOUND;
1629 /* OK: get the ClassObject */
1630 COMPOBJ_DLLList_Add( hLibrary );
1631 return DllGetClassObject(rclsid, iid, ppv);
1636 /* Next try out of process */
1637 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1639 return RPC_GetLocalClassObject(rclsid,iid,ppv);
1642 /* Finally try remote: this requires networked DCOM (a lot of work) */
1643 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1645 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1646 hres = E_NOINTERFACE;
1651 /***********************************************************************
1652 * CoResumeClassObjects (OLE32.@)
1654 * Resumes all class objects registered with REGCLS_SUSPENDED.
1658 * Failure: HRESULT code.
1660 HRESULT WINAPI CoResumeClassObjects(void)
1666 /***********************************************************************
1667 * GetClassFile (OLE32.@)
1669 * This function supplies the CLSID associated with the given filename.
1671 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1675 int nbElm, length, i;
1677 LPOLESTR *pathDec=0,absFile=0,progId=0;
1679 static const WCHAR bkslashW[] = {'\\',0};
1680 static const WCHAR dotW[] = {'.',0};
1682 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1684 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1685 if((StgIsStorageFile(filePathName))==S_OK){
1687 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1690 res=ReadClassStg(pstg,pclsid);
1692 IStorage_Release(pstg);
1696 /* if the file is not a storage object then attemps to match various bits in the file against a
1697 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1700 for(i=0;i<nFileTypes;i++)
1702 for(i=0;j<nPatternsForType;j++){
1707 pat=ReadPatternFromRegistry(i,j);
1708 hFile=CreateFileW(filePathName,,,,,,hFile);
1709 SetFilePosition(hFile,pat.offset);
1710 ReadFile(hFile,buf,pat.size,&r,NULL);
1711 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1713 *pclsid=ReadCLSIDFromRegistry(i);
1719 /* if the above strategies fail then search for the extension key in the registry */
1721 /* get the last element (absolute file) in the path name */
1722 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1723 absFile=pathDec[nbElm-1];
1725 /* failed if the path represente a directory and not an absolute file name*/
1726 if (!lstrcmpW(absFile, bkslashW))
1727 return MK_E_INVALIDEXTENSION;
1729 /* get the extension of the file */
1731 length=lstrlenW(absFile);
1732 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1735 if (!extension || !lstrcmpW(extension, dotW))
1736 return MK_E_INVALIDEXTENSION;
1738 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1740 /* get the progId associated to the extension */
1741 progId = CoTaskMemAlloc(sizeProgId);
1742 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1744 if (res==ERROR_SUCCESS)
1745 /* return the clsid associated to the progId */
1746 res= CLSIDFromProgID(progId,pclsid);
1748 for(i=0; pathDec[i]!=NULL;i++)
1749 CoTaskMemFree(pathDec[i]);
1750 CoTaskMemFree(pathDec);
1752 CoTaskMemFree(progId);
1754 if (res==ERROR_SUCCESS)
1757 return MK_E_INVALIDEXTENSION;
1759 /***********************************************************************
1760 * CoCreateInstance [COMPOBJ.13]
1761 * CoCreateInstance [OLE32.@]
1763 HRESULT WINAPI CoCreateInstance(
1765 LPUNKNOWN pUnkOuter,
1771 LPCLASSFACTORY lpclf = 0;
1773 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1782 * Initialize the "out" parameter
1787 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1788 * Rather than create a class factory, we can just check for it here
1790 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1791 if (StdGlobalInterfaceTableInstance == NULL)
1792 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1793 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1794 if (hres) return hres;
1796 TRACE("Retrieved GIT (%p)\n", *ppv);
1801 * Get a class factory to construct the object we want.
1803 hres = CoGetClassObject(rclsid,
1810 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1811 debugstr_guid(rclsid),hres);
1816 * Create the object and don't forget to release the factory
1818 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1819 IClassFactory_Release(lpclf);
1821 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1822 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1827 /***********************************************************************
1828 * CoCreateInstanceEx [OLE32.@]
1830 HRESULT WINAPI CoCreateInstanceEx(
1832 LPUNKNOWN pUnkOuter,
1834 COSERVERINFO* pServerInfo,
1838 IUnknown* pUnk = NULL;
1841 ULONG successCount = 0;
1846 if ( (cmq==0) || (pResults==NULL))
1847 return E_INVALIDARG;
1849 if (pServerInfo!=NULL)
1850 FIXME("() non-NULL pServerInfo not supported!\n");
1853 * Initialize all the "out" parameters.
1855 for (index = 0; index < cmq; index++)
1857 pResults[index].pItf = NULL;
1858 pResults[index].hr = E_NOINTERFACE;
1862 * Get the object and get its IUnknown pointer.
1864 hr = CoCreateInstance(rclsid,
1874 * Then, query for all the interfaces requested.
1876 for (index = 0; index < cmq; index++)
1878 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1879 pResults[index].pIID,
1880 (VOID**)&(pResults[index].pItf));
1882 if (pResults[index].hr == S_OK)
1887 * Release our temporary unknown pointer.
1889 IUnknown_Release(pUnk);
1891 if (successCount == 0)
1892 return E_NOINTERFACE;
1894 if (successCount!=cmq)
1895 return CO_S_NOTALLINTERFACES;
1900 /***********************************************************************
1901 * CoLoadLibrary (OLE32.@)
1906 * lpszLibName [I] Path to library.
1907 * bAutoFree [I] Whether the library should automatically be freed.
1910 * Success: Handle to loaded library.
1914 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1916 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1918 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1920 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1923 /***********************************************************************
1924 * CoFreeLibrary [OLE32.@]
1926 * Unloads a library from memory.
1929 * hLibrary [I] Handle to library to unload.
1935 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1937 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1939 FreeLibrary(hLibrary);
1943 /***********************************************************************
1944 * CoFreeAllLibraries [OLE32.@]
1946 * Function for backwards compatibility only. Does nothing.
1952 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1954 void WINAPI CoFreeAllLibraries(void)
1960 /***********************************************************************
1961 * CoFreeUnusedLibraries [OLE32.@]
1962 * CoFreeUnusedLibraries [COMPOBJ.17]
1964 * Frees any unused libraries. Unused are identified as those that return
1965 * S_OK from their DllCanUnloadNow function.
1971 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1973 void WINAPI CoFreeUnusedLibraries(void)
1975 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1976 * through the main apartment's thread to call DllCanUnloadNow */
1977 COMPOBJ_DllList_FreeUnused(0);
1980 /***********************************************************************
1981 * CoFileTimeNow [OLE32.@]
1982 * CoFileTimeNow [COMPOBJ.82]
1984 * Retrieves the current time in FILETIME format.
1987 * lpFileTime [O] The current time.
1992 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1994 GetSystemTimeAsFileTime( lpFileTime );
1998 static void COM_RevokeAllClasses()
2000 EnterCriticalSection( &csRegisteredClassList );
2002 while (firstRegisteredClass!=0)
2004 CoRevokeClassObject(firstRegisteredClass->dwCookie);
2007 LeaveCriticalSection( &csRegisteredClassList );
2010 /******************************************************************************
2011 * CoLockObjectExternal [OLE32.@]
2013 * Increments or decrements the external reference count of a stub object.
2016 * pUnk [I] Stub object.
2017 * fLock [I] If TRUE then increments the external ref-count,
2018 * otherwise decrements.
2019 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2020 * calling CoDisconnectObject.
2024 * Failure: HRESULT code.
2026 HRESULT WINAPI CoLockObjectExternal(
2029 BOOL fLastUnlockReleases)
2031 struct stub_manager *stubmgr;
2032 struct apartment *apt;
2034 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2035 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2037 apt = COM_CurrentApt();
2038 if (!apt) return CO_E_NOTINITIALIZED;
2040 stubmgr = get_stub_manager_from_object(apt, pUnk);
2045 stub_manager_ext_addref(stubmgr, 1);
2047 stub_manager_ext_release(stubmgr, 1);
2049 stub_manager_int_release(stubmgr);
2055 WARN("stub object not found %p\n", pUnk);
2056 /* Note: native is pretty broken here because it just silently
2057 * fails, without returning an appropriate error code, making apps
2058 * think that the object was disconnected, when it actually wasn't */
2063 /***********************************************************************
2064 * CoInitializeWOW (OLE32.@)
2066 * WOW equivalent of CoInitialize?
2075 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2077 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2081 /***********************************************************************
2082 * CoGetState [OLE32.@]
2084 * Retrieves the thread state object previously stored by CoSetState().
2087 * ppv [I] Address where pointer to object will be stored.
2091 * Failure: E_OUTOFMEMORY.
2094 * Crashes on all invalid ppv addresses, including NULL.
2095 * If the function returns a non-NULL object then the caller must release its
2096 * reference on the object when the object is no longer required.
2101 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2103 struct oletls *info = COM_CurrentInfo();
2104 if (!info) return E_OUTOFMEMORY;
2110 IUnknown_AddRef(info->state);
2112 TRACE("apt->state=%p\n", info->state);
2118 /***********************************************************************
2119 * CoSetState [OLE32.@]
2121 * Sets the thread state object.
2124 * pv [I] Pointer to state object to be stored.
2127 * The system keeps a reference on the object while the object stored.
2131 * Failure: E_OUTOFMEMORY.
2133 HRESULT WINAPI CoSetState(IUnknown * pv)
2135 struct oletls *info = COM_CurrentInfo();
2136 if (!info) return E_OUTOFMEMORY;
2138 if (pv) IUnknown_AddRef(pv);
2142 TRACE("-- release %p now\n", info->state);
2143 IUnknown_Release(info->state);
2152 /******************************************************************************
2153 * OleGetAutoConvert [OLE32.@]
2155 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2163 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2164 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2166 res = REGDB_E_CLASSNOTREG;
2170 /* we can just query for the default value of AutoConvertTo key like that,
2171 without opening the AutoConvertTo key and querying for NULL (default) */
2172 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2174 res = REGDB_E_KEYMISSING;
2177 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2178 CLSIDFromString(wbuf,pClsidNew);
2180 if (hkey) RegCloseKey(hkey);
2184 /******************************************************************************
2185 * CoTreatAsClass [OLE32.@]
2187 * Sets the TreatAs value of a class.
2190 * clsidOld [I] Class to set TreatAs value on.
2191 * clsidNew [I] The class the clsidOld should be treated as.
2195 * Failure: HRESULT code.
2200 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2204 char szClsidNew[39];
2206 char auto_treat_as[39];
2207 LONG auto_treat_as_size = sizeof(auto_treat_as);
2210 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2211 WINE_StringFromCLSID(clsidNew, szClsidNew);
2212 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2214 res = REGDB_E_CLASSNOTREG;
2217 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2219 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2220 !__CLSIDFromStringA(auto_treat_as, &id))
2222 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2224 res = REGDB_E_WRITEREGDB;
2230 RegDeleteKeyA(hkey, "TreatAs");
2234 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2236 res = REGDB_E_WRITEREGDB;
2241 if (hkey) RegCloseKey(hkey);
2245 /******************************************************************************
2246 * CoGetTreatAsClass [OLE32.@]
2248 * Gets the TreatAs value of a class.
2251 * clsidOld [I] Class to get the TreatAs value of.
2252 * clsidNew [I] The class the clsidOld should be treated as.
2256 * Failure: HRESULT code.
2261 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2264 char buf[200], szClsidNew[200];
2266 LONG len = sizeof(szClsidNew);
2268 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2269 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2270 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2272 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2274 res = REGDB_E_CLASSNOTREG;
2277 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2282 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2284 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2286 if (hkey) RegCloseKey(hkey);
2291 /******************************************************************************
2292 * CoGetCurrentProcess [OLE32.@]
2293 * CoGetCurrentProcess [COMPOBJ.34]
2295 * Gets the current process ID.
2298 * The current process ID.
2301 * Is DWORD really the correct return type for this function?
2303 DWORD WINAPI CoGetCurrentProcess(void)
2305 return GetCurrentProcessId();
2308 /******************************************************************************
2309 * CoRegisterMessageFilter [OLE32.@]
2311 * Registers a message filter.
2314 * lpMessageFilter [I] Pointer to interface.
2315 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2319 * Failure: HRESULT code.
2321 HRESULT WINAPI CoRegisterMessageFilter(
2322 LPMESSAGEFILTER lpMessageFilter,
2323 LPMESSAGEFILTER *lplpMessageFilter)
2326 if (lplpMessageFilter) {
2327 *lplpMessageFilter = NULL;
2332 /***********************************************************************
2333 * CoIsOle1Class [OLE32.@]
2335 * Determines whether the specified class an OLE v1 class.
2338 * clsid [I] Class to test.
2341 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2343 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2345 FIXME("%s\n", debugstr_guid(clsid));
2349 /***********************************************************************
2350 * IsEqualGUID [OLE32.@]
2352 * Compares two Unique Identifiers.
2355 * rguid1 [I] The first GUID to compare.
2356 * rguid2 [I] The other GUID to compare.
2362 BOOL WINAPI IsEqualGUID(
2366 return !memcmp(rguid1,rguid2,sizeof(GUID));
2369 /***********************************************************************
2370 * CoInitializeSecurity [OLE32.@]
2372 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2373 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2374 void* pReserved1, DWORD dwAuthnLevel,
2375 DWORD dwImpLevel, void* pReserved2,
2376 DWORD dwCapabilities, void* pReserved3)
2378 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2379 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2380 dwCapabilities, pReserved3);
2384 /***********************************************************************
2385 * CoSuspendClassObjects [OLE32.@]
2387 * Suspends all registered class objects to prevent further requests coming in
2388 * for those objects.
2392 * Failure: HRESULT code.
2394 HRESULT WINAPI CoSuspendClassObjects(void)
2400 /***********************************************************************
2401 * CoAddRefServerProcess [OLE32.@]
2403 * Helper function for incrementing the reference count of a local-server
2407 * New reference count.
2409 ULONG WINAPI CoAddRefServerProcess(void)
2415 /***********************************************************************
2416 * CoReleaseServerProcess [OLE32.@]
2418 * Helper function for decrementing the reference count of a local-server
2422 * New reference count.
2424 ULONG WINAPI CoReleaseServerProcess(void)
2430 /***********************************************************************
2431 * CoIsHandlerConnected [OLE32.@]
2433 * Determines whether a proxy is connected to a remote stub.
2436 * pUnk [I] Pointer to object that may or may not be connected.
2439 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
2442 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
2444 FIXME("%p\n", pUnk);
2449 /***********************************************************************
2450 * CoQueryProxyBlanket [OLE32.@]
2452 * Retrieves the security settings being used by a proxy.
2455 * pProxy [I] Pointer to the proxy object.
2456 * pAuthnSvc [O] The type of authentication service.
2457 * pAuthzSvc [O] The type of authorization service.
2458 * ppServerPrincName [O] Optional. The server prinicple name.
2459 * pAuthnLevel [O] The authentication level.
2460 * pImpLevel [O] The impersonation level.
2461 * ppAuthInfo [O] Information specific to the authorization/authentication service.
2462 * pCapabilities [O] Flags affecting the security behaviour.
2466 * Failure: HRESULT code.
2469 * CoCopyProxy, CoSetProxyBlanket.
2471 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2472 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2473 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2475 IClientSecurity *pCliSec;
2478 TRACE("%p\n", pProxy);
2480 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2483 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2484 pAuthzSvc, ppServerPrincName,
2485 pAuthnLevel, pImpLevel, ppAuthInfo,
2487 IClientSecurity_Release(pCliSec);
2490 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2494 /***********************************************************************
2495 * CoSetProxyBlanket [OLE32.@]
2497 * Sets the security settings for a proxy.
2500 * pProxy [I] Pointer to the proxy object.
2501 * AuthnSvc [I] The type of authentication service.
2502 * AuthzSvc [I] The type of authorization service.
2503 * pServerPrincName [I] The server prinicple name.
2504 * AuthnLevel [I] The authentication level.
2505 * ImpLevel [I] The impersonation level.
2506 * pAuthInfo [I] Information specific to the authorization/authentication service.
2507 * Capabilities [I] Flags affecting the security behaviour.
2511 * Failure: HRESULT code.
2514 * CoQueryProxyBlanket, CoCopyProxy.
2516 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2517 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2518 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2520 IClientSecurity *pCliSec;
2523 TRACE("%p\n", pProxy);
2525 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2528 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2529 AuthzSvc, pServerPrincName,
2530 AuthnLevel, ImpLevel, pAuthInfo,
2532 IClientSecurity_Release(pCliSec);
2535 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2539 /***********************************************************************
2540 * CoCopyProxy [OLE32.@]
2545 * pProxy [I] Pointer to the proxy object.
2546 * ppCopy [O] Copy of the proxy.
2550 * Failure: HRESULT code.
2553 * CoQueryProxyBlanket, CoSetProxyBlanket.
2555 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2557 IClientSecurity *pCliSec;
2560 TRACE("%p\n", pProxy);
2562 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2565 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2566 IClientSecurity_Release(pCliSec);
2569 if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2574 /***********************************************************************
2575 * CoWaitForMultipleHandles [OLE32.@]
2577 * Waits for one or more handles to become signaled.
2580 * dwFlags [I] Flags. See notes.
2581 * dwTimeout [I] Timeout in milliseconds.
2582 * cHandles [I] Number of handles pointed to by pHandles.
2583 * pHandles [I] Handles to wait for.
2584 * lpdwindex [O] Index of handle that was signaled.
2588 * Failure: RPC_S_CALLPENDING on timeout.
2592 * The dwFlags parameter can be zero or more of the following:
2593 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
2594 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
2597 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
2599 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
2600 ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex)
2603 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
2604 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
2605 DWORD start_time = GetTickCount();
2607 TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles,
2608 pHandles, lpdwindex);
2612 DWORD now = GetTickCount();
2615 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
2617 hr = RPC_S_CALLPENDING;
2621 TRACE("waiting for rpc completion or window message\n");
2623 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
2624 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
2625 QS_ALLINPUT, wait_flags);
2627 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
2630 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2632 /* FIXME: filter the messages here */
2633 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
2634 TranslateMessage(&msg);
2635 DispatchMessageW(&msg);
2638 else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
2640 /* handle signaled, store index */
2641 *lpdwindex = (res - WAIT_OBJECT_0);
2644 else if (res == WAIT_TIMEOUT)
2646 hr = RPC_S_CALLPENDING;
2651 ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError());
2656 TRACE("-- 0x%08lx\n", hr);
2660 /***********************************************************************
2663 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
2665 TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
2668 case DLL_PROCESS_ATTACH:
2669 OLE32_hInstance = hinstDLL;
2670 COMPOBJ_InitProcess();
2671 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
2674 case DLL_PROCESS_DETACH:
2675 if (TRACE_ON(ole)) CoRevokeMallocSpy();
2676 COMPOBJ_UninitProcess();
2677 OLE32_hInstance = 0;
2680 case DLL_THREAD_DETACH:
2687 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */