source: trunk/src/ole32/old/ole32.cpp@ 6496

Last change on this file since 6496 was 5601, checked in by sandervl, 24 years ago

created

File size: 26.3 KB
Line 
1/* $Id: ole32.cpp,v 1.1 2001-04-26 19:26:12 sandervl Exp $ */
2/*
3 *
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 */
7/*
8 * COM/OLE misc. functions.
9 *
10 * 1/7/99
11 *
12 * Copyright 1999 David J. Raison
13 *
14 * Some portions from Wine Implementation
15 * Copyright 1995 Martin von Loewis
16 * Copyright 1998 Justin Bradford
17 * Copyright 1999 Francis Beaudet
18 * Copyright 1999 Sylvain St-Germain
19 */
20
21#include "ole32.h"
22
23#include "oString.h"
24#include "moniker.h" // RunningObjectTableImpl_***
25#include "filemoniker.h" // FileMonikerImpl_***
26
27// ======================================================================
28// Local Data
29// ======================================================================
30typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
31
32/*
33 * This linked list contains the list of registered class objects. These
34 * are mostly used to register the factories for out-of-proc servers of OLE
35 * objects.
36 */
37typedef struct tagRegisteredClass
38{
39 CLSID classIdentifier;
40 LPUNKNOWN classObject;
41 DWORD runContext;
42 DWORD connectFlags;
43 DWORD dwCookie;
44 struct tagRegisteredClass* nextClass;
45} RegisteredClass;
46
47static RegisteredClass* firstRegisteredClass = NULL;
48
49/*
50 * COM External Lock structures and methods declaration
51 *
52 * This api provides a linked list to managed external references to
53 * COM objects.
54 *
55 */
56
57#define EL_END_OF_LIST 0
58#define EL_NOT_FOUND 0
59
60/*
61 * Declaration of the static structure that manage the
62 * external lock to COM objects.
63 */
64typedef struct COM_ExternalLock COM_ExternalLock;
65typedef struct COM_ExternalLockList COM_ExternalLockList;
66
67struct COM_ExternalLock
68{
69 IUnknown *pUnk; /* IUnknown referenced */
70 ULONG uRefCount; /* external lock counter to IUnknown object*/
71 COM_ExternalLock *next; /* Pointer to next element in list */
72};
73
74struct COM_ExternalLockList
75{
76 COM_ExternalLock *head; /* head of list */
77};
78
79/*
80 * Declaration and initialization of the static structure that manages
81 * the external lock to COM objects.
82 */
83static COM_ExternalLockList elList = { EL_END_OF_LIST };
84
85/*
86 * Com Library reference count...
87 *
88 * Used to control loading / unloading of Library resources,
89 * Runnng object table, DLL's etc...
90 */
91static LONG COM_ref = 0;
92
93// ======================================================================
94// Prototypes.
95// ======================================================================
96static HRESULT COM_GetRegisteredClassObject(
97 REFCLSID rclsid,
98 DWORD dwClsContext,
99 LPUNKNOWN * ppUnk);
100
101static void COM_RevokeAllClasses();
102
103static void COM_ExternalLockFreeList();
104
105static void COM_ExternalLockAddRef(
106 IUnknown * pUnk);
107
108static void COM_ExternalLockRelease(
109 IUnknown * pUnk,
110 BOOL bRelAll);
111
112static BOOL COM_ExternalLockInsert(
113 IUnknown * pUnk);
114
115static void COM_ExternalLockDelete(
116 COM_ExternalLock * element);
117
118static COM_ExternalLock * COM_ExternalLockFind(
119 IUnknown * pUnk);
120
121static COM_ExternalLock * COM_ExternalLockLocate(
122 COM_ExternalLock * element,
123 IUnknown * pUnk);
124
125// ======================================================================
126// Public API's
127// ======================================================================
128
129// ----------------------------------------------------------------------
130// CoBuildVersion()
131// ----------------------------------------------------------------------
132DWORD WIN32API CoBuildVersion()
133{
134 dprintf(("OLE32.CoBuildVersion"));
135 return (rmm << 16) + rup;
136}
137
138// ----------------------------------------------------------------------
139// CoDosDateTimeToFileTime
140// ----------------------------------------------------------------------
141BOOL WIN32API CoDosDateTimeToFileTime(WORD nDosDate, WORD nDosTime,
142 FILETIME *lpFileTime)
143{
144 dprintf(("OLE32: CoDosDateTimeToFileTime"));
145
146 return DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
147}
148
149// ----------------------------------------------------------------------
150// CoDosDateTimeToFileTime
151// ----------------------------------------------------------------------
152HRESULT WIN32API CoFileTimeNow(FILETIME *lpFileTime)
153{
154 SYSTEMTIME systime;
155
156 dprintf(("OLE32: CoFileTimeNow"));
157
158 GetSystemTime(&systime);
159 return SystemTimeToFileTime(&systime, lpFileTime);
160}
161
162// ----------------------------------------------------------------------
163// CoDosDateTimeToFileTime
164// ----------------------------------------------------------------------
165BOOL WIN32API CoFileTimeToDosDateTime(FILETIME *lpFileTime, LPWORD lpDosDate,
166 LPWORD lpDosTime)
167{
168 dprintf(("OLE32: CoFileTimeToDosDateTime"));
169
170 return FileTimeToDosDateTime(lpFileTime, lpDosDate, lpDosTime);
171}
172
173// ----------------------------------------------------------------------
174// CoInitialize()
175// ----------------------------------------------------------------------
176HRESULT WIN32API CoInitialize(LPVOID lpReserved)
177{
178 dprintf(("OLE32: CoInitialize\n"));
179
180 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
181}
182
183// ----------------------------------------------------------------------
184// CoInitializeEx()
185// ----------------------------------------------------------------------
186HRESULT WIN32API CoInitializeEx(
187 LPVOID lpReserved, // [in] pointer to win32 malloc interface
188 DWORD dwCoInit) // [in] A value from COINIT specifies the thread
189{
190 HRESULT hr;
191
192 dprintf(("OLE32: CoInitializeEx(%p, %lx)\n", lpReserved, dwCoInit));
193
194 if (lpReserved != NULL)
195 {
196 dprintf(("Warning: Bad parameter %p, must be an old Windows Application", lpReserved));
197 }
198
199 /*
200 * Check for unsupported features.
201 */
202 if (dwCoInit != COINIT_APARTMENTTHREADED)
203 {
204 dprintf(("Warning: Unsupported flag %lx", dwCoInit));
205 /* Hope for the best and continue anyway */
206 }
207
208 /*
209 * Initialise the Running Object Table
210 */
211 hr = S_FALSE;
212 if (++COM_ref == 1)
213 {
214 hr = RunningObjectTableImpl_Initialize();
215 if (hr != S_OK)
216 --COM_ref;
217 }
218
219 return hr;
220}
221
222// ----------------------------------------------------------------------
223// CoUninitialize()
224// ----------------------------------------------------------------------
225void WIN32API CoUninitialize(void)
226{
227 dprintf(("OLE32: CoUninitialize"));
228
229 if (--COM_ref == 0)
230 {
231 dprintf(("OLE32: Releasing COM libraries"));
232
233 RunningObjectTableImpl_UnInitialize();
234
235 COM_RevokeAllClasses();
236
237 CoFreeAllLibraries();
238
239 COM_ExternalLockFreeList();
240 }
241}
242
243// ----------------------------------------------------------------------
244// CoCreateInstance
245// ----------------------------------------------------------------------
246HRESULT WIN32API CoCreateInstance
247 (REFCLSID rclsid,
248 LPUNKNOWN pUnkOuter,
249 DWORD dwClsContext,
250 REFIID iid,
251 LPVOID * ppv)
252{
253 HRESULT hres;
254 LPCLASSFACTORY lpclf = 0;
255
256 oStringA tCLSID(rclsid);
257 oStringA tIId(iid);
258
259 dprintf(("OLE32: CoCreateInstance"));
260 dprintf((" CLSID:%s", (char *)tCLSID));
261 dprintf((" IID :%s", (char *)tIId));
262
263 // Sanity check
264 if (ppv == 0)
265 return E_POINTER;
266
267 *ppv = 0;
268
269 // Get a class factory to construct the object we want.
270 hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID *)&lpclf);
271
272 if (FAILED(hres))
273 return hres;
274
275 // Create the object and don't forget to release the factory
276 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
277 IClassFactory_Release(lpclf);
278
279 return hres;
280}
281
282// ----------------------------------------------------------------------
283// CoCreateInstanceEx
284// ----------------------------------------------------------------------
285HRESULT WIN32API CoCreateInstanceEx
286 (REFCLSID rclsid,
287 LPUNKNOWN pUnkOuter,
288 DWORD dwClsContext,
289 COSERVERINFO * pServerInfo,
290 ULONG cmq,
291 MULTI_QI * pResults)
292{
293 IUnknown * pUnk = NULL;
294 HRESULT hr;
295 ULONG index;
296 int successCount = 0;
297
298 oStringA tCLSID(rclsid);
299
300 dprintf(("OLE32: CoCreateInstanceEx"));
301 dprintf((" CLSID:%s", (char *)tCLSID));
302
303 // Sanity check
304 if ( (cmq == 0) || (pResults == NULL))
305 return E_INVALIDARG;
306
307 if (pServerInfo != NULL)
308 dprintf(("OLE32: CoCreateInstanceEx - pServerInfo not supported!"));
309
310 // Initialize all the "out" parameters.
311 for (index = 0; index < cmq; index++)
312 {
313 pResults[index].pItf = NULL;
314 pResults[index].hr = E_NOINTERFACE;
315 }
316
317 /*
318 * Get the object and get it's IUnknown pointer.
319 */
320 hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, &IID_IUnknown, (VOID**)&pUnk);
321
322 if (hr)
323 return hr;
324
325 /*
326 * Then, query for all the interfaces requested.
327 */
328 for (index = 0; index < cmq; index++)
329 {
330 pResults[index].hr = IUnknown_QueryInterface(pUnk, pResults[index].pIID, (VOID**)&(pResults[index].pItf));
331
332 if (pResults[index].hr == S_OK)
333 successCount++;
334 }
335
336 /*
337 * Release our temporary unknown pointer.
338 */
339 IUnknown_Release(pUnk);
340
341 if (successCount == 0)
342 return E_NOINTERFACE;
343
344 if (successCount != cmq)
345 return CO_S_NOTALLINTERFACES;
346
347 return S_OK;
348}
349
350// ----------------------------------------------------------------------
351// CoGetClassObject
352// ----------------------------------------------------------------------
353HRESULT WIN32API CoGetClassObject
354 (REFCLSID rclsid,
355 DWORD dwClsContext,
356 LPVOID pvReserved,
357 REFIID iid,
358 LPVOID * ppv)
359{
360 LPUNKNOWN regClassObject;
361 HRESULT hres = E_UNEXPECTED;
362
363 char dllName[MAX_PATH+1];
364 LONG dllNameLen = sizeof(dllName);
365 HINSTANCE hLibrary;
366
367 DllGetClassObjectFunc DllGetClassObject;
368 oStringA tCLSID(rclsid);
369
370#ifdef DEBUG
371 oStringA tIId(iid);
372 dprintf(("OLE32: CoGetClassObject"));
373 dprintf((" CLSID:%s", (char *)tCLSID));
374 dprintf((" IID :%s", (char *)tIId));
375#endif
376
377 // First, try and see if we can't match the class ID with one of the
378 // registered classes.
379 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
380 {
381 // Get the required interface from the retrieved pointer.
382 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
383
384 // Since QI got another reference on the pointer, we want to release the
385 // one we already have. If QI was unsuccessful, this will release the object. This
386 // is good since we are not returning it in the "out" parameter.
387 IUnknown_Release(regClassObject);
388
389 return hres;
390 }
391
392 // out of process and remote servers not supported yet...
393 if (dwClsContext & CLSCTX_LOCAL_SERVER)
394 {
395 dprintf(("OLE32: CoGetClassObject - CLSCTX_LOCAL_SERVER not supported!\n"));
396// return E_ACCESSDENIED;
397 dwClsContext |= CLSCTX_INPROC_SERVER; // Kludge as VB uses CLSCTX_LOCAL_SERVER
398 }
399
400 if (dwClsContext & CLSCTX_REMOTE_SERVER)
401 {
402 dprintf(("OLE32: CoGetClassObject - CLSCTX_REMOTE_SERVER not supported!\n"));
403 return E_ACCESSDENIED;
404 }
405
406 // Get down to the biz..
407 if (dwClsContext & (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER))
408 {
409 HKEY CLSIDkey;
410 HKEY key;
411
412 /* lookup CLSID in registry key HKCR/CLSID */
413 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &CLSIDkey);
414 if (hres != ERROR_SUCCESS)
415 return REGDB_E_READREGDB;
416
417 hres = RegOpenKeyExA(CLSIDkey, tCLSID, 0, KEY_QUERY_VALUE, &key);
418 if (hres != ERROR_SUCCESS)
419 {
420 RegCloseKey(CLSIDkey);
421 return REGDB_E_CLASSNOTREG;
422 }
423
424 hres = RegQueryValueA(key, "InprocServer32", dllName, &dllNameLen);
425 RegCloseKey(key);
426 RegCloseKey(CLSIDkey);
427 if (hres != ERROR_SUCCESS)
428 {
429 dprintf(("OLE32: CoGetClassObject - InprocServer32 not found in registry"));
430 return REGDB_E_READREGDB;
431 }
432
433 dprintf(("OLE32: CoGetClassObject - Registry reports InprocServer32 dll as %s\n", dllName));
434
435 /* open dll, call DllGetClassFactory */
436 hLibrary = CoLoadLibrary(dllName, TRUE);
437 if (hLibrary == 0)
438 {
439 dprintf(("OLE32: CoGetClassObject - couldn't load %s\n", dllName));
440 return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
441 }
442
443 DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
444 if (!DllGetClassObject)
445 {
446 dprintf(("OLE32: CoGetClassObject - couldn't function DllGetClassObject in %s\n", dllName));
447 /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
448 return E_ACCESSDENIED;
449 }
450
451 // Ask the DLL for it's class object. (there was a note here about class
452 // factories but this is good.
453 return DllGetClassObject(rclsid, iid, ppv);
454 }
455 return hres;
456}
457
458// ----------------------------------------------------------------------
459// CoLockObjectExternal
460// ----------------------------------------------------------------------
461HRESULT WIN32API CoLockObjectExternal(IUnknown *pUnk, BOOL fLock, BOOL fLastUnlockReleases)
462{
463 dprintf(("OLE32: CoLockObjectExternal"));
464
465 if (fLock)
466 {
467 /*
468 * Increment the external lock coutner, COM_ExternalLockAddRef also
469 * increment the object's internal lock counter.
470 */
471 COM_ExternalLockAddRef( pUnk);
472 }
473 else
474 {
475 /*
476 * Decrement the external lock coutner, COM_ExternalLockRelease also
477 * decrement the object's internal lock counter.
478 */
479 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
480 }
481
482 return S_OK;
483}
484
485// ----------------------------------------------------------------------
486// CoRegisterClassObject
487// ----------------------------------------------------------------------
488HRESULT WIN32API CoRegisterClassObject(
489 REFCLSID rclsid,
490 LPUNKNOWN pUnk,
491 DWORD dwClsContext, // Context in which to run the executable
492 DWORD flags, // how connections are made
493 LPDWORD lpdwRegister)
494{
495 RegisteredClass * newClass;
496 LPUNKNOWN foundObject;
497 HRESULT hr;
498 oStringA tClsid(rclsid);
499
500 dprintf(("OLE32: CoRegisterClassObject(%s)", (char *)tClsid));
501
502 // Perform a sanity check on the parameters
503 if ((lpdwRegister == 0) || (pUnk == 0))
504 return E_INVALIDARG;
505
506 // Initialize the cookie (out parameter)
507 *lpdwRegister = 0;
508
509 // First, check if the class is already registered.
510 // If it is, this should cause an error.
511 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
512 if (hr == S_OK)
513 {
514 // The COM_GetRegisteredClassObject increased the reference count on the
515 // object so it has to be released.
516 IUnknown_Release(foundObject);
517
518 return CO_E_OBJISREG;
519 }
520
521 // If it is not registered, we must create a new entry for this class and
522 // append it to the registered class list.
523 // We use the address of the chain node as the cookie since we are sure it's
524 // unique.
525 newClass = (RegisteredClass *)HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
526
527 // Initialize the node.
528 newClass->classIdentifier = *rclsid;
529 newClass->runContext = dwClsContext;
530 newClass->connectFlags = flags;
531 newClass->dwCookie = (DWORD)newClass;
532 newClass->nextClass = firstRegisteredClass;
533
534 // Since we're making a copy of the object pointer, we have to increase it's
535 // reference count.
536 newClass->classObject = pUnk;
537 IUnknown_AddRef(newClass->classObject);
538
539 firstRegisteredClass = newClass;
540
541 // Assign the out parameter (cookie)
542 *lpdwRegister = newClass->dwCookie;
543
544 return S_OK;
545}
546
547// ----------------------------------------------------------------------
548// CoRevokeClassObject
549//
550// This method will remove a class object from the class registry
551// ----------------------------------------------------------------------
552HRESULT WIN32API CoRevokeClassObject(DWORD dwRegister)
553{
554 RegisteredClass * * prevClassLink;
555 RegisteredClass * curClass;
556
557 dprintf(("OLE32: CoRevokeClassObject"));
558
559 // Iterate through the whole list and try to match the cookie.
560 curClass = firstRegisteredClass;
561 prevClassLink = &firstRegisteredClass;
562
563 while (curClass != 0)
564 {
565 // Check if we have a match on the cookie.
566 if (curClass->dwCookie == dwRegister)
567 {
568 // Remove the class from the chain.
569 *prevClassLink = curClass->nextClass;
570
571 // Release the reference to the class object.
572 IUnknown_Release(curClass->classObject);
573
574 // Free the memory used by the chain node.
575 HeapFree(GetProcessHeap(), 0, curClass);
576
577 return S_OK;
578 }
579
580 // Step to the next class in the list.
581 prevClassLink = &(curClass->nextClass);
582 curClass = curClass->nextClass;
583 }
584
585 return E_INVALIDARG;
586}
587
588// ----------------------------------------------------------------------
589// GetClassFile
590//
591// This function supplies the CLSID associated with the given filename.
592// ----------------------------------------------------------------------
593HRESULT WIN32API GetClassFile(LPOLESTR filePathName, CLSID *pclsid)
594{
595 IStorage * pstg = 0;
596 HRESULT res;
597 int nbElm = 0;
598 int length = 0;
599 int i = 0;
600 LONG sizeProgId = 20;
601 LPOLESTR * pathDec = 0;
602 LPOLESTR absFile = 0;
603 LPOLESTR progId = 0;
604 WCHAR extention[100] = {0};
605
606 dprintf(("OLE32: GetClassFile"));
607
608 // if the file contain a storage object the return the CLSID
609 // writen by IStorage_SetClass method
610
611 if((StgIsStorageFile(filePathName)) == S_OK)
612 {
613 res = StgOpenStorage(filePathName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pstg);
614
615 if (SUCCEEDED(res))
616 res = ReadClassStg(pstg, pclsid);
617
618 IStorage_Release(pstg);
619
620 return res;
621 }
622
623 /* if the obove strategies fail then search for the extension key in the registry */
624
625 /* get the last element (absolute file) in the path name */
626 nbElm = FileMonikerImpl_DecomposePath(filePathName, &pathDec);
627 absFile = pathDec[nbElm-1];
628
629 /* failed if the path represente a directory and not an absolute file name*/
630 if (lstrcmpW(absFile, (LPOLESTR)"\\"))
631 return MK_E_INVALIDEXTENSION;
632
633 /* get the extension of the file */
634 length = lstrlenW(absFile);
635 for(i = length-1; ( (i >= 0) && (extention[i] = absFile[i]) ); i--);
636
637 /* get the progId associated to the extension */
638 progId = (WCHAR *)CoTaskMemAlloc(sizeProgId);
639
640 res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
641
642 if (res == ERROR_MORE_DATA)
643 {
644 CoTaskMemRealloc(progId,sizeProgId);
645
646 res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
647 }
648 if (res == ERROR_SUCCESS)
649 /* return the clsid associated to the progId */
650 res = CLSIDFromProgID(progId, pclsid);
651
652 for(i = 0; pathDec[i] != NULL; i++)
653 CoTaskMemFree(pathDec[i]);
654
655 CoTaskMemFree(pathDec);
656
657 CoTaskMemFree(progId);
658
659 if (res == ERROR_SUCCESS)
660 return res;
661
662 return MK_E_INVALIDEXTENSION;
663}
664// ======================================================================
665// Private functions.
666// ======================================================================
667
668// ----------------------------------------------------------------------
669// COM_GetRegisteredClassObject
670// ----------------------------------------------------------------------
671// This internal method is used to scan the registered class list to
672// find a class object.
673//
674// Params:
675// rclsid Class ID of the class to find.
676// dwClsContext Class context to match.
677// ppv [out] returns a pointer to the class object. Complying
678// to normal COM usage, this method will increase the
679// reference count on this object.
680static HRESULT COM_GetRegisteredClassObject
681 (REFCLSID rclsid,
682 DWORD dwClsContext,
683 LPUNKNOWN * ppUnk)
684{
685 RegisteredClass* curClass;
686
687 oStringA tCLSID(rclsid);
688
689 dprintf(("OLE32: COM_GetRegisteredClassObject"));
690 dprintf((" CLSID:%s", (char *)tCLSID));
691
692 // Sanity check
693 if (ppUnk == 0)
694 return E_POINTER;
695
696 // Iterate through the whole list and try to match the class ID.
697 curClass = firstRegisteredClass;
698
699 while (curClass != 0)
700 {
701 // Check if we have a match on the class ID.
702 if (IsEqualGUID(&curClass->classIdentifier, rclsid))
703 {
704 // Since we don't do out-of process or DCOM just right away,
705 // let's ignore the class context.
706
707 // We have a match, return the pointer to the class object.
708 *ppUnk = curClass->classObject;
709
710 IUnknown_AddRef(curClass->classObject);
711
712 return S_OK;
713 }
714
715 // Step to the next class in the list.
716 curClass = curClass->nextClass;
717 }
718
719 // If we get to here, we haven't found our class.
720 return S_FALSE;
721}
722
723// ----------------------------------------------------------------------
724// COM_RevokeAllClasses
725// ----------------------------------------------------------------------
726// This method is called when the COM libraries are uninitialized to
727// release all the references to the class objects registered with
728// the library
729static void COM_RevokeAllClasses()
730{
731 dprintf(("OLE32: COM_RevokeAllClasses"));
732
733 while (firstRegisteredClass != 0)
734 {
735 CoRevokeClassObject(firstRegisteredClass->dwCookie);
736 }
737}
738
739// ----------------------------------------------------------------------
740// COM_ExternalLockAddRef
741// ----------------------------------------------------------------------
742// Method that increments the count for a IUnknown* in the linked
743// list. The item is inserted if not already in the list.
744static void COM_ExternalLockAddRef(IUnknown * pUnk)
745{
746 dprintf(("OLE32: COM_ExternalLockAddRef"));
747
748 COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
749
750 /*
751 * Add an external lock to the object. If it was already externally
752 * locked, just increase the reference count. If it was not.
753 * add the item to the list.
754 */
755 if ( externalLock == EL_NOT_FOUND )
756 COM_ExternalLockInsert(pUnk);
757 else
758 externalLock->uRefCount++;
759
760 /*
761 * Add an internal lock to the object
762 */
763 IUnknown_AddRef(pUnk);
764}
765
766// ----------------------------------------------------------------------
767// COM_ExternalLockRelease
768// ----------------------------------------------------------------------
769// Method that decrements the count for a IUnknown* in the linked
770// list. The item is removed from the list if its count end up at zero or if
771// bRelAll is TRUE.
772static void COM_ExternalLockRelease(IUnknown * pUnk, BOOL bRelAll)
773{
774 dprintf(("OLE32: COM_ExternalLockRelease"));
775
776 COM_ExternalLock * externalLock = COM_ExternalLockFind(pUnk);
777
778 if ( externalLock != EL_NOT_FOUND )
779 {
780 do
781 {
782 externalLock->uRefCount--; /* release external locks */
783 IUnknown_Release(pUnk); /* release local locks as well */
784
785 if ( bRelAll == FALSE )
786 break; /* perform single release */
787
788 } while ( externalLock->uRefCount > 0 );
789
790 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
791 COM_ExternalLockDelete(externalLock);
792 }
793}
794
795// ----------------------------------------------------------------------
796// COM_ExternalLockFreeList
797// ----------------------------------------------------------------------
798// Method that frees the content of the list.
799static void COM_ExternalLockFreeList()
800{
801 dprintf(("OLE32: COM_ExternalLockFreeList"));
802
803 COM_ExternalLock *head;
804
805 head = elList.head; /* grab it by the head */
806 while (head != EL_END_OF_LIST)
807 {
808 COM_ExternalLockDelete(head); /* get rid of the head stuff */
809
810 head = elList.head; /* get the new head... */
811 }
812}
813
814// ----------------------------------------------------------------------
815// COM_ExternalLockDump
816// ----------------------------------------------------------------------
817// Method that dump the content of the list.
818void COM_ExternalLockDump()
819{
820 dprintf(("OLE32: COM_ExternalLockDump"));
821
822 COM_ExternalLock *current = elList.head;
823
824 printf("External lock list:");
825
826 while ( current != EL_END_OF_LIST )
827 {
828 dprintf((" %p with %lu references count.\n", current->pUnk, current->uRefCount));
829
830 /* Skip to the next item */
831 current = current->next;
832 }
833}
834
835// ----------------------------------------------------------------------
836// COM_ExternalLockFind
837// ----------------------------------------------------------------------
838// Find a IUnknown* in the linked list
839static COM_ExternalLock * COM_ExternalLockFind(IUnknown *pUnk)
840{
841 dprintf(("OLE32: COM_ExternalLockFind"));
842
843 return COM_ExternalLockLocate(elList.head, pUnk);
844}
845
846// ----------------------------------------------------------------------
847// COM_ExternalLockLocate
848// ----------------------------------------------------------------------
849// Recursivity agent for IUnknownExternalLockList_Find
850static COM_ExternalLock * COM_ExternalLockLocate( COM_ExternalLock * element, IUnknown * pUnk)
851{
852 if ( element == EL_END_OF_LIST )
853 return EL_NOT_FOUND;
854
855 else if ( element->pUnk == pUnk ) /* We found it */
856 return element;
857
858 else /* Not the right guy, keep on looking */
859 return COM_ExternalLockLocate( element->next, pUnk);
860}
861
862// ----------------------------------------------------------------------
863// COM_ExternalLockInsert
864// ----------------------------------------------------------------------
865// Insert a new IUnknown* to the linked list
866static BOOL COM_ExternalLockInsert(IUnknown * pUnk)
867{
868 dprintf(("OLE32: COM_ExternalLockInsert"));
869
870 COM_ExternalLock * newLock = NULL;
871 COM_ExternalLock * previousHead = NULL;
872
873 // Allocate space for the new storage object
874 newLock = (COM_ExternalLock *)HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
875
876 if (newLock != NULL)
877 {
878 if ( elList.head == EL_END_OF_LIST )
879 elList.head = newLock; /* The list is empty */
880 else
881 {
882 // insert does it at the head
883 previousHead = elList.head;
884 elList.head = newLock;
885 }
886
887 /*
888 * Set new list item data member
889 */
890 newLock->pUnk = pUnk;
891 newLock->uRefCount = 1;
892 newLock->next = previousHead;
893
894 return TRUE;
895 }
896
897 return FALSE;
898}
899
900// ----------------------------------------------------------------------
901// ExternalLockDelete
902// ----------------------------------------------------------------------
903// Method that removes an item from the linked list.
904static void COM_ExternalLockDelete(COM_ExternalLock * itemList)
905{
906 dprintf(("OLE32: ExternalLockDelete"));
907
908 COM_ExternalLock *current = elList.head;
909
910 if ( current == itemList )
911 {
912 // this section handles the deletion of the first node
913 elList.head = itemList->next;
914 HeapFree( GetProcessHeap(), 0, itemList);
915 }
916 else
917 {
918 do
919 {
920 if ( current->next == itemList ) /* We found the item to free */
921 {
922 current->next = itemList->next; /* readjust the list pointers */
923
924 HeapFree( GetProcessHeap(), 0, itemList);
925 break;
926 }
927
928 /* Skip to the next item */
929 current = current->next;
930
931 } while ( current != EL_END_OF_LIST );
932 }
933}
Note: See TracBrowser for help on using the repository browser.