source: trunk/src/ole32/ole32.cpp@ 291

Last change on this file since 291 was 291, checked in by davidr, 26 years ago

Updated clsid handling to correctly draw textual clsid's
Fixed GUID instansiation.
Moved initialisation to OLE32.CPP
Added many new APIs incl. CoCreateInstance & CoGetClassObject.
Many partially implemented stubs completed and moved to OLE32.CPP
Running Object Table implemented (Moniker.cpp)
IMalloc & Task Memory implemented.

File size: 20.6 KB
Line 
1/*
2 *
3 * Project Odin Software License can be found in LICENSE.TXT
4 *
5 */
6/*
7 * COM/OLE misc. functions.
8 *
9 * 1/7/99
10 *
11 * Copyright 1999 David J. Raison
12 *
13 * Some portions from Wine Implementation
14 * Copyright 1995 Martin von Loewis
15 * Copyright 1998 Justin Bradford
16 * Copyright 1999 Francis Beaudet
17 * Copyright 1999 Sylvain St-Germain
18 */
19
20#include "ole32.h"
21
22#include "oString.h"
23#include "moniker.h" // RunningObjectTableImpl_***
24
25// ======================================================================
26// Local Data
27// ======================================================================
28typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
29
30/*
31 * This linked list contains the list of registered class objects. These
32 * are mostly used to register the factories for out-of-proc servers of OLE
33 * objects.
34 */
35typedef struct tagRegisteredClass
36{
37 CLSID classIdentifier;
38 LPUNKNOWN classObject;
39 DWORD runContext;
40 DWORD connectFlags;
41 DWORD dwCookie;
42 struct tagRegisteredClass* nextClass;
43} RegisteredClass;
44
45static RegisteredClass* firstRegisteredClass = NULL;
46
47/*
48 * COM External Lock structures and methods declaration
49 *
50 * This api provides a linked list to managed external references to
51 * COM objects.
52 *
53 */
54
55#define EL_END_OF_LIST 0
56#define EL_NOT_FOUND 0
57
58/*
59 * Declaration of the static structure that manage the
60 * external lock to COM objects.
61 */
62typedef struct COM_ExternalLock COM_ExternalLock;
63typedef struct COM_ExternalLockList COM_ExternalLockList;
64
65struct COM_ExternalLock
66{
67 IUnknown *pUnk; /* IUnknown referenced */
68 ULONG uRefCount; /* external lock counter to IUnknown object*/
69 COM_ExternalLock *next; /* Pointer to next element in list */
70};
71
72struct COM_ExternalLockList
73{
74 COM_ExternalLock *head; /* head of list */
75};
76
77/*
78 * Declaration and initialization of the static structure that manages
79 * the external lock to COM objects.
80 */
81static COM_ExternalLockList elList = { EL_END_OF_LIST };
82
83/*
84 * This open DLL table belongs in a per process table, but my guess is that
85 * it shouldn't live in the kernel, so I'll put them out here in DLL
86 * space assuming that there is one OLE32 per process.
87 */
88typedef struct tagOpenDll
89{
90 char * DllName; /* really only needed for debugging */
91 HINSTANCE hLibrary;
92 struct tagOpenDll * next;
93} OpenDll;
94
95static OpenDll * openDllList = NULL; /* linked list of open dlls */
96
97/*
98 * Com Library reference count...
99 *
100 * Used to control loading / unloading of Library resources,
101 * Runnng object table, DLL's etc...
102 */
103static LONG COM_ref = 0;
104
105// ======================================================================
106// Prototypes.
107// ======================================================================
108static HRESULT COM_GetRegisteredClassObject(
109 REFCLSID rclsid,
110 DWORD dwClsContext,
111 LPUNKNOWN * ppUnk);
112
113static void COM_RevokeAllClasses();
114
115static void COM_ExternalLockFreeList();
116
117static void COM_ExternalLockAddRef(
118 IUnknown * pUnk);
119
120static void COM_ExternalLockRelease(
121 IUnknown * pUnk,
122 BOOL bRelAll);
123
124static BOOL COM_ExternalLockInsert(
125 IUnknown * pUnk);
126
127static void COM_ExternalLockDelete(
128 COM_ExternalLock * element);
129
130static COM_ExternalLock * COM_ExternalLockFind(
131 IUnknown * pUnk);
132
133static COM_ExternalLock * COM_ExternalLockLocate(
134 COM_ExternalLock * element,
135 IUnknown * pUnk);
136
137// ======================================================================
138// Public API's
139// ======================================================================
140
141// ----------------------------------------------------------------------
142// CoBuildVersion()
143// ----------------------------------------------------------------------
144DWORD WIN32API CoBuildVersion()
145{
146 dprintf(("OLE32.CoBuildVersion\n"));
147 return (rmm << 16) + rup;
148}
149
150// ----------------------------------------------------------------------
151// CoDosDateTimeToFileTime
152// ----------------------------------------------------------------------
153BOOL WIN32API CoDosDateTimeToFileTime(WORD nDosDate, WORD nDosTime,
154 FILETIME *lpFileTime)
155{
156 dprintf(("OLE32: CoDosDateTimeToFileTime"));
157
158 return DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
159}
160
161// ----------------------------------------------------------------------
162// CoDosDateTimeToFileTime
163// ----------------------------------------------------------------------
164HRESULT WIN32API CoFileTimeNow(FILETIME *lpFileTime)
165{
166 SYSTEMTIME systime;
167
168 dprintf(("OLE32: CoFileTimeNow"));
169
170 GetSystemTime(&systime);
171 return SystemTimeToFileTime(&systime, lpFileTime);
172}
173
174// ----------------------------------------------------------------------
175// CoDosDateTimeToFileTime
176// ----------------------------------------------------------------------
177BOOL WIN32API CoFileTimeToDosDateTime(FILETIME *lpFileTime, LPWORD lpDosDate,
178 LPWORD lpDosTime)
179{
180 dprintf(("OLE32: CoFileTimeToDosDateTime"));
181
182 return FileTimeToDosDateTime(lpFileTime, lpDosDate, lpDosTime);
183}
184
185// ----------------------------------------------------------------------
186// CoInitialize()
187// ----------------------------------------------------------------------
188HRESULT WIN32API CoInitialize(LPVOID lpReserved)
189{
190 dprintf(("OLE32: CoInitialize\n"));
191
192 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
193}
194
195// ----------------------------------------------------------------------
196// CoInitializeEx()
197// ----------------------------------------------------------------------
198HRESULT WIN32API CoInitializeEx(
199 LPVOID lpReserved, // [in] pointer to win32 malloc interface
200 DWORD dwCoInit) // [in] A value from COINIT specifies the thread
201{
202 HRESULT hr;
203
204 dprintf(("OLE32: CoInitializeEx(%p, %lx)\n", lpReserved, dwCoInit));
205
206 if (lpReserved != NULL)
207 {
208 dprintf(("Warning: Bad parameter %p, must be an old Windows Application", lpReserved));
209 }
210
211 /*
212 * Check for unsupported features.
213 */
214 if (dwCoInit != COINIT_APARTMENTTHREADED)
215 {
216 dprintf(("Warning: Unsupported flag %lx", dwCoInit));
217 /* Hope for the best and continue anyway */
218 }
219
220 /*
221 * Initialise the Running Object Table
222 */
223 hr = S_FALSE;
224 if (++COM_ref == 1)
225 {
226 hr = RunningObjectTableImpl_Initialize();
227 if (hr != S_OK)
228 --COM_ref;
229 }
230
231 return hr;
232}
233
234// ----------------------------------------------------------------------
235// CoUninitialize()
236// ----------------------------------------------------------------------
237void WIN32API CoUninitialize(void)
238{
239 dprintf(("OLE32: CoUninitialize"));
240
241 if (--COM_ref == 0)
242 {
243 dprintf(("OLE32: Releasing COM libraries"));
244
245 RunningObjectTableImpl_UnInitialize();
246
247 COM_RevokeAllClasses();
248
249 CoFreeAllLibraries();
250
251 COM_ExternalLockFreeList();
252 }
253}
254
255// ----------------------------------------------------------------------
256// CoCreateInstance
257// ----------------------------------------------------------------------
258HRESULT WIN32API CoCreateInstance
259 (REFCLSID rclsid,
260 LPUNKNOWN pUnkOuter,
261 DWORD dwClsContext,
262 REFIID iid,
263 LPVOID * ppv)
264{
265 HRESULT hres;
266 LPCLASSFACTORY lpclf = 0;
267
268 oStringA tCLSID(rclsid);
269 oStringA tIId(iid);
270
271 dprintf(("OLE32: CoCreateInstance"));
272 dprintf((" CLSID:%s", (char *)tCLSID));
273 dprintf((" IID :%s", (char *)tIId));
274
275 // Sanity check
276 if (ppv == 0)
277 return E_POINTER;
278
279 *ppv = 0;
280
281 // Get a class factory to construct the object we want.
282 hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID *)&lpclf);
283
284 if (FAILED(hres))
285 return hres;
286
287 // Create the object and don't forget to release the factory
288 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
289 IClassFactory_Release(lpclf);
290
291 return hres;
292}
293
294// ----------------------------------------------------------------------
295// CoCreateInstanceEx
296// ----------------------------------------------------------------------
297HRESULT WIN32API CoCreateInstanceEx
298 (REFCLSID rclsid,
299 LPUNKNOWN pUnkOuter,
300 DWORD dwClsContext,
301 COSERVERINFO * pServerInfo,
302 ULONG cmq,
303 MULTI_QI * pResults)
304{
305 IUnknown * pUnk = NULL;
306 HRESULT hr;
307 ULONG index;
308 int successCount = 0;
309
310 oStringA tCLSID(rclsid);
311
312 dprintf(("OLE32: CoCreateInstanceEx"));
313 dprintf((" CLSID:%s", (char *)tCLSID));
314
315 // Sanity check
316 if ( (cmq == 0) || (pResults == NULL))
317 return E_INVALIDARG;
318
319 if (pServerInfo != NULL)
320 dprintf(("OLE32: CoCreateInstanceEx - pServerInfo not supported!"));
321
322 // Initialize all the "out" parameters.
323 for (index = 0; index < cmq; index++)
324 {
325 pResults[index].pItf = NULL;
326 pResults[index].hr = E_NOINTERFACE;
327 }
328
329 /*
330 * Get the object and get it's IUnknown pointer.
331 */
332 hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, &IID_IUnknown, (VOID**)&pUnk);
333
334 if (hr)
335 return hr;
336
337 /*
338 * Then, query for all the interfaces requested.
339 */
340 for (index = 0; index < cmq; index++)
341 {
342 pResults[index].hr = IUnknown_QueryInterface(pUnk, pResults[index].pIID, (VOID**)&(pResults[index].pItf));
343
344 if (pResults[index].hr == S_OK)
345 successCount++;
346 }
347
348 /*
349 * Release our temporary unknown pointer.
350 */
351 IUnknown_Release(pUnk);
352
353 if (successCount == 0)
354 return E_NOINTERFACE;
355
356 if (successCount != cmq)
357 return CO_S_NOTALLINTERFACES;
358
359 return S_OK;
360}
361
362// ----------------------------------------------------------------------
363// CoGetClassObject
364// ----------------------------------------------------------------------
365HRESULT WIN32API CoGetClassObject
366 (REFCLSID rclsid,
367 DWORD dwClsContext,
368 LPVOID pvReserved,
369 REFIID iid,
370 LPVOID * ppv)
371{
372 LPUNKNOWN regClassObject;
373 HRESULT hres = E_UNEXPECTED;
374
375 char dllName[MAX_PATH+1];
376 LONG dllNameLen = sizeof(dllName);
377 HINSTANCE hLibrary;
378
379 DllGetClassObjectFunc DllGetClassObject;
380 oStringA tCLSID(rclsid);
381
382#ifdef DEBUG
383 oStringA tIId(iid);
384 dprintf(("OLE32: CoGetClassObject"));
385 dprintf((" CLSID:%s", (char *)tCLSID));
386 dprintf((" IID :%s", (char *)tIId));
387#endif
388
389 // First, try and see if we can't match the class ID with one of the
390 // registered classes.
391 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
392 {
393 // Get the required interface from the retrieved pointer.
394 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
395
396 // Since QI got another reference on the pointer, we want to release the
397 // one we already have. If QI was unsuccessful, this will release the object. This
398 // is good since we are not returning it in the "out" parameter.
399 IUnknown_Release(regClassObject);
400
401 return hres;
402 }
403
404 // out of process and remote servers not supported yet...
405 if (dwClsContext & CLSCTX_LOCAL_SERVER)
406 {
407 dprintf(("OLE32: CoGetClassObject - CLSCTX_LOCAL_SERVER not supported!\n"));
408 return E_ACCESSDENIED;
409 }
410
411 if (dwClsContext & CLSCTX_REMOTE_SERVER)
412 {
413 dprintf(("OLE32: CoGetClassObject - CLSCTX_REMOTE_SERVER not supported!\n"));
414 return E_ACCESSDENIED;
415 }
416
417 // Get down to the biz..
418 if (dwClsContext & (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER))
419 {
420 HKEY CLSIDkey;
421 HKEY key;
422
423 /* lookup CLSID in registry key HKCR/CLSID */
424 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &CLSIDkey);
425 if (hres != ERROR_SUCCESS)
426 return REGDB_E_READREGDB;
427
428 hres = RegOpenKeyExA(CLSIDkey, tCLSID, 0, KEY_QUERY_VALUE, &key);
429 if (hres != ERROR_SUCCESS)
430 {
431 RegCloseKey(CLSIDkey);
432 return REGDB_E_CLASSNOTREG;
433 }
434
435 hres = RegQueryValueA(key, "InprocServer32", dllName, &dllNameLen);
436 RegCloseKey(key);
437 RegCloseKey(CLSIDkey);
438 if (hres != ERROR_SUCCESS)
439 {
440 dprintf(("OLE32: CoGetClassObject - InprocServer32 not found in registry"));
441 return REGDB_E_READREGDB;
442 }
443
444 dprintf(("OLE32: CoGetClassObject - Registry reports InprocServer32 dll as %s\n", dllName));
445
446 /* open dll, call DllGetClassFactory */
447 hLibrary = CoLoadLibrary(dllName, TRUE);
448 if (hLibrary == 0)
449 {
450 dprintf(("OLE32: CoGetClassObject - couldn't load %s\n", dllName));
451 return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
452 }
453
454 DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
455 if (!DllGetClassObject)
456 {
457 dprintf(("OLE32: CoGetClassObject - couldn't function DllGetClassObject in %s\n", dllName));
458 /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
459 return E_ACCESSDENIED;
460 }
461
462 // Ask the DLL for it's class object. (there was a note here about class
463 // factories but this is good.
464 return DllGetClassObject(rclsid, iid, ppv);
465 }
466 return hres;
467}
468
469// ======================================================================
470// Private functions.
471// ======================================================================
472
473// ----------------------------------------------------------------------
474// COM_GetRegisteredClassObject
475// ----------------------------------------------------------------------
476// This internal method is used to scan the registered class list to
477// find a class object.
478//
479// Params:
480// rclsid Class ID of the class to find.
481// dwClsContext Class context to match.
482// ppv [out] returns a pointer to the class object. Complying
483// to normal COM usage, this method will increase the
484// reference count on this object.
485static HRESULT COM_GetRegisteredClassObject
486 (REFCLSID rclsid,
487 DWORD dwClsContext,
488 LPUNKNOWN * ppUnk)
489{
490 RegisteredClass* curClass;
491
492 oStringA tCLSID(rclsid);
493
494 dprintf(("OLE32: COM_GetRegisteredClassObject"));
495 dprintf((" CLSID:%s", (char *)tCLSID));
496
497 // Sanity check
498 if (ppUnk == 0)
499 return E_POINTER;
500
501 // Iterate through the whole list and try to match the class ID.
502 curClass = firstRegisteredClass;
503
504 while (curClass != 0)
505 {
506 // Check if we have a match on the class ID.
507 if (IsEqualGUID(curClass->classIdentifier, rclsid))
508 {
509 // Since we don't do out-of process or DCOM just right away,
510 // let's ignore the class context.
511
512 // We have a match, return the pointer to the class object.
513 *ppUnk = curClass->classObject;
514
515 IUnknown_AddRef(curClass->classObject);
516
517 return S_OK;
518 }
519
520 // Step to the next class in the list.
521 curClass = curClass->nextClass;
522 }
523
524 // If we get to here, we haven't found our class.
525 return S_FALSE;
526}
527
528// ----------------------------------------------------------------------
529// COM_RevokeAllClasses
530// ----------------------------------------------------------------------
531// This method is called when the COM libraries are uninitialized to
532// release all the references to the class objects registered with
533// the library
534static void COM_RevokeAllClasses()
535{
536 dprintf(("OLE32: COM_RevokeAllClasses"));
537
538 while (firstRegisteredClass != 0)
539 {
540 CoRevokeClassObject(firstRegisteredClass->dwCookie);
541 }
542}
543
544// ----------------------------------------------------------------------
545// COM_ExternalLockAddRef
546// ----------------------------------------------------------------------
547// Method that increments the count for a IUnknown* in the linked
548// list. The item is inserted if not already in the list.
549static void COM_ExternalLockAddRef(IUnknown * pUnk)
550{
551 dprintf(("OLE32: COM_ExternalLockAddRef"));
552
553 COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
554
555 /*
556 * Add an external lock to the object. If it was already externally
557 * locked, just increase the reference count. If it was not.
558 * add the item to the list.
559 */
560 if ( externalLock == EL_NOT_FOUND )
561 COM_ExternalLockInsert(pUnk);
562 else
563 externalLock->uRefCount++;
564
565 /*
566 * Add an internal lock to the object
567 */
568 IUnknown_AddRef(pUnk);
569}
570
571// ----------------------------------------------------------------------
572// COM_ExternalLockRelease
573// ----------------------------------------------------------------------
574// Method that decrements the count for a IUnknown* in the linked
575// list. The item is removed from the list if its count end up at zero or if
576// bRelAll is TRUE.
577static void COM_ExternalLockRelease(IUnknown * pUnk, BOOL bRelAll)
578{
579 dprintf(("OLE32: COM_ExternalLockRelease"));
580
581 COM_ExternalLock * externalLock = COM_ExternalLockFind(pUnk);
582
583 if ( externalLock != EL_NOT_FOUND )
584 {
585 do
586 {
587 externalLock->uRefCount--; /* release external locks */
588 IUnknown_Release(pUnk); /* release local locks as well */
589
590 if ( bRelAll == FALSE )
591 break; /* perform single release */
592
593 } while ( externalLock->uRefCount > 0 );
594
595 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
596 COM_ExternalLockDelete(externalLock);
597 }
598}
599
600// ----------------------------------------------------------------------
601// COM_ExternalLockFreeList
602// ----------------------------------------------------------------------
603// Method that frees the content of the list.
604static void COM_ExternalLockFreeList()
605{
606 dprintf(("OLE32: COM_ExternalLockFreeList"));
607
608 COM_ExternalLock *head;
609
610 head = elList.head; /* grab it by the head */
611 while (head != EL_END_OF_LIST)
612 {
613 COM_ExternalLockDelete(head); /* get rid of the head stuff */
614
615 head = elList.head; /* get the new head... */
616 }
617}
618
619// ----------------------------------------------------------------------
620// COM_ExternalLockDump
621// ----------------------------------------------------------------------
622// Method that dump the content of the list.
623void COM_ExternalLockDump()
624{
625 dprintf(("OLE32: COM_ExternalLockDump"));
626
627 COM_ExternalLock *current = elList.head;
628
629 printf("External lock list:");
630
631 while ( current != EL_END_OF_LIST )
632 {
633 dprintf((" %p with %lu references count.\n", current->pUnk, current->uRefCount));
634
635 /* Skip to the next item */
636 current = current->next;
637 }
638}
639
640// ----------------------------------------------------------------------
641// COM_ExternalLockFind
642// ----------------------------------------------------------------------
643// Find a IUnknown* in the linked list
644static COM_ExternalLock * COM_ExternalLockFind(IUnknown *pUnk)
645{
646 dprintf(("OLE32: COM_ExternalLockFind"));
647
648 return COM_ExternalLockLocate(elList.head, pUnk);
649}
650
651// ----------------------------------------------------------------------
652// COM_ExternalLockLocate
653// ----------------------------------------------------------------------
654// Recursivity agent for IUnknownExternalLockList_Find
655static COM_ExternalLock * COM_ExternalLockLocate( COM_ExternalLock * element, IUnknown * pUnk)
656{
657 if ( element == EL_END_OF_LIST )
658 return EL_NOT_FOUND;
659
660 else if ( element->pUnk == pUnk ) /* We found it */
661 return element;
662
663 else /* Not the right guy, keep on looking */
664 return COM_ExternalLockLocate( element->next, pUnk);
665}
666
667// ----------------------------------------------------------------------
668// COM_ExternalLockInsert
669// ----------------------------------------------------------------------
670// Insert a new IUnknown* to the linked list
671static BOOL COM_ExternalLockInsert(IUnknown * pUnk)
672{
673 dprintf(("OLE32: COM_ExternalLockInsert"));
674
675 COM_ExternalLock * newLock = NULL;
676 COM_ExternalLock * previousHead = NULL;
677
678 // Allocate space for the new storage object
679 newLock = (COM_ExternalLock *)HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
680
681 if (newLock != NULL)
682 {
683 if ( elList.head == EL_END_OF_LIST )
684 elList.head = newLock; /* The list is empty */
685 else
686 {
687 // insert does it at the head
688 previousHead = elList.head;
689 elList.head = newLock;
690 }
691
692 /*
693 * Set new list item data member
694 */
695 newLock->pUnk = pUnk;
696 newLock->uRefCount = 1;
697 newLock->next = previousHead;
698
699 return TRUE;
700 }
701
702 return FALSE;
703}
704
705// ----------------------------------------------------------------------
706// ExternalLockDelete
707// ----------------------------------------------------------------------
708// Method that removes an item from the linked list.
709static void COM_ExternalLockDelete(COM_ExternalLock * itemList)
710{
711 dprintf(("OLE32: ExternalLockDelete"));
712
713 COM_ExternalLock *current = elList.head;
714
715 if ( current == itemList )
716 {
717 // this section handles the deletion of the first node
718 elList.head = itemList->next;
719 HeapFree( GetProcessHeap(), 0, itemList);
720 }
721 else
722 {
723 do
724 {
725 if ( current->next == itemList ) /* We found the item to free */
726 {
727 current->next = itemList->next; /* readjust the list pointers */
728
729 HeapFree( GetProcessHeap(), 0, itemList);
730 break;
731 }
732
733 /* Skip to the next item */
734 current = current->next;
735
736 } while ( current != EL_END_OF_LIST );
737 }
738}
Note: See TracBrowser for help on using the repository browser.