4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
50 #include "ole32_main.h"
51 #include "compobj_private.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(ole);
57 typedef LPCSTR LPCOLESTR16;
59 /****************************************************************************
60 * This section defines variables internal to the COM module.
62 * TODO: Most of these things will have to be made thread-safe.
64 HINSTANCE COMPOBJ_hInstance32 = 0;
66 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
67 static void COM_RevokeAllClasses(void);
68 static void COM_ExternalLockFreeList(void);
70 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
74 static CRITICAL_SECTION csApartment;
75 static CRITICAL_SECTION_DEBUG critsect_debug =
78 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
79 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
81 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
84 * This lock count counts the number of times CoInitialize is called. It is
85 * decreased every time CoUninitialize is called. When it hits 0, the COM
88 static LONG s_COMLockCount = 0;
91 * This linked list contains the list of registered class objects. These
92 * are mostly used to register the factories for out-of-proc servers of OLE
95 * TODO: Make this data structure aware of inter-process communication. This
96 * means that parts of this will be exported to the Wine Server.
98 typedef struct tagRegisteredClass
100 CLSID classIdentifier;
101 LPUNKNOWN classObject;
105 HANDLE hThread; /* only for localserver */
106 struct tagRegisteredClass* nextClass;
109 static RegisteredClass* firstRegisteredClass = NULL;
111 static CRITICAL_SECTION csRegisteredClassList;
112 static CRITICAL_SECTION_DEBUG class_cs_debug =
114 0, 0, &csRegisteredClassList,
115 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
116 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
118 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
120 /*****************************************************************************
121 * This section contains OpenDllList definitions
123 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
124 * other functions that do LoadLibrary _without_ giving back a HMODULE.
125 * Without this list these handles would never be freed.
127 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
128 * next unload-call but not before 600 sec.
131 typedef struct tagOpenDll {
133 struct tagOpenDll *next;
136 static OpenDll *openDllList = NULL; /* linked list of open dlls */
138 static CRITICAL_SECTION csOpenDllList;
139 static CRITICAL_SECTION_DEBUG dll_cs_debug =
141 0, 0, &csOpenDllList,
142 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
143 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
145 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
147 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
148 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
150 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
151 static void COMPOBJ_DllList_FreeUnused(int Timeout);
153 void COMPOBJ_InitProcess( void )
157 /* Dispatching to the correct thread in an apartment is done through
158 * window messages rather than RPC transports. When an interface is
159 * marshalled into another apartment in the same process, a window of the
160 * following class is created. The *caller* of CoMarshalInterface (ie the
161 * application) is responsible for pumping the message loop in that thread.
162 * The WM_USER messages which point to the RPCs are then dispatched to
163 * COM_AptWndProc by the user's code from the apartment in which the interface
166 memset(&wclass, 0, sizeof(wclass));
167 wclass.lpfnWndProc = &COM_AptWndProc;
168 wclass.hInstance = OLE32_hInstance;
169 wclass.lpszClassName = aptWinClass;
170 RegisterClassA(&wclass);
173 void COMPOBJ_UninitProcess( void )
175 UnregisterClassA(aptWinClass, OLE32_hInstance);
178 /******************************************************************************
183 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
184 with free threaded (ie thread safe) COM objects. There is only ever one MTA
185 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
187 static void COM_InitMTA(void)
189 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
190 within a network. That is, two different MTAs on different machines will have
193 This method of generating an OXID is therefore wrong as it doesn't work across
194 a network, but for local RPC only it's OK. We can distinguish between MTAs and
195 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
197 The algorithm Microsoft use is currently unknown.
199 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
200 InitializeCriticalSection(&MTA.cs);
203 static void COM_UninitMTA(void)
205 DeleteCriticalSection(&MTA.cs);
209 /* creates an apartment structure which stores OLE thread-local
210 * information. Call with COINIT_UNINITIALIZED to create an apartment
211 * that will be initialized with a model later. Note: do not call
212 * with COINIT_UNINITIALIZED if the apartment has already been initialized
213 * with a different COINIT value */
214 APARTMENT* COM_CreateApartment(DWORD model)
217 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
221 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
222 apt->tid = GetCurrentThreadId();
223 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
224 GetCurrentProcess(), &apt->thread,
225 THREAD_ALL_ACCESS, FALSE, 0);
228 apt = NtCurrentTeb()->ReservedForOle;
231 if (model & COINIT_APARTMENTTHREADED) {
232 /* FIXME: how does windoze create OXIDs? */
233 apt->oxid = MTA.oxid | GetCurrentThreadId();
234 apt->win = CreateWindowA(aptWinClass, NULL, 0,
236 0, 0, OLE32_hInstance, NULL);
237 InitializeCriticalSection(&apt->cs);
239 else if (!(model & COINIT_UNINITIALIZED)) {
241 apt->oxid = MTA.oxid;
243 EnterCriticalSection(&csApartment);
246 if (apts) apts->prev = apt;
250 LeaveCriticalSection(&csApartment);
251 NtCurrentTeb()->ReservedForOle = apt;
255 static void COM_DestroyApartment(APARTMENT *apt)
257 EnterCriticalSection(&csApartment);
258 if (apt->prev) apt->prev->next = apt->next;
259 if (apt->next) apt->next->prev = apt->prev;
260 if (apts == apt) apts = apt->next;
261 apt->prev = NULL; apt->next = NULL;
262 LeaveCriticalSection(&csApartment);
263 if (apt->model & COINIT_APARTMENTTHREADED) {
264 if (apt->win) DestroyWindow(apt->win);
265 DeleteCriticalSection(&apt->cs);
267 CloseHandle(apt->thread);
268 HeapFree(GetProcessHeap(), 0, apt);
271 /* The given OXID must be local to this process: you cannot use apartment
272 windows to send RPCs to other processes. This all needs to move to rpcrt4 */
273 HWND COM_GetApartmentWin(OXID oxid)
278 EnterCriticalSection(&csApartment);
280 while (apt && apt->oxid != oxid) apt = apt->next;
281 if (apt) win = apt->win;
282 LeaveCriticalSection(&csApartment);
286 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
287 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
289 return DefWindowProcA(hWnd, msg, wParam, lParam);
292 /*****************************************************************************
293 * This section contains OpenDllList implemantation
296 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
303 EnterCriticalSection( &csOpenDllList );
305 if (openDllList == NULL) {
306 /* empty list -- add first node */
307 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
308 openDllList->hLibrary=hLibrary;
309 openDllList->next = NULL;
311 /* search for this dll */
313 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
314 if (ptr->hLibrary == hLibrary) {
320 /* dll not found, add it */
322 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
323 openDllList->hLibrary = hLibrary;
324 openDllList->next = tmp;
328 LeaveCriticalSection( &csOpenDllList );
331 static void COMPOBJ_DllList_FreeUnused(int Timeout)
333 OpenDll *curr, *next, *prev = NULL;
334 typedef HRESULT(*DllCanUnloadNowFunc)(void);
335 DllCanUnloadNowFunc DllCanUnloadNow;
339 EnterCriticalSection( &csOpenDllList );
341 for (curr = openDllList; curr != NULL; ) {
342 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
344 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
347 TRACE("freeing %p\n", curr->hLibrary);
348 FreeLibrary(curr->hLibrary);
350 HeapFree(GetProcessHeap(), 0, curr);
351 if (curr == openDllList) {
364 LeaveCriticalSection( &csOpenDllList );
367 /******************************************************************************
368 * CoBuildVersion [COMPOBJ.1]
369 * CoBuildVersion [OLE32.@]
372 * Current build version, hiword is majornumber, loword is minornumber
374 DWORD WINAPI CoBuildVersion(void)
376 TRACE("Returning version %d, build %d.\n", rmm, rup);
377 return (rmm<<16)+rup;
380 /******************************************************************************
381 * CoInitialize [OLE32.@]
383 * Initializes the COM libraries by calling CoInitializeEx with
384 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
389 HRESULT WINAPI CoInitialize(
390 LPVOID lpReserved /* [in] pointer to win32 malloc interface
391 (obsolete, should be NULL) */
395 * Just delegate to the newer method.
397 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
400 /******************************************************************************
401 * CoInitializeEx [OLE32.@]
403 * Initializes the COM libraries. The behavior used to set the win32
404 * IMalloc used for memory management is obsolete. If
405 * COINIT_APARTMENTTHREADED is specified this thread enters a new STA
406 * (single threaded apartment), otherwise COINIT_MULTITHREADED should
407 * be specified which indicates that the thread will enter the MTA.
409 * Currently STA threading is only partly implemented.
412 * S_OK if successful,
413 * S_FALSE if this function was called already.
414 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
420 HRESULT WINAPI CoInitializeEx(
421 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
422 (obsolete, should be NULL) */
423 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
429 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
431 if (lpReserved!=NULL)
433 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
436 apt = NtCurrentTeb()->ReservedForOle;
437 if (apt && !(apt->model == COINIT_UNINITIALIZED))
439 if (dwCoInit != apt->model)
441 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
442 code then we are probably using the wrong threading model to implement that API. */
443 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
444 return RPC_E_CHANGED_MODE;
452 * Check the lock count. If this is the first time going through the initialize
453 * process, we have to initialize the libraries.
455 * And crank-up that lock count.
457 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
460 * Initialize the various COM libraries and data structures.
462 TRACE("() - Initializing the COM libraries\n");
466 RunningObjectTableImpl_Initialize();
469 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
471 InterlockedIncrement(&apt->inits);
472 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
477 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
478 pending RPCs are ignored. Non-COM messages are discarded at this point.
480 void COM_FlushMessageQueue(void)
483 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
485 if (!apt || !apt->win) return;
487 TRACE("Flushing STA message queue\n");
489 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
490 if (message.hwnd != apt->win) continue;
491 TranslateMessage(&message);
492 DispatchMessageA(&message);
496 /***********************************************************************
497 * CoUninitialize [OLE32.@]
499 * This method will decrement the refcount on the COM libraries,
500 * potentially unloading them. The current thread leaves the apartment
501 * it's currently in. If not in an apartment, the routine does
504 * If COM is to be shut down, any outstanding proxies are
505 * disconnected, all registered class objects are unregistered and the
506 * message queue for the thread is flushed (if native does
507 * this or not is unknown).
512 void WINAPI CoUninitialize(void)
519 apt = NtCurrentTeb()->ReservedForOle;
521 if (InterlockedDecrement(&apt->inits)==0) {
522 NtCurrentTeb()->ReservedForOle = NULL;
523 COM_DestroyApartment(apt);
528 * Decrease the reference count.
529 * If we are back to 0 locks on the COM library, make sure we free
530 * all the associated data structures.
532 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
535 TRACE("() - Releasing the COM libraries\n");
537 RunningObjectTableImpl_UnInitialize();
539 /* disconnect proxies to release the corresponding stubs.
540 * It is confirmed in "Essential COM" in the sub-chapter on
541 * "Lifecycle Management and Marshalling" that the native version also
542 * does some kind of proxy cleanup in this function.
543 * FIXME: does it just disconnect or completely destroy the proxies?
544 * FIXME: should this be in the apartment destructor? */
545 MARSHAL_Disconnect_Proxies();
547 /* Release the references to the registered class objects */
548 COM_RevokeAllClasses();
550 /* This will free the loaded COM Dlls */
551 CoFreeAllLibraries();
553 /* This will free list of external references to COM objects */
554 COM_ExternalLockFreeList();
556 /* This ensures we deal with any pending RPCs */
557 COM_FlushMessageQueue();
561 else if (lCOMRefCnt<1) {
562 ERR( "CoUninitialize() - not CoInitialized.\n" );
563 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
567 /******************************************************************************
568 * CoDisconnectObject [COMPOBJ.15]
569 * CoDisconnectObject [OLE32.@]
571 * Disconnects all connections to this object from remote processes. Dispatches
572 * pending RPCs while blocking new RPCs from occurring, and then calls
573 * IMarshal::DisconnectObject on the given object.
575 * Typically called when the object server is forced to shut down, for instance by
578 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
580 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
584 /******************************************************************************
585 * CoCreateGuid[OLE32.@]
587 * Simply forwards to UuidCreate in RPCRT4.
593 HRESULT WINAPI CoCreateGuid(
594 GUID *pguid /* [out] points to the GUID to initialize */
596 return UuidCreate(pguid);
599 /******************************************************************************
600 * CLSIDFromString [OLE32.@]
601 * IIDFromString [OLE32.@]
603 * Converts a unique identifier from its string representation into
606 * In Windows, if idstr is not a valid CLSID string then it gets
607 * treated as a ProgID. Wine currently doesn't do this. If idstr is
608 * NULL it's treated as an all-zero GUID.
612 * CO_E_CLASSSTRING if idstr is not a valid CLSID
614 HRESULT WINAPI __CLSIDFromStringA(
615 LPCSTR idstr, /* [in] string representation of guid */
616 CLSID *id) /* [out] GUID converted from string */
618 const BYTE *s = (const BYTE *) idstr;
623 s = "{00000000-0000-0000-0000-000000000000}";
624 else { /* validate the CLSID string */
627 return CO_E_CLASSSTRING;
629 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
630 return CO_E_CLASSSTRING;
632 for (i=1; i<37; i++) {
633 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
634 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
635 ((s[i] >= 'a') && (s[i] <= 'f')) ||
636 ((s[i] >= 'A') && (s[i] <= 'F'))))
637 return CO_E_CLASSSTRING;
641 TRACE("%s -> %p\n", s, id);
643 /* quick lookup table */
644 memset(table, 0, 256);
646 for (i = 0; i < 10; i++) {
649 for (i = 0; i < 6; i++) {
650 table['A' + i] = i+10;
651 table['a' + i] = i+10;
654 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
656 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
657 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
658 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
659 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
661 /* these are just sequential bytes */
662 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
663 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
664 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
665 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
666 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
667 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
668 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
669 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
674 /*****************************************************************************/
676 HRESULT WINAPI CLSIDFromString(
677 LPOLESTR idstr, /* [in] string representation of GUID */
678 CLSID *id ) /* [out] GUID represented by above string */
683 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
684 return CO_E_CLASSSTRING;
687 ret = __CLSIDFromStringA(xid,id);
688 if(ret != S_OK) { /* It appears a ProgID is also valid */
689 ret = CLSIDFromProgID(idstr, id);
694 /* Converts a GUID into the respective string representation. */
695 HRESULT WINE_StringFromCLSID(
696 const CLSID *id, /* [in] GUID to be converted */
697 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
699 static const char *hex = "0123456789ABCDEF";
704 { ERR("called with id=Null\n");
709 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
710 id->Data1, id->Data2, id->Data3,
711 id->Data4[0], id->Data4[1]);
715 for (i = 2; i < 8; i++) {
716 *s++ = hex[id->Data4[i]>>4];
717 *s++ = hex[id->Data4[i] & 0xf];
723 TRACE("%p->%s\n", id, idstr);
729 /******************************************************************************
730 * StringFromCLSID [OLE32.@]
731 * StringFromIID [OLE32.@]
733 * Converts a GUID into the respective string representation.
734 * The target string is allocated using the OLE IMalloc.
740 HRESULT WINAPI StringFromCLSID(
741 REFCLSID id, /* [in] the GUID to be converted */
742 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
748 if ((ret = CoGetMalloc(0,&mllc)))
751 ret=WINE_StringFromCLSID(id,buf);
753 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
754 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
755 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
760 /******************************************************************************
761 * StringFromGUID2 [COMPOBJ.76]
762 * StringFromGUID2 [OLE32.@]
764 * Modified version of StringFromCLSID that allows you to specify max
768 * The length of the resulting string, 0 if there was any problem.
770 INT WINAPI StringFromGUID2(
771 REFGUID id, /* [in] GUID to convert to string */
772 LPOLESTR str, /* [out] Unicode buffer to hold result */
777 if (WINE_StringFromCLSID(id,xguid))
779 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
782 /******************************************************************************
783 * ProgIDFromCLSID [OLE32.@]
785 * Converts a class id into the respective Program ID. (By using a
791 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
793 HRESULT WINAPI ProgIDFromCLSID(
794 REFCLSID clsid, /* [in] class id as found in registry */
795 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
798 char strCLSID[50], *buf, *buf2;
804 WINE_StringFromCLSID(clsid, strCLSID);
806 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
807 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
808 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
809 ret = REGDB_E_CLASSNOTREG;
811 HeapFree(GetProcessHeap(), 0, buf);
815 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
817 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
818 ret = REGDB_E_CLASSNOTREG;
822 if (CoGetMalloc(0,&mllc))
826 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
827 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
828 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
831 HeapFree(GetProcessHeap(), 0, buf2);
838 HRESULT WINAPI CLSIDFromProgID16(
839 LPCOLESTR16 progid, /* [in] program id as found in registry */
840 LPCLSID riid /* [out] associated CLSID */
847 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
848 sprintf(buf,"%s\\CLSID",progid);
849 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
850 HeapFree(GetProcessHeap(),0,buf);
851 return CO_E_CLASSSTRING;
853 HeapFree(GetProcessHeap(),0,buf);
854 buf2len = sizeof(buf2);
855 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
857 return CO_E_CLASSSTRING;
860 return __CLSIDFromStringA(buf2,riid);
863 /******************************************************************************
864 * CLSIDFromProgID [COMPOBJ.61]
866 * Converts a program id into the respective GUID. (By using a
871 * CO_E_CLASSSTRING if the given ProgID cannot be found
873 HRESULT WINAPI CLSIDFromProgID(
874 LPCOLESTR progid, /* [in] Unicode program id as found in registry */
875 LPCLSID riid ) /* [out] associated CLSID */
877 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
879 DWORD buf2len = sizeof(buf2);
882 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
883 strcpyW( buf, progid );
884 strcatW( buf, clsidW );
885 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
887 HeapFree(GetProcessHeap(),0,buf);
888 return CO_E_CLASSSTRING;
890 HeapFree(GetProcessHeap(),0,buf);
892 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
895 return CO_E_CLASSSTRING;
898 return __CLSIDFromStringA(buf2,riid);
903 /*****************************************************************************
904 * CoGetPSClsid [OLE32.@]
906 * This function returns the CLSID of the proxy/stub factory that
907 * implements IPSFactoryBuffer for the specified interface.
909 * The standard marshaller activates the object with the CLSID
910 * returned and uses the CreateProxy and CreateStub methods on its
911 * IPSFactoryBuffer interface to construct the proxies and stubs for a
914 * CoGetPSClsid determines this CLSID by searching the
915 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
916 * in the registry and any interface id registered by
917 * CoRegisterPSClsid within the current process.
919 * FIXME: We only search the registry, not ids registered with
925 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
927 HRESULT WINAPI CoGetPSClsid(
928 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
929 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
935 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
937 /* Get the input iid as a string */
938 WINE_StringFromCLSID(riid, buf2);
939 /* Allocate memory for the registry key we will construct.
940 (length of iid string plus constant length of static text */
941 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
944 return (E_OUTOFMEMORY);
947 /* Construct the registry key we want */
948 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
951 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
953 WARN("No PSFactoryBuffer object is registered for this IID\n");
954 HeapFree(GetProcessHeap(),0,buf);
955 return (E_INVALIDARG);
957 HeapFree(GetProcessHeap(),0,buf);
959 /* ... Once we have the key, query the registry to get the
960 value of CLSID as a string, and convert it into a
961 proper CLSID structure to be passed back to the app */
962 buf2len = sizeof(buf2);
963 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
970 /* We have the CLSid we want back from the registry as a string, so
971 lets convert it into a CLSID structure */
972 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
976 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
982 /***********************************************************************
983 * WriteClassStm (OLE32.@)
985 * This function write a CLSID on stream
987 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
989 TRACE("(%p,%p)\n",pStm,rclsid);
994 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
997 /***********************************************************************
998 * ReadClassStm (OLE32.@)
1000 * This function read a CLSID from a stream
1002 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1007 TRACE("(%p,%p)\n",pStm,pclsid);
1010 return E_INVALIDARG;
1012 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1017 if (nbByte != sizeof(CLSID))
1025 * COM_GetRegisteredClassObject
1027 * This internal method is used to scan the registered class list to
1028 * find a class object.
1031 * rclsid Class ID of the class to find.
1032 * dwClsContext Class context to match.
1033 * ppv [out] returns a pointer to the class object. Complying
1034 * to normal COM usage, this method will increase the
1035 * reference count on this object.
1037 static HRESULT COM_GetRegisteredClassObject(
1042 HRESULT hr = S_FALSE;
1043 RegisteredClass* curClass;
1045 EnterCriticalSection( &csRegisteredClassList );
1053 * Iterate through the whole list and try to match the class ID.
1055 curClass = firstRegisteredClass;
1057 while (curClass != 0)
1060 * Check if we have a match on the class ID.
1062 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1065 * Since we don't do out-of process or DCOM just right away, let's ignore the
1070 * We have a match, return the pointer to the class object.
1072 *ppUnk = curClass->classObject;
1074 IUnknown_AddRef(curClass->classObject);
1081 * Step to the next class in the list.
1083 curClass = curClass->nextClass;
1087 LeaveCriticalSection( &csRegisteredClassList );
1089 * If we get to here, we haven't found our class.
1095 _LocalServerThread(LPVOID param) {
1098 RegisteredClass *newClass = (RegisteredClass*)param;
1102 unsigned char *buffer;
1104 IClassFactory *classfac;
1105 LARGE_INTEGER seekto;
1106 ULARGE_INTEGER newpos;
1109 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1111 strcpy(pipefn,PIPEPREF);
1112 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1114 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1115 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1116 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1117 if (hPipe == INVALID_HANDLE_VALUE) {
1118 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1122 if (!ConnectNamedPipe(hPipe,NULL)) {
1123 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1127 TRACE("marshalling IClassFactory to client\n");
1129 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1130 if (hres) return hres;
1132 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1134 FIXME("Failed to create stream on hglobal.\n");
1137 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1139 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1143 IUnknown_Release(classfac); /* is this right? */
1145 hres = IStream_Stat(pStm,&ststg,0);
1146 if (hres) return hres;
1148 buflen = ststg.cbSize.u.LowPart;
1149 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1150 seekto.u.LowPart = 0;
1151 seekto.u.HighPart = 0;
1152 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1154 FIXME("IStream_Seek failed, %lx\n",hres);
1158 hres = IStream_Read(pStm,buffer,buflen,&res);
1160 FIXME("Stream Read failed, %lx\n",hres);
1164 IStream_Release(pStm);
1166 WriteFile(hPipe,buffer,buflen,&res,NULL);
1167 FlushFileBuffers(hPipe);
1168 DisconnectNamedPipe(hPipe);
1170 TRACE("done marshalling IClassFactory\n");
1176 /******************************************************************************
1177 * CoRegisterClassObject [OLE32.@]
1179 * This method will register the class object for a given class
1180 * ID. Servers housed in EXE files use this method instead of
1181 * exporting DllGetClassObject to allow other code to connect to their
1184 * When a class object (an object which implements IClassFactory) is
1185 * registered in this way, a new thread is started which listens for
1186 * connections on a named pipe specific to the registered CLSID. When
1187 * something else connects to it, it writes out the marshalled
1188 * IClassFactory interface to the pipe. The code on the other end uses
1189 * this buffer to unmarshal the class factory, and can then call
1192 * In Windows, such objects are registered with the RPC endpoint
1193 * mapper, not with a unique named pipe.
1195 * MSDN claims that multiple interface registrations are legal, but we
1196 * can't do that with our current implementation.
1200 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1201 * CO_E_OBJISREG if the object is already registered. We should not return this.
1204 * CoRevokeClassObject, CoGetClassObject
1206 HRESULT WINAPI CoRegisterClassObject(
1207 REFCLSID rclsid, /* [in] CLSID of the object to register */
1208 LPUNKNOWN pUnk, /* [in] IUnknown of the object */
1209 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1210 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1211 LPDWORD lpdwRegister) /* [out] A unique cookie that can be passed to CoRevokeClassObject */
1213 RegisteredClass* newClass;
1214 LPUNKNOWN foundObject;
1217 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1218 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1220 if ( (lpdwRegister==0) || (pUnk==0) )
1221 return E_INVALIDARG;
1226 * First, check if the class is already registered.
1227 * If it is, this should cause an error.
1229 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1231 IUnknown_Release(foundObject);
1232 return CO_E_OBJISREG;
1235 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1236 if ( newClass == NULL )
1237 return E_OUTOFMEMORY;
1239 EnterCriticalSection( &csRegisteredClassList );
1241 newClass->classIdentifier = *rclsid;
1242 newClass->runContext = dwClsContext;
1243 newClass->connectFlags = flags;
1245 * Use the address of the chain node as the cookie since we are sure it's
1248 newClass->dwCookie = (DWORD)newClass;
1249 newClass->nextClass = firstRegisteredClass;
1252 * Since we're making a copy of the object pointer, we have to increase its
1255 newClass->classObject = pUnk;
1256 IUnknown_AddRef(newClass->classObject);
1258 firstRegisteredClass = newClass;
1259 LeaveCriticalSection( &csRegisteredClassList );
1261 *lpdwRegister = newClass->dwCookie;
1263 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1266 start_listener_thread();
1267 newClass->hThread = CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1272 /***********************************************************************
1273 * CoRevokeClassObject [OLE32.@]
1275 * This method will remove a class object from the class registry
1277 * See the Windows documentation for more details.
1279 HRESULT WINAPI CoRevokeClassObject(
1282 HRESULT hr = E_INVALIDARG;
1283 RegisteredClass** prevClassLink;
1284 RegisteredClass* curClass;
1286 TRACE("(%08lx)\n",dwRegister);
1288 EnterCriticalSection( &csRegisteredClassList );
1291 * Iterate through the whole list and try to match the cookie.
1293 curClass = firstRegisteredClass;
1294 prevClassLink = &firstRegisteredClass;
1296 while (curClass != 0)
1299 * Check if we have a match on the cookie.
1301 if (curClass->dwCookie == dwRegister)
1304 * Remove the class from the chain.
1306 *prevClassLink = curClass->nextClass;
1309 * Release the reference to the class object.
1311 IUnknown_Release(curClass->classObject);
1314 * Free the memory used by the chain node.
1316 HeapFree(GetProcessHeap(), 0, curClass);
1323 * Step to the next class in the list.
1325 prevClassLink = &(curClass->nextClass);
1326 curClass = curClass->nextClass;
1330 LeaveCriticalSection( &csRegisteredClassList );
1332 * If we get to here, we haven't found our class.
1337 /***********************************************************************
1338 * compobj_RegReadPath [internal]
1340 * Reads a registry value and expands it when necessary
1342 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1348 DWORD dwLength = dstlen;
1350 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1351 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1352 if (keytype == REG_EXPAND_SZ) {
1353 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1355 lstrcpynA(dst, src, dstlen);
1363 /***********************************************************************
1364 * CoGetClassObject [COMPOBJ.7]
1365 * CoGetClassObject [OLE32.@]
1367 * FIXME. If request allows of several options and there is a failure
1368 * with one (other than not being registered) do we try the
1369 * others or return failure? (E.g. inprocess is registered but
1370 * the DLL is not found but the server version works)
1372 HRESULT WINAPI CoGetClassObject(
1373 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1374 REFIID iid, LPVOID *ppv
1376 LPUNKNOWN regClassObject;
1377 HRESULT hres = E_UNEXPECTED;
1380 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1381 DllGetClassObjectFunc DllGetClassObject;
1383 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1385 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1388 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1389 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1393 * First, try and see if we can't match the class ID with one of the
1394 * registered classes.
1396 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1399 * Get the required interface from the retrieved pointer.
1401 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1404 * Since QI got another reference on the pointer, we want to release the
1405 * one we already have. If QI was unsuccessful, this will release the object. This
1406 * is good since we are not returning it in the "out" parameter.
1408 IUnknown_Release(regClassObject);
1413 /* first try: in-process */
1414 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1415 char keyname[MAX_PATH];
1416 char dllpath[MAX_PATH+1];
1418 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1420 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1421 /* failure: CLSID is not found in registry */
1422 WARN("class %s not registered inproc\n", xclsid);
1423 hres = REGDB_E_CLASSNOTREG;
1425 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1426 /* failure: DLL could not be loaded */
1427 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1428 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1429 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1430 /* failure: the dll did not export DllGetClassObject */
1431 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1432 FreeLibrary( hLibrary );
1433 hres = CO_E_DLLNOTFOUND;
1435 /* OK: get the ClassObject */
1436 COMPOBJ_DLLList_Add( hLibrary );
1437 return DllGetClassObject(rclsid, iid, ppv);
1442 /* Next try out of process */
1443 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1445 return create_marshalled_proxy(rclsid,iid,ppv);
1448 /* Finally try remote: this requires networked DCOM (a lot of work) */
1449 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1451 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1452 hres = E_NOINTERFACE;
1457 /***********************************************************************
1458 * CoResumeClassObjects (OLE32.@)
1460 * Resumes classobjects registered with REGCLS suspended
1462 HRESULT WINAPI CoResumeClassObjects(void)
1468 /***********************************************************************
1469 * GetClassFile (OLE32.@)
1471 * This function supplies the CLSID associated with the given filename.
1473 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1477 int nbElm, length, i;
1479 LPOLESTR *pathDec=0,absFile=0,progId=0;
1481 static const WCHAR bkslashW[] = {'\\',0};
1482 static const WCHAR dotW[] = {'.',0};
1484 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1486 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1487 if((StgIsStorageFile(filePathName))==S_OK){
1489 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1492 res=ReadClassStg(pstg,pclsid);
1494 IStorage_Release(pstg);
1498 /* if the file is not a storage object then attemps to match various bits in the file against a
1499 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1502 for(i=0;i<nFileTypes;i++)
1504 for(i=0;j<nPatternsForType;j++){
1509 pat=ReadPatternFromRegistry(i,j);
1510 hFile=CreateFileW(filePathName,,,,,,hFile);
1511 SetFilePosition(hFile,pat.offset);
1512 ReadFile(hFile,buf,pat.size,NULL,NULL);
1513 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1515 *pclsid=ReadCLSIDFromRegistry(i);
1521 /* if the above strategies fail then search for the extension key in the registry */
1523 /* get the last element (absolute file) in the path name */
1524 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1525 absFile=pathDec[nbElm-1];
1527 /* failed if the path represente a directory and not an absolute file name*/
1528 if (!lstrcmpW(absFile, bkslashW))
1529 return MK_E_INVALIDEXTENSION;
1531 /* get the extension of the file */
1533 length=lstrlenW(absFile);
1534 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1537 if (!extension || !lstrcmpW(extension, dotW))
1538 return MK_E_INVALIDEXTENSION;
1540 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1542 /* get the progId associated to the extension */
1543 progId = CoTaskMemAlloc(sizeProgId);
1544 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1546 if (res==ERROR_SUCCESS)
1547 /* return the clsid associated to the progId */
1548 res= CLSIDFromProgID(progId,pclsid);
1550 for(i=0; pathDec[i]!=NULL;i++)
1551 CoTaskMemFree(pathDec[i]);
1552 CoTaskMemFree(pathDec);
1554 CoTaskMemFree(progId);
1556 if (res==ERROR_SUCCESS)
1559 return MK_E_INVALIDEXTENSION;
1561 /***********************************************************************
1562 * CoCreateInstance [COMPOBJ.13]
1563 * CoCreateInstance [OLE32.@]
1565 HRESULT WINAPI CoCreateInstance(
1567 LPUNKNOWN pUnkOuter,
1573 LPCLASSFACTORY lpclf = 0;
1575 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1584 * Initialize the "out" parameter
1589 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1590 * Rather than create a class factory, we can just check for it here
1592 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1593 if (StdGlobalInterfaceTableInstance == NULL)
1594 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1595 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1596 if (hres) return hres;
1598 TRACE("Retrieved GIT (%p)\n", *ppv);
1603 * Get a class factory to construct the object we want.
1605 hres = CoGetClassObject(rclsid,
1612 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1613 debugstr_guid(rclsid),hres);
1618 * Create the object and don't forget to release the factory
1620 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1621 IClassFactory_Release(lpclf);
1623 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1624 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1629 /***********************************************************************
1630 * CoCreateInstanceEx [OLE32.@]
1632 HRESULT WINAPI CoCreateInstanceEx(
1634 LPUNKNOWN pUnkOuter,
1636 COSERVERINFO* pServerInfo,
1640 IUnknown* pUnk = NULL;
1643 ULONG successCount = 0;
1648 if ( (cmq==0) || (pResults==NULL))
1649 return E_INVALIDARG;
1651 if (pServerInfo!=NULL)
1652 FIXME("() non-NULL pServerInfo not supported!\n");
1655 * Initialize all the "out" parameters.
1657 for (index = 0; index < cmq; index++)
1659 pResults[index].pItf = NULL;
1660 pResults[index].hr = E_NOINTERFACE;
1664 * Get the object and get its IUnknown pointer.
1666 hr = CoCreateInstance(rclsid,
1676 * Then, query for all the interfaces requested.
1678 for (index = 0; index < cmq; index++)
1680 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1681 pResults[index].pIID,
1682 (VOID**)&(pResults[index].pItf));
1684 if (pResults[index].hr == S_OK)
1689 * Release our temporary unknown pointer.
1691 IUnknown_Release(pUnk);
1693 if (successCount == 0)
1694 return E_NOINTERFACE;
1696 if (successCount!=cmq)
1697 return CO_S_NOTALLINTERFACES;
1702 /***********************************************************************
1703 * CoLoadLibrary (OLE32.@)
1705 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1707 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1709 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1712 /***********************************************************************
1713 * CoFreeLibrary [OLE32.@]
1715 * NOTES: don't believe the documentation
1717 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1719 FreeLibrary(hLibrary);
1723 /***********************************************************************
1724 * CoFreeAllLibraries [OLE32.@]
1726 * NOTES: don't believe the documentation
1728 void WINAPI CoFreeAllLibraries(void)
1734 /***********************************************************************
1735 * CoFreeUnusedLibraries [COMPOBJ.17]
1736 * CoFreeUnusedLibraries [OLE32.@]
1738 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1739 * through the main apartment's thread to call DllCanUnloadNow
1741 void WINAPI CoFreeUnusedLibraries(void)
1743 COMPOBJ_DllList_FreeUnused(0);
1746 /***********************************************************************
1747 * CoFileTimeNow [COMPOBJ.82]
1748 * CoFileTimeNow [OLE32.@]
1751 * the current system time in lpFileTime
1753 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1755 GetSystemTimeAsFileTime( lpFileTime );
1759 /***********************************************************************
1760 * CoLoadLibrary (OLE32.@)
1762 static void COM_RevokeAllClasses()
1764 EnterCriticalSection( &csRegisteredClassList );
1766 while (firstRegisteredClass!=0)
1768 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1771 LeaveCriticalSection( &csRegisteredClassList );
1774 /****************************************************************************
1775 * COM External Lock methods implementation
1777 * This api provides a linked list to managed external references to
1780 * The public interface consists of three calls:
1781 * COM_ExternalLockAddRef
1782 * COM_ExternalLockRelease
1783 * COM_ExternalLockFreeList
1786 #define EL_END_OF_LIST 0
1787 #define EL_NOT_FOUND 0
1790 * Declaration of the static structure that manage the
1791 * external lock to COM objects.
1793 typedef struct COM_ExternalLock COM_ExternalLock;
1794 typedef struct COM_ExternalLockList COM_ExternalLockList;
1796 struct COM_ExternalLock
1798 IUnknown *pUnk; /* IUnknown referenced */
1799 ULONG uRefCount; /* external lock counter to IUnknown object*/
1800 COM_ExternalLock *next; /* Pointer to next element in list */
1803 struct COM_ExternalLockList
1805 COM_ExternalLock *head; /* head of list */
1809 * Declaration and initialization of the static structure that manages
1810 * the external lock to COM objects.
1812 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1815 * Private methods used to managed the linked list
1819 static COM_ExternalLock* COM_ExternalLockLocate(
1820 COM_ExternalLock *element,
1823 /****************************************************************************
1824 * Internal - Insert a new IUnknown* to the linked list
1826 static BOOL COM_ExternalLockInsert(
1829 COM_ExternalLock *newLock = NULL;
1830 COM_ExternalLock *previousHead = NULL;
1833 * Allocate space for the new storage object
1835 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1837 if (newLock!=NULL) {
1838 if ( elList.head == EL_END_OF_LIST ) {
1839 elList.head = newLock; /* The list is empty */
1841 /* insert does it at the head */
1842 previousHead = elList.head;
1843 elList.head = newLock;
1846 /* Set new list item data member */
1847 newLock->pUnk = pUnk;
1848 newLock->uRefCount = 1;
1849 newLock->next = previousHead;
1856 /****************************************************************************
1857 * Internal - Method that removes an item from the linked list.
1859 static void COM_ExternalLockDelete(
1860 COM_ExternalLock *itemList)
1862 COM_ExternalLock *current = elList.head;
1864 if ( current == itemList ) {
1865 /* this section handles the deletion of the first node */
1866 elList.head = itemList->next;
1867 HeapFree( GetProcessHeap(), 0, itemList);
1870 if ( current->next == itemList ){ /* We found the item to free */
1871 current->next = itemList->next; /* readjust the list pointers */
1872 HeapFree( GetProcessHeap(), 0, itemList);
1876 /* Skip to the next item */
1877 current = current->next;
1879 } while ( current != EL_END_OF_LIST );
1883 /****************************************************************************
1884 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1886 * NOTES: how long can the list be ?? (recursive!!!)
1888 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1890 if ( element == EL_END_OF_LIST )
1891 return EL_NOT_FOUND;
1892 else if ( element->pUnk == pUnk ) /* We found it */
1894 else /* Not the right guy, keep on looking */
1895 return COM_ExternalLockLocate( element->next, pUnk);
1898 /****************************************************************************
1899 * Public - Method that increments the count for a IUnknown* in the linked
1900 * list. The item is inserted if not already in the list.
1902 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1904 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1907 * Add an external lock to the object. If it was already externally
1908 * locked, just increase the reference count. If it was not.
1909 * add the item to the list.
1911 if ( externalLock == EL_NOT_FOUND )
1912 COM_ExternalLockInsert(pUnk);
1914 externalLock->uRefCount++;
1917 * Add an internal lock to the object
1919 IUnknown_AddRef(pUnk);
1922 /****************************************************************************
1923 * Public - Method that decrements the count for a IUnknown* in the linked
1924 * list. The item is removed from the list if its count end up at zero or if
1927 static void COM_ExternalLockRelease(
1931 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1933 if ( externalLock != EL_NOT_FOUND ) {
1935 externalLock->uRefCount--; /* release external locks */
1936 IUnknown_Release(pUnk); /* release local locks as well */
1938 if ( bRelAll == FALSE ) break; /* perform single release */
1940 } while ( externalLock->uRefCount > 0 );
1942 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1943 COM_ExternalLockDelete(externalLock);
1946 /****************************************************************************
1947 * Public - Method that frees the content of the list.
1949 static void COM_ExternalLockFreeList()
1951 COM_ExternalLock *head;
1953 head = elList.head; /* grab it by the head */
1954 while ( head != EL_END_OF_LIST ) {
1955 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1956 head = elList.head; /* get the new head... */
1960 /****************************************************************************
1961 * Public - Method that dump the content of the list.
1963 void COM_ExternalLockDump()
1965 COM_ExternalLock *current = elList.head;
1967 DPRINTF("\nExternal lock list contains:\n");
1969 while ( current != EL_END_OF_LIST ) {
1970 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1972 /* Skip to the next item */
1973 current = current->next;
1977 /******************************************************************************
1978 * CoLockObjectExternal [OLE32.@]
1980 HRESULT WINAPI CoLockObjectExternal(
1981 LPUNKNOWN pUnk, /* [in] object to be locked */
1982 BOOL fLock, /* [in] do lock */
1983 BOOL fLastUnlockReleases) /* [in] unlock all */
1988 * Increment the external lock coutner, COM_ExternalLockAddRef also
1989 * increment the object's internal lock counter.
1991 COM_ExternalLockAddRef( pUnk);
1994 * Decrement the external lock coutner, COM_ExternalLockRelease also
1995 * decrement the object's internal lock counter.
1997 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2003 /***********************************************************************
2004 * CoInitializeWOW (OLE32.@)
2006 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
2007 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2011 /***********************************************************************
2012 * CoGetState [OLE32.@]
2014 * NOTES: might be incomplete
2016 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2018 APARTMENT * apt = COM_CurrentInfo();
2022 if(apt && apt->state) {
2023 IUnknown_AddRef(apt->state);
2025 FIXME("-- %p\n", *ppv);
2033 /***********************************************************************
2034 * CoSetState [OLE32.@]
2037 HRESULT WINAPI CoSetState(IUnknown * pv)
2039 APARTMENT * apt = COM_CurrentInfo();
2041 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
2043 FIXME("(%p),stub!\n", pv);
2046 IUnknown_AddRef(pv);
2050 TRACE("-- release %p now\n", apt->state);
2051 IUnknown_Release(apt->state);
2058 /******************************************************************************
2059 * OleGetAutoConvert [OLE32.@]
2061 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2069 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2070 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2072 res = REGDB_E_CLASSNOTREG;
2076 /* we can just query for the default value of AutoConvertTo key like that,
2077 without opening the AutoConvertTo key and querying for NULL (default) */
2078 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2080 res = REGDB_E_KEYMISSING;
2083 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2084 CLSIDFromString(wbuf,pClsidNew);
2086 if (hkey) RegCloseKey(hkey);
2090 /******************************************************************************
2091 * OleSetAutoConvert [OLE32.@]
2093 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2096 char buf[200], szClsidNew[200];
2099 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2100 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2101 WINE_StringFromCLSID(clsidNew, szClsidNew);
2102 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2104 res = REGDB_E_CLASSNOTREG;
2107 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2109 res = REGDB_E_WRITEREGDB;
2114 if (hkey) RegCloseKey(hkey);
2118 /******************************************************************************
2119 * OleDoAutoConvert [OLE32.@]
2121 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2123 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2127 /******************************************************************************
2128 * CoTreatAsClass [OLE32.@]
2130 * Sets TreatAs value of a class
2132 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2136 char szClsidNew[39];
2138 char auto_treat_as[39];
2139 LONG auto_treat_as_size = sizeof(auto_treat_as);
2142 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2143 WINE_StringFromCLSID(clsidNew, szClsidNew);
2144 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2146 res = REGDB_E_CLASSNOTREG;
2149 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2151 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2152 !__CLSIDFromStringA(auto_treat_as, &id))
2154 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2156 res = REGDB_E_WRITEREGDB;
2162 RegDeleteKeyA(hkey, "TreatAs");
2166 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2168 res = REGDB_E_WRITEREGDB;
2173 if (hkey) RegCloseKey(hkey);
2177 /******************************************************************************
2178 * CoGetTreatAsClass [OLE32.@]
2180 * Reads the TreatAs value from a class.
2182 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2185 char buf[200], szClsidNew[200];
2187 LONG len = sizeof(szClsidNew);
2189 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2190 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2191 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2193 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2195 res = REGDB_E_CLASSNOTREG;
2198 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2203 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2205 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2207 if (hkey) RegCloseKey(hkey);
2212 /***********************************************************************
2213 * IsEqualGUID [OLE32.@]
2215 * Compares two Unique Identifiers.
2221 BOOL WINAPI IsEqualGUID(
2222 REFGUID rguid1, /* [in] unique id 1 */
2223 REFGUID rguid2 /* [in] unique id 2 */
2226 return !memcmp(rguid1,rguid2,sizeof(GUID));
2229 /***********************************************************************
2230 * CoInitializeSecurity [OLE32.@]
2232 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2233 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2234 void* pReserved1, DWORD dwAuthnLevel,
2235 DWORD dwImpLevel, void* pReserved2,
2236 DWORD dwCapabilities, void* pReserved3)
2238 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2239 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2240 dwCapabilities, pReserved3);
2244 /***********************************************************************
2245 * CoSuspendClassObjects [OLE32.@]
2247 HRESULT WINAPI CoSuspendClassObjects(void)
2253 /***********************************************************************
2254 * CoAddRefServerProcess [OLE32.@]
2256 ULONG WINAPI CoAddRefServerProcess(void)
2262 /***********************************************************************
2263 * CoReleaseServerProcess [OLE32.@]
2265 ULONG WINAPI CoReleaseServerProcess(void)