Add support for HCBT_SYSCOMMAND hook, add logging for HCBT_SYSCOMMAND
[wine.git] / dlls / ole32 / compobj.c
blob3305cc96aad9165946641f1ac983de72faff23ab
1 /*
2 * COMPOBJ library
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 #include "config.h"
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "objbase.h"
40 #include "ole2.h"
41 #include "ole2ver.h"
42 #include "rpc.h"
43 #include "winerror.h"
44 #include "winreg.h"
45 #include "wownt32.h"
46 #include "wine/unicode.h"
47 #include "objbase.h"
48 #include "ole32_main.h"
49 #include "compobj_private.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
55 typedef LPCSTR LPCOLESTR16;
57 /****************************************************************************
58 * This section defines variables internal to the COM module.
60 * TODO: Most of these things will have to be made thread-safe.
62 HINSTANCE COMPOBJ_hInstance32 = 0;
64 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
65 static void COM_RevokeAllClasses();
66 static void COM_ExternalLockFreeList();
68 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
70 APARTMENT MTA, *apts;
72 static CRITICAL_SECTION csApartment;
73 static CRITICAL_SECTION_DEBUG critsect_debug =
75 0, 0, &csApartment,
76 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
77 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
79 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
82 * This lock count counts the number of times CoInitialize is called. It is
83 * decreased every time CoUninitialize is called. When it hits 0, the COM
84 * libraries are freed
86 static LONG s_COMLockCount = 0;
89 * This linked list contains the list of registered class objects. These
90 * are mostly used to register the factories for out-of-proc servers of OLE
91 * objects.
93 * TODO: Make this data structure aware of inter-process communication. This
94 * means that parts of this will be exported to the Wine Server.
96 typedef struct tagRegisteredClass
98 CLSID classIdentifier;
99 LPUNKNOWN classObject;
100 DWORD runContext;
101 DWORD connectFlags;
102 DWORD dwCookie;
103 HANDLE hThread; /* only for localserver */
104 struct tagRegisteredClass* nextClass;
105 } RegisteredClass;
107 static RegisteredClass* firstRegisteredClass = NULL;
109 static CRITICAL_SECTION csRegisteredClassList;
110 static CRITICAL_SECTION_DEBUG class_cs_debug =
112 0, 0, &csRegisteredClassList,
113 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
114 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
116 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
118 /*****************************************************************************
119 * This section contains OpenDllList definitions
121 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
122 * other functions that do LoadLibrary _without_ giving back a HMODULE.
123 * Without this list these handles would never be freed.
125 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
126 * next unload-call but not before 600 sec.
129 typedef struct tagOpenDll {
130 HINSTANCE hLibrary;
131 struct tagOpenDll *next;
132 } OpenDll;
134 static OpenDll *openDllList = NULL; /* linked list of open dlls */
136 static CRITICAL_SECTION csOpenDllList;
137 static CRITICAL_SECTION_DEBUG dll_cs_debug =
139 0, 0, &csOpenDllList,
140 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
141 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
143 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
145 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
146 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
148 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
149 static void COMPOBJ_DllList_FreeUnused(int Timeout);
151 void COMPOBJ_InitProcess( void )
153 WNDCLASSA wclass;
155 /* Dispatching to the correct thread in an apartment is done through
156 * window messages rather than RPC transports. When an interface is
157 * marshalled into another apartment in the same process, a window of the
158 * following class is created. The *caller* of CoMarshalInterface (ie the
159 * application) is responsible for pumping the message loop in that thread.
160 * The WM_USER messages which point to the RPCs are then dispatched to
161 * COM_AptWndProc by the user's code.
163 memset(&wclass, 0, sizeof(wclass));
164 wclass.lpfnWndProc = &COM_AptWndProc;
165 wclass.hInstance = OLE32_hInstance;
166 wclass.lpszClassName = aptWinClass;
167 RegisterClassA(&wclass);
170 void COMPOBJ_UninitProcess( void )
172 UnregisterClassA(aptWinClass, OLE32_hInstance);
175 /******************************************************************************
176 * Manage apartments.
180 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
181 with free threaded (ie thread safe) COM objects. There is only ever one MTA
182 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
184 static void COM_InitMTA(void)
186 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
187 within a network. That is, two different MTAs on different machines will have
188 different OXIDs.
190 This method of generating an OXID is therefore wrong as it doesn't work across
191 a network, but for local RPC only it's OK. We can distinguish between MTAs and
192 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
194 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
195 InitializeCriticalSection(&MTA.cs);
198 static void COM_UninitMTA(void)
200 DeleteCriticalSection(&MTA.cs);
201 MTA.oxid = 0;
204 /* creates an apartment structure which stores OLE thread-local
205 * information. Call with COINIT_UNINITIALIZED to create an apartment
206 * that will be initialized with a model later. Note: do not call
207 * with COINIT_UNINITIALIZED if the apartment has already been initialized
208 * with a different COINIT value */
209 APARTMENT* COM_CreateApartment(DWORD model)
211 APARTMENT *apt;
212 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
214 if (create)
216 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
217 apt->tid = GetCurrentThreadId();
218 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
219 GetCurrentProcess(), &apt->thread,
220 THREAD_ALL_ACCESS, FALSE, 0);
222 else
223 apt = NtCurrentTeb()->ReservedForOle;
225 apt->model = model;
226 if (model & COINIT_APARTMENTTHREADED) {
227 /* FIXME: how does windoze create OXIDs? */
228 apt->oxid = MTA.oxid | GetCurrentThreadId();
229 apt->win = CreateWindowA(aptWinClass, NULL, 0,
230 0, 0, 0, 0,
231 0, 0, OLE32_hInstance, NULL);
232 InitializeCriticalSection(&apt->cs);
234 else if (!(model & COINIT_UNINITIALIZED)) {
235 apt->parent = &MTA;
236 apt->oxid = MTA.oxid;
238 EnterCriticalSection(&csApartment);
239 if (create)
241 if (apts) apts->prev = apt;
242 apt->next = apts;
243 apts = apt;
245 LeaveCriticalSection(&csApartment);
246 NtCurrentTeb()->ReservedForOle = apt;
247 return apt;
250 static void COM_DestroyApartment(APARTMENT *apt)
252 EnterCriticalSection(&csApartment);
253 if (apt->prev) apt->prev->next = apt->next;
254 if (apt->next) apt->next->prev = apt->prev;
255 if (apts == apt) apts = apt->next;
256 apt->prev = NULL; apt->next = NULL;
257 LeaveCriticalSection(&csApartment);
258 if (apt->model & COINIT_APARTMENTTHREADED) {
259 if (apt->win) DestroyWindow(apt->win);
260 DeleteCriticalSection(&apt->cs);
262 CloseHandle(apt->thread);
263 HeapFree(GetProcessHeap(), 0, apt);
266 /* The given OXID must be local to this process: you cannot use apartment
267 windows to send RPCs to other processes */
268 HWND COM_GetApartmentWin(OXID oxid)
270 APARTMENT *apt;
271 HWND win = 0;
273 EnterCriticalSection(&csApartment);
274 apt = apts;
275 while (apt && apt->oxid != oxid) apt = apt->next;
276 if (apt) win = apt->win;
277 LeaveCriticalSection(&csApartment);
278 return win;
281 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
282 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
284 return DefWindowProcA(hWnd, msg, wParam, lParam);
287 /*****************************************************************************
288 * This section contains OpenDllList implemantation
291 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
293 OpenDll *ptr;
294 OpenDll *tmp;
296 TRACE("\n");
298 EnterCriticalSection( &csOpenDllList );
300 if (openDllList == NULL) {
301 /* empty list -- add first node */
302 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
303 openDllList->hLibrary=hLibrary;
304 openDllList->next = NULL;
305 } else {
306 /* search for this dll */
307 int found = FALSE;
308 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
309 if (ptr->hLibrary == hLibrary) {
310 found = TRUE;
311 break;
314 if (!found) {
315 /* dll not found, add it */
316 tmp = openDllList;
317 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
318 openDllList->hLibrary = hLibrary;
319 openDllList->next = tmp;
323 LeaveCriticalSection( &csOpenDllList );
326 static void COMPOBJ_DllList_FreeUnused(int Timeout)
328 OpenDll *curr, *next, *prev = NULL;
329 typedef HRESULT(*DllCanUnloadNowFunc)(void);
330 DllCanUnloadNowFunc DllCanUnloadNow;
332 TRACE("\n");
334 EnterCriticalSection( &csOpenDllList );
336 for (curr = openDllList; curr != NULL; ) {
337 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
339 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
340 next = curr->next;
342 TRACE("freeing %p\n", curr->hLibrary);
343 FreeLibrary(curr->hLibrary);
345 HeapFree(GetProcessHeap(), 0, curr);
346 if (curr == openDllList) {
347 openDllList = next;
348 } else {
349 prev->next = next;
352 curr = next;
353 } else {
354 prev = curr;
355 curr = curr->next;
359 LeaveCriticalSection( &csOpenDllList );
362 /******************************************************************************
363 * CoBuildVersion [COMPOBJ.1]
364 * CoBuildVersion [OLE32.@]
366 * RETURNS
367 * Current build version, hiword is majornumber, loword is minornumber
369 DWORD WINAPI CoBuildVersion(void)
371 TRACE("Returning version %d, build %d.\n", rmm, rup);
372 return (rmm<<16)+rup;
375 /******************************************************************************
376 * CoInitialize [OLE32.@]
378 * Initializes the COM libraries.
380 * See CoInitializeEx
382 HRESULT WINAPI CoInitialize(
383 LPVOID lpReserved /* [in] pointer to win32 malloc interface
384 (obsolete, should be NULL) */
388 * Just delegate to the newer method.
390 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
393 /******************************************************************************
394 * CoInitializeEx [OLE32.@]
396 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
397 * used for memory management is obsolete.
399 * RETURNS
400 * S_OK if successful,
401 * S_FALSE if this function was called already.
402 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
403 * threading model.
405 HRESULT WINAPI CoInitializeEx(
406 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
407 (obsolete, should be NULL) */
408 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
411 HRESULT hr = S_OK;
412 APARTMENT *apt;
414 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
416 if (lpReserved!=NULL)
418 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
421 apt = NtCurrentTeb()->ReservedForOle;
422 if (apt && !(apt->model == COINIT_UNINITIALIZED))
424 if (dwCoInit != apt->model)
426 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
427 code then we are probably using the wrong threading model to implement that API. */
428 WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
429 return RPC_E_CHANGED_MODE;
431 hr = S_FALSE;
433 else
434 hr = S_OK;
437 * Check the lock count. If this is the first time going through the initialize
438 * process, we have to initialize the libraries.
440 * And crank-up that lock count.
442 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
445 * Initialize the various COM libraries and data structures.
447 TRACE("() - Initializing the COM libraries\n");
449 COM_InitMTA();
451 RunningObjectTableImpl_Initialize();
454 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
456 InterlockedIncrement(&apt->inits);
457 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
459 return hr;
462 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
463 pending RPCs are ignored. Non-COM messages are discarded at this point.
465 void COM_FlushMessageQueue(void)
467 MSG message;
468 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
470 if (!apt || !apt->win) return;
472 TRACE("Flushing STA message queue\n");
474 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
475 if (message.hwnd != apt->win) continue;
476 TranslateMessage(&message);
477 DispatchMessageA(&message);
481 /***********************************************************************
482 * CoUninitialize [OLE32.@]
484 * This method will release the COM libraries.
486 * See the windows documentation for more details.
488 void WINAPI CoUninitialize(void)
490 LONG lCOMRefCnt;
491 APARTMENT *apt;
493 TRACE("()\n");
495 apt = NtCurrentTeb()->ReservedForOle;
496 if (!apt) return;
497 if (InterlockedDecrement(&apt->inits)==0) {
498 NtCurrentTeb()->ReservedForOle = NULL;
499 COM_DestroyApartment(apt);
500 apt = NULL;
504 * Decrease the reference count.
505 * If we are back to 0 locks on the COM library, make sure we free
506 * all the associated data structures.
508 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
509 if (lCOMRefCnt==1)
511 TRACE("() - Releasing the COM libraries\n");
513 RunningObjectTableImpl_UnInitialize();
515 /* disconnect proxies to release the corresponding stubs.
516 * FIXME: native version might not do this and we might just be working
517 * around bugs elsewhere. */
518 MARSHAL_Disconnect_Proxies();
520 /* Release the references to the registered class objects */
521 COM_RevokeAllClasses();
523 /* This will free the loaded COM Dlls */
524 CoFreeAllLibraries();
526 /* This will free list of external references to COM objects */
527 COM_ExternalLockFreeList();
529 /* This ensures we deal with any pending RPCs */
530 COM_FlushMessageQueue();
532 COM_UninitMTA();
534 else if (lCOMRefCnt<1) {
535 ERR( "CoUninitialize() - not CoInitialized.\n" );
536 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
540 /******************************************************************************
541 * CoDisconnectObject [COMPOBJ.15]
542 * CoDisconnectObject [OLE32.@]
544 * Disconnects all connections to this object from remote processes. Dispatches
545 * pending RPCs while blocking new RPCs from occurring, and then calls
546 * IMarshal::DisconnectObject on the given object.
548 * Typically called when the object server is forced to shut down, for instance by
549 * the user.
551 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
553 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
554 return S_OK;
557 /******************************************************************************
558 * CoCreateGuid[OLE32.@]
561 HRESULT WINAPI CoCreateGuid(
562 GUID *pguid /* [out] points to the GUID to initialize */
564 return UuidCreate(pguid);
567 /******************************************************************************
568 * CLSIDFromString [OLE32.@]
569 * IIDFromString [OLE32.@]
570 * Converts a unique identifier from its string representation into
571 * the GUID struct.
573 * UNDOCUMENTED
574 * If idstr is not a valid CLSID string then it gets treated as a ProgID
576 * RETURNS
577 * the converted GUID
579 HRESULT WINAPI __CLSIDFromStringA(
580 LPCSTR idstr, /* [in] string representation of guid */
581 CLSID *id) /* [out] GUID converted from string */
583 const BYTE *s = (BYTE *) idstr;
584 int i;
585 BYTE table[256];
587 if (!s)
588 s = "{00000000-0000-0000-0000-000000000000}";
589 else { /* validate the CLSID string */
591 if (strlen(s) != 38)
592 return CO_E_CLASSSTRING;
594 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
595 return CO_E_CLASSSTRING;
597 for (i=1; i<37; i++) {
598 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
599 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
600 ((s[i] >= 'a') && (s[i] <= 'f')) ||
601 ((s[i] >= 'A') && (s[i] <= 'F'))))
602 return CO_E_CLASSSTRING;
606 TRACE("%s -> %p\n", s, id);
608 /* quick lookup table */
609 memset(table, 0, 256);
611 for (i = 0; i < 10; i++) {
612 table['0' + i] = i;
614 for (i = 0; i < 6; i++) {
615 table['A' + i] = i+10;
616 table['a' + i] = i+10;
619 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
621 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
622 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
623 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
624 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
626 /* these are just sequential bytes */
627 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
628 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
629 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
630 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
631 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
632 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
633 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
634 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
636 return S_OK;
639 /*****************************************************************************/
641 HRESULT WINAPI CLSIDFromString(
642 LPOLESTR idstr, /* [in] string representation of GUID */
643 CLSID *id ) /* [out] GUID represented by above string */
645 char xid[40];
646 HRESULT ret;
648 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
649 return CO_E_CLASSSTRING;
652 ret = __CLSIDFromStringA(xid,id);
653 if(ret != S_OK) { /* It appears a ProgID is also valid */
654 ret = CLSIDFromProgID(idstr, id);
656 return ret;
659 /******************************************************************************
660 * WINE_StringFromCLSID [Internal]
661 * Converts a GUID into the respective string representation.
663 * NOTES
665 * RETURNS
666 * the string representation and HRESULT
668 HRESULT WINE_StringFromCLSID(
669 const CLSID *id, /* [in] GUID to be converted */
670 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
672 static const char *hex = "0123456789ABCDEF";
673 char *s;
674 int i;
676 if (!id)
677 { ERR("called with id=Null\n");
678 *idstr = 0x00;
679 return E_FAIL;
682 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
683 id->Data1, id->Data2, id->Data3,
684 id->Data4[0], id->Data4[1]);
685 s = &idstr[25];
687 /* 6 hex bytes */
688 for (i = 2; i < 8; i++) {
689 *s++ = hex[id->Data4[i]>>4];
690 *s++ = hex[id->Data4[i] & 0xf];
693 *s++ = '}';
694 *s++ = '\0';
696 TRACE("%p->%s\n", id, idstr);
698 return S_OK;
702 /******************************************************************************
703 * StringFromCLSID [OLE32.@]
704 * StringFromIID [OLE32.@]
705 * Converts a GUID into the respective string representation.
706 * The target string is allocated using the OLE IMalloc.
707 * RETURNS
708 * the string representation and HRESULT
710 HRESULT WINAPI StringFromCLSID(
711 REFCLSID id, /* [in] the GUID to be converted */
712 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
714 char buf[80];
715 HRESULT ret;
716 LPMALLOC mllc;
718 if ((ret=CoGetMalloc(0,&mllc)))
719 return ret;
721 ret=WINE_StringFromCLSID(id,buf);
722 if (!ret) {
723 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
724 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
725 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
727 return ret;
730 /******************************************************************************
731 * StringFromGUID2 [COMPOBJ.76]
732 * StringFromGUID2 [OLE32.@]
734 * Converts a global unique identifier into a string of an API-
735 * specified fixed format. (The usual {.....} stuff.)
737 * RETURNS
738 * The (UNICODE) string representation of the GUID in 'str'
739 * The length of the resulting string, 0 if there was any problem.
741 INT WINAPI
742 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
744 char xguid[80];
746 if (WINE_StringFromCLSID(id,xguid))
747 return 0;
748 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
751 /******************************************************************************
752 * ProgIDFromCLSID [OLE32.@]
753 * Converts a class id into the respective Program ID. (By using a registry lookup)
754 * RETURNS S_OK on success
755 * riid associated with the progid
758 HRESULT WINAPI ProgIDFromCLSID(
759 REFCLSID clsid, /* [in] class id as found in registry */
760 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
763 char strCLSID[50], *buf, *buf2;
764 DWORD buf2len;
765 HKEY xhkey;
766 LPMALLOC mllc;
767 HRESULT ret = S_OK;
769 WINE_StringFromCLSID(clsid, strCLSID);
771 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
772 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
773 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
774 ret = REGDB_E_CLASSNOTREG;
776 HeapFree(GetProcessHeap(), 0, buf);
778 if (ret == S_OK)
780 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
781 buf2len = 255;
782 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
783 ret = REGDB_E_CLASSNOTREG;
785 if (ret == S_OK)
787 if (CoGetMalloc(0,&mllc))
788 ret = E_OUTOFMEMORY;
789 else
791 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
792 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
793 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
796 HeapFree(GetProcessHeap(), 0, buf2);
799 RegCloseKey(xhkey);
800 return ret;
803 /******************************************************************************
804 * CLSIDFromProgID [COMPOBJ.61]
805 * Converts a program id into the respective GUID. (By using a registry lookup)
806 * RETURNS
807 * riid associated with the progid
809 HRESULT WINAPI CLSIDFromProgID16(
810 LPCOLESTR16 progid, /* [in] program id as found in registry */
811 LPCLSID riid /* [out] associated CLSID */
813 char *buf,buf2[80];
814 DWORD buf2len;
815 HRESULT err;
816 HKEY xhkey;
818 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
819 sprintf(buf,"%s\\CLSID",progid);
820 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
821 HeapFree(GetProcessHeap(),0,buf);
822 return CO_E_CLASSSTRING;
824 HeapFree(GetProcessHeap(),0,buf);
825 buf2len = sizeof(buf2);
826 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
827 RegCloseKey(xhkey);
828 return CO_E_CLASSSTRING;
830 RegCloseKey(xhkey);
831 return __CLSIDFromStringA(buf2,riid);
834 /******************************************************************************
835 * CLSIDFromProgID [OLE32.@]
836 * Converts a program id into the respective GUID. (By using a registry lookup)
837 * RETURNS
838 * riid associated with the progid
840 HRESULT WINAPI CLSIDFromProgID(
841 LPCOLESTR progid, /* [in] program id as found in registry */
842 LPCLSID riid ) /* [out] associated CLSID */
844 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
845 char buf2[80];
846 DWORD buf2len = sizeof(buf2);
847 HKEY xhkey;
849 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
850 strcpyW( buf, progid );
851 strcatW( buf, clsidW );
852 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
854 HeapFree(GetProcessHeap(),0,buf);
855 return CO_E_CLASSSTRING;
857 HeapFree(GetProcessHeap(),0,buf);
859 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
861 RegCloseKey(xhkey);
862 return CO_E_CLASSSTRING;
864 RegCloseKey(xhkey);
865 return __CLSIDFromStringA(buf2,riid);
870 /*****************************************************************************
871 * CoGetPSClsid [OLE32.@]
873 * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
874 * for the specified interface.
876 * The standard marshaller activates the object with the CLSID returned and uses the
877 * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
878 * the proxies and stubs for a given object.
880 * CoGetPSClsid determines this CLSID by searching the
881 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
882 * and any interface id registered by CoRegisterPSClsid within the current process.
884 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
886 HRESULT WINAPI CoGetPSClsid(
887 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
888 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
890 char *buf, buf2[40];
891 DWORD buf2len;
892 HKEY xhkey;
894 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
896 /* Get the input iid as a string */
897 WINE_StringFromCLSID(riid, buf2);
898 /* Allocate memory for the registry key we will construct.
899 (length of iid string plus constant length of static text */
900 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
901 if (buf == NULL)
903 return (E_OUTOFMEMORY);
906 /* Construct the registry key we want */
907 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
909 /* Open the key.. */
910 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
912 WARN("No PSFactoryBuffer object is registered for this IID\n");
913 HeapFree(GetProcessHeap(),0,buf);
914 return (E_INVALIDARG);
916 HeapFree(GetProcessHeap(),0,buf);
918 /* ... Once we have the key, query the registry to get the
919 value of CLSID as a string, and convert it into a
920 proper CLSID structure to be passed back to the app */
921 buf2len = sizeof(buf2);
922 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
924 RegCloseKey(xhkey);
925 return E_INVALIDARG;
927 RegCloseKey(xhkey);
929 /* We have the CLSid we want back from the registry as a string, so
930 lets convert it into a CLSID structure */
931 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
932 return E_INVALIDARG;
935 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
936 return (S_OK);
941 /***********************************************************************
942 * WriteClassStm (OLE32.@)
944 * This function write a CLSID on stream
946 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
948 TRACE("(%p,%p)\n",pStm,rclsid);
950 if (rclsid==NULL)
951 return E_INVALIDARG;
953 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
956 /***********************************************************************
957 * ReadClassStm (OLE32.@)
959 * This function read a CLSID from a stream
961 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
963 ULONG nbByte;
964 HRESULT res;
966 TRACE("(%p,%p)\n",pStm,pclsid);
968 if (pclsid==NULL)
969 return E_INVALIDARG;
971 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
973 if (FAILED(res))
974 return res;
976 if (nbByte != sizeof(CLSID))
977 return S_FALSE;
978 else
979 return S_OK;
983 /***
984 * COM_GetRegisteredClassObject
986 * This internal method is used to scan the registered class list to
987 * find a class object.
989 * Params:
990 * rclsid Class ID of the class to find.
991 * dwClsContext Class context to match.
992 * ppv [out] returns a pointer to the class object. Complying
993 * to normal COM usage, this method will increase the
994 * reference count on this object.
996 static HRESULT COM_GetRegisteredClassObject(
997 REFCLSID rclsid,
998 DWORD dwClsContext,
999 LPUNKNOWN* ppUnk)
1001 HRESULT hr = S_FALSE;
1002 RegisteredClass* curClass;
1004 EnterCriticalSection( &csRegisteredClassList );
1007 * Sanity check
1009 assert(ppUnk!=0);
1012 * Iterate through the whole list and try to match the class ID.
1014 curClass = firstRegisteredClass;
1016 while (curClass != 0)
1019 * Check if we have a match on the class ID.
1021 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1024 * Since we don't do out-of process or DCOM just right away, let's ignore the
1025 * class context.
1029 * We have a match, return the pointer to the class object.
1031 *ppUnk = curClass->classObject;
1033 IUnknown_AddRef(curClass->classObject);
1035 hr = S_OK;
1036 goto end;
1040 * Step to the next class in the list.
1042 curClass = curClass->nextClass;
1045 end:
1046 LeaveCriticalSection( &csRegisteredClassList );
1048 * If we get to here, we haven't found our class.
1050 return hr;
1053 static DWORD WINAPI
1054 _LocalServerThread(LPVOID param) {
1055 HANDLE hPipe;
1056 char pipefn[200];
1057 RegisteredClass *newClass = (RegisteredClass*)param;
1058 HRESULT hres;
1059 IStream *pStm;
1060 STATSTG ststg;
1061 unsigned char *buffer;
1062 int buflen;
1063 IClassFactory *classfac;
1064 LARGE_INTEGER seekto;
1065 ULARGE_INTEGER newpos;
1066 ULONG res;
1068 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1070 strcpy(pipefn,PIPEPREF);
1071 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1073 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1074 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1075 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1076 if (hPipe == INVALID_HANDLE_VALUE) {
1077 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1078 return 1;
1080 while (1) {
1081 if (!ConnectNamedPipe(hPipe,NULL)) {
1082 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1083 break;
1086 TRACE("marshalling IClassFactory to client\n");
1088 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1089 if (hres) return hres;
1091 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1092 if (hres) {
1093 FIXME("Failed to create stream on hglobal.\n");
1094 return hres;
1096 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1097 if (hres) {
1098 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1099 return hres;
1102 IUnknown_Release(classfac); /* is this right? */
1104 hres = IStream_Stat(pStm,&ststg,0);
1105 if (hres) return hres;
1107 buflen = ststg.cbSize.u.LowPart;
1108 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1109 seekto.u.LowPart = 0;
1110 seekto.u.HighPart = 0;
1111 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1112 if (hres) {
1113 FIXME("IStream_Seek failed, %lx\n",hres);
1114 return hres;
1117 hres = IStream_Read(pStm,buffer,buflen,&res);
1118 if (hres) {
1119 FIXME("Stream Read failed, %lx\n",hres);
1120 return hres;
1123 IStream_Release(pStm);
1125 WriteFile(hPipe,buffer,buflen,&res,NULL);
1126 FlushFileBuffers(hPipe);
1127 DisconnectNamedPipe(hPipe);
1129 TRACE("done marshalling IClassFactory\n");
1131 CloseHandle(hPipe);
1132 return 0;
1135 /******************************************************************************
1136 * CoRegisterClassObject [OLE32.@]
1138 * This method will register the class object for a given class ID. Servers housed
1139 * in EXE files use this method instead of exporting DllGetClassObject to allow other
1140 * code to connect to their objects.
1142 * When a class object (an object which implements IClassFactory) is registered in
1143 * this way, a new thread is started which listens for connections on a named pipe
1144 * specific to the registered CLSID. When something else connects to it, it writes
1145 * out the marshalled IClassFactory interface to the pipe. The code on the other end
1146 * uses this buffer to unmarshal the class factory, and can then call methods on it.
1148 * In Windows, such objects are registered with the RPC endpoint mapper, not with
1149 * a unique named pipe.
1151 * See the Windows documentation for more details.
1153 HRESULT WINAPI CoRegisterClassObject(
1154 REFCLSID rclsid,
1155 LPUNKNOWN pUnk,
1156 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1157 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1158 LPDWORD lpdwRegister
1161 RegisteredClass* newClass;
1162 LPUNKNOWN foundObject;
1163 HRESULT hr;
1165 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1166 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1168 if ( (lpdwRegister==0) || (pUnk==0) )
1169 return E_INVALIDARG;
1171 *lpdwRegister = 0;
1174 * First, check if the class is already registered.
1175 * If it is, this should cause an error.
1177 * MSDN claims that multiple interface registrations are legal, but we can't do that with
1178 * our current implementation.
1180 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1181 if (hr == S_OK) {
1182 IUnknown_Release(foundObject);
1183 return CO_E_OBJISREG;
1186 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1187 if ( newClass == NULL )
1188 return E_OUTOFMEMORY;
1190 EnterCriticalSection( &csRegisteredClassList );
1192 newClass->classIdentifier = *rclsid;
1193 newClass->runContext = dwClsContext;
1194 newClass->connectFlags = flags;
1196 * Use the address of the chain node as the cookie since we are sure it's
1197 * unique.
1199 newClass->dwCookie = (DWORD)newClass;
1200 newClass->nextClass = firstRegisteredClass;
1203 * Since we're making a copy of the object pointer, we have to increase its
1204 * reference count.
1206 newClass->classObject = pUnk;
1207 IUnknown_AddRef(newClass->classObject);
1209 firstRegisteredClass = newClass;
1210 LeaveCriticalSection( &csRegisteredClassList );
1212 *lpdwRegister = newClass->dwCookie;
1214 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1215 DWORD tid;
1217 STUBMGR_Start();
1218 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1220 return S_OK;
1223 /***********************************************************************
1224 * CoRevokeClassObject [OLE32.@]
1226 * This method will remove a class object from the class registry
1228 * See the Windows documentation for more details.
1230 HRESULT WINAPI CoRevokeClassObject(
1231 DWORD dwRegister)
1233 HRESULT hr = E_INVALIDARG;
1234 RegisteredClass** prevClassLink;
1235 RegisteredClass* curClass;
1237 TRACE("(%08lx)\n",dwRegister);
1239 EnterCriticalSection( &csRegisteredClassList );
1242 * Iterate through the whole list and try to match the cookie.
1244 curClass = firstRegisteredClass;
1245 prevClassLink = &firstRegisteredClass;
1247 while (curClass != 0)
1250 * Check if we have a match on the cookie.
1252 if (curClass->dwCookie == dwRegister)
1255 * Remove the class from the chain.
1257 *prevClassLink = curClass->nextClass;
1260 * Release the reference to the class object.
1262 IUnknown_Release(curClass->classObject);
1265 * Free the memory used by the chain node.
1267 HeapFree(GetProcessHeap(), 0, curClass);
1269 hr = S_OK;
1270 goto end;
1274 * Step to the next class in the list.
1276 prevClassLink = &(curClass->nextClass);
1277 curClass = curClass->nextClass;
1280 end:
1281 LeaveCriticalSection( &csRegisteredClassList );
1283 * If we get to here, we haven't found our class.
1285 return hr;
1288 /***********************************************************************
1289 * compobj_RegReadPath [internal]
1291 * Reads a registry value and expands it when necessary
1293 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1295 HRESULT hres;
1296 HKEY key;
1297 DWORD keytype;
1298 char src[MAX_PATH];
1299 DWORD dwLength = dstlen;
1301 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1302 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1303 if (keytype == REG_EXPAND_SZ) {
1304 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1305 } else {
1306 lstrcpynA(dst, src, dstlen);
1309 RegCloseKey (key);
1311 return hres;
1314 /***********************************************************************
1315 * CoGetClassObject [COMPOBJ.7]
1316 * CoGetClassObject [OLE32.@]
1318 * FIXME. If request allows of several options and there is a failure
1319 * with one (other than not being registered) do we try the
1320 * others or return failure? (E.g. inprocess is registered but
1321 * the DLL is not found but the server version works)
1323 HRESULT WINAPI CoGetClassObject(
1324 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1325 REFIID iid, LPVOID *ppv
1327 LPUNKNOWN regClassObject;
1328 HRESULT hres = E_UNEXPECTED;
1329 char xclsid[80];
1330 HINSTANCE hLibrary;
1331 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1332 DllGetClassObjectFunc DllGetClassObject;
1334 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1336 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1338 if (pServerInfo) {
1339 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1340 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1344 * First, try and see if we can't match the class ID with one of the
1345 * registered classes.
1347 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1350 * Get the required interface from the retrieved pointer.
1352 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1355 * Since QI got another reference on the pointer, we want to release the
1356 * one we already have. If QI was unsuccessful, this will release the object. This
1357 * is good since we are not returning it in the "out" parameter.
1359 IUnknown_Release(regClassObject);
1361 return hres;
1364 /* first try: in-process */
1365 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1366 char keyname[MAX_PATH];
1367 char dllpath[MAX_PATH+1];
1369 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1371 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1372 /* failure: CLSID is not found in registry */
1373 WARN("class %s not registered inproc\n", xclsid);
1374 hres = REGDB_E_CLASSNOTREG;
1375 } else {
1376 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1377 /* failure: DLL could not be loaded */
1378 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1379 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1380 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1381 /* failure: the dll did not export DllGetClassObject */
1382 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1383 FreeLibrary( hLibrary );
1384 hres = CO_E_DLLNOTFOUND;
1385 } else {
1386 /* OK: get the ClassObject */
1387 COMPOBJ_DLLList_Add( hLibrary );
1388 return DllGetClassObject(rclsid, iid, ppv);
1393 /* Next try out of process */
1394 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1396 return create_marshalled_proxy(rclsid,iid,ppv);
1399 /* Finally try remote: this requires networked DCOM (a lot of work) */
1400 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1402 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1403 hres = E_NOINTERFACE;
1406 return hres;
1408 /***********************************************************************
1409 * CoResumeClassObjects (OLE32.@)
1411 * Resumes classobjects registered with REGCLS suspended
1413 HRESULT WINAPI CoResumeClassObjects(void)
1415 FIXME("stub\n");
1416 return S_OK;
1419 /***********************************************************************
1420 * GetClassFile (OLE32.@)
1422 * This function supplies the CLSID associated with the given filename.
1424 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1426 IStorage *pstg=0;
1427 HRESULT res;
1428 int nbElm, length, i;
1429 LONG sizeProgId;
1430 LPOLESTR *pathDec=0,absFile=0,progId=0;
1431 LPWSTR extension;
1432 static const WCHAR bkslashW[] = {'\\',0};
1433 static const WCHAR dotW[] = {'.',0};
1435 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1437 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1438 if((StgIsStorageFile(filePathName))==S_OK){
1440 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1442 if (SUCCEEDED(res))
1443 res=ReadClassStg(pstg,pclsid);
1445 IStorage_Release(pstg);
1447 return res;
1449 /* if the file is not a storage object then attemps to match various bits in the file against a
1450 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1451 this case
1453 for(i=0;i<nFileTypes;i++)
1455 for(i=0;j<nPatternsForType;j++){
1457 PATTERN pat;
1458 HANDLE hFile;
1460 pat=ReadPatternFromRegistry(i,j);
1461 hFile=CreateFileW(filePathName,,,,,,hFile);
1462 SetFilePosition(hFile,pat.offset);
1463 ReadFile(hFile,buf,pat.size,NULL,NULL);
1464 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1466 *pclsid=ReadCLSIDFromRegistry(i);
1467 return S_OK;
1472 /* if the above strategies fail then search for the extension key in the registry */
1474 /* get the last element (absolute file) in the path name */
1475 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1476 absFile=pathDec[nbElm-1];
1478 /* failed if the path represente a directory and not an absolute file name*/
1479 if (!lstrcmpW(absFile, bkslashW))
1480 return MK_E_INVALIDEXTENSION;
1482 /* get the extension of the file */
1483 extension = NULL;
1484 length=lstrlenW(absFile);
1485 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1486 /* nothing */;
1488 if (!extension || !lstrcmpW(extension, dotW))
1489 return MK_E_INVALIDEXTENSION;
1491 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1493 /* get the progId associated to the extension */
1494 progId = CoTaskMemAlloc(sizeProgId);
1495 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1497 if (res==ERROR_SUCCESS)
1498 /* return the clsid associated to the progId */
1499 res= CLSIDFromProgID(progId,pclsid);
1501 for(i=0; pathDec[i]!=NULL;i++)
1502 CoTaskMemFree(pathDec[i]);
1503 CoTaskMemFree(pathDec);
1505 CoTaskMemFree(progId);
1507 if (res==ERROR_SUCCESS)
1508 return res;
1510 return MK_E_INVALIDEXTENSION;
1512 /***********************************************************************
1513 * CoCreateInstance [COMPOBJ.13]
1514 * CoCreateInstance [OLE32.@]
1516 HRESULT WINAPI CoCreateInstance(
1517 REFCLSID rclsid,
1518 LPUNKNOWN pUnkOuter,
1519 DWORD dwClsContext,
1520 REFIID iid,
1521 LPVOID *ppv)
1523 HRESULT hres;
1524 LPCLASSFACTORY lpclf = 0;
1527 * Sanity check
1529 if (ppv==0)
1530 return E_POINTER;
1533 * Initialize the "out" parameter
1535 *ppv = 0;
1538 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1539 * Rather than create a class factory, we can just check for it here
1541 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1542 if (StdGlobalInterfaceTableInstance == NULL)
1543 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1544 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1545 if (hres) return hres;
1547 TRACE("Retrieved GIT (%p)\n", *ppv);
1548 return S_OK;
1552 * Get a class factory to construct the object we want.
1554 hres = CoGetClassObject(rclsid,
1555 dwClsContext,
1556 NULL,
1557 &IID_IClassFactory,
1558 (LPVOID)&lpclf);
1560 if (FAILED(hres)) {
1561 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1562 debugstr_guid(rclsid),hres);
1563 return hres;
1567 * Create the object and don't forget to release the factory
1569 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1570 IClassFactory_Release(lpclf);
1571 if(FAILED(hres))
1572 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1573 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1575 return hres;
1578 /***********************************************************************
1579 * CoCreateInstanceEx [OLE32.@]
1581 HRESULT WINAPI CoCreateInstanceEx(
1582 REFCLSID rclsid,
1583 LPUNKNOWN pUnkOuter,
1584 DWORD dwClsContext,
1585 COSERVERINFO* pServerInfo,
1586 ULONG cmq,
1587 MULTI_QI* pResults)
1589 IUnknown* pUnk = NULL;
1590 HRESULT hr;
1591 ULONG index;
1592 ULONG successCount = 0;
1595 * Sanity check
1597 if ( (cmq==0) || (pResults==NULL))
1598 return E_INVALIDARG;
1600 if (pServerInfo!=NULL)
1601 FIXME("() non-NULL pServerInfo not supported!\n");
1604 * Initialize all the "out" parameters.
1606 for (index = 0; index < cmq; index++)
1608 pResults[index].pItf = NULL;
1609 pResults[index].hr = E_NOINTERFACE;
1613 * Get the object and get its IUnknown pointer.
1615 hr = CoCreateInstance(rclsid,
1616 pUnkOuter,
1617 dwClsContext,
1618 &IID_IUnknown,
1619 (VOID**)&pUnk);
1621 if (hr)
1622 return hr;
1625 * Then, query for all the interfaces requested.
1627 for (index = 0; index < cmq; index++)
1629 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1630 pResults[index].pIID,
1631 (VOID**)&(pResults[index].pItf));
1633 if (pResults[index].hr == S_OK)
1634 successCount++;
1638 * Release our temporary unknown pointer.
1640 IUnknown_Release(pUnk);
1642 if (successCount == 0)
1643 return E_NOINTERFACE;
1645 if (successCount!=cmq)
1646 return CO_S_NOTALLINTERFACES;
1648 return S_OK;
1651 /***********************************************************************
1652 * CoLoadLibrary (OLE32.@)
1654 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1656 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1658 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1661 /***********************************************************************
1662 * CoFreeLibrary [OLE32.@]
1664 * NOTES: don't believe the documentation
1666 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1668 FreeLibrary(hLibrary);
1672 /***********************************************************************
1673 * CoFreeAllLibraries [OLE32.@]
1675 * NOTES: don't believe the documentation
1677 void WINAPI CoFreeAllLibraries(void)
1679 /* NOP */
1683 /***********************************************************************
1684 * CoFreeUnusedLibraries [COMPOBJ.17]
1685 * CoFreeUnusedLibraries [OLE32.@]
1687 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1688 * through the main apartment's thread to call DllCanUnloadNow
1690 void WINAPI CoFreeUnusedLibraries(void)
1692 COMPOBJ_DllList_FreeUnused(0);
1695 /***********************************************************************
1696 * CoFileTimeNow [COMPOBJ.82]
1697 * CoFileTimeNow [OLE32.@]
1699 * RETURNS
1700 * the current system time in lpFileTime
1702 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1704 GetSystemTimeAsFileTime( lpFileTime );
1705 return S_OK;
1708 /***********************************************************************
1709 * CoLoadLibrary (OLE32.@)
1711 static void COM_RevokeAllClasses()
1713 EnterCriticalSection( &csRegisteredClassList );
1715 while (firstRegisteredClass!=0)
1717 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1720 LeaveCriticalSection( &csRegisteredClassList );
1723 /****************************************************************************
1724 * COM External Lock methods implementation
1726 * This api provides a linked list to managed external references to
1727 * COM objects.
1729 * The public interface consists of three calls:
1730 * COM_ExternalLockAddRef
1731 * COM_ExternalLockRelease
1732 * COM_ExternalLockFreeList
1735 #define EL_END_OF_LIST 0
1736 #define EL_NOT_FOUND 0
1739 * Declaration of the static structure that manage the
1740 * external lock to COM objects.
1742 typedef struct COM_ExternalLock COM_ExternalLock;
1743 typedef struct COM_ExternalLockList COM_ExternalLockList;
1745 struct COM_ExternalLock
1747 IUnknown *pUnk; /* IUnknown referenced */
1748 ULONG uRefCount; /* external lock counter to IUnknown object*/
1749 COM_ExternalLock *next; /* Pointer to next element in list */
1752 struct COM_ExternalLockList
1754 COM_ExternalLock *head; /* head of list */
1758 * Declaration and initialization of the static structure that manages
1759 * the external lock to COM objects.
1761 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1764 * Private methods used to managed the linked list
1768 static COM_ExternalLock* COM_ExternalLockLocate(
1769 COM_ExternalLock *element,
1770 IUnknown *pUnk);
1772 /****************************************************************************
1773 * Internal - Insert a new IUnknown* to the linked list
1775 static BOOL COM_ExternalLockInsert(
1776 IUnknown *pUnk)
1778 COM_ExternalLock *newLock = NULL;
1779 COM_ExternalLock *previousHead = NULL;
1782 * Allocate space for the new storage object
1784 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1786 if (newLock!=NULL) {
1787 if ( elList.head == EL_END_OF_LIST ) {
1788 elList.head = newLock; /* The list is empty */
1789 } else {
1790 /* insert does it at the head */
1791 previousHead = elList.head;
1792 elList.head = newLock;
1795 /* Set new list item data member */
1796 newLock->pUnk = pUnk;
1797 newLock->uRefCount = 1;
1798 newLock->next = previousHead;
1800 return TRUE;
1802 return FALSE;
1805 /****************************************************************************
1806 * Internal - Method that removes an item from the linked list.
1808 static void COM_ExternalLockDelete(
1809 COM_ExternalLock *itemList)
1811 COM_ExternalLock *current = elList.head;
1813 if ( current == itemList ) {
1814 /* this section handles the deletion of the first node */
1815 elList.head = itemList->next;
1816 HeapFree( GetProcessHeap(), 0, itemList);
1817 } else {
1818 do {
1819 if ( current->next == itemList ){ /* We found the item to free */
1820 current->next = itemList->next; /* readjust the list pointers */
1821 HeapFree( GetProcessHeap(), 0, itemList);
1822 break;
1825 /* Skip to the next item */
1826 current = current->next;
1828 } while ( current != EL_END_OF_LIST );
1832 /****************************************************************************
1833 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1835 * NOTES: how long can the list be ?? (recursive!!!)
1837 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1839 if ( element == EL_END_OF_LIST )
1840 return EL_NOT_FOUND;
1841 else if ( element->pUnk == pUnk ) /* We found it */
1842 return element;
1843 else /* Not the right guy, keep on looking */
1844 return COM_ExternalLockLocate( element->next, pUnk);
1847 /****************************************************************************
1848 * Public - Method that increments the count for a IUnknown* in the linked
1849 * list. The item is inserted if not already in the list.
1851 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1853 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1856 * Add an external lock to the object. If it was already externally
1857 * locked, just increase the reference count. If it was not.
1858 * add the item to the list.
1860 if ( externalLock == EL_NOT_FOUND )
1861 COM_ExternalLockInsert(pUnk);
1862 else
1863 externalLock->uRefCount++;
1866 * Add an internal lock to the object
1868 IUnknown_AddRef(pUnk);
1871 /****************************************************************************
1872 * Public - Method that decrements the count for a IUnknown* in the linked
1873 * list. The item is removed from the list if its count end up at zero or if
1874 * bRelAll is TRUE.
1876 static void COM_ExternalLockRelease(
1877 IUnknown *pUnk,
1878 BOOL bRelAll)
1880 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1882 if ( externalLock != EL_NOT_FOUND ) {
1883 do {
1884 externalLock->uRefCount--; /* release external locks */
1885 IUnknown_Release(pUnk); /* release local locks as well */
1887 if ( bRelAll == FALSE ) break; /* perform single release */
1889 } while ( externalLock->uRefCount > 0 );
1891 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1892 COM_ExternalLockDelete(externalLock);
1895 /****************************************************************************
1896 * Public - Method that frees the content of the list.
1898 static void COM_ExternalLockFreeList()
1900 COM_ExternalLock *head;
1902 head = elList.head; /* grab it by the head */
1903 while ( head != EL_END_OF_LIST ) {
1904 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1905 head = elList.head; /* get the new head... */
1909 /****************************************************************************
1910 * Public - Method that dump the content of the list.
1912 void COM_ExternalLockDump()
1914 COM_ExternalLock *current = elList.head;
1916 DPRINTF("\nExternal lock list contains:\n");
1918 while ( current != EL_END_OF_LIST ) {
1919 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1921 /* Skip to the next item */
1922 current = current->next;
1926 /******************************************************************************
1927 * CoLockObjectExternal [OLE32.@]
1929 HRESULT WINAPI CoLockObjectExternal(
1930 LPUNKNOWN pUnk, /* [in] object to be locked */
1931 BOOL fLock, /* [in] do lock */
1932 BOOL fLastUnlockReleases) /* [in] unlock all */
1935 if (fLock) {
1937 * Increment the external lock coutner, COM_ExternalLockAddRef also
1938 * increment the object's internal lock counter.
1940 COM_ExternalLockAddRef( pUnk);
1941 } else {
1943 * Decrement the external lock coutner, COM_ExternalLockRelease also
1944 * decrement the object's internal lock counter.
1946 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1949 return S_OK;
1952 /***********************************************************************
1953 * CoInitializeWOW (OLE32.@)
1955 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1956 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1957 return 0;
1960 static int nStatCounter = 0; /* global */
1961 static HMODULE hOleAut32 = 0; /* global */
1963 /***********************************************************************
1964 * CoGetState [OLE32.@]
1966 * NOTES: might be incomplete
1968 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1970 APARTMENT * apt = COM_CurrentInfo();
1972 FIXME("\n");
1974 if(apt && apt->state) {
1975 IUnknown_AddRef(apt->state);
1976 *ppv = apt->state;
1977 FIXME("-- %p\n", *ppv);
1978 return S_OK;
1980 *ppv = NULL;
1981 return E_FAIL;
1985 /***********************************************************************
1986 * CoSetState [OLE32.@]
1988 * NOTES: FIXME: protect this with a crst
1990 HRESULT WINAPI CoSetState(IUnknown * pv)
1992 APARTMENT * apt = COM_CurrentInfo();
1994 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1996 FIXME("(%p),stub!\n", pv);
1998 if (pv) {
1999 IUnknown_AddRef(pv);
2000 nStatCounter++;
2001 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
2004 if (apt->state) {
2005 TRACE("-- release %p now\n", apt->state);
2006 IUnknown_Release(apt->state);
2007 nStatCounter--;
2008 if (!nStatCounter) FreeLibrary(hOleAut32);
2010 apt->state = pv;
2011 return S_OK;
2015 /******************************************************************************
2016 * OleGetAutoConvert [OLE32.@]
2018 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2020 HKEY hkey = 0;
2021 char buf[200];
2022 WCHAR wbuf[200];
2023 DWORD len;
2024 HRESULT res = S_OK;
2026 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2027 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2029 res = REGDB_E_CLASSNOTREG;
2030 goto done;
2032 len = 200;
2033 /* we can just query for the default value of AutoConvertTo key like that,
2034 without opening the AutoConvertTo key and querying for NULL (default) */
2035 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2037 res = REGDB_E_KEYMISSING;
2038 goto done;
2040 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2041 CLSIDFromString(wbuf,pClsidNew);
2042 done:
2043 if (hkey) RegCloseKey(hkey);
2044 return res;
2047 /******************************************************************************
2048 * OleSetAutoConvert [OLE32.@]
2050 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2052 HKEY hkey = 0;
2053 char buf[200], szClsidNew[200];
2054 HRESULT res = S_OK;
2056 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2057 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2058 WINE_StringFromCLSID(clsidNew, szClsidNew);
2059 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2061 res = REGDB_E_CLASSNOTREG;
2062 goto done;
2064 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2066 res = REGDB_E_WRITEREGDB;
2067 goto done;
2070 done:
2071 if (hkey) RegCloseKey(hkey);
2072 return res;
2075 /******************************************************************************
2076 * OleDoAutoConvert [OLE32.@]
2078 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2080 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2081 return E_NOTIMPL;
2084 /******************************************************************************
2085 * CoTreatAsClass [OLE32.@]
2087 * Sets TreatAs value of a class
2089 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2091 HKEY hkey = 0;
2092 char buf[47];
2093 char szClsidNew[39];
2094 HRESULT res = S_OK;
2095 char auto_treat_as[39];
2096 LONG auto_treat_as_size = sizeof(auto_treat_as);
2097 CLSID id;
2099 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2100 WINE_StringFromCLSID(clsidNew, szClsidNew);
2101 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2103 res = REGDB_E_CLASSNOTREG;
2104 goto done;
2106 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2108 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2109 !__CLSIDFromStringA(auto_treat_as, &id))
2111 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2113 res = REGDB_E_WRITEREGDB;
2114 goto done;
2117 else
2119 RegDeleteKeyA(hkey, "TreatAs");
2120 goto done;
2123 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2125 res = REGDB_E_WRITEREGDB;
2126 goto done;
2129 done:
2130 if (hkey) RegCloseKey(hkey);
2131 return res;
2134 /******************************************************************************
2135 * CoGetTreatAsClass [OLE32.@]
2137 * Reads the TreatAs value from a class.
2139 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2141 HKEY hkey = 0;
2142 char buf[200], szClsidNew[200];
2143 HRESULT res = S_OK;
2144 LONG len = sizeof(szClsidNew);
2146 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2147 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2148 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2150 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2152 res = REGDB_E_CLASSNOTREG;
2153 goto done;
2155 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2157 res = S_FALSE;
2158 goto done;
2160 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2161 if (FAILED(res))
2162 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2163 done:
2164 if (hkey) RegCloseKey(hkey);
2165 return res;
2169 /***********************************************************************
2170 * IsEqualGUID [OLE32.@]
2172 * Compares two Unique Identifiers.
2174 * RETURNS
2175 * TRUE if equal
2177 #undef IsEqualGUID
2178 BOOL WINAPI IsEqualGUID(
2179 REFGUID rguid1, /* [in] unique id 1 */
2180 REFGUID rguid2 /* [in] unique id 2 */
2183 return !memcmp(rguid1,rguid2,sizeof(GUID));
2186 /***********************************************************************
2187 * CoInitializeSecurity [OLE32.@]
2189 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2190 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2191 void* pReserved1, DWORD dwAuthnLevel,
2192 DWORD dwImpLevel, void* pReserved2,
2193 DWORD dwCapabilities, void* pReserved3)
2195 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2196 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2197 dwCapabilities, pReserved3);
2198 return S_OK;