1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Header: Com Callable wrapper classes
8**
9
10===========================================================*/
11
12#ifndef _COMCALLABLEWRAPPER_H
13#define _COMCALLABLEWRAPPER_H
14
15#ifdef FEATURE_COMINTEROP
16
17#include "vars.hpp"
18#include "stdinterfaces.h"
19#include "threads.h"
20#include "comutilnative.h"
21#include "spinlock.h"
22#include "comtoclrcall.h"
23#include "dispatchinfo.h"
24#include "wrappers.h"
25#include "internalunknownimpl.h"
26#include "rcwwalker.h"
27#include "util.hpp"
28
29class CCacheLineAllocator;
30class ConnectionPoint;
31class MethodTable;
32class ComCallWrapper;
33struct SimpleComCallWrapper;
34class RCWHolder;
35struct ComMethodTable;
36
37typedef DPTR(struct SimpleComCallWrapper) PTR_SimpleComCallWrapper;
38
39// Terminator to indicate that indicates the end of a chain of linked wrappers.
40#define LinkedWrapperTerminator (PTR_ComCallWrapper)-1
41
42class ComCallWrapperCache
43{
44public:
45 // Encapsulate a SpinLockHolder, so that clients of our lock don't have to know
46 // the details of our implementation.
47 class LockHolder : public CrstHolder
48 {
49 public:
50 LockHolder(ComCallWrapperCache *pCache)
51 : CrstHolder(&pCache->m_lock)
52 {
53 WRAPPER_NO_CONTRACT;
54 }
55 };
56
57 ComCallWrapperCache();
58 ~ComCallWrapperCache();
59
60 // create a new WrapperCache (one per each LoaderAllocator)
61 static ComCallWrapperCache* Create(LoaderAllocator *pLoaderAllocator);
62
63 // refcount
64 LONG AddRef();
65 LONG Release();
66
67 CCacheLineAllocator* GetCacheLineAllocator()
68 {
69 CONTRACT (CCacheLineAllocator*)
70 {
71 WRAPPER(THROWS);
72 WRAPPER(GC_TRIGGERS);
73 MODE_ANY;
74 POSTCONDITION(CheckPointer(RETVAL));
75 }
76 CONTRACT_END;
77
78 RETURN m_pCacheLineAllocator;
79 }
80
81 LoaderAllocator* GetLoaderAllocator()
82 {
83 CONTRACT (LoaderAllocator*)
84 {
85 WRAPPER(THROWS);
86 WRAPPER(GC_TRIGGERS);
87 MODE_ANY;
88 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
89 }
90 CONTRACT_END;
91
92 RETURN m_pLoaderAllocator;
93 }
94
95private:
96 LONG m_cbRef;
97 CCacheLineAllocator* m_pCacheLineAllocator;
98 LoaderAllocator* m_pLoaderAllocator;
99
100 // spin lock for fast synchronization
101 Crst m_lock;
102};
103
104
105//---------------------------------------------------------------------------------
106// COM called wrappers on CLR objects
107// Purpose: Expose CLR objects as COM classic Interfaces
108// Reqmts: Wrapper has to have the same layout as the COM2 interface
109//
110// The wrapper objects are aligned at 16 bytes, and the original this
111// pointer is replicated every 16 bytes, so for any COM2 interface
112// within the wrapper, the original 'this' can be obtained by masking
113// low 4 bits of COM2 IP.
114//
115// 16 byte aligned COM2 Vtable
116// +-----------+
117// | Org. this |
118// +-----------+ +-----+
119// COM2 IP-->| VTable ptr|----------------------------->|slot1|
120// +-----------+ +-----+ +-----+
121// COM2 IP-->| VTable ptr|---------->|slot1| |slot2|
122// +-----------+ +-----+ + +
123// | VTable ptr| | ....| | ... |
124// +-----------+ + + + +
125// | Org. this | |slotN| |slotN|
126// + + +-----+ +-----+
127// | .... |
128// + +
129// | |
130// +-----------+
131//
132//
133// The first slot of the first CCW is used to hold the basic interface -
134// an interface that implements the methods of IUnknown & IDispatch. The basic
135// interface's IDispatch implementation will call through to the class methods
136// as if it were the class interface.
137//
138// The second slot of the first CCW is used to hold the IClassX interface -
139// an interface that implements IUnknown, IDispatch, and a custom interface
140// that contains all of the members of the class and its hierarchy. This
141// will only be generated on demand and is only usable if the class and all
142// of its parents are visible to COM.
143//
144// VTable and Stubs: can share stub code, we need to have different vtables
145// for different interfaces, so the stub can jump to different
146// marshalling code.
147// Stubs : adjust this pointer and jump to the approp. address,
148// Marshalling params and results, based on the method signature the stub jumps to
149// approp. code to handle marshalling and unmarshalling.
150//
151//
152//--------------------------------------------------------------------------------
153
154class WinRTManagedClassFactory;
155
156//--------------------------------------------------------------------------------
157// COM callable wrappers for CLR objects
158//--------------------------------------------------------------------------------
159typedef DPTR(class ComCallWrapperTemplate) PTR_ComCallWrapperTemplate;
160class ComCallWrapperTemplate
161{
162 friend class ClrDataAccess;
163
164public:
165 // Small "L1" cache to speed up QI's on CCWs with variance. It caches both positive and negative
166 // results (i.e. also keeps track of IIDs that the QI doesn't respond to).
167 class IIDToInterfaceTemplateCache
168 {
169 enum
170 {
171 // There is a small number of types that the class is castable to via variance and QI'ed for
172 // (typically just IFoo<object> where the class implements IFoo<IBar> and IFoo is covariant).
173 // There is also some number of IIDs QI'ed for by external code (e.g. Jupiter) that we won't
174 // recognize - this number is potentially unbounded so even if this was a different data
175 // structure, we would want to limit its size. Simple sequentially searched array seems to
176 // work the best both in terms of memory footprint and lookup performance.
177 CACHE_SIZE = 16,
178 };
179
180 struct CacheItem
181 {
182 IID m_iid;
183
184 // The lowest bit indicates whether this item is being used (since NULL is a legal value).
185 // The second lowest bit indicates whether the item has been accessed since the last eviction.
186 // The rest of the bits contain ComCallWrapperTemplate pointer.
187 SIZE_T m_pTemplate;
188
189 bool IsFree()
190 {
191 LIMITED_METHOD_CONTRACT;
192 return (m_pTemplate == 0);
193 }
194
195 bool IsHot()
196 {
197 LIMITED_METHOD_CONTRACT;
198 return ((m_pTemplate & 0x2) == 0x2);
199 }
200
201 ComCallWrapperTemplate *GetTemplate()
202 {
203 LIMITED_METHOD_CONTRACT;
204 return (ComCallWrapperTemplate *)(m_pTemplate & ~0x3);
205 }
206
207 void SetTemplate(ComCallWrapperTemplate *pTemplate)
208 {
209 LIMITED_METHOD_CONTRACT;
210 m_pTemplate = ((SIZE_T)pTemplate | 0x1);
211 }
212
213 void MarkHot()
214 {
215 LIMITED_METHOD_CONTRACT;
216 m_pTemplate |= 0x2;
217 }
218
219 void MarkCold()
220 {
221 LIMITED_METHOD_CONTRACT;
222 m_pTemplate &= ~0x2;
223 }
224 };
225
226 // array of cache items
227 CacheItem m_items[CACHE_SIZE];
228
229 // spin lock to protect concurrent access to m_items
230 SpinLock m_lock;
231
232 public:
233 IIDToInterfaceTemplateCache()
234 {
235 CONTRACTL
236 {
237 THROWS;
238 GC_NOTRIGGER;
239 }
240 CONTRACTL_END;
241
242 ZeroMemory(this, sizeof(IIDToInterfaceTemplateCache));
243 m_lock.Init(LOCK_TYPE_DEFAULT);
244 }
245
246 bool LookupInterfaceTemplate(REFIID riid, ComCallWrapperTemplate **ppTemplate);
247 void InsertInterfaceTemplate(REFIID riid, ComCallWrapperTemplate *pTemplate);
248 };
249
250 // Iterates COM-exposed interfaces of a class. Handles arrays which support IIterable<T>,
251 // IVector<T>, and IVectorView<T>, as well as WinRT class factories which support factory
252 // and static interfaces. It is also aware of redirected interfaces - both the .NET and the
253 // corresponding WinRT type are reported
254 class CCWInterfaceMapIterator
255 {
256 private:
257 struct InterfaceProps
258 {
259 MethodTable *m_pItfMT;
260
261 WinMDAdapter::RedirectedTypeIndex m_RedirectedIndex; // valid if m_dwIsRedirectedInterface is set
262
263 DWORD m_dwIsRedirectedInterface : 1;
264 DWORD m_dwIsFactoryInterface : 1;
265 DWORD m_dwIsStaticInterface : 1;
266 };
267
268 StackSArray<InterfaceProps> m_Interfaces;
269 COUNT_T m_Index;
270
271 inline const InterfaceProps &GetCurrentInterfaceProps() const
272 {
273 LIMITED_METHOD_CONTRACT;
274 return m_Interfaces[(COUNT_T)m_Index];
275 }
276
277 InterfaceProps &AppendInterface(MethodTable *pItfMT, bool isRedirected);
278
279 public:
280 CCWInterfaceMapIterator(TypeHandle thClass, WinRTManagedClassFactory *pClsFact, bool fIterateRedirectedInterfaces);
281
282 BOOL Next()
283 {
284 LIMITED_METHOD_CONTRACT;
285 return (++m_Index < GetCount());
286 }
287
288 MethodTable *GetInterface() const
289 {
290 LIMITED_METHOD_CONTRACT;
291 return GetCurrentInterfaceProps().m_pItfMT;
292 }
293
294 DWORD GetIndex() const
295 {
296 LIMITED_METHOD_CONTRACT;
297 return m_Index;
298 }
299
300 DWORD GetCount() const
301 {
302 LIMITED_METHOD_CONTRACT;
303 return m_Interfaces.GetCount();
304 }
305
306 void Reset()
307 {
308 LIMITED_METHOD_CONTRACT;
309 m_Index = (COUNT_T)-1;
310 }
311
312 BOOL IsFactoryInterface() const
313 {
314 LIMITED_METHOD_CONTRACT;
315 return GetCurrentInterfaceProps().m_dwIsFactoryInterface;
316 }
317
318 BOOL IsStaticInterface() const
319 {
320 LIMITED_METHOD_CONTRACT;
321 return GetCurrentInterfaceProps().m_dwIsStaticInterface;
322 }
323
324 BOOL IsRedirectedInterface() const
325 {
326 LIMITED_METHOD_CONTRACT;
327 return GetCurrentInterfaceProps().m_dwIsRedirectedInterface;
328 }
329
330 WinMDAdapter::RedirectedTypeIndex GetRedirectedInterfaceIndex() const
331 {
332 LIMITED_METHOD_CONTRACT;
333 return GetCurrentInterfaceProps().m_RedirectedIndex;
334 }
335 };
336
337 // Static initializer run at startup.
338 static void Init();
339
340 // Template accessor, creates a template if one is not already cached.
341 static ComCallWrapperTemplate* GetTemplate(TypeHandle thClass);
342
343 // Ref-count the templates
344 LONG AddRef();
345 LONG Release();
346
347 // Properties
348 ComMethodTable* GetClassComMT();
349 ComMethodTable* GetComMTForItf(MethodTable *pItfMT);
350 ComMethodTable* GetComMTForIndex(ULONG ulItfIndex);
351 ComMethodTable* GetBasicComMT();
352 ULONG GetNumInterfaces();
353 SLOT* GetVTableSlot(ULONG index);
354 void CheckParentComVisibility(BOOL fForIDispatch);
355 BOOL CheckParentComVisibilityNoThrow(BOOL fForIDispatch);
356
357 // Calls GetDefaultInterfaceForClassInternal and caches the result.
358 DefaultInterfaceType GetDefaultInterface(MethodTable **ppDefaultItf);
359
360 // Sets up the class method table for the IClassX and also lays it out.
361 static ComMethodTable *SetupComMethodTableForClass(MethodTable *pMT, BOOL bLayOutComMT);
362
363 MethodDesc * GetICustomQueryInterfaceGetInterfaceMD();
364
365 IIDToInterfaceTemplateCache *GetOrCreateIIDToInterfaceTemplateCache();
366
367 BOOL HasInvisibleParent()
368 {
369 LIMITED_METHOD_CONTRACT;
370 return (m_flags & enum_InvisibleParent);
371 }
372
373 BOOL SupportsICustomQueryInterface()
374 {
375 LIMITED_METHOD_CONTRACT;
376 return (m_flags & enum_ImplementsICustomQueryInterface);
377 }
378
379 BOOL SupportsIInspectable()
380 {
381 LIMITED_METHOD_CONTRACT;
382 return (m_flags & enum_SupportsIInspectable);
383 }
384
385 BOOL SupportsVariantInterface()
386 {
387 LIMITED_METHOD_CONTRACT;
388 return (m_flags & enum_SupportsVariantInterface);
389 }
390
391 BOOL RepresentsVariantInterface()
392 {
393 LIMITED_METHOD_CONTRACT;
394 return (m_flags & enum_RepresentsVariantInterface);
395 }
396
397 BOOL IsUseOleAutDispatchImpl()
398 {
399 LIMITED_METHOD_CONTRACT;
400 return (m_flags & enum_UseOleAutDispatchImpl);
401 }
402
403 BOOL ImplementsIMarshal()
404 {
405 LIMITED_METHOD_CONTRACT;
406 return (m_flags & enum_ImplementsIMarshal);
407 }
408
409 BOOL SupportsIClassX()
410 {
411 LIMITED_METHOD_CONTRACT;
412 return (m_flags & enum_SupportsIClassX);
413 }
414
415 TypeHandle GetClassType()
416 {
417 LIMITED_METHOD_CONTRACT;
418 return m_thClass;
419 }
420
421 MethodTable *GetWinRTRuntimeClass()
422 {
423 LIMITED_METHOD_CONTRACT;
424 return m_pWinRTRuntimeClass;
425 }
426
427 BOOL IsSafeTypeForMarshalling();
428
429 // Creates a new Template and caches it on the MethodTable/ArrayTypeDesc or class factory.
430 static ComCallWrapperTemplate *CreateTemplate(TypeHandle thClass, WinRTManagedClassFactory *pClsFact = NULL);
431
432 // Creates a new Template for just one interface. Used for lazily created CCWs for interfaces with variance.
433 static ComCallWrapperTemplate *CreateTemplateForInterface(MethodTable *pItfMT);
434
435private:
436
437 // Hide the constructor
438 ComCallWrapperTemplate();
439
440 // Cleanup called when the ref-count hits zero.
441 void Cleanup();
442
443 // Helper method called by code:CreateTemplate.
444 ComMethodTable* InitializeForInterface(MethodTable *pParentMT, MethodTable *pItfMT, DWORD dwIndex);
445
446 // Create a non laid out COM method table for the specified class or interface.
447 ComMethodTable* CreateComMethodTableForClass(MethodTable *pClassMT);
448 ComMethodTable* CreateComMethodTableForInterface(MethodTable* pInterfaceMT);
449 ComMethodTable* CreateComMethodTableForBasic(MethodTable* pClassMT);
450 ComMethodTable* CreateComMethodTableForDelegate(MethodTable *pDelegateMT);
451
452 void DetermineComVisibility();
453
454private:
455 LONG m_cbRefCount;
456 ComCallWrapperTemplate* m_pParent;
457 TypeHandle m_thClass;
458 MethodTable* m_pDefaultItf;
459 MethodTable* m_pWinRTRuntimeClass;
460 ComMethodTable* m_pClassComMT;
461 ComMethodTable* m_pBasicComMT;
462
463 enum
464 {
465 // first 3 bits are interpreted as DefaultInterfaceType
466 enum_DefaultInterfaceTypeMask = 0x7,
467 enum_DefaultInterfaceTypeComputed = 0x10,
468
469 enum_InvisibleParent = 0x20,
470 enum_ImplementsICustomQueryInterface = 0x40,
471 enum_SupportsIInspectable = 0x80,
472 enum_SupportsIClassX = 0x100,
473
474 enum_SupportsVariantInterface = 0x200, // this is a template for a class that implements an interface with variance
475 enum_RepresentsVariantInterface = 0x400, // this is a template for an interface with variance
476
477 enum_UseOleAutDispatchImpl = 0x800, // the class is decorated with IDispatchImplAttribute(CompatibleImpl)
478
479 enum_ImplementsIMarshal = 0x1000, // the class implements a managed interface with Guid == IID_IMarshal
480
481 enum_IsSafeTypeForMarshalling = 0x2000, // The class can be safely marshalled out of process via DCOM
482 };
483 DWORD m_flags;
484 MethodDesc* m_pICustomQueryInterfaceGetInterfaceMD;
485 Volatile<IIDToInterfaceTemplateCache *> m_pIIDToInterfaceTemplateCache;
486 ULONG m_cbInterfaces;
487 SLOT* m_rgpIPtr[1];
488};
489
490inline void ComCallWrapperTemplateRelease(ComCallWrapperTemplate *value)
491{
492 WRAPPER_NO_CONTRACT;
493
494 if (value)
495 {
496 value->Release();
497 }
498}
499
500typedef Wrapper<ComCallWrapperTemplate *, DoNothing<ComCallWrapperTemplate *>, ComCallWrapperTemplateRelease, NULL> ComCallWrapperTemplateHolder;
501
502
503//--------------------------------------------------------------------------------
504// Header on top of Vtables that we create for COM callable interfaces
505//--------------------------------------------------------------------------------
506#pragma pack(push)
507#pragma pack(1)
508
509struct IUnkVtable
510{
511 SLOT m_qi; // IUnk::QI
512 SLOT m_addref; // IUnk::AddRef
513 SLOT m_release; // IUnk::Release
514};
515
516struct IDispatchVtable : IUnkVtable
517{
518 // idispatch methods
519 SLOT m_GetTypeInfoCount;
520 SLOT m_GetTypeInfo;
521 SLOT m_GetIDsOfNames;
522 SLOT m_Invoke;
523};
524
525struct IInspectableVtable : IUnkVtable
526{
527 SLOT m_GetIIDs;
528 SLOT m_GetRuntimeClassName;
529 SLOT m_GetTrustLevel;
530};
531
532enum Masks
533{
534 enum_InterfaceTypeMask = 0x00000003,
535 enum_ClassInterfaceTypeMask = 0x00000003,
536 enum_ClassVtableMask = 0x00000004,
537 enum_LayoutComplete = 0x00000010,
538 enum_ComVisible = 0x00000040,
539 enum_SigClassCannotLoad = 0x00000080,
540 enum_SigClassLoadChecked = 0x00000100,
541 enum_ComClassItf = 0x00000200,
542 enum_GuidGenerated = 0x00000400,
543 // enum_unused = 0x00001000,
544 enum_IsBasic = 0x00002000,
545 enum_IsWinRTDelegate = 0x00004000,
546 enum_IsWinRTTrivialAggregate = 0x00008000,
547 enum_IsWinRTFactoryInterface = 0x00010000,
548 enum_IsWinRTStaticInterface = 0x00020000,
549 enum_IsWinRTRedirectedInterface = 0x00040000,
550
551 enum_WinRTRedirectedInterfaceMask = 0xFF000000, // the highest byte contains redirected interface index
552};
553
554typedef DPTR(struct ComMethodTable) PTR_ComMethodTable;
555struct ComMethodTable
556{
557 friend class ComCallWrapperTemplate;
558
559 // Cleanup, frees all the stubs and the vtable
560 void Cleanup();
561
562 // The appropriate finalize method must be called before the COM method table is
563 // exposed to COM or before any methods are called on it.
564 void LayOutClassMethodTable();
565 BOOL LayOutInterfaceMethodTable(MethodTable* pClsMT);
566 void LayOutBasicMethodTable();
567 void LayOutDelegateMethodTable();
568
569 // Accessor for the IDispatch information.
570 DispatchInfo* GetDispatchInfo();
571
572 LONG AddRef()
573 {
574 LIMITED_METHOD_CONTRACT;
575
576 return InterlockedIncrement(&m_cbRefCount);
577 }
578
579 LONG Release()
580 {
581 CONTRACTL
582 {
583 WRAPPER(THROWS);
584 WRAPPER(GC_TRIGGERS);
585 MODE_ANY;
586 PRECONDITION(m_cbRefCount > 0);
587 }
588 CONTRACTL_END;
589
590 // use a different var here becuase cleanup will delete the object
591 // so can no longer make member refs
592 LONG cbRef = InterlockedDecrement(&m_cbRefCount);
593 if (cbRef == 0)
594 Cleanup();
595
596 return cbRef;
597 }
598
599 CorIfaceAttr GetInterfaceType()
600 {
601 WRAPPER_NO_CONTRACT;
602
603 if (IsIClassXOrBasicItf())
604 return ifDual;
605 else
606 return (CorIfaceAttr)(m_Flags & enum_InterfaceTypeMask);
607 }
608
609 CorClassIfaceAttr GetClassInterfaceType()
610 {
611 LIMITED_METHOD_CONTRACT;
612
613 _ASSERTE(IsIClassXOrBasicItf());
614 return (CorClassIfaceAttr)(m_Flags & enum_ClassInterfaceTypeMask);
615 }
616
617 BOOL IsIClassX()
618 {
619 LIMITED_METHOD_CONTRACT;
620 return (IsIClassXOrBasicItf() && !IsBasic());
621 }
622
623 BOOL IsIClassXOrBasicItf()
624 {
625 LIMITED_METHOD_CONTRACT;
626 return (m_Flags & enum_ClassVtableMask) != 0;
627 }
628
629 BOOL IsComClassItf()
630 {
631 LIMITED_METHOD_CONTRACT;
632 return (m_Flags & enum_ComClassItf) != 0;
633 }
634
635 BOOL IsLayoutComplete()
636 {
637 LIMITED_METHOD_CONTRACT;
638 return (m_Flags & enum_LayoutComplete) != 0;
639 }
640
641 BOOL IsComVisible()
642 {
643 LIMITED_METHOD_CONTRACT;
644 return (m_Flags & enum_ComVisible) != 0;
645 }
646
647 BOOL IsBasic()
648 {
649 LIMITED_METHOD_CONTRACT;
650 return (m_Flags & enum_IsBasic) != 0;
651 }
652
653 BOOL IsWinRTDelegate()
654 {
655 LIMITED_METHOD_CONTRACT;
656 return (m_Flags & enum_IsWinRTDelegate) != 0;
657 }
658
659 BOOL IsWinRTTrivialAggregate()
660 {
661 LIMITED_METHOD_CONTRACT;
662 return (m_Flags & enum_IsWinRTTrivialAggregate) != 0;
663 }
664
665 BOOL IsWinRTFactoryInterface()
666 {
667 LIMITED_METHOD_CONTRACT;
668 return (m_Flags & enum_IsWinRTFactoryInterface) != 0;
669 }
670
671 BOOL IsWinRTStaticInterface()
672 {
673 LIMITED_METHOD_CONTRACT;
674 return (m_Flags & enum_IsWinRTStaticInterface) != 0;
675 }
676
677 VOID SetIsWinRTFactoryInterface()
678 {
679 LIMITED_METHOD_CONTRACT;
680 m_Flags |= enum_IsWinRTFactoryInterface;
681 }
682
683 VOID SetIsWinRTStaticInterface()
684 {
685 LIMITED_METHOD_CONTRACT;
686 m_Flags |= enum_IsWinRTStaticInterface;
687 }
688
689 BOOL IsWinRTRedirectedInterface()
690 {
691 LIMITED_METHOD_CONTRACT;
692 return (m_Flags & enum_IsWinRTRedirectedInterface) != 0;
693 }
694
695 WinMDAdapter::RedirectedTypeIndex GetWinRTRedirectedInterfaceIndex()
696 {
697 LIMITED_METHOD_CONTRACT;
698 return (WinMDAdapter::RedirectedTypeIndex)((m_Flags & enum_WinRTRedirectedInterfaceMask) >> 24);
699 }
700
701 void SetWinRTRedirectedInterfaceIndex(WinMDAdapter::RedirectedTypeIndex index)
702 {
703 LIMITED_METHOD_CONTRACT;
704
705 m_Flags |= ((size_t)index << 24);
706 m_Flags |= enum_IsWinRTRedirectedInterface;
707 _ASSERTE(GetWinRTRedirectedInterfaceIndex() == index);
708 }
709
710 BOOL HasInvisibleParent()
711 {
712 LIMITED_METHOD_CONTRACT;
713 return ((ComCallWrapperTemplate*)m_pMT->GetComCallWrapperTemplate())->HasInvisibleParent();
714 }
715
716 BOOL IsSigClassLoadChecked()
717 {
718 LIMITED_METHOD_CONTRACT;
719 return (m_Flags & enum_SigClassLoadChecked) != 0;
720 }
721
722 BOOL IsSigClassCannotLoad()
723 {
724 LIMITED_METHOD_CONTRACT;
725 return 0 != (m_Flags & enum_SigClassCannotLoad);
726 }
727
728 VOID SetSigClassCannotLoad()
729 {
730 LIMITED_METHOD_CONTRACT;
731 m_Flags |= enum_SigClassCannotLoad;
732 }
733
734 VOID SetSigClassLoadChecked()
735 {
736 LIMITED_METHOD_CONTRACT;
737 m_Flags |= enum_SigClassLoadChecked;
738 }
739
740 DWORD GetSlots()
741 {
742 LIMITED_METHOD_CONTRACT;
743 return m_cbSlots;
744 }
745
746 ITypeInfo *GetITypeInfo()
747 {
748 LIMITED_METHOD_CONTRACT;
749 return m_pITypeInfo;
750 }
751
752 void SetITypeInfo(ITypeInfo *pITI);
753
754 static WORD GetNumExtraSlots(CorIfaceAttr ItfType)
755 {
756 LIMITED_METHOD_CONTRACT;
757
758 switch (ItfType)
759 {
760 case ifVtable: return (sizeof(IUnkVtable) / sizeof(SLOT));
761 case ifInspectable: return (sizeof(IInspectableVtable) / sizeof(SLOT));
762 default: return (sizeof(IDispatchVtable) / sizeof(SLOT));
763 }
764 }
765
766 // Gets the ComCallMethodDesc out of a Vtable slot correctly for all platforms
767 ComCallMethodDesc* ComCallMethodDescFromSlot(unsigned i);
768
769 BOOL IsSlotAField(unsigned i)
770 {
771 CONTRACTL
772 {
773 WRAPPER(THROWS);
774 WRAPPER(GC_TRIGGERS);
775 MODE_ANY;
776 PRECONDITION(IsLayoutComplete());
777 PRECONDITION(i < m_cbSlots);
778 }
779 CONTRACTL_END;
780
781 i += GetNumExtraSlots(GetInterfaceType());
782 ComCallMethodDesc* pCMD = ComCallMethodDescFromSlot(i);
783 return pCMD->IsFieldCall();
784 }
785
786 MethodDesc* GetMethodDescForSlot(unsigned i)
787 {
788 CONTRACT (MethodDesc*)
789 {
790 WRAPPER(THROWS);
791 WRAPPER(GC_TRIGGERS);
792 MODE_ANY;
793 PRECONDITION(IsLayoutComplete());
794 PRECONDITION(i < m_cbSlots);
795 PRECONDITION(!IsSlotAField(i));
796 POSTCONDITION(CheckPointer(RETVAL));
797 }
798 CONTRACT_END;
799
800 i += GetNumExtraSlots(GetInterfaceType());
801
802 ComCallMethodDesc* pCMD;
803
804 pCMD = ComCallMethodDescFromSlot(i);
805 _ASSERTE(pCMD->IsMethodCall());
806
807 RETURN pCMD->GetMethodDesc();
808 }
809
810 ComCallMethodDesc* GetFieldCallMethodDescForSlot(unsigned i)
811 {
812 CONTRACT (ComCallMethodDesc*)
813 {
814 WRAPPER(THROWS);
815 WRAPPER(GC_TRIGGERS);
816 MODE_ANY;
817 PRECONDITION(IsLayoutComplete());
818 PRECONDITION(i < m_cbSlots);
819 PRECONDITION(IsSlotAField(i));
820 POSTCONDITION(CheckPointer(RETVAL));
821 }
822 CONTRACT_END;
823
824 i += GetNumExtraSlots(GetInterfaceType());
825 ComCallMethodDesc* pCMD = ComCallMethodDescFromSlot(i);
826
827 _ASSERTE(pCMD->IsFieldCall());
828 RETURN (ComCallMethodDesc *)pCMD;
829 }
830
831 BOOL OwnedbyThisMT(unsigned slotIndex)
832 {
833 CONTRACTL
834 {
835 WRAPPER(THROWS);
836 WRAPPER(GC_TRIGGERS);
837 MODE_ANY;
838 }
839 CONTRACTL_END;
840
841 if (!IsIClassXOrBasicItf())
842 return TRUE;
843
844 if (m_pMDescr != NULL)
845 {
846 // These are the methods from the default interfaces such as IUnknown.
847 unsigned cbExtraSlots = GetNumExtraSlots(GetInterfaceType());
848
849 // Refer to ComMethodTable::LayOutClassMethodTable().
850 ULONG cbSize = *(ULONG *)m_pMDescr;
851 ULONG cbNewSlots = cbSize / (COMMETHOD_PREPAD + sizeof(ComCallMethodDesc));
852 _ASSERTE( (cbSize % (COMMETHOD_PREPAD + sizeof(ComCallMethodDesc))) == 0);
853
854 // m_cbSlots is the total number of methods in addition to the ones from the
855 // default interfaces. cbNewSlots is the total number of methods introduced
856 // by this class (== m_cbSlots - <slots from parent MT>).
857 return (slotIndex >= (cbExtraSlots + m_cbSlots - cbNewSlots));
858 }
859
860 return FALSE;
861 }
862
863 ComMethodTable *GetParentClassComMT();
864
865 static inline PTR_ComMethodTable ComMethodTableFromIP(PTR_IUnknown pUnk)
866 {
867 CONTRACT (PTR_ComMethodTable)
868 {
869 WRAPPER(THROWS);
870 WRAPPER(GC_TRIGGERS);
871 MODE_ANY;
872 SUPPORTS_DAC;
873 PRECONDITION(CheckPointer(pUnk));
874 POSTCONDITION(CheckPointer(RETVAL));
875 }
876 CONTRACT_END;
877
878 PTR_ComMethodTable pMT = dac_cast<PTR_ComMethodTable>(*PTR_TADDR(pUnk) - sizeof(ComMethodTable));
879
880 // validate the object
881 _ASSERTE((SLOT)(size_t)0xDEADC0FF == pMT->m_ptReserved );
882
883 RETURN pMT;
884 }
885
886 ULONG GetNumSlots()
887 {
888 LIMITED_METHOD_CONTRACT;
889 return m_cbSlots;
890 }
891
892 PTR_MethodTable GetMethodTable()
893 {
894 LIMITED_METHOD_CONTRACT;
895 return m_pMT;
896 }
897
898
899 inline REFIID GetIID()
900 {
901 // Cannot use a normal CONTRACT since the return type is ref type which
902 // causes problems with normal CONTRACTs.
903 CONTRACTL
904 {
905 WRAPPER(THROWS);
906 WRAPPER(GC_TRIGGERS);
907 MODE_ANY;
908 }
909 CONTRACTL_END;
910
911 // Generate the IClassX IID if it hasn't been generated yet.
912 if (!(m_Flags & enum_GuidGenerated))
913 {
914 GenerateClassItfGuid(TypeHandle(m_pMT), &m_IID);
915 m_Flags |= enum_GuidGenerated;
916 }
917
918 return m_IID;
919 }
920
921 void CheckParentComVisibility(BOOL fForIDispatch)
922 {
923 WRAPPER_NO_CONTRACT;
924
925 ((ComCallWrapperTemplate*)m_pMT->GetComCallWrapperTemplate())->CheckParentComVisibility(fForIDispatch);
926 }
927
928 BOOL CheckParentComVisibilityNoThrow(BOOL fForIDispatch)
929 {
930 WRAPPER_NO_CONTRACT;
931
932 return ((ComCallWrapperTemplate*)m_pMT->GetComCallWrapperTemplate())->CheckParentComVisibilityNoThrow(fForIDispatch);
933 }
934
935private:
936 // Helper methods.
937 BOOL CheckSigTypesCanBeLoaded(MethodTable *pItfClass);
938
939 SLOT m_ptReserved; //= (SLOT) 0xDEADC0FF; reserved
940 PTR_MethodTable m_pMT; // pointer to the VMs method table
941 ULONG m_cbSlots; // number of slots in the interface (excluding IUnk/IDisp)
942 LONG m_cbRefCount; // ref-count the vtable as it is being shared
943 size_t m_Flags; // make sure this is initialized to zero
944 LPVOID m_pMDescr; // pointer to methoddescr.s owned by this MT
945 ITypeInfo* m_pITypeInfo; // cached pointer to ITypeInfo
946 DispatchInfo* m_pDispatchInfo; // The dispatch info used to expose IDispatch to COM.
947 IID m_IID; // The IID of the interface.
948};
949
950#pragma pack(pop)
951
952
953struct GetComIPFromCCW
954{
955 enum flags
956 {
957 None = 0,
958 CheckVisibility = 1,
959 SuppressSecurityCheck = 2,
960 SuppressCustomizedQueryInterface = 4
961 };
962};
963
964inline GetComIPFromCCW::flags operator|(GetComIPFromCCW::flags lhs, GetComIPFromCCW::flags rhs)
965{
966 LIMITED_METHOD_CONTRACT;
967 return static_cast<GetComIPFromCCW::flags>(static_cast<DWORD>(lhs) | static_cast<DWORD>(rhs));
968}
969inline GetComIPFromCCW::flags operator|=(GetComIPFromCCW::flags & lhs, GetComIPFromCCW::flags rhs)
970{
971 LIMITED_METHOD_CONTRACT;
972 lhs = static_cast<GetComIPFromCCW::flags>(static_cast<DWORD>(lhs) | static_cast<DWORD>(rhs));
973 return lhs;
974}
975
976class ComCallWrapper
977{
978 friend class MarshalNative;
979 friend class ClrDataAccess;
980
981private:
982 enum
983 {
984#ifdef _WIN64
985 NumVtablePtrs = 5,
986 enum_ThisMask = ~0x3f, // mask on IUnknown ** to get at the OBJECT-REF handle
987#else
988
989 NumVtablePtrs = 5,
990 enum_ThisMask = ~0x1f, // mask on IUnknown ** to get at the OBJECT-REF handle
991#endif
992 Slot_IClassX = 1,
993 Slot_Basic = 0,
994
995 Slot_FirstInterface = 2,
996 };
997
998public:
999 ADID GetDomainID();
1000
1001 VOID ResetHandleStrength();
1002 VOID MarkHandleWeak();
1003
1004 BOOL IsHandleWeak();
1005
1006 OBJECTHANDLE GetObjectHandle();
1007 OBJECTHANDLE GetRawObjectHandle() { LIMITED_METHOD_CONTRACT; return m_ppThis; } // no NULL check
1008
1009protected:
1010 // don't instantiate this class directly
1011 ComCallWrapper()
1012 {
1013 LIMITED_METHOD_CONTRACT;
1014 }
1015 ~ComCallWrapper()
1016 {
1017 LIMITED_METHOD_CONTRACT;
1018 }
1019
1020 void Init();
1021
1022#ifndef DACCESS_COMPILE
1023 inline static void SetNext(ComCallWrapper* pWrap, ComCallWrapper* pNextWrapper)
1024 {
1025 CONTRACTL
1026 {
1027 WRAPPER(THROWS);
1028 WRAPPER(GC_TRIGGERS);
1029 MODE_ANY;
1030 PRECONDITION(CheckPointer(pWrap));
1031 PRECONDITION(CheckPointer(pNextWrapper, NULL_OK));
1032 }
1033 CONTRACTL_END;
1034
1035 pWrap->m_pNext = pNextWrapper;
1036 }
1037#endif // !DACCESS_COMPILE
1038
1039 inline static PTR_ComCallWrapper GetNext(PTR_ComCallWrapper pWrap)
1040 {
1041 CONTRACT (PTR_ComCallWrapper)
1042 {
1043 WRAPPER(THROWS);
1044 WRAPPER(GC_TRIGGERS);
1045 MODE_ANY;
1046 SUPPORTS_DAC;
1047 PRECONDITION(CheckPointer(pWrap));
1048 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1049 }
1050 CONTRACT_END;
1051
1052 RETURN (LinkedWrapperTerminator == pWrap->m_pNext ? NULL : pWrap->m_pNext);
1053 }
1054
1055 // Helper to create a wrapper, pClassCCW must be specified if pTemplate->RepresentsVariantInterface()
1056 static ComCallWrapper* CreateWrapper(OBJECTREF* pObj, ComCallWrapperTemplate *pTemplate, ComCallWrapper *pClassCCW);
1057
1058 // helper to get the IUnknown* within a wrapper
1059 static SLOT** GetComIPLocInWrapper(ComCallWrapper* pWrap, unsigned iIndex);
1060
1061 // helper to get index within the interface map for an interface that matches
1062 // the interface MT
1063 static signed GetIndexForIntfMT(ComCallWrapperTemplate *pTemplate, MethodTable *pIntfMT);
1064
1065 // helper to get wrapper from sync block
1066 static PTR_ComCallWrapper GetStartWrapper(PTR_ComCallWrapper pWrap);
1067
1068 // helper to create a wrapper from a template
1069 static ComCallWrapper* CopyFromTemplate(ComCallWrapperTemplate* pTemplate,
1070 ComCallWrapperCache *pWrapperCache,
1071 OBJECTHANDLE oh);
1072
1073 // helper to find a covariant supertype of pMT with the given IID
1074 static MethodTable *FindCovariantSubtype(MethodTable *pMT, REFIID riid);
1075
1076 // Like GetComIPFromCCW, but will try to find riid/pIntfMT among interfaces implemented by this
1077 // object that have variance. Assumes that call GetComIPFromCCW with same arguments has failed.
1078 IUnknown *GetComIPFromCCWUsingVariance(REFIID riid, MethodTable *pIntfMT, GetComIPFromCCW::flags flags);
1079
1080 static IUnknown * GetComIPFromCCW_VariantInterface(
1081 ComCallWrapper * pWrap, REFIID riid, MethodTable * pIntfMT, GetComIPFromCCW::flags flags,
1082 ComCallWrapperTemplate * pTemplate);
1083
1084 inline static IUnknown * GetComIPFromCCW_VisibilityCheck(
1085 IUnknown * pIntf, MethodTable * pIntfMT, ComMethodTable * pIntfComMT,
1086 GetComIPFromCCW::flags flags);
1087
1088 static IUnknown * GetComIPFromCCW_HandleExtendsCOMObject(
1089 ComCallWrapper * pWrap, REFIID riid, MethodTable * pIntfMT,
1090 ComCallWrapperTemplate * pTemplate, signed imapIndex, unsigned intfIndex);
1091
1092 static IUnknown * GetComIPFromCCW_ForIID_Worker(
1093 ComCallWrapper * pWrap, REFIID riid, MethodTable * pIntfMT, GetComIPFromCCW::flags flags,
1094 ComCallWrapperTemplate * pTemplate);
1095
1096 static IUnknown * GetComIPFromCCW_ForIntfMT_Worker(
1097 ComCallWrapper * pWrap, MethodTable * pIntfMT, GetComIPFromCCW::flags flags);
1098
1099
1100public:
1101 static bool GetComIPFromCCW_HandleCustomQI(
1102 ComCallWrapper * pWrap, REFIID riid, MethodTable * pIntfMT, IUnknown ** ppUnkOut);
1103
1104 // walk the list and free all blocks
1105 void FreeWrapper(ComCallWrapperCache *pWrapperCache);
1106
1107 BOOL IsWrapperActive();
1108
1109 // IsLinkedWrapper
1110 inline BOOL IsLinked()
1111 {
1112 CONTRACTL
1113 {
1114 NOTHROW;
1115 GC_NOTRIGGER;
1116 MODE_ANY;
1117 INSTANCE_CHECK;
1118 }
1119 CONTRACTL_END;
1120
1121 return m_pNext != NULL;
1122 }
1123
1124
1125 // wrapper is not guaranteed to be present
1126 // accessor to wrapper object in the sync block
1127 inline static PTR_ComCallWrapper GetWrapperForObject(OBJECTREF pObj, ComCallWrapperTemplate *pTemplate = NULL)
1128 {
1129 CONTRACT (PTR_ComCallWrapper)
1130 {
1131 NOTHROW;
1132 GC_NOTRIGGER;
1133 MODE_COOPERATIVE;
1134 SUPPORTS_DAC;
1135 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1136 }
1137 CONTRACT_END;
1138
1139 PTR_SyncBlock pSync = pObj->PassiveGetSyncBlock();
1140 if (!pSync)
1141 RETURN NULL;
1142
1143 PTR_InteropSyncBlockInfo pInteropInfo = pSync->GetInteropInfoNoCreate();
1144 if (!pInteropInfo)
1145 RETURN NULL;
1146
1147 PTR_ComCallWrapper pCCW = pInteropInfo->GetCCW();
1148
1149 if (pTemplate != NULL)
1150 {
1151 // make sure we use the right CCW - the object may have multiple CCWs associated
1152 // with it which were created based on different CCW templates
1153 while (pCCW != NULL && pCCW->GetComCallWrapperTemplate() != pTemplate)
1154 {
1155 pCCW = GetNext(pCCW);
1156 }
1157 }
1158
1159 RETURN pCCW;
1160 }
1161
1162 // get inner unknown
1163 HRESULT GetInnerUnknown(void **pv);
1164
1165 // Init outer unknown
1166 void InitializeOuter(IUnknown* pOuter);
1167
1168 // is the object aggregated by a COM component
1169 BOOL IsAggregated();
1170
1171 // is the object extends from (aggregates) a COM component
1172 BOOL IsExtendsCOMObject();
1173
1174 // get syncblock stored in the simplewrapper
1175 SyncBlock* GetSyncBlock();
1176
1177 // get the CCW template this wrapper is based on
1178 PTR_ComCallWrapperTemplate GetComCallWrapperTemplate();
1179
1180 // get outer unk
1181 IUnknown* GetOuter();
1182
1183 // Get IClassX interface pointer from the wrapper.
1184 // The inspectionOnly parameter should only be true to this function if you are
1185 // only passively inspecting the value and not using the interface (such as
1186 // passing out the pointer via ETW or in the dac).
1187 IUnknown* GetIClassXIP(bool inspectionOnly=false);
1188
1189 // Get the basic interface pointer from the wrapper.
1190 // The inspectionOnly parameter should only be true to this function if you are
1191 // only passively inspecting the value and not using the interface (such as
1192 // passing out the pointer via ETW or in the dac).
1193 IUnknown* GetBasicIP(bool inspectionOnly=false);
1194
1195 // Get the IDispatch interface pointer from the wrapper.
1196 IDispatch *GetIDispatchIP();
1197
1198 // Get ObjectRef from wrapper - this is called by GetObjectRef and GetStartWrapper.
1199 // Need this becuase GetDomainSynchronized will call GetStartWrapper which will call
1200 // GetObjectRef which will cause a little bit of nasty infinite recursion.
1201 inline OBJECTREF GetObjectRef()
1202 {
1203 CONTRACT (OBJECTREF)
1204 {
1205 WRAPPER(THROWS);
1206 WRAPPER(GC_TRIGGERS);
1207 MODE_COOPERATIVE;
1208 PRECONDITION(CheckPointer(m_ppThis));
1209 SO_TOLERANT;
1210 }
1211 CONTRACT_END;
1212
1213 if (m_ppThis == NULL)
1214 {
1215 // Force a fail fast if this CCW is already neutered
1216 AccessNeuteredCCW_FailFast();
1217 }
1218
1219 RETURN ObjectFromHandle(m_ppThis);
1220 }
1221
1222 //
1223 // Force a fail fast for better diagnostics
1224 // Don't inline so that this call would show up in the callstack
1225 //
1226 NOINLINE void AccessNeuteredCCW_FailFast()
1227 {
1228 LIMITED_METHOD_CONTRACT;
1229
1230 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_ACCESSING_CCW);
1231 }
1232
1233 // A MODE_ANY helper to get the MethodTable of the 'this' object. This helper keeps
1234 // the GCX_COOP transition out of the caller (it implies a holder which implies an
1235 // FS:0 handler on x86).
1236 MethodTable* GetMethodTableOfObjectRef();
1237
1238 // clean up an object wrapper
1239 void Cleanup();
1240
1241 // If the object gets collected while the CCW is still active, neuter (disconnect) the CCW.
1242 void Neuter();
1243 void ClearHandle();
1244
1245 // fast access to wrapper for a com+ object,
1246 // inline check, and call out of line to create, out of line version might cause gc
1247 //to be enabled
1248 static ComCallWrapper* __stdcall InlineGetWrapper(OBJECTREF* pObj, ComCallWrapperTemplate *pTemplate = NULL,
1249 ComCallWrapper *pClassCCW = NULL);
1250
1251 // Get RefCount
1252 inline ULONG GetRefCount();
1253
1254 // AddRef a wrapper
1255 inline ULONG AddRef();
1256
1257 // AddRef a wrapper
1258 inline ULONG AddRefWithAggregationCheck();
1259
1260 // Release for a Wrapper object
1261 inline ULONG Release();
1262
1263 // Get Jupiter RefCount
1264 inline ULONG GetJupiterRefCount();
1265
1266 // AddRef Jupiter Ref Count
1267 // Jupiter Ref count becomes strong ref if pegged, otherwise weak ref
1268 inline ULONG AddJupiterRef();
1269
1270 // Release Jupiter Ref Count
1271 // Jupiter Ref count becomes strong ref if pegged, otherwise weak ref
1272 inline ULONG ReleaseJupiterRef();
1273
1274 // Return whether this CCW is pegged or not by Jupiter
1275 inline BOOL IsPegged();
1276
1277 // Return whether this CCW is pegged or not (either by Jupiter, or globally)
1278 // We globally peg every Jupiter CCW outside Gen 2 GCs
1279 inline BOOL IsConsideredPegged();
1280
1281 // Initialize the simple wrapper.
1282 static void InitSimpleWrapper(ComCallWrapper* pWrap, SimpleComCallWrapper* pSimpleWrap);
1283
1284 // Clear the simple wrapper. This must be called on the start wrapper.
1285 static void ClearSimpleWrapper(ComCallWrapper* pWrap);
1286
1287 //Get Simple wrapper, for std interfaces such as IProvideClassInfo
1288 PTR_SimpleComCallWrapper GetSimpleWrapper()
1289 {
1290 CONTRACT (PTR_SimpleComCallWrapper)
1291 {
1292 NOTHROW;
1293 GC_NOTRIGGER;
1294 MODE_ANY;
1295 INSTANCE_CHECK;
1296 POSTCONDITION(CheckPointer(RETVAL));
1297 SUPPORTS_DAC;
1298 SO_TOLERANT;
1299 }
1300 CONTRACT_END;
1301
1302 RETURN m_pSimpleWrapper;
1303 }
1304
1305
1306 // Get wrapper from IP, for std. interfaces like IDispatch
1307 inline static PTR_ComCallWrapper GetWrapperFromIP(PTR_IUnknown pUnk);
1308
1309#if !defined(DACCESS_COMPILE)
1310 inline static ComCallWrapper* GetStartWrapperFromIP(IUnknown* pUnk)
1311 {
1312 CONTRACT (ComCallWrapper*)
1313 {
1314 WRAPPER(THROWS);
1315 WRAPPER(GC_TRIGGERS);
1316 MODE_ANY;
1317 PRECONDITION(CheckPointer(pUnk));
1318 POSTCONDITION(CheckPointer(RETVAL));
1319 }
1320 CONTRACT_END;
1321
1322 ComCallWrapper* pWrap = GetWrapperFromIP(pUnk);
1323 if (pWrap->IsLinked())
1324 pWrap = GetStartWrapper(pWrap);
1325
1326 RETURN pWrap;
1327 }
1328#endif // DACCESS_COMPILE
1329
1330 // Get an interface from wrapper, based on riid or pIntfMT
1331 static IUnknown* GetComIPFromCCW(ComCallWrapper *pWrap, REFIID riid, MethodTable* pIntfMT, GetComIPFromCCW::flags flags = GetComIPFromCCW::None);
1332
1333private:
1334 // pointer to OBJECTREF
1335 OBJECTHANDLE m_ppThis;
1336
1337 // Pointer to the simple wrapper.
1338 PTR_SimpleComCallWrapper m_pSimpleWrapper;
1339
1340 // Block of vtable pointers.
1341 SLOT* m_rgpIPtr[NumVtablePtrs];
1342
1343 // Pointer to the next wrapper.
1344 PTR_ComCallWrapper m_pNext;
1345};
1346
1347FORCEINLINE void CCWRelease(ComCallWrapper* p)
1348{
1349 WRAPPER_NO_CONTRACT;
1350
1351 p->Release();
1352}
1353
1354class CCWHolder : public Wrapper<ComCallWrapper*, CCWHolderDoNothing, CCWRelease, NULL>
1355{
1356public:
1357 CCWHolder(ComCallWrapper* p = NULL)
1358 : Wrapper<ComCallWrapper*, CCWHolderDoNothing, CCWRelease, NULL>(p)
1359 {
1360 WRAPPER_NO_CONTRACT;
1361 }
1362
1363 FORCEINLINE void operator=(ComCallWrapper* p)
1364 {
1365 WRAPPER_NO_CONTRACT;
1366
1367 Wrapper<ComCallWrapper*, CCWHolderDoNothing, CCWRelease, NULL>::operator=(p);
1368 }
1369};
1370
1371typedef DPTR(class WeakReferenceImpl) PTR_WeakReferenceImpl;
1372
1373//
1374// Represents a domain-bound weak reference to the object (not the CCW)
1375//
1376class WeakReferenceImpl : public IUnknownCommon<IWeakReference>
1377{
1378private:
1379 ADID m_adid; // AppDomain ID of where this weak reference is created
1380 OBJECTHANDLE m_ppObject; // Short weak global handle points back to the object,
1381 // created in domain ID = m_adid
1382
1383public:
1384 WeakReferenceImpl(SimpleComCallWrapper *pSimpleWrapper, Thread *pCurrentThread);
1385 virtual ~WeakReferenceImpl();
1386
1387 // IWeakReference methods
1388 virtual HRESULT STDMETHODCALLTYPE Resolve(REFIID riid, IInspectable **ppvObject);
1389
1390private :
1391 static void Resolve_Callback(LPVOID lpData);
1392 static void Resolve_Callback_SwitchToPreemp(LPVOID lpData);
1393
1394 HRESULT ResolveInternal(Thread *pThread, REFIID riid, IInspectable **ppvObject);
1395
1396 HRESULT Cleanup();
1397};
1398
1399//
1400// Uncommonly used data on Simple CCW
1401// Created on-demand
1402//
1403// We used to have two fields now it only has one field, and I'm keeping this structure
1404// just in case we want to put more stuff in here later
1405//
1406struct SimpleCCWAuxData
1407{
1408 VolatilePtr<DispatchExInfo> m_pDispatchExInfo; // Information required by the IDispatchEx standard interface
1409 // Not available on WinRT types
1410
1411 SimpleCCWAuxData()
1412 {
1413 LIMITED_METHOD_CONTRACT;
1414
1415 m_pDispatchExInfo = NULL;
1416 }
1417
1418 ~SimpleCCWAuxData()
1419 {
1420 LIMITED_METHOD_CONTRACT;
1421
1422 if (m_pDispatchExInfo)
1423 {
1424 delete m_pDispatchExInfo;
1425 m_pDispatchExInfo = NULL;
1426 }
1427 }
1428};
1429
1430//--------------------------------------------------------------------------------
1431// simple ComCallWrapper for all simple std interfaces, that are not used very often
1432// like IProvideClassInfo, ISupportsErrorInfo etc.
1433//--------------------------------------------------------------------------------
1434struct SimpleComCallWrapper
1435{
1436private:
1437 friend class ComCallWrapper;
1438 friend class ClrDataAccess;
1439 friend class WeakReferenceImpl;
1440
1441 enum SimpleComCallWrapperFlags
1442 {
1443 enum_IsAggregated = 0x1,
1444 enum_IsExtendsCom = 0x2,
1445 enum_IsHandleWeak = 0x4,
1446 // unused = 0x8,
1447 // unused = 0x10,
1448 enum_IsPegged = 0x80,
1449 // unused = 0x100,
1450 enum_CustomQIRespondsToIMarshal = 0x200,
1451 enum_CustomQIRespondsToIMarshal_Inited = 0x400,
1452 };
1453
1454public :
1455 enum : LONGLONG
1456 {
1457 CLEANUP_SENTINEL = 0x0000000080000000, // Sentinel -> 1 bit
1458 COM_REFCOUNT_MASK = 0x000000007FFFFFFF, // COM -> 31 bits
1459 JUPITER_REFCOUNT_MASK = 0xFFFFFFFF00000000, // Jupiter -> 32 bits
1460 JUPITER_REFCOUNT_SHIFT = 32,
1461 JUPITER_REFCOUNT_INC = 0x0000000100000000,
1462 EXT_COM_REFCOUNT_MASK = 0x00000000FFFFFFFF, // For back-compat, preserve the higher-bit so that outside can observe it
1463 ALL_REFCOUNT_MASK = 0xFFFFFFFF7FFFFFFF,
1464 };
1465
1466 #define GET_JUPITER_REF(x) ((ULONG)(((x) & SimpleComCallWrapper::JUPITER_REFCOUNT_MASK) >> SimpleComCallWrapper::JUPITER_REFCOUNT_SHIFT))
1467 #define GET_COM_REF(x) ((ULONG)((x) & SimpleComCallWrapper::COM_REFCOUNT_MASK))
1468 #define GET_EXT_COM_REF(x) ((ULONG)((x) & SimpleComCallWrapper::EXT_COM_REFCOUNT_MASK))
1469
1470#ifdef _WIN64
1471 #define READ_REF(x) (x)
1472#else
1473 #define READ_REF(x) (::InterlockedCompareExchange64((LONGLONG *)&x, 0, 0))
1474#endif
1475
1476public:
1477 HRESULT IErrorInfo_hr();
1478 BSTR IErrorInfo_bstrDescription();
1479 BSTR IErrorInfo_bstrSource();
1480 BSTR IErrorInfo_bstrHelpFile();
1481 DWORD IErrorInfo_dwHelpContext();
1482 GUID IErrorInfo_guid();
1483
1484 // non virtual methods
1485 SimpleComCallWrapper();
1486
1487 VOID Cleanup();
1488
1489 // Used to neuter a CCW if its AD is being unloaded underneath it.
1490 VOID Neuter(bool fSkipHandleCleanup = false);
1491
1492 ~SimpleComCallWrapper();
1493
1494
1495 VOID ResetSyncBlock()
1496 {
1497 LIMITED_METHOD_CONTRACT;
1498 m_pSyncBlock = NULL;
1499 }
1500
1501 SyncBlock* GetSyncBlock()
1502 {
1503 CONTRACT (SyncBlock*)
1504 {
1505 WRAPPER(THROWS);
1506 WRAPPER(GC_TRIGGERS);
1507 MODE_ANY;
1508 }
1509 CONTRACT_END;
1510
1511 RETURN m_pSyncBlock;
1512 }
1513
1514 // Init pointer to the vtable of the interface
1515 // and the main ComCallWrapper if the interface needs it
1516 void InitNew(OBJECTREF oref, ComCallWrapperCache *pWrapperCache, ComCallWrapper* pWrap,
1517 ComCallWrapper *pClassWrap, SyncBlock* pSyncBlock,
1518 ComCallWrapperTemplate* pTemplate);
1519
1520 // used by reconnect wrapper to new object
1521 void ReInit(SyncBlock* pSyncBlock);
1522
1523 void InitOuter(IUnknown* pOuter);
1524
1525 void ResetOuter();
1526
1527 IUnknown* GetOuter();
1528
1529 // get inner unknown
1530 HRESULT GetInnerUnknown(void **ppv)
1531 {
1532 CONTRACTL
1533 {
1534 WRAPPER(THROWS);
1535 WRAPPER(GC_TRIGGERS);
1536 MODE_ANY;
1537 PRECONDITION(CheckPointer(ppv));
1538 }
1539 CONTRACTL_END;
1540
1541 *ppv = QIStandardInterface(enum_InnerUnknown);
1542 if (*ppv)
1543 return S_OK;
1544 else
1545 return E_NOINTERFACE;
1546 }
1547
1548 OBJECTREF GetObjectRef()
1549 {
1550 CONTRACT (OBJECTREF)
1551 {
1552 WRAPPER(THROWS);
1553 WRAPPER(GC_TRIGGERS);
1554 MODE_COOPERATIVE;
1555 SO_TOLERANT;
1556 }
1557 CONTRACT_END;
1558
1559 RETURN (GetMainWrapper()->GetObjectRef());
1560 }
1561
1562 ComCallWrapperCache* GetWrapperCache()
1563 {
1564 CONTRACT (ComCallWrapperCache*)
1565 {
1566 WRAPPER(THROWS);
1567 WRAPPER(GC_TRIGGERS);
1568 MODE_ANY;
1569 POSTCONDITION(CheckPointer(RETVAL));
1570 }
1571 CONTRACT_END;
1572
1573 RETURN m_pWrapperCache;
1574 }
1575
1576 // Connection point helper methods.
1577 BOOL FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP);
1578 void EnumConnectionPoints(IEnumConnectionPoints **ppEnumCP);
1579
1580 ADID GetDomainID()
1581 {
1582 CONTRACTL
1583 {
1584 WRAPPER(THROWS);
1585 WRAPPER(GC_TRIGGERS);
1586 MODE_ANY;
1587 }
1588 CONTRACTL_END;
1589
1590 return m_dwDomainId;
1591 }
1592
1593 ADID GetRawDomainID()
1594 {
1595 LIMITED_METHOD_DAC_CONTRACT;
1596 return m_dwDomainId;
1597 }
1598
1599 // is the object aggregated by a COM component
1600 BOOL IsAggregated()
1601 {
1602 LIMITED_METHOD_CONTRACT;
1603
1604 return m_flags & enum_IsAggregated;
1605 }
1606
1607 void MarkAggregated()
1608 {
1609 WRAPPER_NO_CONTRACT;
1610
1611 FastInterlockOr((ULONG*)&m_flags, enum_IsAggregated);
1612 }
1613
1614 void UnMarkAggregated()
1615 {
1616 WRAPPER_NO_CONTRACT;
1617
1618 FastInterlockAnd((ULONG*)&m_flags, ~enum_IsAggregated);
1619 }
1620
1621 BOOL IsHandleWeak()
1622 {
1623 LIMITED_METHOD_CONTRACT;
1624
1625 return m_flags & enum_IsHandleWeak;
1626 }
1627
1628 void MarkHandleWeak()
1629 {
1630 WRAPPER_NO_CONTRACT;
1631
1632 FastInterlockOr((ULONG*)&m_flags, enum_IsHandleWeak);
1633 }
1634
1635 VOID ResetHandleStrength()
1636 {
1637 WRAPPER_NO_CONTRACT;
1638
1639 FastInterlockAnd((ULONG*)&m_flags, ~enum_IsHandleWeak);
1640 }
1641
1642 // is the object extends from (aggregates) a COM component
1643 BOOL IsExtendsCOMObject()
1644 {
1645 LIMITED_METHOD_CONTRACT;
1646
1647 return m_flags & enum_IsExtendsCom;
1648 }
1649
1650 inline BOOL IsPegged()
1651 {
1652 LIMITED_METHOD_DAC_CONTRACT;
1653
1654 return m_flags & enum_IsPegged;
1655 }
1656
1657 inline void MarkPegged()
1658 {
1659 LIMITED_METHOD_CONTRACT;
1660
1661 FastInterlockOr((ULONG*)&m_flags, enum_IsPegged);
1662 }
1663
1664 inline void UnMarkPegged()
1665 {
1666 LIMITED_METHOD_CONTRACT;
1667
1668 FastInterlockAnd((ULONG*)&m_flags, ~enum_IsPegged);
1669 }
1670
1671 // Used for the creation and deletion of simple wrappers
1672 static SimpleComCallWrapper* CreateSimpleWrapper();
1673
1674 // Determines if the type associated with the ComCallWrapper supports exceptions.
1675 static BOOL SupportsExceptions(MethodTable *pMT);
1676 static BOOL SupportsIStringable(MethodTable *pMT);
1677
1678 // Determines if the type supports IReflect / IExpando.
1679 static BOOL SupportsIReflect(MethodTable *pMT);
1680 static BOOL SupportsIExpando(MethodTable *pMT);
1681
1682 NOINLINE BOOL ShouldUseManagedIProvideClassInfo();
1683
1684 //--------------------------------------------------------------------------
1685 // Retrieves the simple wrapper from an IUnknown pointer that is for one
1686 // of the interfaces exposed by the simple wrapper.
1687 //--------------------------------------------------------------------------
1688 static PTR_SimpleComCallWrapper GetWrapperFromIP(PTR_IUnknown pUnk)
1689 {
1690 CONTRACT (SimpleComCallWrapper*)
1691 {
1692 NOTHROW;
1693 GC_NOTRIGGER;
1694 MODE_ANY;
1695 PRECONDITION(CheckPointer(pUnk));
1696 POSTCONDITION(CheckPointer(RETVAL));
1697 SO_TOLERANT;
1698 SUPPORTS_DAC;
1699 }
1700 CONTRACT_END;
1701
1702 int i = GetStdInterfaceKind(pUnk);
1703 PTR_SimpleComCallWrapper pSimpleWrapper = dac_cast<PTR_SimpleComCallWrapper>(dac_cast<TADDR>(pUnk) - sizeof(LPBYTE) * i - offsetof(SimpleComCallWrapper,m_rgpVtable));
1704
1705 // We should never getting back a built-in interface from a SimpleCCW that represents a variant interface
1706 _ASSERTE(pSimpleWrapper->m_pClassWrap == NULL);
1707
1708 RETURN pSimpleWrapper;
1709 }
1710
1711 // get the main wrapper
1712 PTR_ComCallWrapper GetMainWrapper()
1713 {
1714 CONTRACT (PTR_ComCallWrapper)
1715 {
1716 NOTHROW;
1717 GC_NOTRIGGER;
1718 MODE_ANY;
1719 SUPPORTS_DAC;
1720 INSTANCE_CHECK;
1721 POSTCONDITION(CheckPointer(RETVAL));
1722 SO_TOLERANT;
1723 }
1724 CONTRACT_END;
1725
1726 RETURN m_pWrap;
1727 }
1728
1729 inline PTR_ComCallWrapper GetClassWrapper()
1730 {
1731 LIMITED_METHOD_CONTRACT;
1732
1733 _ASSERTE(m_pMT->IsInterface());
1734 _ASSERTE(m_pClassWrap != NULL);
1735
1736 return m_pClassWrap;
1737 }
1738
1739 inline ULONG GetRefCount()
1740 {
1741 LIMITED_METHOD_CONTRACT;
1742
1743 return GET_COM_REF(READ_REF(m_llRefCount));
1744 }
1745
1746 // Returns the unmarked raw ref count
1747 // Make sure we always make a copy of the value instead of inlining
1748 NOINLINE LONGLONG GetRealRefCount()
1749 {
1750 LIMITED_METHOD_CONTRACT;
1751
1752 return READ_REF(m_llRefCount);
1753 }
1754
1755 inline BOOL IsNeutered()
1756 {
1757 LIMITED_METHOD_DAC_CONTRACT;
1758 return !!(READ_REF(m_llRefCount) & CLEANUP_SENTINEL);
1759 }
1760
1761#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1762 // CCW refcount logging consists of two steps. BuildRefCountLogMessage is an instance method which
1763 // must be called at a point where the CCW is guaranteed to be alive. LogRefCount is static because
1764 // we generally don't know the new refcount (the one we want to log) until the CCW is at risk of
1765 // having been destroyed by other threads.
1766 void BuildRefCountLogMessage(LPCWSTR wszOperation, StackSString &ssMessage, ULONG dwEstimatedRefCount);
1767 static void LogRefCount(ComCallWrapper *pWrap, StackSString &ssMessage, ULONG dwRefCountToLog);
1768
1769 NOINLINE HRESULT LogCCWAddRef(ULONG newRefCount)
1770 {
1771 CONTRACTL
1772 {
1773 NOTHROW;
1774 GC_NOTRIGGER;
1775 MODE_ANY;
1776 SO_TOLERANT;
1777 }
1778 CONTRACTL_END;
1779
1780 SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode();
1781
1782 // we can safely assume that the CCW is still alive since this is an AddRef
1783 StackSString ssMessage;
1784 BuildRefCountLogMessage(W("AddRef"), ssMessage, newRefCount);
1785 LogRefCount(GetMainWrapper(), ssMessage, newRefCount);
1786
1787 return S_OK;
1788 }
1789
1790 inline ULONG AddRef()
1791 {
1792 CONTRACTL
1793 {
1794 NOTHROW;
1795 GC_NOTRIGGER;
1796 MODE_ANY;
1797 SO_TOLERANT;
1798 }
1799 CONTRACTL_END;
1800
1801 if (m_pClassWrap)
1802 {
1803 // Forward to the real wrapper if this CCW represents a variant interface
1804 return m_pClassWrap->GetSimpleWrapper()->AddRef();
1805 }
1806
1807 LONGLONG newRefCount = ::InterlockedIncrement64(&m_llRefCount);
1808 if (g_pConfig->LogCCWRefCountChangeEnabled())
1809 {
1810 LogCCWAddRef(GET_EXT_COM_REF(newRefCount));
1811 }
1812 return GET_EXT_COM_REF(newRefCount);
1813 }
1814
1815 inline ULONG AddRefWithAggregationCheck()
1816 {
1817 CONTRACTL
1818 {
1819 NOTHROW;
1820 GC_TRIGGERS;
1821 MODE_ANY;
1822 SO_TOLERANT;
1823 }
1824 CONTRACTL_END;
1825
1826 // aggregation check
1827 IUnknown* pOuter = this->GetOuter();
1828 if (pOuter != NULL)
1829 return SafeAddRef(pOuter);
1830
1831 return this->AddRef();
1832 }
1833
1834private:
1835 LONGLONG ReleaseImplWithLogging(LONGLONG * pRefCount);
1836
1837 NOINLINE void ReleaseImplCleanup()
1838 {
1839 CONTRACTL
1840 {
1841 NOTHROW;
1842 GC_TRIGGERS;
1843 MODE_ANY;
1844 SO_TOLERANT;
1845 }
1846 CONTRACTL_END;
1847
1848 if (!CanRunManagedCode())
1849 return;
1850 SO_INTOLERANT_CODE_NOTHROW(GetThread(), return; );
1851
1852 m_pWrap->Cleanup();
1853 }
1854public:
1855
1856 inline ULONG Release()
1857 {
1858 CONTRACTL
1859 {
1860 NOTHROW;
1861 GC_TRIGGERS;
1862 MODE_ANY;
1863 SO_TOLERANT;
1864 }
1865 CONTRACTL_END;
1866
1867 if (m_pClassWrap)
1868 {
1869 // Forward to the real wrapper if this CCW represents a variant interface
1870 return m_pClassWrap->GetSimpleWrapper()->Release();
1871 }
1872
1873 LONGLONG *pRefCount = &m_llRefCount;
1874 ULONG ulComRef = GET_COM_REF(READ_REF(*pRefCount));
1875
1876 if (ulComRef <= 0)
1877 {
1878 _ASSERTE(!"Invalid Release() call on already released object. A managed object exposed to COM is being over-released from unmanaged code");
1879 return -1;
1880 }
1881
1882 // Null the outer pointer if refcount is about to drop to 0. We cannot perform this
1883 // operation after decrementing the refcount as that would race with the finalizer
1884 // that may clean this CCW up any time after the refcount drops to 0. With this pre-
1885 // decrement reset, we are racing with other Release's and may call ResetOuter multiple
1886 // times (which is fine - it's thread safe and idempotent) or call it when the refcount
1887 // doesn't really drop to 0 (which is also fine - it would have dropped to 0 under
1888 // slightly different timing and the COM client is responsible for preventing this).
1889 if (ulComRef == 1)
1890 ResetOuter();
1891
1892 LONGLONG newRefCount;
1893 if (g_pConfig->LogCCWRefCountChangeEnabled())
1894 {
1895 newRefCount = ReleaseImplWithLogging(pRefCount);
1896 }
1897 else
1898 {
1899 // Decrement the ref count
1900 newRefCount = ::InterlockedDecrement64(pRefCount);
1901 }
1902
1903 // IMPORTANT: Do not touch instance fields or any other data associated with the CCW beyond this
1904 // point unless newRefCount equals CLEANUP_SENTINEL (it's the only case when we know that Neuter
1905 // or another Release could not swoop in and destroy our data structures).
1906
1907 // If we hit the sentinel value in COM ref count and jupiter ref count == 0, it's our responsibility to clean up.
1908 if (newRefCount == CLEANUP_SENTINEL)
1909 {
1910 ReleaseImplCleanup();
1911 return 0;
1912 }
1913
1914 return GET_EXT_COM_REF(newRefCount);
1915 }
1916
1917 inline ULONG AddJupiterRef()
1918 {
1919 WRAPPER_NO_CONTRACT;
1920
1921 LONGLONG llOldRefCount;
1922 LONGLONG llNewRefCount;
1923
1924 do {
1925 llOldRefCount = m_llRefCount;
1926 llNewRefCount = llOldRefCount + JUPITER_REFCOUNT_INC;
1927 } while (InterlockedCompareExchange64(&m_llRefCount, llNewRefCount, llOldRefCount) != llOldRefCount);
1928
1929 LOG((LF_INTEROP, LL_INFO1000,
1930 "SimpleComCallWrapper::AddJupiterRef() called on SimpleComCallWrapper 0x%p, cbRef = 0x%x, cbJupiterRef = 0x%x\n", this, GET_COM_REF(llNewRefCount), GET_JUPITER_REF(llNewRefCount)));
1931
1932 return GET_JUPITER_REF(llNewRefCount);
1933 }
1934
1935 inline ULONG ReleaseJupiterRef()
1936 {
1937 WRAPPER_NO_CONTRACT;
1938
1939 LONGLONG llOldRefCount;
1940 LONGLONG llNewRefCount;
1941
1942 do {
1943 llOldRefCount = m_llRefCount;
1944 llNewRefCount = llOldRefCount - JUPITER_REFCOUNT_INC;
1945 } while (InterlockedCompareExchange64(&m_llRefCount, llNewRefCount, llOldRefCount) != llOldRefCount);
1946
1947 LOG((LF_INTEROP, LL_INFO1000,
1948 "SimpleComCallWrapper::ReleaseJupiterRef() called on SimpleComCallWrapper 0x%p, cbRef = 0x%x, cbJupiterRef = 0x%x\n", this, GET_COM_REF(llNewRefCount), GET_JUPITER_REF(llNewRefCount)));
1949
1950 if (llNewRefCount == CLEANUP_SENTINEL)
1951 {
1952 // If we hit the sentinel value, it's our responsibility to clean up.
1953 m_pWrap->Cleanup();
1954 }
1955
1956 return GET_JUPITER_REF(llNewRefCount);
1957 }
1958
1959#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1960
1961 inline ULONG GetJupiterRefCount()
1962 {
1963 LIMITED_METHOD_CONTRACT;
1964
1965 return GET_JUPITER_REF(READ_REF(m_llRefCount));
1966 }
1967
1968 MethodTable* GetMethodTable()
1969 {
1970 CONTRACT (MethodTable*)
1971 {
1972 WRAPPER(THROWS);
1973 WRAPPER(GC_TRIGGERS);
1974 MODE_ANY;
1975 POSTCONDITION(CheckPointer(RETVAL));
1976 }
1977 CONTRACT_END;
1978
1979 RETURN m_pMT;
1980 }
1981
1982 DispatchExInfo* GetDispatchExInfo()
1983 {
1984 CONTRACT (DispatchExInfo*)
1985 {
1986 WRAPPER(THROWS);
1987 WRAPPER(GC_TRIGGERS);
1988 MODE_ANY;
1989 }
1990 CONTRACT_END;
1991
1992 if (m_pAuxData.Load() == NULL)
1993 RETURN NULL;
1994 else
1995 RETURN m_pAuxData->m_pDispatchExInfo;
1996 }
1997
1998 BOOL SupportsICustomQueryInterface()
1999 {
2000 LIMITED_METHOD_CONTRACT;
2001 return m_pTemplate->SupportsICustomQueryInterface();
2002 }
2003
2004 PTR_ComCallWrapperTemplate GetComCallWrapperTemplate()
2005 {
2006 LIMITED_METHOD_CONTRACT;
2007 return m_pTemplate;
2008 }
2009
2010 // Creates new AddRef-ed IWeakReference*
2011 IWeakReference *CreateWeakReference(Thread *pCurrentThread)
2012 {
2013 CONTRACTL
2014 {
2015 THROWS;
2016 GC_TRIGGERS;
2017 MODE_PREEMPTIVE;
2018 PRECONDITION(pCurrentThread == GetThread());
2019 }
2020 CONTRACTL_END;
2021
2022 // Create a WeakReferenceImpl with RefCount = 1
2023 // No need to call AddRef
2024 WeakReferenceImpl *pWeakRef = new WeakReferenceImpl(this, pCurrentThread);
2025
2026 return pWeakRef;
2027 }
2028
2029 // Returns TRUE if the ICustomQI implementation returns Handled or Failed for IID_IMarshal.
2030 BOOL CustomQIRespondsToIMarshal();
2031
2032 SimpleCCWAuxData *GetOrCreateAuxData()
2033 {
2034 CONTRACTL
2035 {
2036 THROWS;
2037 GC_NOTRIGGER;
2038 MODE_ANY;
2039 }
2040 CONTRACTL_END;
2041
2042 if (m_pAuxData.Load())
2043 return m_pAuxData;
2044
2045 NewHolder<SimpleCCWAuxData> pAuxData = new SimpleCCWAuxData();
2046 if (InterlockedCompareExchangeT(&m_pAuxData, (SimpleCCWAuxData *)pAuxData, NULL) == NULL)
2047 pAuxData.SuppressRelease();
2048
2049 return m_pAuxData;
2050 }
2051
2052private:
2053 // Methods to initialize the DispatchEx and exception info.
2054 void InitExceptionInfo();
2055 void InitDispatchExInfo();
2056
2057 // Methods to set up the connection point list.
2058 void SetUpCPList();
2059 void SetUpCPListHelper(MethodTable **apSrcItfMTs, int cSrcItfs);
2060 ConnectionPoint *CreateConnectionPoint(ComCallWrapper *pWrap, MethodTable *pEventMT);
2061 ConnectionPoint *TryCreateConnectionPoint(ComCallWrapper *pWrap, MethodTable *pEventMT);
2062 CQuickArray<ConnectionPoint*> *CreateCPArray();
2063
2064 // QI for well known interfaces from within the runtime direct fetch, instead of guid comparisons
2065 IUnknown* QIStandardInterface(Enum_StdInterfaces index);
2066
2067 // QI for well known interfaces from within the runtime based on an IID.
2068 IUnknown* QIStandardInterface(REFIID riid);
2069
2070 CQuickArray<ConnectionPoint*>* m_pCPList;
2071
2072 // syncblock for the ObjecRef
2073 SyncBlock* m_pSyncBlock;
2074
2075 //outer unknown cookie
2076 IUnknown* m_pOuter;
2077
2078 // array of pointers to std. vtables
2079 SLOT const* m_rgpVtable[enum_LastStdVtable];
2080
2081 PTR_ComCallWrapper m_pWrap; // the first ComCallWrapper associated with this SimpleComCallWrapper
2082 PTR_ComCallWrapper m_pClassWrap; // the first ComCallWrapper associated with the class (only if m_pMT is an interface)
2083 MethodTable* m_pMT;
2084 ComCallWrapperCache* m_pWrapperCache;
2085 PTR_ComCallWrapperTemplate m_pTemplate;
2086
2087 // Points to uncommonly used data that are dynamically allocated
2088 VolatilePtr<SimpleCCWAuxData> m_pAuxData;
2089
2090 ADID m_dwDomainId;
2091
2092 DWORD m_flags;
2093
2094 // This maintains both COM ref and Jupiter ref in 64-bit
2095 LONGLONG m_llRefCount;
2096 };
2097
2098inline OBJECTHANDLE ComCallWrapper::GetObjectHandle()
2099{
2100 CONTRACT (OBJECTHANDLE)
2101 {
2102 WRAPPER(THROWS);
2103 WRAPPER(GC_TRIGGERS);
2104 MODE_COOPERATIVE;
2105 POSTCONDITION(CheckPointer(RETVAL));
2106 }
2107 CONTRACT_END;
2108
2109 RETURN m_ppThis;
2110}
2111
2112//--------------------------------------------------------------------------------
2113// ComCallWrapper* ComCallWrapper::InlineGetWrapper(OBJECTREF* ppObj, ComCallWrapperTemplate *pTemplate)
2114// returns the wrapper for the object, if not yet created, creates one
2115// returns null for out of memory scenarios.
2116// Note: the wrapper is returned AddRef'd and should be Released when finished
2117// with.
2118//--------------------------------------------------------------------------------
2119inline ComCallWrapper* __stdcall ComCallWrapper::InlineGetWrapper(OBJECTREF* ppObj, ComCallWrapperTemplate *pTemplate /*= NULL*/,
2120 ComCallWrapper *pClassCCW /*= NULL*/)
2121{
2122 CONTRACT (ComCallWrapper*)
2123 {
2124 THROWS;
2125 GC_TRIGGERS;
2126 MODE_COOPERATIVE;
2127 PRECONDITION(CheckPointer(ppObj));
2128 POSTCONDITION(CheckPointer(RETVAL));
2129 }
2130 CONTRACT_END;
2131
2132 // get the wrapper for this com+ object
2133 ComCallWrapper* pWrap = GetWrapperForObject(*ppObj, pTemplate);
2134
2135 if (NULL == pWrap)
2136 {
2137 pWrap = CreateWrapper(ppObj, pTemplate, pClassCCW);
2138 }
2139 _ASSERTE(pTemplate == NULL || pTemplate == pWrap->GetSimpleWrapper()->GetComCallWrapperTemplate());
2140
2141 // All threads will have the same resulting CCW at this point, and
2142 // they should all check to see if the CCW they got back is
2143 // appropriate for the current AD. If not, then we must mark the
2144 // CCW as agile.
2145 // If we are creating a CCW that represents a variant interface, use the pClassCCW (which is the main CCW)
2146 ComCallWrapper *pMainWrap;
2147 if (pClassCCW)
2148 pMainWrap = pClassCCW;
2149 else
2150 pMainWrap = pWrap;
2151
2152 pWrap->AddRef();
2153
2154 RETURN pWrap;
2155}
2156
2157inline ADID ComCallWrapper::GetDomainID()
2158{
2159 WRAPPER_NO_CONTRACT;
2160
2161 return GetSimpleWrapper()->GetDomainID();
2162}
2163
2164inline ULONG ComCallWrapper::GetRefCount()
2165{
2166 CONTRACTL
2167 {
2168 WRAPPER(THROWS);
2169 WRAPPER(GC_TRIGGERS);
2170 MODE_ANY;
2171 INSTANCE_CHECK;
2172 }
2173 CONTRACTL_END;
2174
2175 return m_pSimpleWrapper->GetRefCount();
2176}
2177
2178#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
2179inline ULONG ComCallWrapper::AddRef()
2180{
2181 CONTRACTL
2182 {
2183 WRAPPER(THROWS);
2184 WRAPPER(GC_TRIGGERS);
2185 MODE_ANY;
2186 SO_TOLERANT;
2187 INSTANCE_CHECK;
2188 }
2189 CONTRACTL_END;
2190
2191 return m_pSimpleWrapper->AddRef();
2192}
2193
2194inline ULONG ComCallWrapper::AddRefWithAggregationCheck()
2195{
2196 WRAPPER_NO_CONTRACT;
2197 return m_pSimpleWrapper->AddRefWithAggregationCheck();
2198}
2199
2200inline ULONG ComCallWrapper::Release()
2201{
2202 CONTRACTL
2203 {
2204 WRAPPER(THROWS);
2205 WRAPPER(GC_TRIGGERS);
2206 MODE_ANY;
2207 SO_TOLERANT;
2208 INSTANCE_CHECK;
2209 PRECONDITION(CheckPointer(m_pSimpleWrapper));
2210 }
2211 CONTRACTL_END;
2212
2213 return m_pSimpleWrapper->Release();
2214}
2215
2216inline ULONG ComCallWrapper::AddJupiterRef()
2217{
2218 CONTRACTL
2219 {
2220 WRAPPER(THROWS);
2221 WRAPPER(GC_TRIGGERS);
2222 MODE_ANY;
2223 INSTANCE_CHECK;
2224 }
2225 CONTRACTL_END;
2226
2227 return m_pSimpleWrapper->AddJupiterRef();
2228}
2229
2230inline ULONG ComCallWrapper::ReleaseJupiterRef()
2231{
2232 CONTRACTL
2233 {
2234 WRAPPER(THROWS);
2235 WRAPPER(GC_TRIGGERS);
2236 MODE_ANY;
2237 INSTANCE_CHECK;
2238 PRECONDITION(CheckPointer(m_pSimpleWrapper));
2239 }
2240 CONTRACTL_END;
2241
2242 return m_pSimpleWrapper->ReleaseJupiterRef();
2243}
2244
2245inline void ComCallWrapper::InitSimpleWrapper(ComCallWrapper* pWrap, SimpleComCallWrapper* pSimpleWrap)
2246{
2247 CONTRACTL
2248 {
2249 WRAPPER(THROWS);
2250 WRAPPER(GC_TRIGGERS);
2251 MODE_ANY;
2252 PRECONDITION(CheckPointer(pWrap));
2253 PRECONDITION(CheckPointer(pSimpleWrap));
2254 PRECONDITION(pSimpleWrap->GetMainWrapper() == pWrap);
2255 }
2256 CONTRACTL_END;
2257
2258 while (pWrap)
2259 {
2260 pWrap->m_pSimpleWrapper = pSimpleWrap;
2261 pWrap = GetNext(pWrap);
2262 }
2263}
2264
2265inline void ComCallWrapper::ClearSimpleWrapper(ComCallWrapper* pWrap)
2266{
2267 CONTRACTL
2268 {
2269 WRAPPER(THROWS);
2270 WRAPPER(GC_TRIGGERS);
2271 MODE_ANY;
2272 PRECONDITION(CheckPointer(pWrap));
2273 }
2274 CONTRACTL_END;
2275
2276 // clear the m_pSimpleWrapper field in all wrappers that share the same SimpleComCallWrapper
2277 SimpleComCallWrapper *pSimpleWrapper = pWrap->m_pSimpleWrapper;
2278
2279 while (pWrap && pWrap->m_pSimpleWrapper == pSimpleWrapper)
2280 {
2281 pWrap->m_pSimpleWrapper = NULL;
2282 pWrap = GetNext(pWrap);
2283 }
2284}
2285#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
2286
2287inline BOOL ComCallWrapper::IsPegged()
2288{
2289 CONTRACTL
2290 {
2291 NOTHROW;
2292 GC_NOTRIGGER;
2293 MODE_ANY;
2294 INSTANCE_CHECK;
2295 }
2296 CONTRACTL_END;
2297
2298 return m_pSimpleWrapper->IsPegged();
2299}
2300
2301inline BOOL ComCallWrapper::IsConsideredPegged()
2302{
2303 LIMITED_METHOD_DAC_CONTRACT;
2304
2305 return m_pSimpleWrapper->IsPegged() || RCWWalker::IsGlobalPeggingOn();
2306}
2307
2308inline ULONG ComCallWrapper::GetJupiterRefCount()
2309{
2310 CONTRACTL
2311 {
2312 NOTHROW;
2313 GC_NOTRIGGER;
2314 MODE_ANY;
2315 INSTANCE_CHECK;
2316 }
2317 CONTRACTL_END;
2318
2319 return m_pSimpleWrapper->GetJupiterRefCount();
2320}
2321
2322
2323
2324inline PTR_ComCallWrapper ComCallWrapper::GetWrapperFromIP(PTR_IUnknown pUnk)
2325{
2326 CONTRACT (PTR_ComCallWrapper)
2327 {
2328 NOTHROW;
2329 GC_NOTRIGGER;
2330 MODE_ANY;
2331 PRECONDITION(CheckPointer(pUnk));
2332 POSTCONDITION(CheckPointer(RETVAL));
2333 SUPPORTS_DAC;
2334 SO_TOLERANT;
2335 }
2336 CONTRACT_END;
2337
2338 // This code path may be exercised from out-of-process. Unfortunately, we need to manipulate the
2339 // target address here, and so we need to do some non-trivial casting. First, cast the PTR type
2340 // to the target address first, and then mask off the least significant bits. Then use the end
2341 // result as a target address to instantiate a ComCallWrapper. The line below is equivalent to:
2342 // ComCallWrapper* pWrap = (ComCallWrapper*)((size_t)pUnk & enum_ThisMask);
2343 PTR_ComCallWrapper pWrap = dac_cast<PTR_ComCallWrapper>(dac_cast<TADDR>(pUnk) & enum_ThisMask);
2344
2345 // Use class wrapper if this CCW represents a variant interface
2346 PTR_ComCallWrapper pClassWrapper = pWrap->GetSimpleWrapper()->m_pClassWrap;
2347 if (pClassWrapper)
2348 {
2349 _ASSERTE(pClassWrapper->GetSimpleWrapper()->m_pClassWrap == NULL);
2350
2351 RETURN pClassWrapper;
2352 }
2353
2354 RETURN pWrap;
2355}
2356
2357//--------------------------------------------------------------------------
2358// PTR_ComCallWrapper ComCallWrapper::GetStartWrapper(PTR_ComCallWrapper pWrap)
2359// get outermost wrapper, given a linked wrapper
2360// get the start wrapper from the sync block
2361//--------------------------------------------------------------------------
2362inline PTR_ComCallWrapper ComCallWrapper::GetStartWrapper(PTR_ComCallWrapper pWrap)
2363{
2364 CONTRACT (PTR_ComCallWrapper)
2365 {
2366 NOTHROW;
2367 GC_TRIGGERS;
2368 MODE_ANY;
2369 SUPPORTS_DAC;
2370 PRECONDITION(CheckPointer(pWrap));
2371 PRECONDITION(pWrap->IsLinked());
2372 POSTCONDITION(CheckPointer(RETVAL));
2373 }
2374 CONTRACT_END;
2375
2376 PTR_SimpleComCallWrapper pSimpleWrap = pWrap->GetSimpleWrapper();
2377 RETURN (pSimpleWrap->GetMainWrapper());
2378}
2379
2380//--------------------------------------------------------------------------
2381// PTR_ComCallWrapperTemplate ComCallWrapper::GetComCallWrapperTemplate()
2382inline PTR_ComCallWrapperTemplate ComCallWrapper::GetComCallWrapperTemplate()
2383{
2384 LIMITED_METHOD_CONTRACT;
2385 return GetSimpleWrapper()->GetComCallWrapperTemplate();
2386}
2387
2388//--------------------------------------------------------------------------
2389// BOOL ComCallWrapper::BOOL IsHandleWeak()
2390// check if the wrapper has been deactivated
2391// Moved here to make DAC build happy and hopefully get it inlined
2392//--------------------------------------------------------------------------
2393inline BOOL ComCallWrapper::IsHandleWeak()
2394{
2395 CONTRACTL
2396 {
2397 NOTHROW;
2398 GC_NOTRIGGER;
2399 MODE_ANY;
2400 }
2401 CONTRACTL_END;
2402
2403 SimpleComCallWrapper* pSimpleWrap = GetSimpleWrapper();
2404 _ASSERTE(pSimpleWrap);
2405
2406 return pSimpleWrap->IsHandleWeak();
2407}
2408
2409inline BOOL ComCallWrapper::IsWrapperActive()
2410{
2411 CONTRACTL
2412 {
2413 NOTHROW;
2414 GC_NOTRIGGER;
2415 MODE_COOPERATIVE;
2416 }
2417 CONTRACTL_END;
2418
2419 // Since its called by GCPromote, we assume that this is the start wrapper
2420
2421 LONGLONG llRefCount = m_pSimpleWrapper->GetRealRefCount();
2422 ULONG cbRef = GET_COM_REF(llRefCount);
2423 ULONG cbJupiterRef = GET_JUPITER_REF(llRefCount);
2424
2425 // We only consider jupiter ref count to be a "strong" ref count if it is pegged and it is alive
2426 // Note that there is no concern for resurrecting this CCW in the next Gen0/1 GC
2427 // because this CCW will be promoted to Gen 2 very quickly
2428 BOOL bHasJupiterStrongRefCount = (cbJupiterRef > 0 && IsConsideredPegged());
2429
2430 BOOL bHasStrongCOMRefCount = ((cbRef > 0) || bHasJupiterStrongRefCount);
2431
2432 BOOL bIsWrapperActive = (bHasStrongCOMRefCount && !IsHandleWeak());
2433
2434 LOG((LF_INTEROP, LL_INFO1000,
2435 "CCW 0x%p: cbRef = 0x%x, cbJupiterRef = 0x%x, IsPegged = %d, GlobalPegging = %d, IsHandleWeak = %d\n",
2436 this,
2437 cbRef, cbJupiterRef, IsPegged(), RCWWalker::IsGlobalPeggingOn(), IsHandleWeak()));
2438 LOG((LF_INTEROP, LL_INFO1000, "CCW 0x%p: IsWrapperActive returned %d\n", this, bIsWrapperActive));
2439
2440 return bIsWrapperActive;
2441}
2442
2443
2444#endif // FEATURE_COMINTEROP
2445
2446#endif // _COMCALLABLEWRAPPER_H
2447