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// File: MarshalNative.cpp
6//
7
8//
9// FCall's for the PInvoke classlibs
10//
11
12
13#include "common.h"
14#include "clsload.hpp"
15#include "method.hpp"
16#include "class.h"
17#include "object.h"
18#include "field.h"
19#include "util.hpp"
20#include "excep.h"
21#include "siginfo.hpp"
22#include "threads.h"
23#include "stublink.h"
24#include "dllimport.h"
25#include "jitinterface.h"
26#include "eeconfig.h"
27#include "log.h"
28#include "fieldmarshaler.h"
29#include "cgensys.h"
30#include "gcheaputilities.h"
31#include "dbginterface.h"
32#include "marshalnative.h"
33#include "fcall.h"
34#include "dllimportcallback.h"
35#include "comdelegate.h"
36#include "mdaassistants.h"
37#include "typestring.h"
38#include "appdomain.inl"
39
40#ifdef FEATURE_COMINTEROP
41#include "comcallablewrapper.h"
42#include "cominterfacemarshaler.h"
43#include "commtmemberinfomap.h"
44#include "runtimecallablewrapper.h"
45#include "olevariant.h"
46#include "interoputil.h"
47#include "stubhelpers.h"
48#endif // FEATURE_COMINTEROP
49
50#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
51#include "olecontexthelpers.h"
52#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
53
54//
55// NumParamBytes
56// Counts # of parameter bytes
57INT32 QCALLTYPE MarshalNative::NumParamBytes(MethodDesc * pMD)
58{
59 QCALL_CONTRACT;
60
61 // Arguments are check on managed side
62 PRECONDITION(pMD != NULL);
63
64 INT32 cbParamBytes = 0;
65
66 BEGIN_QCALL;
67
68 if (!(pMD->IsNDirect()))
69 COMPlusThrow(kArgumentException, IDS_EE_NOTNDIRECT);
70
71 // Read the unmanaged stack size from the stub MethodDesc. For vararg P/Invoke,
72 // this function returns size of the fixed portion of the stack.
73 // Note that the following code does not throw if the DllImport declaration is
74 // incorrect (such as a vararg method not marked as CallingConvention.Cdecl).
75
76 MethodDesc * pStubMD = NULL;
77
78 PCODE pTempStub = NULL;
79 pTempStub = GetStubForInteropMethod(pMD, NDIRECTSTUB_FL_FOR_NUMPARAMBYTES, &pStubMD);
80 _ASSERTE(pTempStub == NULL);
81
82 _ASSERTE(pStubMD != NULL && pStubMD->IsILStub());
83
84 cbParamBytes = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
85
86#ifdef _X86_
87 if (((NDirectMethodDesc *)pMD)->IsThisCall())
88 {
89 // The size of 'this' is not included in native stack arg size.
90 cbParamBytes += sizeof(LPVOID);
91 }
92#endif // _X86_
93
94 END_QCALL;
95
96 return cbParamBytes;
97}
98
99
100// Prelink
101// Does advance loading of an N/Direct library
102VOID QCALLTYPE MarshalNative::Prelink(MethodDesc * pMD)
103{
104 QCALL_CONTRACT;
105
106 // Arguments are check on managed side
107 PRECONDITION(pMD != NULL);
108
109 // If the code is already ready, we are done. Else, we need to execute the prestub
110 // This is a perf thing since it's always safe to execute the prestub twice.
111 if (!pMD->IsPointingToPrestub())
112 return;
113
114 // Silently ignore if not N/Direct and not runtime generated.
115 if (!(pMD->IsNDirect()) && !(pMD->IsRuntimeSupplied()))
116 return;
117
118 BEGIN_QCALL;
119
120 pMD->CheckRestore();
121 pMD->DoPrestub(NULL);
122
123 END_QCALL;
124}
125
126
127FCIMPL3(VOID, MarshalNative::StructureToPtr, Object* pObjUNSAFE, LPVOID ptr, CLR_BOOL fDeleteOld)
128{
129 CONTRACTL
130 {
131 FCALL_CHECK;
132 PRECONDITION(CheckPointer(ptr, NULL_OK));
133 }
134 CONTRACTL_END;
135
136 OBJECTREF pObj = (OBJECTREF) pObjUNSAFE;
137
138 HELPER_METHOD_FRAME_BEGIN_1(pObj);
139
140 if (ptr == NULL)
141 COMPlusThrowArgumentNull(W("ptr"));
142 if (pObj == NULL)
143 COMPlusThrowArgumentNull(W("structure"));
144
145 // Code path will accept both regular layout objects and boxed value classes
146 // with layout.
147
148 MethodTable *pMT = pObj->GetMethodTable();
149
150 if (pMT->HasInstantiation())
151 COMPlusThrowArgumentException(W("structure"), W("Argument_NeedNonGenericObject"));
152
153 if (pMT->IsBlittable())
154 {
155 memcpyNoGCRefs(ptr, pObj->GetData(), pMT->GetNativeSize());
156 }
157 else if (pMT->HasLayout())
158 {
159 if (fDeleteOld)
160 LayoutDestroyNative(ptr, pMT);
161
162 FmtClassUpdateNative( &(pObj), (LPBYTE)(ptr), NULL );
163 }
164 else
165 {
166 COMPlusThrowArgumentException(W("structure"), W("Argument_MustHaveLayoutOrBeBlittable"));
167 }
168
169 HELPER_METHOD_FRAME_END();
170}
171FCIMPLEND
172
173FCIMPL3(VOID, MarshalNative::PtrToStructureHelper, LPVOID ptr, Object* pObjIn, CLR_BOOL allowValueClasses)
174{
175 CONTRACTL
176 {
177 FCALL_CHECK;
178 PRECONDITION(CheckPointer(ptr, NULL_OK));
179 }
180 CONTRACTL_END;
181
182 OBJECTREF pObj = ObjectToOBJECTREF(pObjIn);
183
184 HELPER_METHOD_FRAME_BEGIN_1(pObj);
185
186 if (ptr == NULL)
187 COMPlusThrowArgumentNull(W("ptr"));
188 if (pObj == NULL)
189 COMPlusThrowArgumentNull(W("structure"));
190
191 // Code path will accept regular layout objects.
192 MethodTable *pMT = pObj->GetMethodTable();
193
194 // Validate that the object passed in is not a value class.
195 if (!allowValueClasses && pMT->IsValueType())
196 {
197 COMPlusThrowArgumentException(W("structure"), W("Argument_StructMustNotBeValueClass"));
198 }
199 else if (pMT->IsBlittable())
200 {
201 memcpyNoGCRefs(pObj->GetData(), ptr, pMT->GetNativeSize());
202 }
203 else if (pMT->HasLayout())
204 {
205 LayoutUpdateCLR((LPVOID*) &(pObj), Object::GetOffsetOfFirstField(), pMT, (LPBYTE)(ptr));
206 }
207 else
208 {
209 COMPlusThrowArgumentException(W("structure"), W("Argument_MustHaveLayoutOrBeBlittable"));
210 }
211
212 HELPER_METHOD_FRAME_END();
213}
214FCIMPLEND
215
216
217FCIMPL2(VOID, MarshalNative::DestroyStructure, LPVOID ptr, ReflectClassBaseObject* refClassUNSAFE)
218{
219 CONTRACTL
220 {
221 FCALL_CHECK;
222 PRECONDITION(CheckPointer(ptr, NULL_OK));
223 }
224 CONTRACTL_END;
225
226 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
227 HELPER_METHOD_FRAME_BEGIN_1(refClass);
228
229 if (ptr == NULL)
230 COMPlusThrowArgumentNull(W("ptr"));
231 if (refClass == NULL)
232 COMPlusThrowArgumentNull(W("structureType"));
233 if (refClass->GetMethodTable() != g_pRuntimeTypeClass)
234 COMPlusThrowArgumentException(W("structureType"), W("Argument_MustBeRuntimeType"));
235
236 TypeHandle th = refClass->GetType();
237
238 if (th.HasInstantiation())
239 COMPlusThrowArgumentException(W("structureType"), W("Argument_NeedNonGenericType"));
240
241 if (th.IsBlittable())
242 {
243 // ok to call with blittable structure, but no work to do in this case.
244 }
245 else if (th.HasLayout())
246 {
247 LayoutDestroyNative(ptr, th.GetMethodTable());
248 }
249 else
250 {
251 COMPlusThrowArgumentException(W("structureType"), W("Argument_MustHaveLayoutOrBeBlittable"));
252 }
253
254 HELPER_METHOD_FRAME_END();
255}
256FCIMPLEND
257
258
259/************************************************************************
260 * PInvoke.SizeOf(Class)
261 */
262FCIMPL2(UINT32, MarshalNative::SizeOfClass, ReflectClassBaseObject* refClassUNSAFE, CLR_BOOL throwIfNotMarshalable)
263{
264 CONTRACTL
265 {
266 FCALL_CHECK;
267 PRECONDITION(CheckPointer(refClassUNSAFE));
268 }
269 CONTRACTL_END;
270
271 UINT32 rv = 0;
272 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF)refClassUNSAFE;
273
274 HELPER_METHOD_FRAME_BEGIN_RET_1(refClass);
275
276 // refClass is validated to be non-NULL RuntimeType by callers
277 TypeHandle th = refClass->GetType();
278
279 if (throwIfNotMarshalable)
280 {
281 // Determine if the type is marshalable
282 if (!IsStructMarshalable(th))
283 {
284 // It isn't marshalable so throw an ArgumentException.
285 StackSString strTypeName;
286 TypeString::AppendType(strTypeName, th);
287 COMPlusThrow(kArgumentException, IDS_CANNOT_MARSHAL, strTypeName.GetUnicode(), NULL, NULL);
288 }
289 }
290
291 // The type is marshalable or we don't care so return its size.
292 rv = th.GetMethodTable()->GetNativeSize();
293 HELPER_METHOD_FRAME_END();
294 return rv;
295}
296FCIMPLEND
297
298
299/************************************************************************
300 * PInvoke.UnsafeAddrOfPinnedArrayElement(Array arr, int index)
301 */
302
303FCIMPL2(LPVOID, MarshalNative::FCUnsafeAddrOfPinnedArrayElement, ArrayBase *arr, INT32 index)
304{
305 FCALL_CONTRACT;
306
307 if (!arr)
308 FCThrowArgumentNull(W("arr"));
309
310 return (arr->GetDataPtr() + (index*arr->GetComponentSize()));
311}
312FCIMPLEND
313
314
315/************************************************************************
316 * PInvoke.OffsetOfHelper(Class, Field)
317 */
318FCIMPL1(UINT32, MarshalNative::OffsetOfHelper, ReflectFieldObject *pFieldUNSAFE)
319{
320 CONTRACTL
321 {
322 FCALL_CHECK;
323 PRECONDITION(CheckPointer(pFieldUNSAFE));
324 }
325 CONTRACTL_END;
326
327 REFLECTFIELDREF refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
328
329 FieldDesc *pField = refField->GetField();
330 TypeHandle th = TypeHandle(pField->GetApproxEnclosingMethodTable());
331
332 // Determine if the type is marshalable.
333 if (!IsStructMarshalable(th))
334 {
335 // It isn't marshalable so throw an ArgumentException.
336 HELPER_METHOD_FRAME_BEGIN_RET_1(refField);
337
338 StackSString strTypeName;
339 TypeString::AppendType(strTypeName, th);
340 COMPlusThrow(kArgumentException, IDS_CANNOT_MARSHAL, strTypeName.GetUnicode(), NULL, NULL);
341
342 HELPER_METHOD_FRAME_END();
343 }
344
345 FieldMarshaler *pFM = th.GetMethodTable()->GetLayoutInfo()->GetFieldMarshalers();
346 UINT numReferenceFields = th.GetMethodTable()->GetLayoutInfo()->GetNumCTMFields();
347
348 while (numReferenceFields--)
349 {
350 if (pFM->GetFieldDesc() == pField)
351 {
352 return pFM->GetExternalOffset();
353 }
354 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
355 }
356
357 UNREACHABLE_MSG("We should never hit this point since we already verified that the requested field was present from managed code");
358}
359FCIMPLEND
360
361FCIMPL2(Object*, MarshalNative::GetDelegateForFunctionPointerInternal, LPVOID FPtr, ReflectClassBaseObject* refTypeUNSAFE)
362{
363 CONTRACTL
364 {
365 FCALL_CHECK;
366 PRECONDITION(refTypeUNSAFE != NULL);
367 }
368 CONTRACTL_END;
369
370 OBJECTREF refDelegate = NULL;
371
372 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF) refTypeUNSAFE;
373 HELPER_METHOD_FRAME_BEGIN_RET_2(refType, refDelegate);
374
375 // Retrieve the method table from the RuntimeType. We already verified in managed
376 // code that the type was a RuntimeType that represented a delegate. Because type handles
377 // for delegates must have a method table, we are safe in telling prefix to assume it below.
378 MethodTable* pMT = refType->GetType().GetMethodTable();
379 PREFIX_ASSUME(pMT != NULL);
380 refDelegate = COMDelegate::ConvertToDelegate(FPtr, pMT);
381
382 HELPER_METHOD_FRAME_END();
383
384 return OBJECTREFToObject(refDelegate);
385}
386FCIMPLEND
387
388FCIMPL1(LPVOID, MarshalNative::GetFunctionPointerForDelegateInternal, Object* refDelegateUNSAFE)
389{
390 FCALL_CONTRACT;
391
392 LPVOID pFPtr = NULL;
393
394 OBJECTREF refDelegate = (OBJECTREF) refDelegateUNSAFE;
395 HELPER_METHOD_FRAME_BEGIN_RET_1(refDelegate);
396
397 pFPtr = COMDelegate::ConvertToCallback(refDelegate);
398
399 HELPER_METHOD_FRAME_END();
400
401 return pFPtr;
402}
403FCIMPLEND
404
405//====================================================================
406// map a fiber cookie from the hosting APIs into a managed Thread object
407//====================================================================
408FCIMPL1(THREADBASEREF, MarshalNative::GetThreadFromFiberCookie, int cookie)
409{
410 FCALL_CONTRACT;
411
412 _ASSERTE(cookie);
413
414 THREADBASEREF ret = 0;
415
416 // Set up a frame
417 HELPER_METHOD_FRAME_BEGIN_RET_0();
418
419 // Any host who is sophisticated enough to correctly schedule fibers
420 // had better be sophisticated enough to give us a real fiber cookie.
421 Thread *pThread = *((Thread **) &cookie);
422
423 // Minimal check that it smells like a thread:
424 _ASSERTE(pThread->m_fPreemptiveGCDisabled.Load() == 0 || pThread->m_fPreemptiveGCDisabled.Load() == 1);
425
426 ret = (THREADBASEREF)(pThread->GetExposedObject());
427 HELPER_METHOD_FRAME_END();
428
429 return ret;
430}
431FCIMPLEND
432
433FCIMPL3(LPVOID, MarshalNative::GetUnmanagedThunkForManagedMethodPtr, LPVOID pfnMethodToWrap, PCCOR_SIGNATURE pbSignature, ULONG cbSignature)
434{
435 CONTRACTL
436 {
437 FCALL_CHECK;
438 INJECT_FAULT(FCThrow(kOutOfMemoryException););
439 PRECONDITION(CheckPointer(pfnMethodToWrap, NULL_OK));
440 PRECONDITION(CheckPointer(pbSignature, NULL_OK));
441 }
442 CONTRACTL_END;
443
444 LPVOID pThunk = NULL;
445 return pThunk;
446}
447FCIMPLEND
448
449
450/************************************************************************
451 * PInvoke.GetManagedThunkForUnmanagedMethodPtr()
452 */
453FCIMPL3(LPVOID, MarshalNative::GetManagedThunkForUnmanagedMethodPtr, LPVOID pfnMethodToWrap, PCCOR_SIGNATURE pbSignature, ULONG cbSignature)
454{
455 CONTRACTL
456 {
457 FCALL_CHECK;
458 PRECONDITION(CheckPointer(pfnMethodToWrap, NULL_OK));
459 PRECONDITION(CheckPointer(pbSignature, NULL_OK));
460 }
461 CONTRACTL_END;
462
463 LPVOID pThunk = NULL;
464 return pThunk;
465}
466FCIMPLEND
467
468
469FCIMPL0(UINT32, MarshalNative::GetSystemMaxDBCSCharSize)
470{
471 FCALL_CONTRACT;
472
473 return GetMaxDBCSCharByteSize();
474}
475FCIMPLEND
476
477
478/************************************************************************
479 * Handles all PInvoke.Copy(array source, ....) methods.
480 */
481FCIMPL4(void, MarshalNative::CopyToNative, Object* psrcUNSAFE, INT32 startindex, LPVOID pdst, INT32 length)
482{
483 CONTRACTL
484 {
485 FCALL_CHECK;
486 PRECONDITION(CheckPointer(pdst, NULL_OK));
487 }
488 CONTRACTL_END;
489
490 // The BCL code guarantees that Array will be passed in
491 _ASSERTE(!psrcUNSAFE || psrcUNSAFE->GetMethodTable()->IsArray());
492
493 BASEARRAYREF psrc = (BASEARRAYREF)(OBJECTREF)psrcUNSAFE;
494
495 HELPER_METHOD_FRAME_BEGIN_1(psrc);
496
497 if (pdst == NULL)
498 COMPlusThrowArgumentNull(W("destination"));
499 if (psrc == NULL)
500 COMPlusThrowArgumentNull(W("source"));
501
502 SIZE_T numelem = psrc->GetNumComponents();
503
504 if (startindex < 0 || length < 0 || (SIZE_T)startindex + (SIZE_T)length > numelem)
505 {
506 COMPlusThrow(kArgumentOutOfRangeException, IDS_EE_COPY_OUTOFRANGE);
507 }
508
509 SIZE_T componentsize = psrc->GetComponentSize();
510
511 memcpyNoGCRefs(pdst,
512 componentsize*startindex + (BYTE*)(psrc->GetDataPtr()),
513 componentsize*length);
514
515 HELPER_METHOD_FRAME_END();
516}
517FCIMPLEND
518
519FCIMPL4(void, MarshalNative::CopyToManaged, LPVOID psrc, Object* pdstUNSAFE, INT32 startindex, INT32 length)
520{
521 CONTRACTL
522 {
523 FCALL_CHECK;
524 PRECONDITION(CheckPointer(psrc, NULL_OK));
525 }
526 CONTRACTL_END;
527
528 // The BCL code guarantees that Array will be passed in
529 _ASSERTE(!pdstUNSAFE || pdstUNSAFE->GetMethodTable()->IsArray());
530
531 BASEARRAYREF pdst = (BASEARRAYREF)(OBJECTREF)pdstUNSAFE;
532
533 HELPER_METHOD_FRAME_BEGIN_1(pdst);
534
535 if (pdst == NULL)
536 COMPlusThrowArgumentNull(W("destination"));
537 if (psrc == NULL)
538 COMPlusThrowArgumentNull(W("source"));
539 if (startindex < 0)
540 COMPlusThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Count"));
541 if (length < 0)
542 COMPlusThrowArgumentOutOfRange(W("length"), W("ArgumentOutOfRange_NeedNonNegNum"));
543
544 SIZE_T numelem = pdst->GetNumComponents();
545
546 if ((SIZE_T)startindex + (SIZE_T)length > numelem)
547 {
548 COMPlusThrow(kArgumentOutOfRangeException, IDS_EE_COPY_OUTOFRANGE);
549 }
550
551 SIZE_T componentsize = pdst->GetComponentSize();
552
553 _ASSERTE(CorTypeInfo::IsPrimitiveType(pdst->GetArrayElementTypeHandle().GetInternalCorElementType()));
554 memcpyNoGCRefs(componentsize*startindex + (BYTE*)(pdst->GetDataPtr()),
555 psrc,
556 componentsize*length);
557
558 HELPER_METHOD_FRAME_END();
559}
560FCIMPLEND
561
562
563/************************************************************************
564 * PInvoke.GetLastWin32Error
565 */
566FCIMPL0(int, MarshalNative::GetLastWin32Error)
567{
568 FCALL_CONTRACT;
569
570 return (UINT32)(GetThread()->m_dwLastError);
571}
572FCIMPLEND
573
574
575/************************************************************************
576 * PInvoke.SetLastWin32Error
577 */
578FCIMPL1(void, MarshalNative::SetLastWin32Error, int error)
579{
580 FCALL_CONTRACT;
581
582 GetThread()->m_dwLastError = (DWORD)error;
583}
584FCIMPLEND
585
586
587/************************************************************************
588 * Support for the GCHandle class.
589 */
590
591 // Check that the supplied object is valid to put in a pinned handle.
592// Throw an exception if not.
593void ValidatePinnedObject(OBJECTREF obj)
594{
595 CONTRACTL
596 {
597 THROWS;
598 GC_TRIGGERS;
599 MODE_COOPERATIVE;
600 }
601 CONTRACTL_END;
602
603 // NULL is fine.
604 if (obj == NULL)
605 return;
606
607 if (obj->GetMethodTable() == g_pStringClass)
608 return;
609
610 if (obj->GetMethodTable()->IsArray())
611 {
612 BASEARRAYREF asArray = (BASEARRAYREF) obj;
613 if (CorTypeInfo::IsPrimitiveType(asArray->GetArrayElementType()))
614 return;
615
616 TypeHandle th = asArray->GetArrayElementTypeHandle();
617 if (!th.IsTypeDesc())
618 {
619 MethodTable *pMT = th.AsMethodTable();
620 if (pMT->IsValueType() && pMT->IsBlittable())
621 return;
622 }
623 }
624 else if (obj->GetMethodTable()->IsBlittable())
625 {
626 return;
627 }
628
629 COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC);
630}
631
632FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type)
633{
634 FCALL_CONTRACT;
635
636 OBJECTREF objRef(obj);
637 OBJECTHANDLE hnd = 0;
638
639 HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL();
640
641 // If it is a pinned handle, check the object type.
642 if (type == HNDTYPE_PINNED)
643 ValidatePinnedObject(objRef);
644
645 assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT);
646 // Create the handle.
647 hnd = GetAppDomain()->CreateTypedHandle(objRef, static_cast<HandleType>(type));
648
649 HELPER_METHOD_FRAME_END_POLL();
650 return (LPVOID) hnd;
651}
652FCIMPLEND
653
654// Free a GC handle.
655FCIMPL1(VOID, MarshalNative::GCHandleInternalFree, OBJECTHANDLE handle)
656{
657 FCALL_CONTRACT;
658
659 HELPER_METHOD_FRAME_BEGIN_0();
660
661#ifdef MDA_SUPPORTED
662 UINT handleType = HandleFetchType(handle);
663#endif
664
665 DestroyTypedHandle(handle);
666
667#ifdef MDA_SUPPORTED
668 if (handleType == HNDTYPE_PINNED)
669 {
670 MDA_TRIGGER_ASSISTANT(GcManagedToUnmanaged, TriggerGC());
671 }
672#endif
673
674 HELPER_METHOD_FRAME_END();
675}
676FCIMPLEND
677
678// Get the object referenced by a GC handle.
679FCIMPL1(LPVOID, MarshalNative::GCHandleInternalGet, OBJECTHANDLE handle)
680{
681 FCALL_CONTRACT;
682
683 OBJECTREF objRef;
684
685 objRef = ObjectFromHandle(handle);
686
687 return *((LPVOID*)&objRef);
688}
689FCIMPLEND
690
691// Update the object referenced by a GC handle.
692FCIMPL3(VOID, MarshalNative::GCHandleInternalSet, OBJECTHANDLE handle, Object *obj, CLR_BOOL isPinned)
693{
694 FCALL_CONTRACT;
695
696 OBJECTREF objRef(obj);
697 HELPER_METHOD_FRAME_BEGIN_1(objRef);
698
699 //<TODO>@todo: If the handle is pinned check the object type.</TODO>
700 if (isPinned)
701 {
702 ValidatePinnedObject(objRef);
703 }
704
705 // Update the stored object reference.
706 StoreObjectInHandle(handle, objRef);
707 HELPER_METHOD_FRAME_END();
708}
709FCIMPLEND
710
711// Update the object referenced by a GC handle.
712FCIMPL4(Object*, MarshalNative::GCHandleInternalCompareExchange, OBJECTHANDLE handle, Object *obj, Object* oldObj, CLR_BOOL isPinned)
713{
714 FCALL_CONTRACT;
715
716 OBJECTREF newObjref(obj);
717 OBJECTREF oldObjref(oldObj);
718 LPVOID ret = NULL;
719 HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL();
720
721 //<TODO>@todo: If the handle is pinned check the object type.</TODO>
722 if (isPinned)
723 ValidatePinnedObject(newObjref);
724
725 // Update the stored object reference.
726 ret = InterlockedCompareExchangeObjectInHandle(handle, newObjref, oldObjref);
727 HELPER_METHOD_FRAME_END_POLL();
728 return (Object*)ret;
729}
730FCIMPLEND
731
732// Get the address of a pinned object referenced by the supplied pinned
733// handle. This routine assumes the handle is pinned and does not check.
734FCIMPL1(LPVOID, MarshalNative::GCHandleInternalAddrOfPinnedObject, OBJECTHANDLE handle)
735{
736 FCALL_CONTRACT;
737
738 LPVOID p;
739 OBJECTREF objRef = ObjectFromHandle(handle);
740
741 if (objRef == NULL)
742 {
743 p = NULL;
744 }
745 else
746 {
747 // Get the interior pointer for the supported pinned types.
748 if (objRef->GetMethodTable() == g_pStringClass)
749 p = ((*(StringObject **)&objRef))->GetBuffer();
750 else if (objRef->GetMethodTable()->IsArray())
751 p = (*((ArrayBase**)&objRef))->GetDataPtr();
752 else
753 p = objRef->GetData();
754 }
755
756 return p;
757}
758FCIMPLEND
759
760// Make sure the handle is accessible from the current domain. (Throw if not.)
761FCIMPL1(INT32, MarshalNative::GCHandleInternalGetHandleType, OBJECTHANDLE handle)
762{
763 FCALL_CONTRACT;
764
765 return GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle);
766}
767FCIMPLEND
768
769FCIMPL1(INT32, MarshalNative::CalculateCount, ArrayWithOffsetData* pArrayWithOffset)
770{
771 FCALL_CONTRACT;
772
773 INT32 uRetVal = 0;
774 BASEARRAYREF arrayObj = pArrayWithOffset->m_Array;
775 HELPER_METHOD_FRAME_BEGIN_RET_1(arrayObj);
776
777 SIZE_T cbTotalSize = 0;
778
779 if (arrayObj != NULL)
780 {
781 if (!(arrayObj->GetMethodTable()->IsArray()))
782 COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC);
783 if (arrayObj->GetMethodTable()->IsMultiDimArray())
784 COMPlusThrow(kArgumentException, IDS_EE_NOTISOMORPHIC);
785
786 ValidatePinnedObject(arrayObj);
787 }
788
789 if (arrayObj == NULL)
790 {
791 if (pArrayWithOffset->m_cbOffset != 0)
792 COMPlusThrow(kIndexOutOfRangeException, IDS_EE_ARRAYWITHOFFSETOVERFLOW);
793
794 goto lExit;
795 }
796
797 cbTotalSize = arrayObj->GetNumComponents() * arrayObj->GetComponentSize();
798
799 if (cbTotalSize > MAX_SIZE_FOR_INTEROP)
800 COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
801
802 if (pArrayWithOffset->m_cbOffset > (INT32)cbTotalSize)
803 COMPlusThrow(kIndexOutOfRangeException, IDS_EE_ARRAYWITHOFFSETOVERFLOW);
804
805 uRetVal = (INT32)cbTotalSize - pArrayWithOffset->m_cbOffset;
806 _ASSERTE(uRetVal >= 0);
807
808lExit: ;
809 HELPER_METHOD_FRAME_END();
810 return uRetVal;
811}
812FCIMPLEND
813
814
815//====================================================================
816// *** Interop Helpers ***
817//====================================================================
818
819FCIMPL2(Object *, MarshalNative::GetExceptionForHR, INT32 errorCode, LPVOID errorInfo)
820{
821 CONTRACTL
822 {
823 FCALL_CHECK;
824 PRECONDITION(FAILED(errorCode));
825 PRECONDITION(CheckPointer(errorInfo, NULL_OK));
826 }
827 CONTRACTL_END;
828
829 OBJECTREF RetExceptionObj = NULL;
830
831 HELPER_METHOD_FRAME_BEGIN_RET_1(RetExceptionObj);
832
833 // Retrieve the IErrorInfo to use.
834 IErrorInfo *pErrorInfo = (IErrorInfo*)errorInfo;
835 if (pErrorInfo == (IErrorInfo*)(-1))
836 {
837 pErrorInfo = NULL;
838 }
839 else if (!pErrorInfo)
840 {
841 if (SafeGetErrorInfo(&pErrorInfo) != S_OK)
842 pErrorInfo = NULL;
843 }
844
845 ::GetExceptionForHR(errorCode, pErrorInfo, &RetExceptionObj);
846
847 HELPER_METHOD_FRAME_END();
848
849 return OBJECTREFToObject(RetExceptionObj);
850}
851FCIMPLEND
852
853FCIMPL2(void, MarshalNative::ThrowExceptionForHR, INT32 errorCode, LPVOID errorInfo)
854{
855 CONTRACTL
856 {
857 FCALL_CHECK;
858 PRECONDITION(FAILED(errorCode));
859 PRECONDITION(CheckPointer(errorInfo, NULL_OK));
860 }
861 CONTRACTL_END;
862
863
864 HELPER_METHOD_FRAME_BEGIN_0();
865
866 // Retrieve the IErrorInfo to use.
867 IErrorInfo *pErrorInfo = (IErrorInfo*)errorInfo;
868 if (pErrorInfo == (IErrorInfo*)(-1))
869 {
870 pErrorInfo = NULL;
871 }
872 else if (!pErrorInfo)
873 {
874 if (SafeGetErrorInfo(&pErrorInfo) != S_OK)
875 pErrorInfo = NULL;
876 }
877
878 // Throw the exception based on the HR and the IErrorInfo.
879 COMPlusThrowHR(errorCode, pErrorInfo);
880
881 HELPER_METHOD_FRAME_END();
882}
883FCIMPLEND
884
885
886FCIMPL1(int, MarshalNative::GetHRForException, Object* eUNSAFE)
887{
888 CONTRACTL {
889 NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM
890 DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS
891 MODE_COOPERATIVE;
892 SO_TOLERANT;
893 } CONTRACTL_END;
894
895 int retVal = 0;
896 OBJECTREF e = (OBJECTREF) eUNSAFE;
897 HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1({ retVal = COR_E_STACKOVERFLOW; }, e);
898
899 retVal = SetupErrorInfo(e);
900
901 HELPER_METHOD_FRAME_END_NOTHROW();
902 return retVal;
903}
904FCIMPLEND
905
906FCIMPL1(int, MarshalNative::GetHRForException_WinRT, Object* eUNSAFE)
907{
908 CONTRACTL {
909 NOTHROW; // Used by reverse COM IL stubs, so we must not throw exceptions back to COM
910 DISABLED(GC_TRIGGERS); // FCALLS with HELPER frames have issues with GC_TRIGGERS
911 MODE_COOPERATIVE;
912 SO_TOLERANT;
913 } CONTRACTL_END;
914
915 int retVal = 0;
916 OBJECTREF e = (OBJECTREF) eUNSAFE;
917 HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1({ retVal = COR_E_STACKOVERFLOW; }, e);
918
919 retVal = SetupErrorInfo(e, /* isWinRTScenario = */ TRUE);
920
921 HELPER_METHOD_FRAME_END_NOTHROW();
922 return retVal;
923}
924FCIMPLEND
925
926#ifdef FEATURE_COMINTEROP
927
928//====================================================================
929// map GUID to Type
930//====================================================================
931
932/*OBJECTREF */
933FCIMPL1(Object*, MarshalNative::GetLoadedTypeForGUID, GUID* pGuid)
934{
935 CONTRACTL
936 {
937 FCALL_CHECK;
938 PRECONDITION(CheckPointer(pGuid, NULL_OK));
939 }
940 CONTRACTL_END;
941
942 OBJECTREF refRetVal = NULL;
943 HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
944
945 if (!pGuid)
946 COMPlusThrowArgumentNull(W("pGuid"));
947
948 AppDomain* pDomain = SystemDomain::GetCurrentDomain();
949 _ASSERTE(pDomain);
950
951 MethodTable* pMT = pDomain->LookupClass(*(pGuid));
952 if (pMT)
953 refRetVal = pMT->GetManagedClassObject();
954
955 HELPER_METHOD_FRAME_END();
956 return OBJECTREFToObject(refRetVal);
957}
958FCIMPLEND
959
960//====================================================================
961// map Type to ITypeInfo*
962//====================================================================
963FCIMPL1(ITypeInfo*, MarshalNative::GetITypeInfoForType, ReflectClassBaseObject* refClassUNSAFE)
964{
965 FCALL_CONTRACT;
966
967 ITypeInfo* pTI = NULL;
968 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
969 HELPER_METHOD_FRAME_BEGIN_RET_1(refClass);
970
971 // Check for null arguments.
972 if(!refClass)
973 COMPlusThrowArgumentNull(W("t"));
974
975 MethodTable *pRefMT = refClass->GetMethodTable();
976 if (pRefMT != g_pRuntimeTypeClass)
977 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
978
979 TypeHandle th = refClass->GetType();
980
981 if (th.GetMethodTable() != NULL && (th.IsProjectedFromWinRT() || th.IsExportedToWinRT()))
982 COMPlusThrowArgumentException(W("t"), W("Argument_ObjIsWinRTObject"));
983
984 if (th.HasInstantiation())
985 COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType"));
986
987 // Make sure the type is visible from COM.
988 if (!::IsTypeVisibleFromCom(th))
989 COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom"));
990
991 // Retrieve the EE class from the reflection type.
992 MethodTable* pMT = th.GetMethodTable();
993 _ASSERTE(pMT);
994
995 // Retrieve the ITypeInfo for the class.
996 IfFailThrow(GetITypeInfoForEEClass(pMT, &pTI, true /* bClassInfo */));
997 _ASSERTE(pTI != NULL);
998
999 HELPER_METHOD_FRAME_END();
1000 return pTI;
1001}
1002FCIMPLEND
1003
1004//====================================================================
1005// return the IUnknown* for an Object.
1006//====================================================================
1007FCIMPL2(IUnknown*, MarshalNative::GetIUnknownForObjectNative, Object* orefUNSAFE, CLR_BOOL fOnlyInContext)
1008{
1009 FCALL_CONTRACT;
1010
1011 IUnknown* retVal = NULL;
1012 OBJECTREF oref = (OBJECTREF) orefUNSAFE;
1013 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1014
1015 HRESULT hr = S_OK;
1016
1017 if(!oref)
1018 COMPlusThrowArgumentNull(W("o"));
1019
1020 // Ensure COM is started up.
1021 EnsureComStarted();
1022
1023 if (fOnlyInContext && !IsObjectInContext(&oref))
1024 retVal = NULL;
1025 else
1026 retVal = GetComIPFromObjectRef(&oref, ComIpType_OuterUnknown, NULL);
1027
1028 HELPER_METHOD_FRAME_END();
1029 return retVal;
1030}
1031FCIMPLEND
1032
1033//====================================================================
1034// return the raw IUnknown* for a COM Object not related to current
1035// context.
1036// Does not AddRef the returned pointer
1037//====================================================================
1038FCIMPL1(IUnknown*, MarshalNative::GetRawIUnknownForComObjectNoAddRef, Object* orefUNSAFE)
1039{
1040 FCALL_CONTRACT;
1041
1042 IUnknown* retVal = NULL;
1043 OBJECTREF oref = (OBJECTREF) orefUNSAFE;
1044 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1045
1046 HRESULT hr = S_OK;
1047
1048 if(!oref)
1049 COMPlusThrowArgumentNull(W("o"));
1050
1051 MethodTable* pMT = oref->GetMethodTable();
1052 PREFIX_ASSUME(pMT != NULL);
1053 if(!pMT->IsComObjectType())
1054 COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT);
1055
1056 // Ensure COM is started up.
1057 EnsureComStarted();
1058
1059 RCWHolder pRCW(GetThread());
1060 pRCW.Init(oref);
1061
1062 // Retrieve raw IUnknown * without AddRef for better performance
1063 retVal = pRCW->GetRawIUnknown_NoAddRef();
1064
1065 HELPER_METHOD_FRAME_END();
1066 return retVal;
1067}
1068FCIMPLEND
1069
1070//====================================================================
1071// return the IDispatch* for an Object.
1072//====================================================================
1073FCIMPL2(IDispatch*, MarshalNative::GetIDispatchForObjectNative, Object* orefUNSAFE, CLR_BOOL fOnlyInContext)
1074{
1075 FCALL_CONTRACT;
1076
1077 IDispatch* retVal = NULL;
1078 OBJECTREF oref = (OBJECTREF) orefUNSAFE;
1079 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1080
1081 HRESULT hr = S_OK;
1082
1083 if(!oref)
1084 COMPlusThrowArgumentNull(W("o"));
1085
1086 // Ensure COM is started up.
1087 EnsureComStarted();
1088
1089 if (fOnlyInContext && !IsObjectInContext(&oref))
1090 retVal = NULL;
1091 else
1092 retVal = (IDispatch*)GetComIPFromObjectRef(&oref, ComIpType_Dispatch, NULL);
1093
1094 HELPER_METHOD_FRAME_END();
1095 return retVal;
1096}
1097FCIMPLEND
1098
1099//====================================================================
1100// return the IUnknown* representing the interface for the Object
1101// Object o should support Type T
1102//====================================================================
1103FCIMPL4(IUnknown*, MarshalNative::GetComInterfaceForObjectNative, Object* orefUNSAFE, ReflectClassBaseObject* refClassUNSAFE, CLR_BOOL fOnlyInContext, CLR_BOOL bEnableCustomizedQueryInterface)
1104{
1105 FCALL_CONTRACT;
1106
1107 IUnknown* retVal = NULL;
1108 OBJECTREF oref = (OBJECTREF) orefUNSAFE;
1109 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
1110 HELPER_METHOD_FRAME_BEGIN_RET_2(oref, refClass);
1111
1112 HRESULT hr = S_OK;
1113
1114 if(!oref)
1115 COMPlusThrowArgumentNull(W("o"));
1116 if(!refClass)
1117 COMPlusThrowArgumentNull(W("t"));
1118
1119 // Ensure COM is started up.
1120 EnsureComStarted();
1121
1122 if (refClass->GetMethodTable() != g_pRuntimeTypeClass)
1123 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1124
1125 TypeHandle th = refClass->GetType();
1126
1127 if (!th.SupportsGenericInterop(TypeHandle::Interop_NativeToManaged))
1128 {
1129 if (th.HasInstantiation())
1130 COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType"));
1131
1132 if (oref->GetMethodTable()->HasInstantiation())
1133 COMPlusThrowArgumentException(W("o"), W("Argument_NeedNonGenericObject"));
1134 }
1135
1136 // If the IID being asked for does not represent an interface then
1137 // throw an argument exception.
1138 if (!th.IsInterface())
1139 COMPlusThrowArgumentException(W("t"), W("Arg_MustBeInterface"));
1140
1141 // If the interface being asked for is not visible from COM then
1142 // throw an argument exception.
1143 if (!::IsTypeVisibleFromCom(th))
1144 COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom"));
1145
1146 if (fOnlyInContext && !IsObjectInContext(&oref))
1147 retVal = NULL;
1148 else
1149 retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), TRUE, bEnableCustomizedQueryInterface);
1150
1151 HELPER_METHOD_FRAME_END();
1152 return retVal;
1153}
1154FCIMPLEND
1155
1156//====================================================================
1157// return an Object for IUnknown
1158//====================================================================
1159FCIMPL1(Object*, MarshalNative::GetObjectForIUnknown, IUnknown* pUnk)
1160{
1161 CONTRACTL
1162 {
1163 FCALL_CHECK;
1164 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1165 }
1166 CONTRACTL_END;
1167
1168 OBJECTREF oref = NULL;
1169 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1170
1171 HRESULT hr = S_OK;
1172
1173 if(!pUnk)
1174 COMPlusThrowArgumentNull(W("pUnk"));
1175
1176 // Ensure COM is started up.
1177 EnsureComStarted();
1178
1179 GetObjectRefFromComIP(&oref, pUnk);
1180
1181 HELPER_METHOD_FRAME_END();
1182 return OBJECTREFToObject(oref);
1183}
1184FCIMPLEND
1185
1186
1187FCIMPL1(Object*, MarshalNative::GetUniqueObjectForIUnknown, IUnknown* pUnk)
1188{
1189 CONTRACTL
1190 {
1191 FCALL_CHECK;
1192 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1193 }
1194 CONTRACTL_END;
1195
1196 OBJECTREF oref = NULL;
1197 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1198
1199 HRESULT hr = S_OK;
1200
1201 if(!pUnk)
1202 COMPlusThrowArgumentNull(W("pUnk"));
1203
1204 // Ensure COM is started up.
1205 EnsureComStarted();
1206
1207 GetObjectRefFromComIP(&oref, pUnk, NULL, NULL, ObjFromComIP::UNIQUE_OBJECT);
1208
1209 HELPER_METHOD_FRAME_END();
1210 return OBJECTREFToObject(oref);
1211}
1212FCIMPLEND
1213
1214//====================================================================
1215// return an Object for IUnknown, using the Type T,
1216// NOTE:
1217// Type T should be either a COM imported Type or a sub-type of COM imported Type
1218//====================================================================
1219FCIMPL2(Object*, MarshalNative::GetTypedObjectForIUnknown, IUnknown* pUnk, ReflectClassBaseObject* refClassUNSAFE)
1220{
1221 CONTRACTL
1222 {
1223 FCALL_CHECK;
1224 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1225 }
1226 CONTRACTL_END;
1227
1228 OBJECTREF oref = NULL;
1229 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
1230 HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, oref);
1231
1232 HRESULT hr = S_OK;
1233
1234 MethodTable* pMTClass = NULL;
1235
1236 if(!pUnk)
1237 COMPlusThrowArgumentNull(W("pUnk"));
1238
1239 if(refClass != NULL)
1240 {
1241 if (refClass->GetMethodTable() != g_pRuntimeTypeClass)
1242 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1243
1244 TypeHandle th = refClass->GetType();
1245
1246 if (th.GetMethodTable() != NULL && (th.IsProjectedFromWinRT() || th.IsExportedToWinRT()))
1247 COMPlusThrowArgumentException(W("t"), W("Argument_ObjIsWinRTObject"));
1248
1249 if (th.HasInstantiation())
1250 COMPlusThrowArgumentException(W("t"), W("Argument_NeedNonGenericType"));
1251
1252 pMTClass = th.GetMethodTable();
1253 }
1254 else
1255 COMPlusThrowArgumentNull(W("t"));
1256
1257
1258 // Ensure COM is started up.
1259 EnsureComStarted();
1260
1261 GetObjectRefFromComIP(&oref, pUnk, pMTClass);
1262
1263 HELPER_METHOD_FRAME_END();
1264 return OBJECTREFToObject(oref);
1265}
1266FCIMPLEND
1267
1268FCIMPL2(IUnknown*, MarshalNative::CreateAggregatedObject, IUnknown* pOuter, Object* refObjUNSAFE)
1269{
1270 CONTRACTL
1271 {
1272 FCALL_CHECK;
1273 PRECONDITION(CheckPointer(pOuter, NULL_OK));
1274 }
1275 CONTRACTL_END;
1276
1277 IUnknown* pInner = NULL;
1278
1279 OBJECTREF oref = (OBJECTREF)refObjUNSAFE;
1280 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
1281
1282 HRESULT hr = S_OK;
1283
1284 if (!pOuter)
1285 COMPlusThrowArgumentNull(W("pOuter"));
1286
1287 if (oref == NULL)
1288 COMPlusThrowArgumentNull(W("o"));
1289
1290 MethodTable *pMT = oref->GetMethodTable();
1291 if (pMT->IsWinRTObjectType() || pMT->IsExportedToWinRT())
1292 COMPlusThrowArgumentException(W("o"), W("Argument_ObjIsWinRTObject"));
1293
1294 // Ensure COM is started up.
1295 EnsureComStarted();
1296
1297 if (NULL != ComCallWrapper::GetWrapperForObject(oref))
1298 COMPlusThrowArgumentException(W("o"), W("Argument_AlreadyACCW"));
1299
1300 //get wrapper for the object, this could enable GC
1301 CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&oref);
1302
1303 // Aggregation support,
1304 pWrap->InitializeOuter(pOuter);
1305 IfFailThrow(pWrap->GetInnerUnknown((LPVOID*)&pInner));
1306
1307 HELPER_METHOD_FRAME_END();
1308 return pInner;
1309}
1310FCIMPLEND
1311
1312//====================================================================
1313// Free unused RCWs in the current COM+ context.
1314//====================================================================
1315FCIMPL0(void, MarshalNative::CleanupUnusedObjectsInCurrentContext)
1316{
1317 FCALL_CONTRACT;
1318
1319 HELPER_METHOD_FRAME_BEGIN_0();
1320
1321 if (g_pRCWCleanupList)
1322 {
1323 g_pRCWCleanupList->CleanupWrappersInCurrentCtxThread(
1324 TRUE, // fWait
1325 TRUE, // fManualCleanupRequested
1326 TRUE // bIgnoreComObjectEagerCleanupSetting
1327 );
1328 }
1329
1330 HELPER_METHOD_FRAME_END();
1331}
1332FCIMPLEND
1333
1334//====================================================================
1335// Checks whether there are RCWs from any context available for cleanup.
1336//====================================================================
1337FCIMPL0(FC_BOOL_RET, MarshalNative::AreComObjectsAvailableForCleanup)
1338{
1339 FCALL_CONTRACT;
1340
1341 BOOL retVal = FALSE;
1342 if (g_pRCWCleanupList)
1343 {
1344 retVal = !g_pRCWCleanupList->IsEmpty();
1345 }
1346
1347 FC_RETURN_BOOL(retVal);
1348}
1349FCIMPLEND
1350
1351//====================================================================
1352// check if the object is classic COM component
1353//====================================================================
1354FCIMPL1(FC_BOOL_RET, MarshalNative::IsComObject, Object* objUNSAFE)
1355{
1356 FCALL_CONTRACT;
1357
1358 BOOL retVal = FALSE;
1359 OBJECTREF obj = (OBJECTREF) objUNSAFE;
1360 HELPER_METHOD_FRAME_BEGIN_RET_1(obj);
1361
1362 if(!obj)
1363 COMPlusThrowArgumentNull(W("o"));
1364
1365 MethodTable* pMT = obj->GetMethodTable();
1366 PREFIX_ASSUME(pMT != NULL);
1367 retVal = pMT->IsComObjectType();
1368
1369 HELPER_METHOD_FRAME_END();
1370 FC_RETURN_BOOL(retVal);
1371}
1372FCIMPLEND
1373
1374
1375//====================================================================
1376// free the COM component and zombie this object if the ref count hits 0
1377// further usage of this Object might throw an exception,
1378//====================================================================
1379FCIMPL1(INT32, MarshalNative::ReleaseComObject, Object* objUNSAFE)
1380{
1381 FCALL_CONTRACT;
1382
1383 INT32 retVal = 0;
1384 OBJECTREF obj = (OBJECTREF) objUNSAFE;
1385 HELPER_METHOD_FRAME_BEGIN_RET_1(obj);
1386
1387 if(!obj)
1388 COMPlusThrowArgumentNull(W("o"));
1389
1390 MethodTable* pMT = obj->GetMethodTable();
1391 PREFIX_ASSUME(pMT != NULL);
1392 if(!pMT->IsComObjectType())
1393 COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT);
1394
1395 // remove the wrapper from the object
1396 retVal = RCW::ExternalRelease(&obj);
1397
1398 HELPER_METHOD_FRAME_END();
1399 return retVal;
1400}
1401FCIMPLEND
1402
1403//====================================================================
1404// free the COM component and zombie this object
1405// further usage of this Object might throw an exception,
1406//====================================================================
1407FCIMPL1(void, MarshalNative::FinalReleaseComObject, Object* objUNSAFE)
1408{
1409 FCALL_CONTRACT;
1410
1411 OBJECTREF obj = (OBJECTREF) objUNSAFE;
1412 HELPER_METHOD_FRAME_BEGIN_1(obj);
1413
1414 if(!obj)
1415 COMPlusThrowArgumentNull(W("o"));
1416
1417 MethodTable* pMT = obj->GetMethodTable();
1418 PREFIX_ASSUME(pMT != NULL);
1419 if(!pMT->IsComObjectType())
1420 COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT);
1421
1422 // remove the wrapper from the object
1423 RCW::FinalExternalRelease(&obj);
1424
1425 HELPER_METHOD_FRAME_END();
1426}
1427FCIMPLEND
1428
1429
1430//====================================================================
1431// This method takes the given COM object and wraps it in an object
1432// of the specified type. The type must be derived from __ComObject.
1433//====================================================================
1434FCIMPL2(Object*, MarshalNative::InternalCreateWrapperOfType, Object* objUNSAFE, ReflectClassBaseObject* refClassUNSAFE)
1435{
1436 CONTRACTL
1437 {
1438 FCALL_CHECK;
1439 PRECONDITION(objUNSAFE != NULL);
1440 PRECONDITION(refClassUNSAFE != NULL);
1441 }
1442 CONTRACTL_END;
1443
1444 struct _gc
1445 {
1446 OBJECTREF refRetVal;
1447 OBJECTREF obj;
1448 REFLECTCLASSBASEREF refClass;
1449 } gc;
1450
1451 gc.refRetVal = NULL;
1452 gc.obj = (OBJECTREF) objUNSAFE;
1453 gc.refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
1454
1455 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1456
1457 // Validate the arguments.
1458 if (gc.refClass->GetMethodTable() != g_pRuntimeTypeClass)
1459 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1460
1461 // Retrieve the class of the COM object.
1462 MethodTable *pObjMT = gc.obj->GetMethodTable();
1463
1464 // Retrieve the method table for new wrapper type.
1465 MethodTable *pNewWrapMT = gc.refClass->GetType().GetMethodTable();
1466
1467 // Validate that the destination type is a COM object.
1468 _ASSERTE(pNewWrapMT->IsComObjectType());
1469
1470 BOOL fSet = FALSE;
1471
1472 // Start by checking if we can cast the obj to the wrapper type.
1473 if (TypeHandle(pObjMT).CanCastTo(TypeHandle(pNewWrapMT)))
1474 {
1475 gc.refRetVal = gc.obj;
1476 fSet = TRUE;
1477 }
1478
1479 if (!fSet)
1480 {
1481 // Validate that the source object is a valid COM object.
1482 _ASSERTE(pObjMT->IsComObjectType());
1483
1484 RCWHolder pRCW(GetThread());
1485
1486 RCWPROTECT_BEGIN(pRCW, gc.obj);
1487
1488 // Make sure the COM object supports all the COM imported interfaces that the new
1489 // wrapper class implements.
1490 MethodTable::InterfaceMapIterator it = pNewWrapMT->IterateInterfaceMap();
1491 while (it.Next())
1492 {
1493 MethodTable *pItfMT = it.GetInterface();
1494 if (pItfMT->IsComImport())
1495 {
1496 if (!Object::SupportsInterface(gc.obj, pItfMT))
1497 COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_COMOBJECT);
1498 }
1499 }
1500
1501 // Create the duplicate wrapper object.
1502 {
1503 RCWHolder pNewRCW(GetThread());
1504 pRCW->CreateDuplicateWrapper(pNewWrapMT, &pNewRCW);
1505
1506 gc.refRetVal = pNewRCW->GetExposedObject();
1507 }
1508
1509 RCWPROTECT_END(pRCW);
1510 }
1511
1512 HELPER_METHOD_FRAME_END();
1513 return OBJECTREFToObject(gc.refRetVal);
1514}
1515FCIMPLEND
1516
1517
1518//====================================================================
1519// check if the type is visible from COM.
1520//====================================================================
1521FCIMPL1(FC_BOOL_RET, MarshalNative::IsTypeVisibleFromCom, ReflectClassBaseObject* refClassUNSAFE)
1522{
1523 FCALL_CONTRACT;
1524
1525 BOOL retVal = FALSE;
1526 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) refClassUNSAFE;
1527 HELPER_METHOD_FRAME_BEGIN_RET_1(refClass);
1528
1529 // Validate the arguments.
1530 if (refClass == NULL)
1531 COMPlusThrowArgumentNull(W("t"));
1532
1533 MethodTable *pRefMT = refClass->GetMethodTable();
1534 if (pRefMT != g_pRuntimeTypeClass)
1535 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1536
1537 // Call the internal version of IsTypeVisibleFromCom.
1538 retVal = ::IsTypeVisibleFromCom(refClass->GetType());
1539
1540 HELPER_METHOD_FRAME_END();
1541 FC_RETURN_BOOL(retVal);
1542}
1543FCIMPLEND
1544
1545
1546//====================================================================
1547// IUnknown Helpers
1548//====================================================================
1549// IUnknown::QueryInterface
1550FCIMPL3(HRESULT, MarshalNative::QueryInterface, IUnknown* pUnk, REFGUID iid, void** ppv)
1551{
1552 CONTRACTL
1553 {
1554 FCALL_CHECK;
1555 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1556 PRECONDITION(CheckPointer(ppv));
1557 }
1558 CONTRACTL_END;
1559
1560 HRESULT hr = S_OK;
1561 HELPER_METHOD_FRAME_BEGIN_RET_0();
1562
1563 if (!pUnk)
1564 COMPlusThrowArgumentNull(W("pUnk"));
1565
1566 hr = SafeQueryInterface(pUnk,iid,(IUnknown**)ppv);
1567 LogInteropQI(pUnk, iid, hr, "PInvoke::QI");
1568
1569 HELPER_METHOD_FRAME_END();
1570 return hr;
1571}
1572FCIMPLEND
1573
1574// IUnknown::AddRef
1575FCIMPL1(ULONG, MarshalNative::AddRef, IUnknown* pUnk)
1576{
1577 CONTRACTL
1578 {
1579 FCALL_CHECK;
1580 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1581 }
1582 CONTRACTL_END;
1583
1584 ULONG cbRef = 0;
1585 HELPER_METHOD_FRAME_BEGIN_RET_0();
1586
1587 if (!pUnk)
1588 COMPlusThrowArgumentNull(W("pUnk"));
1589
1590 cbRef = SafeAddRef(pUnk);
1591 LogInteropAddRef(pUnk, cbRef, "PInvoke.AddRef");
1592
1593 HELPER_METHOD_FRAME_END();
1594 return cbRef;
1595}
1596FCIMPLEND
1597
1598//IUnknown::Release
1599FCIMPL1(ULONG, MarshalNative::Release, IUnknown* pUnk)
1600{
1601 CONTRACTL
1602 {
1603 FCALL_CHECK;
1604 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1605 }
1606 CONTRACTL_END;
1607
1608 ULONG cbRef = 0;
1609 HELPER_METHOD_FRAME_BEGIN_RET_0();
1610
1611 if (!pUnk)
1612 COMPlusThrowArgumentNull(W("pUnk"));
1613
1614 cbRef = SafeRelease(pUnk);
1615 LogInteropRelease(pUnk, cbRef, "PInvoke.Release");
1616
1617 HELPER_METHOD_FRAME_END();
1618 return cbRef;
1619}
1620FCIMPLEND
1621
1622FCIMPL2(void, MarshalNative::GetNativeVariantForObject, Object* ObjUNSAFE, LPVOID pDestNativeVariant)
1623{
1624 CONTRACTL
1625 {
1626 FCALL_CHECK;
1627 PRECONDITION(CheckPointer(pDestNativeVariant, NULL_OK));
1628 }
1629 CONTRACTL_END;
1630
1631 OBJECTREF Obj = (OBJECTREF) ObjUNSAFE;
1632 HELPER_METHOD_FRAME_BEGIN_1(Obj);
1633
1634 if (pDestNativeVariant == NULL)
1635 COMPlusThrowArgumentNull(W("pDstNativeVariant"));
1636
1637 if (Obj == NULL)
1638 {
1639 // Will return empty variant in MarshalOleVariantForObject
1640 }
1641 else if (Obj->GetMethodTable()->HasInstantiation())
1642 {
1643 COMPlusThrowArgumentException(W("obj"), W("Argument_NeedNonGenericObject"));
1644 }
1645
1646 // intialize the output variant
1647 SafeVariantInit((VARIANT*)pDestNativeVariant);
1648 OleVariant::MarshalOleVariantForObject(&Obj, (VARIANT*)pDestNativeVariant);
1649
1650 HELPER_METHOD_FRAME_END();
1651}
1652FCIMPLEND
1653
1654FCIMPL1(Object*, MarshalNative::GetObjectForNativeVariant, LPVOID pSrcNativeVariant)
1655{
1656 CONTRACTL
1657 {
1658 FCALL_CHECK;
1659 PRECONDITION(CheckPointer(pSrcNativeVariant, NULL_OK));
1660 }
1661 CONTRACTL_END;
1662
1663 OBJECTREF Obj = NULL;
1664 HELPER_METHOD_FRAME_BEGIN_RET_1(Obj);
1665
1666 if (pSrcNativeVariant == NULL)
1667 COMPlusThrowArgumentNull(W("pSrcNativeVariant"));
1668
1669 OleVariant::MarshalObjectForOleVariant((VARIANT*)pSrcNativeVariant, &Obj);
1670
1671 HELPER_METHOD_FRAME_END();
1672 return OBJECTREFToObject(Obj);
1673}
1674FCIMPLEND
1675
1676FCIMPL2(Object*, MarshalNative::GetObjectsForNativeVariants, VARIANT* aSrcNativeVariant, int cVars)
1677{
1678 CONTRACTL
1679 {
1680 FCALL_CHECK;
1681 INJECT_FAULT(FCThrow(kOutOfMemoryException););
1682 PRECONDITION(CheckPointer(aSrcNativeVariant, NULL_OK));
1683 }
1684 CONTRACTL_END;
1685
1686 PTRARRAYREF Array = NULL;
1687 HELPER_METHOD_FRAME_BEGIN_RET_1(Array);
1688
1689 if (aSrcNativeVariant == NULL)
1690 COMPlusThrowArgumentNull(W("aSrcNativeVariant"));
1691 if (cVars < 0)
1692 COMPlusThrowArgumentOutOfRange(W("cVars"), W("ArgumentOutOfRange_NeedNonNegNum"));
1693
1694 OBJECTREF Obj = NULL;
1695 GCPROTECT_BEGIN(Obj)
1696 {
1697 // Allocate the array of objects.
1698 Array = (PTRARRAYREF)AllocateObjectArray(cVars, g_pObjectClass);
1699
1700 // Convert each VARIANT in the array into an object.
1701 for (int i = 0; i < cVars; i++)
1702 {
1703 OleVariant::MarshalObjectForOleVariant(&aSrcNativeVariant[i], &Obj);
1704 Array->SetAt(i, Obj);
1705 }
1706 }
1707 GCPROTECT_END();
1708
1709 HELPER_METHOD_FRAME_END();
1710 return OBJECTREFToObject(Array);
1711}
1712FCIMPLEND
1713
1714
1715FCIMPL2(void, MarshalNative::DoGenerateGuidForType, GUID * result, ReflectClassBaseObject* refTypeUNSAFE)
1716{
1717 FCALL_CONTRACT;
1718
1719 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF) refTypeUNSAFE;
1720 HELPER_METHOD_FRAME_BEGIN_1(refType);
1721 GCPROTECT_BEGININTERIOR (result);
1722
1723 // Validate the arguments.
1724 if (refType == NULL)
1725 COMPlusThrowArgumentNull(W("type"));
1726
1727 MethodTable *pRefMT = refType->GetMethodTable();
1728 if (pRefMT != g_pRuntimeTypeClass)
1729 COMPlusThrowArgumentException(W("type"), W("Argument_MustBeRuntimeType"));
1730 if (result == NULL)
1731 COMPlusThrow(kArgumentNullException, W("ArgumentNull_GUID"));
1732
1733 // Check to see if the type is a COM object or not.
1734 if (IsComObjectClass(refType->GetType()))
1735 {
1736#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
1737 // The type is a COM object then we get the GUID from the class factory.
1738 SyncBlock* pSyncBlock = refType->GetSyncBlock();
1739
1740 ComClassFactory* pComClsFac = pSyncBlock->GetInteropInfo()->GetComClassFactory();
1741 memcpy(result, &pComClsFac->m_rclsid, sizeof(GUID));
1742#else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
1743 memset(result,0,sizeof(GUID));
1744#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
1745 }
1746 else
1747 {
1748 // The type is a normal COM+ class so we need to generate the GUID.
1749 TypeHandle classTH = refType->GetType();
1750 classTH.GetMethodTable()->GetGuid(result, TRUE);
1751 }
1752
1753 GCPROTECT_END ();
1754 HELPER_METHOD_FRAME_END();
1755}
1756FCIMPLEND
1757
1758FCIMPL2(void, MarshalNative::DoGetTypeLibGuid, GUID * result, Object* refTlbUNSAFE)
1759{
1760 FCALL_CONTRACT;
1761
1762 OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE;
1763 HELPER_METHOD_FRAME_BEGIN_1(refTlb);
1764 GCPROTECT_BEGININTERIOR (result);
1765
1766 if (refTlb == NULL)
1767 COMPlusThrowArgumentNull(W("pTLB"));
1768
1769 // Ensure COM is started up.
1770 EnsureComStarted();
1771
1772 SafeComHolder<ITypeLib> pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib);
1773 if (!pTLB)
1774 COMPlusThrow(kArgumentException, W("Arg_NoITypeLib"));
1775
1776 GCX_PREEMP();
1777
1778 // Retrieve the TLIBATTR.
1779 TLIBATTR *pAttr;
1780 IfFailThrow(pTLB->GetLibAttr(&pAttr));
1781
1782 // Extract the guid from the TLIBATTR.
1783 *result = pAttr->guid;
1784
1785 // Release the TLIBATTR now that we have the GUID.
1786 pTLB->ReleaseTLibAttr(pAttr);
1787
1788 GCPROTECT_END ();
1789 HELPER_METHOD_FRAME_END();
1790}
1791FCIMPLEND
1792
1793FCIMPL1(LCID, MarshalNative::GetTypeLibLcid, Object* refTlbUNSAFE)
1794{
1795 FCALL_CONTRACT;
1796
1797 LCID retVal = 0;
1798 OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE;
1799 HELPER_METHOD_FRAME_BEGIN_RET_1(refTlb);
1800
1801 if (refTlb == NULL)
1802 COMPlusThrowArgumentNull(W("pTLB"));
1803
1804 // Ensure COM is started up.
1805 EnsureComStarted();
1806
1807 SafeComHolder<ITypeLib> pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib);
1808 if (!pTLB)
1809 COMPlusThrow(kArgumentException, W("Arg_NoITypeLib"));
1810
1811 GCX_PREEMP();
1812
1813 // Retrieve the TLIBATTR.
1814 TLIBATTR *pAttr;
1815 IfFailThrow(pTLB->GetLibAttr(&pAttr));
1816
1817 // Extract the LCID from the TLIBATTR.
1818 retVal = pAttr->lcid;
1819
1820 // Release the TLIBATTR now that we have the LCID.
1821 pTLB->ReleaseTLibAttr(pAttr);
1822
1823 HELPER_METHOD_FRAME_END();
1824 return retVal;
1825}
1826FCIMPLEND
1827
1828FCIMPL3(void, MarshalNative::GetTypeLibVersion, Object* refTlbUNSAFE, int *pMajor, int *pMinor)
1829{
1830 FCALL_CONTRACT;
1831
1832 OBJECTREF refTlb = (OBJECTREF) refTlbUNSAFE;
1833 HELPER_METHOD_FRAME_BEGIN_1(refTlb);
1834
1835 if (refTlb == NULL)
1836 COMPlusThrowArgumentNull(W("typeLibrary"));
1837
1838 // Ensure COM is started up.
1839 EnsureComStarted();
1840
1841 SafeComHolder<ITypeLib> pTLB = (ITypeLib*)GetComIPFromObjectRef(&refTlb, IID_ITypeLib);
1842 if (!pTLB)
1843 COMPlusThrow(kArgumentException, W("Arg_NoITypeLib"));
1844
1845 GCX_PREEMP();
1846
1847 // Retrieve the TLIBATTR.
1848 TLIBATTR *pAttr;
1849 IfFailThrow(pTLB->GetLibAttr(&pAttr));
1850
1851 // Extract the LCID from the TLIBATTR.
1852 *pMajor = pAttr->wMajorVerNum;
1853 *pMinor = pAttr->wMinorVerNum;
1854
1855 // Release the TLIBATTR now that we have the version numbers.
1856 pTLB->ReleaseTLibAttr(pAttr);
1857
1858 HELPER_METHOD_FRAME_END();
1859}
1860FCIMPLEND
1861
1862FCIMPL2(void, MarshalNative::DoGetTypeInfoGuid, GUID * result, Object* refTypeInfoUNSAFE)
1863{
1864 FCALL_CONTRACT;
1865
1866 OBJECTREF refTypeInfo = (OBJECTREF) refTypeInfoUNSAFE;
1867 HELPER_METHOD_FRAME_BEGIN_1(refTypeInfo);
1868 GCPROTECT_BEGININTERIOR (result);
1869
1870 if (refTypeInfo == NULL)
1871 COMPlusThrowArgumentNull(W("typeInfo"));
1872
1873 // Ensure COM is started up.
1874 EnsureComStarted();
1875
1876 SafeComHolder<ITypeInfo> pTI = (ITypeInfo*)GetComIPFromObjectRef(&refTypeInfo, IID_ITypeInfo);
1877 if (!pTI)
1878 COMPlusThrow(kArgumentException, W("Arg_NoITypeInfo"));
1879
1880 GCX_PREEMP();
1881
1882 // Retrieve the TYPEATTR.
1883 TYPEATTR *pAttr;
1884 IfFailThrow(pTI->GetTypeAttr(&pAttr));
1885
1886 // Extract the guid from the TYPEATTR.
1887 *result = pAttr->guid;
1888
1889 // Release the TYPEATTR now that we have the GUID.
1890 pTI->ReleaseTypeAttr(pAttr);
1891
1892 GCPROTECT_END ();
1893 HELPER_METHOD_FRAME_END();
1894}
1895FCIMPLEND
1896
1897FCIMPL2(void, MarshalNative::DoGetTypeLibGuidForAssembly, GUID * result, AssemblyBaseObject* refAsmUNSAFE)
1898{
1899 FCALL_CONTRACT;
1900
1901 // Validate the arguments.
1902 _ASSERTE(refAsmUNSAFE != NULL);
1903 _ASSERTE(result != NULL);
1904
1905 ASSEMBLYREF refAsm = (ASSEMBLYREF) refAsmUNSAFE;
1906 HELPER_METHOD_FRAME_BEGIN_1(refAsm);
1907 GCPROTECT_BEGININTERIOR (result)
1908
1909 HRESULT hr = S_OK;
1910
1911 // Retrieve the assembly from the ASSEMBLYREF.
1912 Assembly *pAssembly = refAsm->GetAssembly();
1913 _ASSERTE(pAssembly);
1914
1915 // Retrieve the TLBID for the assembly.
1916 IfFailThrow(::GetTypeLibGuidForAssembly(pAssembly, result));
1917
1918 GCPROTECT_END ();
1919 HELPER_METHOD_FRAME_END();
1920}
1921FCIMPLEND
1922
1923FCIMPL3(void, MarshalNative::GetTypeLibVersionForAssembly, AssemblyBaseObject* refAsmUNSAFE, INT32 *pMajorVersion, INT32 *pMinorVersion)
1924{
1925 FCALL_CONTRACT;
1926
1927 // Validate the arguments.
1928 _ASSERTE(refAsmUNSAFE != NULL);
1929
1930 ASSEMBLYREF refAsm = (ASSEMBLYREF) refAsmUNSAFE;
1931 HELPER_METHOD_FRAME_BEGIN_1(refAsm);
1932
1933 HRESULT hr = S_OK;
1934
1935 // Retrieve the assembly from the ASSEMBLYREF.
1936 Assembly *pAssembly = refAsm->GetAssembly();
1937 _ASSERTE(pAssembly);
1938
1939 // Retrieve the version for the assembly.
1940 USHORT usMaj, usMin;
1941 IfFailThrow(::GetTypeLibVersionForAssembly(pAssembly, &usMaj, &usMin));
1942
1943 // Set the out parameters.
1944 *pMajorVersion = usMaj;
1945 *pMinorVersion = usMin;
1946
1947 HELPER_METHOD_FRAME_END();
1948}
1949FCIMPLEND
1950
1951FCIMPL1(int, MarshalNative::GetStartComSlot, ReflectClassBaseObject* tUNSAFE)
1952{
1953 FCALL_CONTRACT;
1954
1955 int retVal = 0;
1956 REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE;
1957 HELPER_METHOD_FRAME_BEGIN_RET_1(t);
1958
1959 if (!(t))
1960 COMPlusThrow(kArgumentNullException);
1961
1962 MethodTable *pTMT = t->GetMethodTable();
1963 if (pTMT != g_pRuntimeTypeClass)
1964 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1965
1966 MethodTable *pMT = t->GetType().GetMethodTable();
1967 if (NULL == pMT)
1968 COMPlusThrow(kArgumentNullException);
1969
1970 // The service does not make any sense to be called for non COM visible types.
1971 if (!::IsTypeVisibleFromCom(TypeHandle(pMT)))
1972 COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom"));
1973
1974 retVal = GetComSlotInfo(pMT, &pMT);
1975
1976 HELPER_METHOD_FRAME_END();
1977 return retVal;
1978}
1979FCIMPLEND
1980
1981
1982FCIMPL1(int, MarshalNative::GetEndComSlot, ReflectClassBaseObject* tUNSAFE)
1983{
1984 FCALL_CONTRACT;
1985
1986 int retVal = 0;
1987 REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE;
1988 HELPER_METHOD_FRAME_BEGIN_RET_1(t);
1989
1990 int StartSlot = -1;
1991
1992 if (!(t))
1993 COMPlusThrow(kArgumentNullException);
1994
1995 MethodTable *pTMT = t->GetMethodTable();
1996 if (pTMT != g_pRuntimeTypeClass)
1997 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
1998
1999 TypeHandle classTH = t->GetType();
2000 MethodTable *pMT = classTH.GetMethodTable();
2001 if (NULL == pMT)
2002 COMPlusThrow(kArgumentNullException);
2003
2004 // The service does not make any sense to be called for non COM visible types.
2005 if (!::IsTypeVisibleFromCom(classTH))
2006 COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom"));
2007
2008 // Retrieve the start slot and the default interface class.
2009 StartSlot = GetComSlotInfo(pMT, &pMT);
2010 if (StartSlot == -1)
2011 {
2012 retVal = StartSlot;
2013 }
2014 else
2015 {
2016 // Retrieve the map of members.
2017 ComMTMemberInfoMap MemberMap(pMT);
2018 MemberMap.Init(sizeof(void*));
2019
2020 // The end slot is the start slot plus the number of user defined methods.
2021 retVal = int(StartSlot + MemberMap.GetMethods().Size() - 1);
2022 }
2023
2024 HELPER_METHOD_FRAME_END();
2025 return retVal;
2026}
2027FCIMPLEND
2028
2029FCIMPL1(int, MarshalNative::GetComSlotForMethodInfo, ReflectMethodObject* pMethodUNSAFE)
2030{
2031 CONTRACTL
2032 {
2033 FCALL_CHECK;
2034 PRECONDITION(CheckPointer(pMethodUNSAFE));
2035 PRECONDITION(pMethodUNSAFE->GetMethod()->GetMethodTable()->IsInterface());
2036 }
2037 CONTRACTL_END;
2038
2039 REFLECTMETHODREF refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
2040 MethodDesc *pMeth = refMethod->GetMethod();
2041 _ASSERTE(pMeth);
2042 int retVal = 0;
2043 HELPER_METHOD_FRAME_BEGIN_RET_1(refMethod);
2044
2045 retVal = pMeth->GetComSlot();
2046
2047 HELPER_METHOD_FRAME_END();
2048 return retVal;
2049}
2050FCIMPLEND
2051
2052FCIMPL3(Object*, MarshalNative::GetMethodInfoForComSlot, ReflectClassBaseObject* tUNSAFE, INT32 slot, ComMemberType* pMemberType)
2053{
2054 CONTRACTL
2055 {
2056 FCALL_CHECK;
2057 PRECONDITION(CheckPointer(pMemberType, NULL_OK));
2058 }
2059 CONTRACTL_END;
2060
2061 OBJECTREF refRetVal = NULL;
2062 REFLECTCLASSBASEREF t = (REFLECTCLASSBASEREF) tUNSAFE;
2063 REFLECTCLASSBASEREF tInterface = NULL;
2064
2065 HELPER_METHOD_FRAME_BEGIN_RET_2(t, tInterface);
2066
2067 int StartSlot = -1;
2068 OBJECTREF MemberInfoObj = NULL;
2069
2070 if (!(t))
2071 COMPlusThrow(kArgumentNullException);
2072
2073 MethodTable *pTMT = t->GetMethodTable();
2074 if (pTMT != g_pRuntimeTypeClass)
2075 COMPlusThrowArgumentException(W("t"), W("Argument_MustBeRuntimeType"));
2076
2077 TypeHandle type = t->GetType();
2078 MethodTable *pMT= type.GetMethodTable();
2079 if (NULL == pMT)
2080 COMPlusThrow(kArgumentNullException);
2081
2082 // The service does not make any sense to be called for non COM visible types.
2083 if (!::IsTypeVisibleFromCom(type))
2084 COMPlusThrowArgumentException(W("t"), W("Argument_TypeMustBeVisibleFromCom"));
2085
2086 // Retrieve the start slot and the default interface class.
2087 StartSlot = GetComSlotInfo(pMT, &pMT);
2088 if (StartSlot == -1)
2089 COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count"));
2090
2091 // Retrieve the map of members.
2092 ComMTMemberInfoMap MemberMap(pMT);
2093 MemberMap.Init(sizeof(void*));
2094 CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
2095
2096 // Update the typehandle we'll be using based on the interface returned by GetComSlotInfo.
2097 tInterface = (REFLECTCLASSBASEREF)pMT->GetManagedClassObject();
2098 type = TypeHandle(pMT);
2099
2100 // Make sure the specified slot is valid.
2101 if (slot < StartSlot)
2102 COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count"));
2103 if (slot >= StartSlot + (int)rProps.Size())
2104 COMPlusThrowArgumentOutOfRange(W("slot"), W("ArgumentOutOfRange_Count"));
2105
2106 ComMTMethodProps *pProps = &rProps[slot - StartSlot];
2107 if (pProps->semantic >= FieldSemanticOffset)
2108 {
2109 // We are dealing with a field.
2110 ComCallMethodDesc *pFieldMeth = reinterpret_cast<ComCallMethodDesc*>(pProps->pMeth);
2111 FieldDesc *pField = pFieldMeth->GetFieldDesc();
2112
2113 // call the managed code to get the FieldInfo
2114 MethodDescCallSite getFieldInfo(METHOD__CLASS__GET_FIELD_INFO);
2115 ARG_SLOT args[] =
2116 {
2117 ObjToArgSlot(tInterface),
2118 (ARG_SLOT)pField
2119 };
2120
2121 MemberInfoObj = getFieldInfo.Call_RetOBJECTREF(args);
2122
2123 *(pMemberType) = (pProps->semantic == (FieldSemanticOffset + msGetter)) ? CMT_PropGet : CMT_PropSet;
2124 }
2125 else if (pProps->property == mdPropertyNil)
2126 {
2127 // We are dealing with a normal property.
2128
2129 // call the managed code to get the MethodInfo
2130 MethodDescCallSite getMethodBase(METHOD__CLASS__GET_METHOD_BASE);
2131 ARG_SLOT args[] =
2132 {
2133 ObjToArgSlot(tInterface),
2134 (ARG_SLOT)pProps->pMeth
2135 };
2136
2137 MemberInfoObj = getMethodBase.Call_RetOBJECTREF(args);
2138
2139 *(pMemberType) = CMT_Method;
2140 }
2141 else
2142 {
2143 // We are dealing with a property.
2144 mdProperty tkProp;
2145 if (TypeFromToken(pProps->property) == mdtProperty)
2146 tkProp = pProps->property;
2147 else
2148 tkProp = rProps[pProps->property].property;
2149
2150 // call the managed code to get the PropertyInfo
2151 MethodDescCallSite getPropertyInfo(METHOD__CLASS__GET_PROPERTY_INFO);
2152 ARG_SLOT args[] =
2153 {
2154 ObjToArgSlot(tInterface),
2155 tkProp
2156 };
2157
2158 MemberInfoObj = getPropertyInfo.Call_RetOBJECTREF(args);
2159
2160 *(pMemberType) = (pProps->semantic == msGetter) ? CMT_PropGet : CMT_PropSet;
2161 }
2162
2163 refRetVal = MemberInfoObj;
2164
2165 HELPER_METHOD_FRAME_END();
2166 return OBJECTREFToObject(refRetVal);
2167}
2168FCIMPLEND
2169
2170//+----------------------------------------------------------------------------
2171//
2172// Method: MarshalNative::WrapIUnknownWithComObject
2173// Synopsis: unmarshal the buffer and return IUnknown
2174//
2175
2176//
2177//+----------------------------------------------------------------------------
2178FCIMPL1(Object*, MarshalNative::WrapIUnknownWithComObject, IUnknown* pUnk)
2179{
2180 CONTRACTL
2181 {
2182 FCALL_CHECK;
2183 PRECONDITION(CheckPointer(pUnk, NULL_OK));
2184 }
2185 CONTRACTL_END;
2186
2187 OBJECTREF cref = NULL;
2188 HELPER_METHOD_FRAME_BEGIN_RET_0();
2189
2190 if(pUnk == NULL)
2191 COMPlusThrowArgumentNull(W("punk"));
2192
2193 EnsureComStarted();
2194
2195 COMInterfaceMarshaler marshaler;
2196 marshaler.Init(pUnk, g_pBaseCOMObject, GET_THREAD());
2197
2198 cref = marshaler.WrapWithComObject();
2199
2200 if (cref == NULL)
2201 COMPlusThrowOM();
2202
2203 HELPER_METHOD_FRAME_END();
2204 return OBJECTREFToObject(cref);
2205}
2206FCIMPLEND
2207
2208FCIMPL2(void, MarshalNative::ChangeWrapperHandleStrength, Object* orefUNSAFE, CLR_BOOL fIsWeak)
2209{
2210 FCALL_CONTRACT;
2211
2212 OBJECTREF oref = (OBJECTREF) orefUNSAFE;
2213 HELPER_METHOD_FRAME_BEGIN_1(oref);
2214
2215 if(oref == NULL)
2216 COMPlusThrowArgumentNull(W("otp"));
2217
2218 if (
2219 !oref->GetMethodTable()->IsComImport())
2220 {
2221 CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&oref);
2222
2223 if (pWrap == NULL)
2224 COMPlusThrowOM();
2225 if (fIsWeak != 0)
2226 pWrap->MarkHandleWeak();
2227 else
2228 pWrap->ResetHandleStrength();
2229 }
2230
2231 HELPER_METHOD_FRAME_END();
2232}
2233FCIMPLEND
2234
2235FCIMPL2(void, MarshalNative::InitializeWrapperForWinRT, Object *unsafe_pThis, IUnknown **ppUnk)
2236{
2237 FCALL_CONTRACT;
2238
2239 OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
2240 HELPER_METHOD_FRAME_BEGIN_1(oref);
2241
2242 _ASSERTE(ppUnk != NULL);
2243 if (*ppUnk == NULL)
2244 {
2245 // this should never happen but it's not nice to AV if the factory method is busted and returns NULL
2246 COMPlusThrow(kNullReferenceException);
2247 }
2248
2249 // the object does not have the right RCW yet
2250 COMInterfaceMarshaler marshaler;
2251 marshaler.Init(*ppUnk, oref->GetMethodTable(), GET_THREAD(), RCW::CF_SupportsIInspectable | RCW::CF_QueryForIdentity);
2252
2253 // the following will assign NULL to *ppUnk which signals to the caller that we successfully
2254 // initialized the RCW so (*ppUnk)->Release() should be suppressed
2255 marshaler.InitializeExistingComObject(&oref, ppUnk);
2256
2257 HELPER_METHOD_FRAME_END();
2258}
2259FCIMPLEND
2260
2261FCIMPL2(void, MarshalNative::InitializeManagedWinRTFactoryObject, Object *unsafe_pThis, ReflectClassBaseObject *unsafe_pType)
2262{
2263 FCALL_CONTRACT;
2264
2265 OBJECTREF orefThis = ObjectToOBJECTREF(unsafe_pThis);
2266 REFLECTCLASSBASEREF orefType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(unsafe_pType);
2267 HELPER_METHOD_FRAME_BEGIN_2(orefThis, orefType);
2268
2269 MethodTable *pMT = orefType->GetType().GetMethodTable();
2270
2271 // get the special "factory" template for the type
2272 _ASSERTE(pMT->IsExportedToWinRT());
2273 WinRTManagedClassFactory *pFactory = GetComClassFactory(pMT)->AsWinRTManagedClassFactory();
2274
2275 ComCallWrapperTemplate *pTemplate = pFactory->GetOrCreateComCallWrapperTemplate(orefThis->GetMethodTable());
2276
2277 // create a CCW for the factory object using the template
2278 CCWHolder pCCWHold = ComCallWrapper::InlineGetWrapper(&orefThis, pTemplate);
2279
2280 HELPER_METHOD_FRAME_END();
2281}
2282FCIMPLEND
2283
2284//
2285// Create activation factory and wraps it with a unique RCW
2286//
2287// This is necessary because WinRT factories are often implemented as a singleton,
2288// and getting back a RCW for such WinRT factory would usually get back a RCW from
2289// another apartment, even if the interface pointe returned from GetActivationFactory
2290// is a raw pointer. As a result, user would randomly get back RCWs for activation
2291// factories from other apartments and make transiton to those apartments and cause
2292// deadlocks and create objects in incorrect apartments
2293//
2294// The solution here is to always create a unique RCW
2295//
2296FCIMPL1(Object *, MarshalNative::GetNativeActivationFactory, ReflectClassBaseObject *unsafe_pType)
2297{
2298 FCALL_CONTRACT;
2299
2300 REFLECTCLASSBASEREF orefType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(unsafe_pType);
2301 OBJECTREF orefFactory = NULL;
2302 HELPER_METHOD_FRAME_BEGIN_RET_2(orefFactory, orefType);
2303
2304 MethodTable *pMT = orefType->GetType().GetMethodTable();
2305
2306 // Must be a native WinRT type
2307 _ASSERTE(pMT->IsProjectedFromWinRT());
2308
2309 //
2310 // Get the activation factory instance for this WinRT type and create a RCW for it
2311 //
2312 GetNativeWinRTFactoryObject(
2313 pMT,
2314 GET_THREAD(),
2315 NULL, // No factory interface available at this point
2316 TRUE, // Create unique RCW - See comments for this function for more details
2317 NULL, // No callback necessary
2318 &orefFactory // return value
2319 );
2320
2321 HELPER_METHOD_FRAME_END();
2322
2323 return OBJECTREFToObject(orefFactory);
2324}
2325FCIMPLEND
2326
2327void QCALLTYPE MarshalNative::GetInspectableIIDs(
2328 QCall::ObjectHandleOnStack hobj,
2329 QCall::ObjectHandleOnStack retArrayGuids)
2330{
2331 CONTRACTL
2332 {
2333 QCALL_CHECK;
2334 PRECONDITION(CheckPointer(*hobj.m_ppObject));
2335 }
2336 CONTRACTL_END;
2337
2338 BEGIN_QCALL;
2339
2340 SyncBlock * pSyncBlock = NULL;
2341
2342 {
2343 GCX_COOP();
2344
2345 // set return to failure value
2346 retArrayGuids.Set(NULL);
2347
2348 OBJECTREF orComObject = NULL;
2349 GCPROTECT_BEGIN(orComObject);
2350
2351 orComObject = ObjectToOBJECTREF(*hobj.m_ppObject);
2352
2353 // Validation: hobj represents a non-NULL System.__ComObject instance
2354 if(orComObject == NULL)
2355 COMPlusThrowArgumentNull(W("obj"));
2356
2357 MethodTable* pMT = orComObject->GetMethodTable();
2358 PREFIX_ASSUME(pMT != NULL);
2359 if(!pMT->IsComObjectType())
2360 COMPlusThrow(kArgumentException, IDS_EE_SRC_OBJ_NOT_COMOBJECT);
2361
2362 // while in cooperative mode, retrieve the object's sync block
2363 pSyncBlock = orComObject->PassiveGetSyncBlock();
2364
2365 GCPROTECT_END();
2366 } // close the GCX_COOP scope
2367
2368
2369 InteropSyncBlockInfo * pInteropInfo;
2370 RCW * pRCW;
2371 SafeComHolderPreemp<IInspectable> pInspectable;
2372
2373 // Retrieve obj's IInspectable interface pointer
2374 if (pSyncBlock != NULL
2375 && (pInteropInfo = pSyncBlock->GetInteropInfoNoCreate()) != NULL
2376 && (pRCW = pInteropInfo->GetRawRCW()) != NULL
2377 && (pInspectable = pRCW->GetIInspectable()) != NULL)
2378 {
2379 // retrieve IIDs using IInspectable::GetIids()
2380 ULONG size = 0;
2381 CoTaskMemHolder<IID> rgIIDs(NULL);
2382 if (SUCCEEDED(pInspectable->GetIids(&size, &rgIIDs)))
2383 {
2384 retArrayGuids.SetGuidArray(rgIIDs, size);
2385 }
2386 }
2387
2388 END_QCALL;
2389}
2390
2391//====================================================================
2392// Helper function used in the COM slot to method info mapping.
2393//====================================================================
2394
2395int MarshalNative::GetComSlotInfo(MethodTable *pMT, MethodTable **ppDefItfMT)
2396{
2397 CONTRACTL
2398 {
2399 THROWS;
2400 GC_TRIGGERS;
2401 MODE_ANY;
2402 PRECONDITION(CheckPointer(pMT));
2403 PRECONDITION(CheckPointer(ppDefItfMT));
2404 }
2405 CONTRACTL_END;
2406
2407 *ppDefItfMT = NULL;
2408
2409 // If a class was passed in then retrieve the default interface.
2410 if (!pMT->IsInterface())
2411 {
2412 TypeHandle hndDefItfClass;
2413 DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass);
2414
2415 if (DefItfType == DefaultInterfaceType_AutoDual || DefItfType == DefaultInterfaceType_Explicit)
2416 {
2417 pMT = hndDefItfClass.GetMethodTable();
2418 PREFIX_ASSUME(pMT != NULL);
2419 }
2420 else
2421 {
2422 // The default interface does not have any user defined methods.
2423 return -1;
2424 }
2425 }
2426
2427 // Set the default interface class.
2428 *ppDefItfMT = pMT;
2429
2430 if (pMT->IsInterface())
2431 {
2432 // Return the right number of slots depending on interface type.
2433 return ComMethodTable::GetNumExtraSlots(pMT->GetComInterfaceType());
2434 }
2435 else
2436 {
2437 // We are dealing with an IClassX which are always IDispatch based.
2438 return ComMethodTable::GetNumExtraSlots(ifDispatch);
2439 }
2440}
2441
2442BOOL MarshalNative::IsObjectInContext(OBJECTREF *pObj)
2443{
2444 CONTRACTL
2445 {
2446 THROWS;
2447 GC_TRIGGERS;
2448 MODE_COOPERATIVE;
2449 PRECONDITION(pObj != NULL);
2450 }
2451 CONTRACTL_END;
2452
2453 SyncBlock* pBlock = (*pObj)->GetSyncBlock();
2454
2455 InteropSyncBlockInfo* pInteropInfo = pBlock->GetInteropInfo();
2456
2457 ComCallWrapper* pCCW = pInteropInfo->GetCCW();
2458
2459 if((pCCW) || (!pInteropInfo->RCWWasUsed()))
2460 {
2461 // We are dealing with a CCW. Since CCW's are agile, they are always in the
2462 // correct context.
2463 return TRUE;
2464 }
2465 else
2466 {
2467 RCWHolder pRCW(GetThread());
2468 pRCW.Init(pBlock);
2469
2470 // We are dealing with an RCW, we need to check to see if the current
2471 // context is the one it was first seen in.
2472 LPVOID pCtxCookie = GetCurrentCtxCookie();
2473 _ASSERTE(pCtxCookie != NULL);
2474
2475 return pCtxCookie == pRCW->GetWrapperCtxCookie();
2476 }
2477}
2478
2479#endif // FEATURE_COMINTEROP
2480