2016-01-27 11:41:24 -08:00
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
#include "vars.hpp"
|
|
|
|
|
#include "excep.h"
|
|
|
|
|
#include "interoputil.h"
|
|
|
|
|
#include "cachelinealloc.h"
|
|
|
|
|
#include "comutilnative.h"
|
|
|
|
|
#include "field.h"
|
|
|
|
|
#include "guidfromname.h"
|
|
|
|
|
#include "eeconfig.h"
|
|
|
|
|
#include "mlinfo.h"
|
|
|
|
|
#include "comdelegate.h"
|
|
|
|
|
#include "appdomain.hpp"
|
|
|
|
|
#include "prettyprintsig.h"
|
|
|
|
|
#include "util.hpp"
|
|
|
|
|
#include "interopconverter.h"
|
|
|
|
|
#include "wrappers.h"
|
|
|
|
|
#include "invokeutil.h"
|
|
|
|
|
#include "comcallablewrapper.h"
|
|
|
|
|
#include "../md/compiler/custattr.h"
|
|
|
|
|
#include "siginfo.hpp"
|
|
|
|
|
#include "finalizerthread.h"
|
2020-03-06 23:37:47 -08:00
|
|
|
#include "interoplibinterface.h"
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
|
|
|
#include "cominterfacemarshaler.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
|
|
|
#include "olecontexthelpers.h"
|
|
|
|
|
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
|
|
|
#include "dispex.h"
|
|
|
|
|
#include "runtimecallablewrapper.h"
|
|
|
|
|
#include "comtoclrcall.h"
|
|
|
|
|
#include "clrtocomcall.h"
|
|
|
|
|
#include "comcache.h"
|
|
|
|
|
#include "commtmemberinfomap.h"
|
|
|
|
|
#include "olevariant.h"
|
|
|
|
|
#include "stdinterfaces.h"
|
|
|
|
|
#include "typeparse.h"
|
|
|
|
|
#include "interoputil.inl"
|
|
|
|
|
#include "typestring.h"
|
|
|
|
|
|
|
|
|
|
#define STANDARD_DISPID_PREFIX W("[DISPID")
|
|
|
|
|
#define STANDARD_DISPID_PREFIX_LENGTH 7
|
|
|
|
|
#define GET_ENUMERATOR_METHOD_NAME W("GetEnumerator")
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
2022-07-17 08:11:11 +03:00
|
|
|
VOID InitializeInteropLogging();
|
2019-11-02 06:29:45 -07:00
|
|
|
#endif
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
struct ByrefArgumentInfo
|
|
|
|
|
{
|
|
|
|
|
BOOL m_bByref;
|
|
|
|
|
VARIANT m_Val;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Flag indicating if COM support has been initialized.
|
|
|
|
|
BOOL g_fComStarted = FALSE;
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
void AllocateComClassObject(ComClassFactory* pComClsFac, OBJECTREF* pComObj);
|
|
|
|
|
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
|
|
|
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
|
// setup error info for exception object
|
|
|
|
|
//
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
2018-12-13 14:41:08 -08:00
|
|
|
|
|
|
|
|
// HRESULT for CLR created IErrorInfo pointers are accessible
|
|
|
|
|
// from the enclosing simple wrapper
|
|
|
|
|
// This is in-proc only.
|
|
|
|
|
HRESULT GetHRFromCLRErrorInfo(IErrorInfo* pErr)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
PRECONDITION(CheckPointer(pErr));
|
|
|
|
|
PRECONDITION(IsInProcCCWTearOff(pErr));
|
|
|
|
|
PRECONDITION(IsSimpleTearOff(pErr));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
SimpleComCallWrapper* pSimpleWrap = SimpleComCallWrapper::GetWrapperFromIP(pErr);
|
|
|
|
|
return pSimpleWrap->IErrorInfo_hr();
|
|
|
|
|
}
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
HRESULT SetupErrorInfo(OBJECTREF pThrownObject)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
|
|
Exception* pException = NULL;
|
|
|
|
|
|
|
|
|
|
GCPROTECT_BEGIN(pThrownObject)
|
|
|
|
|
{
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
// Calls to COM up ahead.
|
|
|
|
|
hr = EnsureComStartedNoThrow();
|
|
|
|
|
if (SUCCEEDED(hr) && pThrownObject != NULL)
|
|
|
|
|
{
|
|
|
|
|
IErrorInfo* pErr = NULL;
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
// set the error info object for the exception that was thrown.
|
|
|
|
|
pErr = (IErrorInfo *)GetComIPFromObjectRef(&pThrownObject, IID_IErrorInfo);
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
GCX_PREEMP();
|
|
|
|
|
SetErrorInfo(0, pErr);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Release the pErr in case it exists.
|
|
|
|
|
if (pErr)
|
|
|
|
|
{
|
|
|
|
|
hr = GetHRFromCLRErrorInfo(pErr);
|
|
|
|
|
ULONG cbRef = SafeRelease(pErr);
|
|
|
|
|
LogInteropRelease(pErr, cbRef, "IErrorInfo");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
hr = GET_EXCEPTION()->GetHR();
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
hr = E_FAIL;
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
2018-12-13 14:41:08 -08:00
|
|
|
// Used to populate ExceptionData with COM data
|
2015-01-30 14:14:42 -08:00
|
|
|
//-------------------------------------------------------------------
|
2018-12-13 14:41:08 -08:00
|
|
|
void FillExceptionData(
|
|
|
|
|
_Inout_ ExceptionData* pedata,
|
2020-05-29 17:37:12 -07:00
|
|
|
_In_ IErrorInfo* pErrInfo)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pedata));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if (pErrInfo != NULL)
|
|
|
|
|
{
|
2021-03-25 14:26:44 -07:00
|
|
|
Thread* pThread = GetThreadNULLOk();
|
2015-01-30 14:14:42 -08:00
|
|
|
if (pThread != NULL)
|
|
|
|
|
{
|
|
|
|
|
GCX_PREEMP();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
pErrInfo->GetSource (&pedata->bstrSource);
|
|
|
|
|
pErrInfo->GetDescription (&pedata->bstrDescription);
|
|
|
|
|
pErrInfo->GetHelpFile (&pedata->bstrHelpFile);
|
|
|
|
|
pErrInfo->GetHelpContext (&pedata->dwHelpContext );
|
|
|
|
|
pErrInfo->GetGUID(&pedata->guid);
|
|
|
|
|
ULONG cbRef = SafeRelease(pErrInfo); // release the IErrorInfo interface pointer
|
|
|
|
|
LogInteropRelease(pErrInfo, cbRef, "IErrorInfo");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-09 05:58:11 +08:00
|
|
|
#endif // FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
2019-11-02 06:29:45 -07:00
|
|
|
// If pImport has the DefaultDllImportSearchPathsAttribute,
|
2019-01-18 09:24:41 -08:00
|
|
|
// set the value of the attribute in pDlImportSearchPathFlags and return true.
|
2019-05-20 15:15:52 -07:00
|
|
|
BOOL GetDefaultDllImportSearchPathsAttributeValue(Module *pModule, mdToken token, DWORD * pDllImportSearchPathFlags)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
2019-05-20 15:15:52 -07:00
|
|
|
PRECONDITION(CheckPointer(pModule));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
BYTE* pData = NULL;
|
|
|
|
|
LONG cData = 0;
|
|
|
|
|
|
2019-05-20 15:15:52 -07:00
|
|
|
HRESULT hr = pModule->GetCustomAttribute(token,
|
|
|
|
|
WellKnownAttribute::DefaultDllImportSearchPaths,
|
|
|
|
|
(const VOID **)(&pData),
|
|
|
|
|
(ULONG *)&cData);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
IfFailThrow(hr);
|
|
|
|
|
if(cData == 0 )
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CustomAttributeParser ca(pData, cData);
|
|
|
|
|
CaArg args[1];
|
|
|
|
|
args[0].InitEnum(SERIALIZATION_TYPE_U4, (ULONG)0);
|
|
|
|
|
|
2021-11-24 18:52:12 +02:00
|
|
|
ParseKnownCaArgs(ca, args, ARRAY_SIZE(args));
|
2019-01-18 09:24:41 -08:00
|
|
|
*pDllImportSearchPathFlags = args[0].val.u4;
|
2015-01-30 14:14:42 -08:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// Returns the index of the LCID parameter if one exists and -1 otherwise.
|
|
|
|
|
int GetLCIDParameterIndex(MethodDesc *pMD)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pMD));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
int iLCIDParam = -1;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
const BYTE * pVal;
|
|
|
|
|
ULONG cbVal;
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// Check to see if the method has the LCIDConversionAttribute.
|
|
|
|
|
hr = pMD->GetCustomAttribute(WellKnownAttribute::LCIDConversion, (const void**)&pVal, &cbVal);
|
|
|
|
|
if (hr == S_OK)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
CustomAttributeParser caLCID(pVal, cbVal);
|
|
|
|
|
CaArg args[1];
|
|
|
|
|
args[0].Init(SERIALIZATION_TYPE_I4, 0);
|
2021-11-24 18:52:12 +02:00
|
|
|
IfFailGo(ParseKnownCaArgs(caLCID, args, ARRAY_SIZE(args)));
|
2020-05-29 17:37:12 -07:00
|
|
|
iLCIDParam = args[0].val.i4;
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrExit:
|
|
|
|
|
return iLCIDParam;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// Transforms an LCID into a CultureInfo.
|
|
|
|
|
void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(CheckPointer(pCultureObj));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
OBJECTREF CultureObj = NULL;
|
|
|
|
|
GCPROTECT_BEGIN(CultureObj)
|
|
|
|
|
{
|
|
|
|
|
// Allocate a CultureInfo with the specified LCID.
|
2020-07-28 16:10:38 -07:00
|
|
|
CultureObj = AllocateObject(CoreLibBinder::GetClass(CLASS__CULTURE_INFO));
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
MethodDescCallSite cultureInfoCtor(METHOD__CULTURE_INFO__INT_CTOR, &CultureObj);
|
|
|
|
|
|
|
|
|
|
// Call the CultureInfo(int culture) constructor.
|
|
|
|
|
ARG_SLOT pNewArgs[] = {
|
|
|
|
|
ObjToArgSlot(CultureObj),
|
|
|
|
|
(ARG_SLOT)lcid
|
|
|
|
|
};
|
|
|
|
|
cultureInfoCtor.Call(pNewArgs);
|
|
|
|
|
|
|
|
|
|
// Set the returned culture object.
|
|
|
|
|
*pCultureObj = CultureObj;
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
}
|
2018-03-27 14:20:09 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// This method determines if a member is visible from COM.
|
|
|
|
|
BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef mdAssociate)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pDeclaringMT));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
HRESULT hr;
|
|
|
|
|
const BYTE * pVal;
|
|
|
|
|
ULONG cbVal;
|
|
|
|
|
DWORD dwFlags;
|
|
|
|
|
|
|
|
|
|
IMDInternalImport *pInternalImport = pDeclaringMT->GetMDImport();
|
2019-05-20 15:15:52 -07:00
|
|
|
Module *pModule = pDeclaringMT->GetModule();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Check to see if the member is public.
|
|
|
|
|
switch (TypeFromToken(tk))
|
|
|
|
|
{
|
|
|
|
|
case mdtFieldDef:
|
|
|
|
|
_ASSERTE(IsNilToken(mdAssociate));
|
|
|
|
|
if (FAILED(pInternalImport->GetFieldDefProps(tk, &dwFlags)))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!IsFdPublic(dwFlags))
|
|
|
|
|
return FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case mdtMethodDef:
|
|
|
|
|
_ASSERTE(IsNilToken(mdAssociate));
|
|
|
|
|
if (FAILED(pInternalImport->GetMethodDefProps(tk, &dwFlags)))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!IsMdPublic(dwFlags))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// Generic Methods are not visible from COM
|
|
|
|
|
MDEnumHolder hEnumTyPars(pInternalImport);
|
|
|
|
|
if (FAILED(pInternalImport->EnumInit(mdtGenericParam, tk, &hEnumTyPars)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (pInternalImport->EnumGetCount(&hEnumTyPars) != 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case mdtProperty:
|
|
|
|
|
_ASSERTE(!IsNilToken(mdAssociate));
|
|
|
|
|
if (FAILED(pInternalImport->GetMethodDefProps(mdAssociate, &dwFlags)))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!IsMdPublic(dwFlags))
|
|
|
|
|
return FALSE;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// Check to see if the associate has the ComVisible attribute set
|
|
|
|
|
hr = pModule->GetCustomAttribute(mdAssociate, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
|
|
|
|
|
if (hr == S_OK)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
CustomAttributeParser cap(pVal, cbVal);
|
|
|
|
|
if (FAILED(cap.SkipProlog()))
|
|
|
|
|
return FALSE;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
UINT8 u1;
|
|
|
|
|
if (FAILED(cap.GetU1(&u1)))
|
|
|
|
|
return FALSE;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
return (BOOL)u1;
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
_ASSERTE(!"The type of the specified member is not handled by IsMemberVisibleFromCom");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// Check to see if the member has the ComVisible attribute set (non-WinRT members only).
|
|
|
|
|
hr = pModule->GetCustomAttribute(tk, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
|
|
|
|
|
if (hr == S_OK)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
CustomAttributeParser cap(pVal, cbVal);
|
|
|
|
|
if (FAILED(cap.SkipProlog()))
|
|
|
|
|
return FALSE;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
UINT8 u1;
|
|
|
|
|
if (FAILED(cap.GetU1(&u1)))
|
|
|
|
|
return FALSE;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
return (BOOL)u1;
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The member is visible.
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// This method checks whether the given IErrorInfo is actually a managed CLR object.
|
|
|
|
|
BOOL IsManagedObject(IUnknown *pIUnknown)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(CheckPointer(pIUnknown));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
#if FEATURE_COMINTEROP
|
|
|
|
|
//Check based on IUnknown slots, i.e. we'll see whether the IP maps to a CCW.
|
|
|
|
|
if (MapIUnknownToWrapper(pIUnknown) != NULL)
|
|
|
|
|
{
|
|
|
|
|
// We found an existing CCW hence this is a managed exception.
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
ULONG GetStringizedMethodDef(MethodTable *pDeclaringMT, mdToken tkMb, CQuickArray<BYTE> &rDef, ULONG cbCur)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pDeclaringMT));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
IMDInternalImport *pMDImport = pDeclaringMT->GetMDImport();
|
|
|
|
|
CQuickBytes rSig;
|
|
|
|
|
MDEnumHolder ePm(pMDImport); // For enumerating params.
|
|
|
|
|
mdParamDef tkPm; // A param token.
|
|
|
|
|
DWORD dwFlags; // Param flags.
|
|
|
|
|
USHORT usSeq; // Sequence of a parameter.
|
|
|
|
|
ULONG cPm; // Count of params.
|
|
|
|
|
PCCOR_SIGNATURE pSig;
|
|
|
|
|
ULONG cbSig;
|
|
|
|
|
|
|
|
|
|
// Don't count invisible members.
|
|
|
|
|
if (!IsMemberVisibleFromCom(pDeclaringMT, tkMb, mdMethodDefNil))
|
|
|
|
|
return cbCur;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// accumulate the signatures.
|
|
|
|
|
IfFailThrow(pMDImport->GetSigOfMethodDef(tkMb, &cbSig, &pSig));
|
|
|
|
|
IfFailThrow(::PrettyPrintSigInternalLegacy(pSig, cbSig, "", &rSig, pMDImport));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Get the parameter flags.
|
|
|
|
|
IfFailThrow(pMDImport->EnumInit(mdtParamDef, tkMb, &ePm));
|
|
|
|
|
cPm = pMDImport->EnumGetCount(&ePm);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Resize for sig and params. Just use 1 byte of param.
|
|
|
|
|
rDef.ReSizeThrows(cbCur + rSig.Size() + cPm);
|
|
|
|
|
memcpy(rDef.Ptr() + cbCur, rSig.Ptr(), rSig.Size());
|
|
|
|
|
cbCur += (ULONG)(rSig.Size()-1);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Enumerate through the params and get the flags.
|
|
|
|
|
while (pMDImport->EnumNext(&ePm, &tkPm))
|
|
|
|
|
{
|
|
|
|
|
LPCSTR szParamName_Ignore;
|
|
|
|
|
IfFailThrow(pMDImport->GetParamDefProps(tkPm, &usSeq, &dwFlags, &szParamName_Ignore));
|
|
|
|
|
if (usSeq == 0) // Skip return type flags.
|
|
|
|
|
continue;
|
|
|
|
|
rDef[cbCur++] = (BYTE)dwFlags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return the number of bytes.
|
|
|
|
|
return cbCur;
|
|
|
|
|
} // void GetStringizedMethodDef()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ULONG GetStringizedFieldDef(MethodTable *pDeclaringMT, mdToken tkMb, CQuickArray<BYTE> &rDef, ULONG cbCur)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pDeclaringMT));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
CQuickBytes rSig;
|
|
|
|
|
PCCOR_SIGNATURE pSig;
|
|
|
|
|
ULONG cbSig;
|
|
|
|
|
|
|
|
|
|
// Don't count invisible members.
|
|
|
|
|
if (!IsMemberVisibleFromCom(pDeclaringMT, tkMb, mdMethodDefNil))
|
|
|
|
|
return cbCur;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
IMDInternalImport *pMDImport = pDeclaringMT->GetMDImport();
|
|
|
|
|
|
|
|
|
|
// accumulate the signatures.
|
|
|
|
|
IfFailThrow(pMDImport->GetSigOfFieldDef(tkMb, &cbSig, &pSig));
|
|
|
|
|
IfFailThrow(::PrettyPrintSigInternalLegacy(pSig, cbSig, "", &rSig, pMDImport));
|
|
|
|
|
rDef.ReSizeThrows(cbCur + rSig.Size());
|
|
|
|
|
memcpy(rDef.Ptr() + cbCur, rSig.Ptr(), rSig.Size());
|
|
|
|
|
cbCur += (ULONG)(rSig.Size()-1);
|
|
|
|
|
|
|
|
|
|
// Return the number of bytes.
|
|
|
|
|
return cbCur;
|
|
|
|
|
} // void GetStringizedFieldDef()
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// This method generates a stringized version of an interface that contains the
|
|
|
|
|
// name of the interface along with the signature of all the methods.
|
|
|
|
|
SIZE_T GetStringizedItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
MethodTable* pIntfMT = InterfaceType.GetMethodTable();
|
|
|
|
|
PREFIX_ASSUME(pIntfMT != NULL);
|
|
|
|
|
|
|
|
|
|
IMDInternalImport* pMDImport = pIntfMT->GetMDImport();
|
|
|
|
|
PREFIX_ASSUME(pMDImport != NULL);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
|
|
|
|
LPCWSTR szName;
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG cchName;
|
|
|
|
|
MDEnumHolder eMb(pMDImport); // For enumerating methods and fields.
|
|
|
|
|
mdToken tkMb; // A method or field token.
|
|
|
|
|
SIZE_T cbCur;
|
|
|
|
|
|
|
|
|
|
// Make sure the specified type is an interface with a valid token.
|
|
|
|
|
_ASSERTE(!IsNilToken(pIntfMT->GetCl()) && pIntfMT->IsInterface());
|
|
|
|
|
|
|
|
|
|
// Get the name of the class.
|
|
|
|
|
DefineFullyQualifiedNameForClassW();
|
|
|
|
|
szName = GetFullyQualifiedNameForClassNestedAwareW(pIntfMT);
|
|
|
|
|
|
2023-05-11 14:15:05 -07:00
|
|
|
cchName = (ULONG)u16_strlen(szName);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Start with the interface name.
|
|
|
|
|
cbCur = cchName * sizeof(WCHAR);
|
|
|
|
|
rDef.ReSizeThrows(cbCur + sizeof(WCHAR));
|
|
|
|
|
wcscpy_s(reinterpret_cast<LPWSTR>(rDef.Ptr()), rDef.Size()/sizeof(WCHAR), szName);
|
|
|
|
|
|
|
|
|
|
// Enumerate the methods...
|
|
|
|
|
IfFailThrow(pMDImport->EnumInit(mdtMethodDef, pIntfMT->GetCl(), &eMb));
|
|
|
|
|
while(pMDImport->EnumNext(&eMb, &tkMb))
|
|
|
|
|
{ // accumulate the signatures.
|
|
|
|
|
cbCur = GetStringizedMethodDef(pIntfMT, tkMb, rDef, (ULONG)cbCur);
|
|
|
|
|
}
|
|
|
|
|
pMDImport->EnumClose(&eMb);
|
|
|
|
|
|
|
|
|
|
// Enumerate the fields...
|
|
|
|
|
IfFailThrow(pMDImport->EnumInit(mdtFieldDef, pIntfMT->GetCl(), &eMb));
|
|
|
|
|
while(pMDImport->EnumNext(&eMb, &tkMb))
|
|
|
|
|
{ // accumulate the signatures.
|
|
|
|
|
cbCur = GetStringizedFieldDef(pIntfMT, tkMb, rDef, (ULONG)cbCur);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return the number of bytes.
|
|
|
|
|
return cbCur;
|
|
|
|
|
} // ULONG GetStringizedItfDef()
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Helper to get the stringized form of typelib guid.
|
|
|
|
|
HRESULT GetStringizedTypeLibGuidForAssembly(Assembly *pAssembly, CQuickArray<BYTE> &rDef, ULONG cbCur, ULONG *pcbFetched)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
2019-11-02 06:29:45 -07:00
|
|
|
GC_TRIGGERS;
|
2015-01-30 14:14:42 -08:00
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pAssembly));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pcbFetched));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK; // A result.
|
|
|
|
|
LPCUTF8 pszName = NULL; // Library name in UTF8.
|
|
|
|
|
ULONG cbName; // Length of name, UTF8 characters.
|
|
|
|
|
LPWSTR pName; // Pointer to library name.
|
|
|
|
|
ULONG cchName; // Length of name, wide chars.
|
|
|
|
|
LPWSTR pch=0; // Pointer into lib name.
|
|
|
|
|
const void *pSN=NULL; // Pointer to public key.
|
|
|
|
|
DWORD cbSN=0; // Size of public key.
|
|
|
|
|
USHORT usMajorVersion; // The major version number.
|
|
|
|
|
USHORT usMinorVersion; // The minor version number.
|
|
|
|
|
USHORT usBuildNumber; // The build number.
|
|
|
|
|
USHORT usRevisionNumber; // The revision number.
|
|
|
|
|
const BYTE *pbData = NULL; // Pointer to a custom attribute data.
|
|
|
|
|
ULONG cbData = 0; // Size of custom attribute data.
|
|
|
|
|
static char szTypeLibKeyName[] = {"TypeLib"};
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Get the name, and determine its length.
|
|
|
|
|
pszName = pAssembly->GetSimpleName();
|
|
|
|
|
cbName=(ULONG)strlen(pszName);
|
|
|
|
|
cchName = WszMultiByteToWideChar(CP_ACP,0, pszName,cbName+1, 0,0);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// See if there is a public key.
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
pSN = pAssembly->GetPublicKey(&cbSN);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
IfFailGo(COR_E_BADIMAGEFORMAT);
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(RethrowTerminalExceptions)
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
2020-05-29 17:37:12 -07:00
|
|
|
// If the ComCompatibleVersionAttribute is set, then use the version
|
|
|
|
|
// number in the attribute when generating the GUID.
|
|
|
|
|
IfFailGo(pAssembly->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::ComCompatibleVersion, (const void**)&pbData, &cbData));
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
if (hr == S_OK && cbData >= (2 + 4 * sizeof(INT32)))
|
|
|
|
|
{
|
|
|
|
|
CustomAttributeParser cap(pbData, cbData);
|
|
|
|
|
IfFailRet(cap.SkipProlog());
|
|
|
|
|
|
|
|
|
|
// Retrieve the major and minor version from the attribute.
|
|
|
|
|
UINT32 u4;
|
|
|
|
|
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
usMajorVersion = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
usMinorVersion = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
usBuildNumber = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
usRevisionNumber = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
|
{
|
|
|
|
|
pAssembly->GetVersion(&usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the version information.
|
|
|
|
|
struct versioninfo
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
USHORT usMajorVersion; // Major Version.
|
2015-01-30 14:14:42 -08:00
|
|
|
USHORT usMinorVersion; // Minor Version.
|
|
|
|
|
USHORT usBuildNumber; // Build Number.
|
|
|
|
|
USHORT usRevisionNumber; // Revision Number.
|
|
|
|
|
} ver;
|
|
|
|
|
|
|
|
|
|
// <REVISIT_TODO> An issue here is that usMajor is used twice and usMinor not at all.
|
|
|
|
|
// We're not fixing that because everyone has a major version, so all the
|
2019-11-02 06:29:45 -07:00
|
|
|
// generated guids would change, which is breaking. To compensate, if
|
2015-01-30 14:14:42 -08:00
|
|
|
// the minor is non-zero, we add it separately, below.</REVISIT_TODO>
|
|
|
|
|
ver.usMajorVersion = usMajorVersion;
|
|
|
|
|
ver.usMinorVersion = usMajorVersion; // Don't fix this line!
|
|
|
|
|
ver.usBuildNumber = usBuildNumber;
|
|
|
|
|
ver.usRevisionNumber = usRevisionNumber;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Resize the output buffer.
|
|
|
|
|
IfFailGo(rDef.ReSizeNoThrow(cbCur + cchName*sizeof(WCHAR) + sizeof(szTypeLibKeyName)-1 + cbSN + sizeof(ver)+sizeof(USHORT)));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Put it all together. Name first.
|
|
|
|
|
WszMultiByteToWideChar(CP_ACP,0, pszName,cbName+1, (LPWSTR)(&rDef[cbCur]),cchName);
|
|
|
|
|
pName = (LPWSTR)(&rDef[cbCur]);
|
|
|
|
|
for (pch=pName; *pch; ++pch)
|
|
|
|
|
if (*pch == '.' || *pch == ' ')
|
|
|
|
|
*pch = '_';
|
|
|
|
|
else
|
|
|
|
|
if (iswupper(*pch))
|
|
|
|
|
*pch = towlower(*pch);
|
|
|
|
|
cbCur += (cchName-1)*sizeof(WCHAR);
|
|
|
|
|
memcpy(&rDef[cbCur], szTypeLibKeyName, sizeof(szTypeLibKeyName)-1);
|
|
|
|
|
cbCur += sizeof(szTypeLibKeyName)-1;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Version.
|
|
|
|
|
memcpy(&rDef[cbCur], &ver, sizeof(ver));
|
|
|
|
|
cbCur += sizeof(ver);
|
|
|
|
|
|
|
|
|
|
// If minor version is non-zero, add it to the hash. It should have been in the ver struct,
|
|
|
|
|
// but due to a bug, it was omitted there, and fixing it "right" would have been
|
|
|
|
|
// breaking. So if it isn't zero, add it; if it is zero, don't add it. Any
|
|
|
|
|
// possible value of minor thus generates a different guid, and a value of 0 still generates
|
|
|
|
|
// the guid that the original, buggy, code generated.
|
|
|
|
|
if (usMinorVersion != 0)
|
|
|
|
|
{
|
|
|
|
|
SET_UNALIGNED_16(&rDef[cbCur], usMinorVersion);
|
|
|
|
|
cbCur += sizeof(USHORT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Public key.
|
|
|
|
|
memcpy(&rDef[cbCur], pSN, cbSN);
|
|
|
|
|
cbCur += cbSN;
|
|
|
|
|
|
|
|
|
|
if (pcbFetched)
|
|
|
|
|
*pcbFetched = cbCur;
|
|
|
|
|
|
|
|
|
|
ErrExit:
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include <optsmallperfcritical.h>
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Release helper, must be called in preemptive mode. Only use this variant if
|
2019-11-02 06:29:45 -07:00
|
|
|
// you already know you're in preemptive mode for other reasons.
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG SafeReleasePreemp(IUnknown * pUnk, RCW * pRCW)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL {
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_PREEMPTIVE;
|
|
|
|
|
PRECONDITION(CheckPointer(pUnk, NULL_OK));
|
|
|
|
|
} CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
if (pUnk == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// Message pump could happen, so arbitrary managed code could run.
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation | FaultViolation);
|
|
|
|
|
|
2019-06-17 17:15:56 -07:00
|
|
|
return pUnk->Release();
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Release helper, enables and disables GC during call-outs
|
|
|
|
|
ULONG SafeRelease(IUnknown* pUnk, RCW* pRCW)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL {
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pUnk, NULL_OK));
|
|
|
|
|
} CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
if (pUnk == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ULONG res = 0;
|
|
|
|
|
Thread * const pThread = GetThreadNULLOk();
|
|
|
|
|
GCX_PREEMP_NO_DTOR_HAVE_THREAD(pThread);
|
|
|
|
|
|
|
|
|
|
// Message pump could happen, so arbitrary managed code could run.
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation | FaultViolation);
|
|
|
|
|
|
2019-06-17 17:15:56 -07:00
|
|
|
res = pUnk->Release();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
GCX_PREEMP_NO_DTOR_END();
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include <optdefault.h>
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Determines if a COM object can be cast to the specified type.
|
|
|
|
|
BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if (!obj)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (pTargetMT->IsInterface())
|
|
|
|
|
{
|
|
|
|
|
return Object::SupportsInterface(obj, pTargetMT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-11-09 17:49:12 -08:00
|
|
|
return obj->GetMethodTable()->CanCastToClass(pTargetMT);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-27 14:20:09 -07:00
|
|
|
// Returns TRUE iff the argument represents the "__ComObject" type.
|
|
|
|
|
BOOL IsComObjectClass(TypeHandle type)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
|
|
|
if (!type.IsTypeDesc())
|
|
|
|
|
{
|
|
|
|
|
MethodTable *pMT = type.AsMethodTable();
|
|
|
|
|
|
|
|
|
|
if (pMT->IsComObjectType())
|
|
|
|
|
{
|
|
|
|
|
// May be __ComObject or typed RCW. __ComObject must have already been loaded
|
|
|
|
|
// if we see an MT marked like this so calling the *NoInit method is sufficient.
|
|
|
|
|
|
|
|
|
|
return pMT == g_pBaseCOMObject;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
VOID
|
|
|
|
|
ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2019-05-20 15:15:52 -07:00
|
|
|
ReadBestFitCustomAttribute(pMD->GetModule(),
|
2015-01-30 14:14:42 -08:00
|
|
|
pMD->GetMethodTable()->GetCl(),
|
|
|
|
|
BestFit, ThrowOnUnmappableChar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
2019-05-20 15:15:52 -07:00
|
|
|
ReadBestFitCustomAttribute(Module* pModule, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
// Set the attributes to their defaults, just to be safe.
|
|
|
|
|
*BestFit = TRUE;
|
|
|
|
|
*ThrowOnUnmappableChar = FALSE;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
2019-05-20 15:15:52 -07:00
|
|
|
PRECONDITION(CheckPointer(pModule));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
HRESULT hr;
|
|
|
|
|
BYTE* pData;
|
2019-11-02 06:29:45 -07:00
|
|
|
ULONG cbCount;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// A well-formed BestFitMapping attribute will have at least 5 bytes
|
|
|
|
|
// 1,2 for the prolog (should be 0x1, 0x0)
|
|
|
|
|
// 3 for the BestFitMapping bool
|
|
|
|
|
// 4,5 for the number of named parameters (will be 0 if ThrowOnUnmappableChar doesn't exist)
|
|
|
|
|
// 6 - 29 for the description of ThrowOnUnmappableChar
|
|
|
|
|
// 30 for the ThrowOnUnmappableChar bool
|
|
|
|
|
|
|
|
|
|
// Try the assembly first
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pModule->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::BestFitMapping, (const VOID**)(&pData), &cbCount);
|
2015-01-30 14:14:42 -08:00
|
|
|
if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE((cbCount == 5) || (cbCount == 30));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// index to 2 to skip prolog
|
|
|
|
|
*BestFit = pData[2] != 0;
|
|
|
|
|
|
|
|
|
|
// If this parameter exists,
|
|
|
|
|
if (cbCount == 30)
|
|
|
|
|
// index to end of data to skip description of named argument
|
|
|
|
|
*ThrowOnUnmappableChar = pData[29] != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now try the interface/class/struct
|
|
|
|
|
if (IsNilToken(cl))
|
|
|
|
|
return;
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pModule->GetCustomAttribute(cl, WellKnownAttribute::BestFitMapping, (const VOID**)(&pData), &cbCount);
|
2015-01-30 14:14:42 -08:00
|
|
|
if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE((cbCount == 5) || (cbCount == 30));
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
// index to 2 to skip prolog
|
2015-01-30 14:14:42 -08:00
|
|
|
*BestFit = pData[2] != 0;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// If this parameter exists,
|
|
|
|
|
if (cbCount == 30)
|
|
|
|
|
// index to end of data to skip description of named argument
|
|
|
|
|
*ThrowOnUnmappableChar = pData[29] != 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-01-06 08:49:08 +02:00
|
|
|
int InternalWideToAnsi(_In_reads_(iNumWideChars) LPCWSTR szWideString, int iNumWideChars, _Out_writes_bytes_opt_(cbAnsiBufferSize) LPSTR szAnsiString, int cbAnsiBufferSize, BOOL fBestFit, BOOL fThrowOnUnmappableChar)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((szWideString == 0) || (iNumWideChars == 0) || (szAnsiString == 0) || (cbAnsiBufferSize == 0))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
DWORD flags = 0;
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (fBestFit == FALSE)
|
|
|
|
|
flags = WC_NO_BEST_FIT_CHARS;
|
|
|
|
|
|
|
|
|
|
if (fThrowOnUnmappableChar)
|
|
|
|
|
{
|
|
|
|
|
BOOL DefaultCharUsed = FALSE;
|
|
|
|
|
retval = WszWideCharToMultiByte(CP_ACP,
|
|
|
|
|
flags,
|
|
|
|
|
szWideString,
|
|
|
|
|
iNumWideChars,
|
|
|
|
|
szAnsiString,
|
|
|
|
|
cbAnsiBufferSize,
|
|
|
|
|
NULL,
|
|
|
|
|
&DefaultCharUsed);
|
|
|
|
|
DWORD lastError = GetLastError();
|
|
|
|
|
|
|
|
|
|
if (retval == 0)
|
|
|
|
|
{
|
2023-08-24 22:50:20 +02:00
|
|
|
INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX;
|
2015-01-30 14:14:42 -08:00
|
|
|
COMPlusThrowHR(HRESULT_FROM_WIN32(lastError));
|
2023-08-24 22:50:20 +02:00
|
|
|
UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(true);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DefaultCharUsed)
|
|
|
|
|
{
|
|
|
|
|
struct HelperThrow
|
|
|
|
|
{
|
|
|
|
|
static void Throw()
|
|
|
|
|
{
|
|
|
|
|
COMPlusThrow( kArgumentException, IDS_EE_MARSHAL_UNMAPPABLE_CHAR );
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
ENCLOSE_IN_EXCEPTION_HANDLER( HelperThrow::Throw );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
retval = WszWideCharToMultiByte(CP_ACP,
|
|
|
|
|
flags,
|
|
|
|
|
szWideString,
|
|
|
|
|
iNumWideChars,
|
|
|
|
|
szAnsiString,
|
|
|
|
|
cbAnsiBufferSize,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
DWORD lastError = GetLastError();
|
|
|
|
|
|
|
|
|
|
if (retval == 0)
|
|
|
|
|
{
|
2023-08-24 22:50:20 +02:00
|
|
|
INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX;
|
2015-01-30 14:14:42 -08:00
|
|
|
COMPlusThrowHR(HRESULT_FROM_WIN32(lastError));
|
2023-08-24 22:50:20 +02:00
|
|
|
UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(true);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 14:41:08 -08:00
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
HRESULT TryParseClassInterfaceAttribute(
|
2019-05-20 15:15:52 -07:00
|
|
|
_In_ Module *pModule,
|
2018-12-13 14:41:08 -08:00
|
|
|
_In_ mdToken tkObj,
|
|
|
|
|
_Out_ CorClassIfaceAttr *val)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
2019-05-20 15:15:52 -07:00
|
|
|
PRECONDITION(CheckPointer(pModule));
|
2018-12-13 14:41:08 -08:00
|
|
|
PRECONDITION(CheckPointer(val));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END
|
|
|
|
|
|
|
|
|
|
const BYTE *pVal = nullptr;
|
|
|
|
|
ULONG cbVal = 0;
|
2019-05-20 15:15:52 -07:00
|
|
|
HRESULT hr = pModule->GetCustomAttribute(tkObj, WellKnownAttribute::ClassInterface, (const void**)&pVal, &cbVal);
|
2018-12-13 14:41:08 -08:00
|
|
|
if (hr != S_OK)
|
|
|
|
|
{
|
|
|
|
|
*val = clsIfNone;
|
|
|
|
|
return S_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CustomAttributeParser cap(pVal, cbVal);
|
|
|
|
|
if (FAILED(cap.ValidateProlog()))
|
|
|
|
|
return COR_E_BADIMAGEFORMAT;
|
|
|
|
|
|
2022-06-16 11:07:56 -07:00
|
|
|
UINT8 u1;
|
2018-12-13 14:41:08 -08:00
|
|
|
if (FAILED(cap.GetU1(&u1)))
|
|
|
|
|
return COR_E_BADIMAGEFORMAT;
|
|
|
|
|
|
|
|
|
|
*val = (CorClassIfaceAttr)(u1);
|
|
|
|
|
_ASSERTE(*val < clsIfLast);
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
//---------------------------------------------------------
|
2019-11-02 06:29:45 -07:00
|
|
|
// Read the ClassInterfaceType custom attribute info from
|
2018-12-13 14:41:08 -08:00
|
|
|
// both assembly level and class level
|
2015-01-30 14:14:42 -08:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
CorClassIfaceAttr ReadClassInterfaceTypeCustomAttribute(TypeHandle type)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(!type.IsInterface());
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
CorClassIfaceAttr attrValueMaybe;
|
2018-12-13 14:41:08 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// First look for the class interface attribute at the class level.
|
|
|
|
|
HRESULT hr = TryParseClassInterfaceAttribute(type.GetModule(), type.GetCl(), &attrValueMaybe);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
|
|
|
|
|
|
|
|
|
|
if (hr == S_FALSE)
|
|
|
|
|
{
|
|
|
|
|
// Check the class interface attribute at the assembly level.
|
|
|
|
|
Assembly *pAssembly = type.GetAssembly();
|
2022-01-28 17:00:27 -08:00
|
|
|
hr = TryParseClassInterfaceAttribute(pAssembly->GetModule(), pAssembly->GetManifestToken(), &attrValueMaybe);
|
2018-12-13 14:41:08 -08:00
|
|
|
if (FAILED(hr))
|
|
|
|
|
ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
if (hr == S_OK)
|
|
|
|
|
return attrValueMaybe;
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
return DEFAULT_CLASS_INTERFACE_TYPE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-04 00:27:00 +08:00
|
|
|
#ifdef FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// GetErrorInfo helper, enables and disables GC during call-outs
|
|
|
|
|
HRESULT SafeGetErrorInfo(IErrorInfo **ppIErrInfo)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(ppIErrInfo));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
*ppIErrInfo = NULL;
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
hr = GetErrorInfo(0, ppIErrInfo);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-04 00:27:00 +08:00
|
|
|
#endif // FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
#include <optsmallperfcritical.h>
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// QI helper, enables and disables GC during call-outs
|
|
|
|
|
HRESULT SafeQueryInterface(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk)
|
|
|
|
|
{
|
|
|
|
|
STATIC_CONTRACT_NOTHROW;
|
|
|
|
|
STATIC_CONTRACT_GC_TRIGGERS;
|
|
|
|
|
STATIC_CONTRACT_MODE_ANY;
|
|
|
|
|
_ASSERTE(pUnk);
|
|
|
|
|
_ASSERTE(pResUnk);
|
|
|
|
|
|
|
|
|
|
Thread * const pThread = GetThreadNULLOk();
|
|
|
|
|
|
|
|
|
|
*pResUnk = NULL;
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP_NO_DTOR_HAVE_THREAD(pThread);
|
|
|
|
|
|
|
|
|
|
BEGIN_CONTRACT_VIOLATION(ThrowsViolation); // message pump could happen, so arbitrary managed code could run
|
|
|
|
|
|
|
|
|
|
struct Param { HRESULT * const hr; IUnknown** const pUnk; REFIID riid; IUnknown*** const pResUnk; } param = { &hr, &pUnk, riid, &pResUnk };
|
|
|
|
|
#define PAL_TRY_ARG(argName) (*(pParam->argName))
|
|
|
|
|
#define PAL_TRY_REFARG(argName) (pParam->argName)
|
|
|
|
|
PAL_TRY(Param * const, pParam, ¶m)
|
|
|
|
|
{
|
2017-03-05 17:51:40 -08:00
|
|
|
PAL_TRY_ARG(hr) = PAL_TRY_ARG(pUnk)->QueryInterface(PAL_TRY_REFARG(riid), (void**) PAL_TRY_ARG(pResUnk));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{
|
|
|
|
|
#if defined(STACK_GUARDS_DEBUG)
|
|
|
|
|
// Catching and just swallowing an exception means we need to tell
|
|
|
|
|
// the SO code that it should go back to normal operation, as it
|
|
|
|
|
// currently thinks that the exception is still on the fly.
|
|
|
|
|
GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
PAL_ENDTRY;
|
|
|
|
|
#undef PAL_TRY_ARG
|
|
|
|
|
#undef PAL_TRY_REFARG
|
|
|
|
|
|
|
|
|
|
END_CONTRACT_VIOLATION;
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
LOG((LF_INTEROP, LL_EVERYTHING, hr == S_OK ? "QI Succeeded\n" : "QI Failed\n"));
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Ensure if the QI returned ok that it actually set a pointer.
|
|
|
|
|
if (hr == S_OK)
|
|
|
|
|
{
|
|
|
|
|
if (*pResUnk == NULL)
|
|
|
|
|
hr = E_NOINTERFACE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP_NO_DTOR_END();
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
2019-11-02 06:29:45 -07:00
|
|
|
// QI helper, must be called in preemptive mode. Faster than the MODE_ANY version
|
2015-01-30 14:14:42 -08:00
|
|
|
// because it doesn't need to toggle the mode. Use this version only if you already
|
|
|
|
|
// know that you're in preemptive mode for other reasons.
|
|
|
|
|
HRESULT SafeQueryInterfacePreemp(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk)
|
|
|
|
|
{
|
|
|
|
|
STATIC_CONTRACT_NOTHROW;
|
|
|
|
|
STATIC_CONTRACT_GC_TRIGGERS;
|
|
|
|
|
STATIC_CONTRACT_MODE_PREEMPTIVE;
|
|
|
|
|
_ASSERTE(pUnk);
|
|
|
|
|
_ASSERTE(pResUnk);
|
|
|
|
|
|
|
|
|
|
Thread * const pThread = GetThreadNULLOk();
|
|
|
|
|
|
|
|
|
|
*pResUnk = NULL;
|
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
|
|
BEGIN_CONTRACT_VIOLATION(ThrowsViolation); // message pump could happen, so arbitrary managed code could run
|
|
|
|
|
|
|
|
|
|
struct Param { HRESULT * const hr; IUnknown** const pUnk; REFIID riid; IUnknown*** const pResUnk; } param = { &hr, &pUnk, riid, &pResUnk };
|
|
|
|
|
#define PAL_TRY_ARG(argName) (*(pParam->argName))
|
|
|
|
|
#define PAL_TRY_REFARG(argName) (pParam->argName)
|
|
|
|
|
PAL_TRY(Param * const, pParam, ¶m)
|
|
|
|
|
{
|
2017-03-05 17:51:40 -08:00
|
|
|
PAL_TRY_ARG(hr) = PAL_TRY_ARG(pUnk)->QueryInterface(PAL_TRY_REFARG(riid), (void**) PAL_TRY_ARG(pResUnk));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{
|
|
|
|
|
#if defined(STACK_GUARDS_DEBUG)
|
|
|
|
|
// Catching and just swallowing an exception means we need to tell
|
|
|
|
|
// the SO code that it should go back to normal operation, as it
|
|
|
|
|
// currently thinks that the exception is still on the fly.
|
|
|
|
|
GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
PAL_ENDTRY;
|
|
|
|
|
#undef PAL_TRY_ARG
|
|
|
|
|
#undef PAL_TRY_REFARG
|
|
|
|
|
|
|
|
|
|
END_CONTRACT_VIOLATION;
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
LOG((LF_INTEROP, LL_EVERYTHING, hr == S_OK ? "QI Succeeded\n" : "QI Failed\n"));
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Ensure if the QI returned ok that it actually set a pointer.
|
|
|
|
|
if (hr == S_OK)
|
|
|
|
|
{
|
|
|
|
|
if (*pResUnk == NULL)
|
|
|
|
|
hr = E_NOINTERFACE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
#include <optdefault.h>
|
|
|
|
|
|
2021-07-30 00:09:56 +02:00
|
|
|
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Cleanup helpers
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
void MinorCleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
2016-09-08 11:27:24 -07:00
|
|
|
PRECONDITION( GCHeapUtilities::IsGCInProgress() || ( (g_fEEShutDown & ShutDown_SyncBlock) && g_fProcessDetach ) );
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
2021-07-30 00:09:56 +02:00
|
|
|
#ifdef FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
// No need to notify the thread that the RCW is in use here.
|
|
|
|
|
// This is a privileged function called during GC or shutdown.
|
|
|
|
|
RCW* pRCW = pInteropInfo->GetRawRCW();
|
|
|
|
|
if (pRCW)
|
|
|
|
|
pRCW->MinorCleanup();
|
2021-07-30 00:09:56 +02:00
|
|
|
#endif // FEATURE_COMINTEROP
|
2020-03-06 23:37:47 -08:00
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMWRAPPERS
|
|
|
|
|
void* eoc;
|
|
|
|
|
if (pInteropInfo->TryGetExternalComObjectContext(&eoc))
|
|
|
|
|
ComWrappersNative::MarkExternalComObjectContextCollected(eoc);
|
|
|
|
|
#endif // FEATURE_COMWRAPPERS
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if ((g_fEEShutDown & ShutDown_SyncBlock) && g_fProcessDetach )
|
|
|
|
|
MinorCleanupSyncBlockComData(pInteropInfo);
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
ComClassFactory* pComClassFactory = pInteropInfo->GetComClassFactory();
|
|
|
|
|
if (pComClassFactory)
|
|
|
|
|
{
|
|
|
|
|
delete pComClassFactory;
|
|
|
|
|
pInteropInfo->SetComClassFactory(NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
|
2021-07-30 00:09:56 +02:00
|
|
|
#ifdef FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
// No need to notify the thread that the RCW is in use here.
|
|
|
|
|
// This is only called during finalization of a __ComObject so no one
|
|
|
|
|
// else could have a reference to this object.
|
|
|
|
|
RCW* pRCW = pInteropInfo->GetRawRCW();
|
|
|
|
|
if (pRCW)
|
|
|
|
|
{
|
|
|
|
|
pInteropInfo->SetRawRCW(NULL);
|
|
|
|
|
pRCW->Cleanup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ComCallWrapper* pCCW = pInteropInfo->GetCCW();
|
|
|
|
|
if (pCCW)
|
|
|
|
|
{
|
|
|
|
|
pInteropInfo->SetCCW(NULL);
|
|
|
|
|
pCCW->Cleanup();
|
|
|
|
|
}
|
2021-07-30 00:09:56 +02:00
|
|
|
#endif // FEATURE_COMINTEROP
|
2020-03-06 23:37:47 -08:00
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMWRAPPERS
|
2020-06-16 20:10:20 -07:00
|
|
|
pInteropInfo->ClearManagedObjectComWrappers(&ComWrappersNative::DestroyManagedObjectComWrapper);
|
2020-03-06 23:37:47 -08:00
|
|
|
|
|
|
|
|
void* eoc;
|
|
|
|
|
if (pInteropInfo->TryGetExternalComObjectContext(&eoc))
|
|
|
|
|
{
|
|
|
|
|
(void)pInteropInfo->TrySetExternalComObjectContext(NULL, eoc);
|
|
|
|
|
ComWrappersNative::DestroyExternalComObjectContext(eoc);
|
|
|
|
|
}
|
|
|
|
|
#endif // FEATURE_COMWRAPPERS
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 00:09:56 +02:00
|
|
|
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Helper to release all of the RCWs in the specified context across all caches.
|
|
|
|
|
// If pCtxCookie is NULL, release all RCWs
|
2020-11-11 19:16:53 -08:00
|
|
|
static void ReleaseRCWsInCaches(LPVOID pCtxCookie)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pCtxCookie, NULL_OK));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2022-11-09 21:57:59 -08:00
|
|
|
// Release all the RCW's that live in the AppDomain.
|
|
|
|
|
AppDomain::GetCurrentDomain()->ReleaseRCWs(pCtxCookie);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
if (!g_fEEShutDown)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
GCX_COOP();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// If the finalizer thread has sync blocks to clean up or if it is in the process
|
|
|
|
|
// of cleaning up the sync blocks, we need to wait for it to finish.
|
|
|
|
|
if (FinalizerThread::GetFinalizerThread()->RequireSyncBlockCleanup() || SyncBlockCache::GetSyncBlockCache()->IsSyncBlockCleanupInProgress())
|
|
|
|
|
FinalizerThread::FinalizerThreadWait();
|
|
|
|
|
|
|
|
|
|
// If more sync blocks were added while the finalizer thread was calling the finalizers
|
|
|
|
|
// or while it was transitioning into a context to clean up the IP's, we need to wake
|
|
|
|
|
// it up again to have it clean up the newly added sync blocks.
|
|
|
|
|
if (FinalizerThread::GetFinalizerThread()->RequireSyncBlockCleanup() || SyncBlockCache::GetSyncBlockCache()->IsSyncBlockCleanupInProgress())
|
|
|
|
|
FinalizerThread::FinalizerThreadWait();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:16:53 -08:00
|
|
|
void ReleaseRCWsInCachesNoThrow(LPVOID pCtxCookie)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
DISABLED(NOTHROW);
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pCtxCookie, NULL_OK));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
ReleaseRCWsInCaches(pCtxCookie);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Marshalling Helpers
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Convert an IUnknown to CCW, returns NULL if the pUnk is not on
|
|
|
|
|
// a managed tear-off (OR) if the pUnk is to a managed tear-off that
|
|
|
|
|
// has been aggregated
|
|
|
|
|
ComCallWrapper* GetCCWFromIUnknown(IUnknown* pUnk, BOOL bEnableCustomization)
|
|
|
|
|
{
|
|
|
|
|
CONTRACT (ComCallWrapper*)
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pUnk));
|
|
|
|
|
POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
|
|
|
|
|
}
|
|
|
|
|
CONTRACT_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
ComCallWrapper* pWrap = MapIUnknownToWrapper(pUnk);
|
|
|
|
|
if (pWrap != NULL)
|
|
|
|
|
{
|
|
|
|
|
// check if this wrapper is aggregated
|
|
|
|
|
if (pWrap->GetOuter() != NULL)
|
|
|
|
|
{
|
|
|
|
|
pWrap = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
RETURN pWrap;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-07 14:31:24 -08:00
|
|
|
HRESULT LoadRegTypeLib(_In_ REFGUID guid,
|
|
|
|
|
_In_ unsigned short wVerMajor,
|
|
|
|
|
_In_ unsigned short wVerMinor,
|
|
|
|
|
_Outptr_ ITypeLib **pptlib)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
*pptlib = NULL;
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
|
|
|
|
|
BSTRHolder wzPath;
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
hr = QueryPathOfRegTypeLib(guid, wVerMajor, wVerMinor, LOCALE_USER_DEFAULT, &wzPath);
|
2018-12-07 14:31:24 -08:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
2020-01-31 19:36:44 -05:00
|
|
|
#ifdef HOST_64BIT
|
2018-12-07 14:31:24 -08:00
|
|
|
REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_64BIT);
|
|
|
|
|
#else
|
|
|
|
|
REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_32BIT);
|
2020-01-31 19:36:44 -05:00
|
|
|
#endif // HOST_64BIT
|
2018-12-07 14:31:24 -08:00
|
|
|
hr = LoadTypeLibEx(wzPath, rk, pptlib);
|
|
|
|
|
}
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
hr = GET_EXCEPTION()->GetHR();
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID EnsureComStarted(BOOL fCoInitCurrentThread)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
2021-03-25 14:26:44 -07:00
|
|
|
PRECONDITION(GetThreadNULLOk() || !fCoInitCurrentThread);
|
2015-01-30 14:14:42 -08:00
|
|
|
PRECONDITION(g_fEEStarted);
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
if (g_fComStarted == FALSE)
|
|
|
|
|
{
|
|
|
|
|
FinalizerThread::GetFinalizerThread()->SetRequiresCoInitialize();
|
|
|
|
|
|
|
|
|
|
// Attempt to set the thread's apartment model (to MTA by default). May not
|
|
|
|
|
// succeed (if someone beat us to the punch). That doesn't matter (since
|
|
|
|
|
// COM+ objects are now apartment agile), we only care that a CoInitializeEx
|
|
|
|
|
// has been performed on this thread by us.
|
|
|
|
|
if (fCoInitCurrentThread)
|
2020-07-07 08:05:20 -07:00
|
|
|
GetThread()->SetApartment(Thread::AS_InMTA);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// set the finalizer event
|
|
|
|
|
FinalizerThread::EnableFinalization();
|
|
|
|
|
|
|
|
|
|
g_fComStarted = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT EnsureComStartedNoThrow(BOOL fCoInitCurrentThread)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(g_fEEStarted);
|
2021-03-25 14:26:44 -07:00
|
|
|
PRECONDITION(GetThreadNULLOk() != NULL); // Should always be inside BEGIN_EXTERNAL_ENTRYPOINT
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
|
|
|
|
if (!g_fComStarted)
|
|
|
|
|
{
|
|
|
|
|
GCX_COOP();
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
EnsureComStarted(fCoInitCurrentThread);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH_HRESULT(hr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include <optsmallperfcritical.h>
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// AddRef helper, enables and disables GC during call-outs
|
|
|
|
|
ULONG SafeAddRef(IUnknown* pUnk)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG res = ~0;
|
|
|
|
|
if (pUnk == NULL)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP_NO_DTOR();
|
|
|
|
|
|
|
|
|
|
// @TODO: Consider special-casing this when we know it's one of ours so
|
|
|
|
|
// that we can avoid having to 'leave' and then 'enter'.
|
|
|
|
|
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation); // arbitrary managed code could run
|
|
|
|
|
|
2017-03-05 17:51:40 -08:00
|
|
|
res = pUnk->AddRef();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
GCX_PREEMP_NO_DTOR_END();
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// AddRef helper, must be called in preemptive mode. Only use this variant if
|
2019-11-02 06:29:45 -07:00
|
|
|
// you already know you're in preemptive mode for other reasons.
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG SafeAddRefPreemp(IUnknown* pUnk)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_PREEMPTIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG res = ~0;
|
|
|
|
|
if (pUnk == NULL)
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
// @TODO: Consider special-casing this when we know it's one of ours so
|
|
|
|
|
// that we can avoid having to 'leave' and then 'enter'.
|
|
|
|
|
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation); // arbitrary managed code could run
|
|
|
|
|
|
2017-03-05 17:51:40 -08:00
|
|
|
res = pUnk->AddRef();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
#include <optdefault.h>
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Ole RPC seems to return an inconsistent SafeArray for arrays created with
|
|
|
|
|
// SafeArrayVector(VT_BSTR). OleAut's SafeArrayGetVartype() doesn't notice
|
|
|
|
|
// the inconsistency and returns a valid-seeming (but wrong vartype.)
|
|
|
|
|
// Our version is more discriminating. This should only be used for
|
|
|
|
|
// marshaling scenarios where we can assume unmanaged code permissions
|
|
|
|
|
// (and hence are already in a position of trusting unmanaged data.)
|
|
|
|
|
|
2018-12-13 14:41:08 -08:00
|
|
|
HRESULT ClrSafeArrayGetVartype(_In_ SAFEARRAY *psa, _Out_ VARTYPE *pvt)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(psa));
|
|
|
|
|
PRECONDITION(CheckPointer(pvt));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
if (pvt == NULL || psa == NULL)
|
|
|
|
|
{
|
2018-12-13 14:41:08 -08:00
|
|
|
// This is the HRESULT returned by OLEAUT if either of the args are null.
|
2015-01-30 14:14:42 -08:00
|
|
|
return E_INVALIDARG;
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
USHORT fFeatures = psa->fFeatures;
|
|
|
|
|
USHORT hardwiredType = (fFeatures & (FADF_BSTR|FADF_UNKNOWN|FADF_DISPATCH|FADF_VARIANT));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if (hardwiredType == FADF_BSTR && psa->cbElements == sizeof(BSTR))
|
|
|
|
|
{
|
|
|
|
|
*pvt = VT_BSTR;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
else if (hardwiredType == FADF_UNKNOWN && psa->cbElements == sizeof(IUnknown*))
|
|
|
|
|
{
|
|
|
|
|
*pvt = VT_UNKNOWN;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
else if (hardwiredType == FADF_DISPATCH && psa->cbElements == sizeof(IDispatch*))
|
|
|
|
|
{
|
|
|
|
|
*pvt = VT_DISPATCH;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
else if (hardwiredType == FADF_VARIANT && psa->cbElements == sizeof(VARIANT))
|
|
|
|
|
{
|
|
|
|
|
*pvt = VT_VARIANT;
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
|
|
|
|
|
// We have got a SAFEARRAY. Oleaut32.dll should have been loaded.
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation);
|
|
|
|
|
return ::SafeArrayGetVartype(psa, pvt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// // safe VariantChangeType
|
|
|
|
|
// Release helper, enables and disables GC during call-outs
|
2016-02-01 10:48:17 -08:00
|
|
|
HRESULT SafeVariantChangeType(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
|
2015-01-30 14:14:42 -08:00
|
|
|
unsigned short wFlags, VARTYPE vt)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pVarRes));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pVarSrc));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
if (pVarRes)
|
|
|
|
|
{
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
2017-03-05 17:51:40 -08:00
|
|
|
hr = VariantChangeType(pVarRes, pVarSrc, wFlags, vt);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
hr = GET_EXCEPTION()->GetHR();
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
2016-02-01 10:48:17 -08:00
|
|
|
HRESULT SafeVariantChangeTypeEx(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
|
2015-01-30 14:14:42 -08:00
|
|
|
LCID lcid, unsigned short wFlags, VARTYPE vt)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pVarRes));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pVarSrc));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
GCX_PREEMP();
|
|
|
|
|
_ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
|
|
|
|
|
CONTRACT_VIOLATION(ThrowsViolation);
|
|
|
|
|
|
2017-03-05 17:51:40 -08:00
|
|
|
HRESULT hr = VariantChangeTypeEx (pVarRes, pVarSrc,lcid,wFlags,vt);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
void SafeVariantInit(VARIANT* pVar)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pVar));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// From the oa sources
|
|
|
|
|
V_VT(pVar) = VT_EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// void SafeReleaseStream(IStream *pStream)
|
|
|
|
|
void SafeReleaseStream(IStream *pStream)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pStream));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
|
|
|
|
|
{
|
2017-03-05 17:51:40 -08:00
|
|
|
HRESULT hr = CoReleaseMarshalData(pStream);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
2022-05-16 09:53:31 -07:00
|
|
|
UTF8 logStr[512];
|
|
|
|
|
sprintf_s(logStr, ARRAY_SIZE(logStr), "Object gone: CoReleaseMarshalData returned %x, file %s, line %d\n", hr, __FILE__, __LINE__);
|
2015-01-30 14:14:42 -08:00
|
|
|
LogInterop(logStr);
|
|
|
|
|
if (hr != S_OK)
|
|
|
|
|
{
|
2020-01-23 20:40:29 +02:00
|
|
|
// Reset the stream to the beginning
|
2015-01-30 14:14:42 -08:00
|
|
|
LARGE_INTEGER li;
|
|
|
|
|
LISet32(li, 0);
|
|
|
|
|
ULARGE_INTEGER li2;
|
|
|
|
|
pStream->Seek(li, STREAM_SEEK_SET, &li2);
|
|
|
|
|
hr = CoReleaseMarshalData(pStream);
|
2022-05-16 09:53:31 -07:00
|
|
|
sprintf_s(logStr, ARRAY_SIZE(logStr), "Object gone: CoReleaseMarshalData returned %x, file %s, line %d\n", hr, __FILE__, __LINE__);
|
2015-01-30 14:14:42 -08:00
|
|
|
LogInterop(logStr);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG cbRef = SafeReleasePreemp(pStream);
|
|
|
|
|
LogInteropRelease(pStream, cbRef, "Release marshal Stream");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// is the iid represent an IClassX for this class
|
|
|
|
|
BOOL IsIClassX(MethodTable *pMT, REFIID riid, ComMethodTable **ppComMT)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pMT));
|
|
|
|
|
PRECONDITION(CheckPointer(ppComMT));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// Walk up the hierarchy starting at the specified method table and compare
|
|
|
|
|
// the IID's of the IClassX's against the specified IID.
|
|
|
|
|
while (pMT != NULL)
|
|
|
|
|
{
|
|
|
|
|
ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(pMT);
|
|
|
|
|
if (pTemplate->SupportsIClassX())
|
|
|
|
|
{
|
|
|
|
|
ComMethodTable *pComMT =
|
|
|
|
|
ComCallWrapperTemplate::SetupComMethodTableForClass(pMT, FALSE);
|
|
|
|
|
_ASSERTE(pComMT);
|
|
|
|
|
|
|
|
|
|
if (IsEqualIID(riid, pComMT->GetIID()))
|
|
|
|
|
{
|
|
|
|
|
*ppComMT = pComMT;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pMT = pMT->GetComPlusParentMethodTable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// Returns TRUE if we support IClassX (the auto-generated class interface)
|
|
|
|
|
// for the given class.
|
|
|
|
|
BOOL ClassSupportsIClassX(MethodTable *pMT)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// OBJECTREF AllocateComObject_ForManaged(MethodTable* pMT)
|
|
|
|
|
OBJECTREF AllocateComObject_ForManaged(MethodTable* pMT)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
PRECONDITION(CheckPointer(pMT));
|
|
|
|
|
PRECONDITION(pMT->IsComObjectType());
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// Calls to COM up ahead.
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
EnsureComStarted();
|
|
|
|
|
|
|
|
|
|
ComClassFactory *pComClsFac = (ComClassFactory *)GetComClassFactory(pMT);
|
|
|
|
|
return pComClsFac->CreateInstance(pMT, TRUE);
|
|
|
|
|
}
|
|
|
|
|
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// This method returns the default interface for the class.
|
|
|
|
|
DefaultInterfaceType GetDefaultInterfaceForClassInternal(TypeHandle hndClass, TypeHandle *pHndDefClass)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(!hndClass.IsNull());
|
|
|
|
|
PRECONDITION(CheckPointer(pHndDefClass));
|
|
|
|
|
PRECONDITION(!hndClass.GetMethodTable()->IsInterface());
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// Set ppDefComMT to NULL before we start.
|
|
|
|
|
*pHndDefClass = TypeHandle();
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
|
MethodTable* pClassMT = hndClass.GetMethodTable();
|
|
|
|
|
const void* pvData;
|
|
|
|
|
ULONG cbData;
|
|
|
|
|
CorClassIfaceAttr ClassItfType;
|
|
|
|
|
BOOL bComVisible;
|
|
|
|
|
|
|
|
|
|
PREFIX_ASSUME(pClassMT != NULL);
|
|
|
|
|
|
|
|
|
|
if (pClassMT->IsComImport())
|
|
|
|
|
{
|
|
|
|
|
ClassItfType = clsIfNone;
|
|
|
|
|
bComVisible = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ClassItfType = pClassMT->GetComClassInterfaceType();
|
|
|
|
|
bComVisible = IsTypeVisibleFromCom(hndClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the class is not COM visible, then its default interface is IUnknown.
|
|
|
|
|
if (!bComVisible)
|
|
|
|
|
return DefaultInterfaceType_IUnknown;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Start by checking for the ComDefaultInterface attribute.
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pClassMT->GetCustomAttribute(WellKnownAttribute::ComDefaultInterface, &pvData, &cbData);
|
2015-01-30 14:14:42 -08:00
|
|
|
IfFailThrow(hr);
|
|
|
|
|
if (hr == S_OK && cbData > 2)
|
|
|
|
|
{
|
|
|
|
|
TypeHandle DefItfType;
|
|
|
|
|
AppDomain *pCurrDomain = SystemDomain::GetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
CustomAttributeParser cap(pvData, cbData);
|
|
|
|
|
IfFailThrow(cap.SkipProlog());
|
|
|
|
|
|
|
|
|
|
LPCUTF8 szStr;
|
|
|
|
|
ULONG cbStr;
|
|
|
|
|
IfFailThrow(cap.GetNonNullString(&szStr, &cbStr));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Allocate a new buffer that will contain the name of the default COM interface.
|
|
|
|
|
StackSString defItf(SString::Utf8, szStr, cbStr);
|
|
|
|
|
|
|
|
|
|
// Load the default COM interface specified in the CA.
|
|
|
|
|
{
|
|
|
|
|
GCX_COOP();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2023-03-31 14:30:34 -07:00
|
|
|
DefItfType = TypeName::GetTypeReferencedByCustomAttribute(defItf.GetUnicode(), pClassMT->GetAssembly());
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// If the type handle isn't a named type, then throw an exception using
|
|
|
|
|
// the name of the type obtained from pCurrInterfaces.
|
|
|
|
|
if (!DefItfType.GetMethodTable())
|
|
|
|
|
{
|
|
|
|
|
// This should only occur for TypeDesc's.
|
|
|
|
|
StackSString ssClassName;
|
|
|
|
|
DefineFullyQualifiedNameForClassW()
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMDEFITF,
|
|
|
|
|
GetFullyQualifiedNameForClassW(pClassMT),
|
|
|
|
|
defItf.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, if the type is not an interface thrown an exception using the actual
|
|
|
|
|
// name of the type.
|
|
|
|
|
if (!DefItfType.IsInterface())
|
|
|
|
|
{
|
|
|
|
|
StackSString ssClassName;
|
|
|
|
|
StackSString ssInvalidItfName;
|
|
|
|
|
pClassMT->_GetFullyQualifiedNameForClass(ssClassName);
|
|
|
|
|
DefItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMDEFITF,
|
|
|
|
|
ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure the class implements the interface.
|
2019-11-05 09:51:21 -08:00
|
|
|
if (!pClassMT->CanCastToInterface(DefItfType.GetMethodTable()))
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
StackSString ssClassName;
|
|
|
|
|
StackSString ssInvalidItfName;
|
|
|
|
|
pClassMT->_GetFullyQualifiedNameForClass(ssClassName);
|
|
|
|
|
DefItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_COMDEFITFNOTSUPPORTED,
|
|
|
|
|
ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The default interface is valid so return it.
|
|
|
|
|
*pHndDefClass = DefItfType;
|
|
|
|
|
return DefaultInterfaceType_Explicit;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
// If the class's interface type is AutoDispatch or AutoDual then return either the
|
2015-01-30 14:14:42 -08:00
|
|
|
// IClassX for the current class or IDispatch.
|
|
|
|
|
if (ClassItfType != clsIfNone)
|
|
|
|
|
{
|
|
|
|
|
*pHndDefClass = hndClass;
|
|
|
|
|
return ClassItfType == clsIfAutoDisp ? DefaultInterfaceType_AutoDispatch : DefaultInterfaceType_AutoDual;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The class interface is set to NONE for this level of the hierarchy. So we need to check
|
|
|
|
|
// to see if this class implements an interface.
|
|
|
|
|
|
|
|
|
|
// Search for the first COM visible implemented interface. We start with the most
|
2019-11-02 06:29:45 -07:00
|
|
|
// derived class and work our way up the hierarchy.
|
2015-01-30 14:14:42 -08:00
|
|
|
for (MethodTable *pParentMT = pClassMT->GetParentMethodTable(); pParentMT; pParentMT = pParentMT->GetParentMethodTable())
|
|
|
|
|
{
|
|
|
|
|
MethodTable::InterfaceMapIterator it = pClassMT->IterateInterfaceMap();
|
|
|
|
|
while (it.Next())
|
|
|
|
|
{
|
|
|
|
|
MethodTable *pItfMT = it.GetInterfaceInfo()->GetApproxMethodTable(pClassMT->GetLoaderModule());
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Skip generic interfaces. Classic COM interop does not support these and we don't
|
|
|
|
|
// use the result of this function in WinRT scenarios. WinRT parameter marshaling
|
|
|
|
|
// doesn't come here at all because the default interface is always specified using
|
|
|
|
|
// the DefaultAttribute. Field marshaling does come here but WinRT does not support
|
|
|
|
|
// fields of reference types other than string.
|
|
|
|
|
if (!pItfMT->HasInstantiation())
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
// If the interface is visible from COM and not implemented by our parent,
|
2015-01-30 14:14:42 -08:00
|
|
|
// then use it as the default.
|
|
|
|
|
if (IsTypeVisibleFromCom(TypeHandle(pItfMT)) && !pParentMT->ImplementsInterface(pItfMT))
|
|
|
|
|
{
|
|
|
|
|
*pHndDefClass = TypeHandle(pItfMT);
|
|
|
|
|
return DefaultInterfaceType_Explicit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the class is a COM import with no interfaces, then its default interface will
|
|
|
|
|
// be IUnknown.
|
|
|
|
|
if (pClassMT->IsComImport())
|
|
|
|
|
return DefaultInterfaceType_IUnknown;
|
|
|
|
|
|
|
|
|
|
// If we have a managed parent class then return its default interface.
|
|
|
|
|
MethodTable *pParentClass = pClassMT->GetComPlusParentMethodTable();
|
|
|
|
|
if (pParentClass)
|
|
|
|
|
return GetDefaultInterfaceForClassWrapper(TypeHandle(pParentClass), pHndDefClass);
|
|
|
|
|
|
|
|
|
|
// Check to see if the class is an extensible RCW.
|
|
|
|
|
if (pClassMT->IsComObjectType())
|
|
|
|
|
return DefaultInterfaceType_BaseComClass;
|
|
|
|
|
|
|
|
|
|
// The class has no interfaces and is marked as ClassInterfaceType.None.
|
|
|
|
|
return DefaultInterfaceType_IUnknown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DefaultInterfaceType GetDefaultInterfaceForClassWrapper(TypeHandle hndClass, TypeHandle *pHndDefClass)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(!hndClass.IsNull());
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
if (!hndClass.IsTypeDesc())
|
|
|
|
|
{
|
|
|
|
|
ComCallWrapperTemplate *pTemplate = hndClass.AsMethodTable()->GetComCallWrapperTemplate();
|
|
|
|
|
if (pTemplate != NULL)
|
|
|
|
|
{
|
|
|
|
|
// if CCW template is available, use its cache
|
|
|
|
|
MethodTable *pDefaultItf;
|
|
|
|
|
DefaultInterfaceType itfType = pTemplate->GetDefaultInterface(&pDefaultItf);
|
|
|
|
|
|
|
|
|
|
*pHndDefClass = TypeHandle(pDefaultItf);
|
|
|
|
|
return itfType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return GetDefaultInterfaceForClassInternal(hndClass, pHndDefClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT TryGetDefaultInterfaceForClass(TypeHandle hndClass, TypeHandle *pHndDefClass, DefaultInterfaceType *pDefItfType)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(!hndClass.IsNull());
|
|
|
|
|
PRECONDITION(CheckPointer(pHndDefClass));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pDefItfType));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
GCX_COOP();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
OBJECTREF pThrowable = NULL;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
GCPROTECT_BEGIN(pThrowable)
|
|
|
|
|
{
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
*pDefItfType = GetDefaultInterfaceForClassWrapper(hndClass, pHndDefClass);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
pThrowable = GET_THROWABLE();
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(SwallowAllExceptions);
|
|
|
|
|
|
|
|
|
|
if (pThrowable != NULL)
|
|
|
|
|
hr = SetupErrorInfo(pThrowable);
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the default interface for a class if it's an explicit interface or the AutoDual
|
|
|
|
|
// class interface. Sets *pbDispatch otherwise. This is the logic used by array marshaling
|
|
|
|
|
// in code:OleVariant::MarshalInterfaceArrayComToOleHelper.
|
|
|
|
|
MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pMT));
|
|
|
|
|
PRECONDITION(!pMT->IsInterface());
|
|
|
|
|
PRECONDITION(CheckPointer(pbDispatch));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
TypeHandle hndDefItfClass;
|
|
|
|
|
DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass);
|
|
|
|
|
|
|
|
|
|
switch (DefItfType)
|
|
|
|
|
{
|
|
|
|
|
case DefaultInterfaceType_Explicit:
|
|
|
|
|
case DefaultInterfaceType_AutoDual:
|
|
|
|
|
{
|
|
|
|
|
return hndDefItfClass.GetMethodTable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DefaultInterfaceType_IUnknown:
|
|
|
|
|
case DefaultInterfaceType_BaseComClass:
|
|
|
|
|
{
|
|
|
|
|
*pbDispatch = FALSE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case DefaultInterfaceType_AutoDispatch:
|
|
|
|
|
{
|
|
|
|
|
*pbDispatch = TRUE;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE(!"Invalid default interface type!");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// This method retrieves the list of source interfaces for a given class.
|
|
|
|
|
void GetComSourceInterfacesForClass(MethodTable *pMT, CQuickArray<MethodTable *> &rItfList)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(CheckPointer(pMT));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
const void* pvData;
|
|
|
|
|
ULONG cbData;
|
|
|
|
|
CQuickArray<CHAR> qbCurrInterfaces;
|
|
|
|
|
|
|
|
|
|
GCX_COOP();
|
|
|
|
|
|
|
|
|
|
// Reset the size of the interface list to 0.
|
|
|
|
|
rItfList.Shrink(0);
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
// Starting at the specified class MT retrieve the COM source interfaces
|
2015-01-30 14:14:42 -08:00
|
|
|
// of all the striped of the hierarchy.
|
|
|
|
|
for (; pMT != NULL; pMT = pMT->GetParentMethodTable())
|
|
|
|
|
{
|
|
|
|
|
// See if there is any [source] interface at this level of the hierarchy.
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pMT->GetCustomAttribute(WellKnownAttribute::ComSourceInterfaces, &pvData, &cbData);
|
2015-01-30 14:14:42 -08:00
|
|
|
IfFailThrow(hr);
|
|
|
|
|
if (hr == S_OK && cbData > 2)
|
|
|
|
|
{
|
|
|
|
|
AppDomain *pCurrDomain = SystemDomain::GetCurrentDomain();
|
|
|
|
|
|
|
|
|
|
CustomAttributeParser cap(pvData, cbData);
|
|
|
|
|
IfFailThrow(cap.SkipProlog());
|
|
|
|
|
|
|
|
|
|
while (cap.BytesLeft() != 0)
|
|
|
|
|
{
|
|
|
|
|
// Uncompress the current string of source interfaces.
|
|
|
|
|
BYTE const *pbStr;
|
|
|
|
|
ULONG cbStr;
|
|
|
|
|
IfFailThrow(cap.GetData(&pbStr, &cbStr));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Allocate a new buffer that will contain the current list of source interfaces.
|
|
|
|
|
qbCurrInterfaces.ReSizeThrows(cbStr + 1);
|
|
|
|
|
LPUTF8 strCurrInterfaces = qbCurrInterfaces.Ptr();
|
|
|
|
|
memcpyNoGCRefs(strCurrInterfaces, pbStr, cbStr);
|
|
|
|
|
strCurrInterfaces[cbStr] = 0;
|
|
|
|
|
LPUTF8 pCurrInterfaces = strCurrInterfaces;
|
|
|
|
|
LPUTF8 pCurrInterfacesEnd = pCurrInterfaces + cbStr + 1;
|
|
|
|
|
|
|
|
|
|
while (pCurrInterfaces < pCurrInterfacesEnd && *pCurrInterfaces != 0)
|
|
|
|
|
{
|
|
|
|
|
// Load the COM source interface specified in the CA.
|
|
|
|
|
TypeHandle ItfType;
|
2023-03-31 14:30:34 -07:00
|
|
|
ItfType = TypeName::GetTypeReferencedByCustomAttribute(pCurrInterfaces, pMT->GetAssembly());
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// If the type handle isn't a named type, then throw an exception using
|
|
|
|
|
// the name of the type obtained from pCurrInterfaces.
|
|
|
|
|
if (!ItfType.GetMethodTable())
|
|
|
|
|
{
|
|
|
|
|
// This should only occur for TypeDesc's.
|
|
|
|
|
StackSString ssInvalidItfName(SString::Utf8, pCurrInterfaces);
|
|
|
|
|
DefineFullyQualifiedNameForClassW()
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
|
|
|
|
|
GetFullyQualifiedNameForClassW(pMT),
|
|
|
|
|
ssInvalidItfName.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, if the type is not an interface thrown an exception using the actual
|
|
|
|
|
// name of the type.
|
|
|
|
|
if (!ItfType.IsInterface())
|
|
|
|
|
{
|
|
|
|
|
StackSString ssClassName;
|
|
|
|
|
StackSString ssInvalidItfName;
|
|
|
|
|
pMT->_GetFullyQualifiedNameForClass(ssClassName);
|
|
|
|
|
ItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
|
|
|
|
|
ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure the source interface is not generic.
|
|
|
|
|
if (ItfType.HasInstantiation())
|
|
|
|
|
{
|
|
|
|
|
StackSString ssClassName;
|
|
|
|
|
StackSString ssInvalidItfName;
|
|
|
|
|
pMT->_GetFullyQualifiedNameForClass(ssClassName);
|
|
|
|
|
ItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
|
|
|
|
|
COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
|
|
|
|
|
ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Retrieve the IID of the COM source interface.
|
|
|
|
|
IID ItfIID;
|
2019-11-02 06:29:45 -07:00
|
|
|
ItfType.GetMethodTable()->GetGuid(&ItfIID, TRUE);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Go through the list of source interfaces and check to see if the new one is a duplicate.
|
|
|
|
|
// It can be a duplicate either if it is the same interface or if it has the same IID.
|
|
|
|
|
BOOL bItfInList = FALSE;
|
|
|
|
|
for (UINT i = 0; i < rItfList.Size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (rItfList[i] == ItfType.GetMethodTable())
|
|
|
|
|
{
|
|
|
|
|
bItfInList = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IID ItfIID2;
|
|
|
|
|
rItfList[i]->GetGuid(&ItfIID2, TRUE);
|
|
|
|
|
if (IsEqualIID(ItfIID, ItfIID2))
|
|
|
|
|
{
|
|
|
|
|
bItfInList = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the COM source interface is not in the list then add it.
|
|
|
|
|
if (!bItfInList)
|
|
|
|
|
{
|
|
|
|
|
size_t OldSize = rItfList.Size();
|
|
|
|
|
rItfList.ReSizeThrows(OldSize + 1);
|
|
|
|
|
rItfList[OldSize] = ItfType.GetMethodTable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process the next COM source interfaces in the CA.
|
|
|
|
|
pCurrInterfaces += strlen(pCurrInterfaces) + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// These methods convert a native IEnumVARIANT to a managed IEnumerator.
|
|
|
|
|
OBJECTREF ConvertEnumVariantToMngEnum(IEnumVARIANT *pNativeEnum)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
OBJECTREF MngEnum = NULL;
|
|
|
|
|
OBJECTREF EnumeratorToEnumVariantMarshaler = NULL;
|
|
|
|
|
GCPROTECT_BEGIN(EnumeratorToEnumVariantMarshaler)
|
|
|
|
|
{
|
|
|
|
|
// Retrieve the custom marshaler and the MD to use to convert the IEnumVARIANT.
|
|
|
|
|
StdMngIEnumerator *pStdMngIEnumInfo = SystemDomain::GetCurrentDomain()->GetMngStdInterfacesInfo()->GetStdMngIEnumerator();
|
|
|
|
|
MethodDesc *pEnumNativeToManagedMD = pStdMngIEnumInfo->GetCustomMarshalerMD(CustomMarshalerMethods_MarshalNativeToManaged);
|
|
|
|
|
EnumeratorToEnumVariantMarshaler = pStdMngIEnumInfo->GetCustomMarshaler();
|
|
|
|
|
MethodDescCallSite enumNativeToManaged(pEnumNativeToManagedMD, &EnumeratorToEnumVariantMarshaler);
|
|
|
|
|
|
|
|
|
|
// Prepare the arguments that will be passed to MarshalNativeToManaged.
|
|
|
|
|
ARG_SLOT MarshalNativeToManagedArgs[] = {
|
|
|
|
|
ObjToArgSlot(EnumeratorToEnumVariantMarshaler),
|
|
|
|
|
(ARG_SLOT)pNativeEnum
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Retrieve the managed view for the current native interface pointer.
|
|
|
|
|
MngEnum = enumNativeToManaged.Call_RetOBJECTREF(MarshalNativeToManagedArgs);
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
|
|
|
|
|
return MngEnum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// This method converts an OLE_COLOR to a System.Color.
|
|
|
|
|
void ConvertOleColorToSystemColor(OLE_COLOR SrcOleColor, SYSTEMCOLOR *pDestSysColor)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// Retrieve the method desc to use for the current AD.
|
2019-11-02 06:29:45 -07:00
|
|
|
MethodDesc *pOleColorToSystemColorMD =
|
2019-01-14 15:49:45 -08:00
|
|
|
GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
MethodDescCallSite oleColorToSystemColor(pOleColorToSystemColorMD);
|
|
|
|
|
|
|
|
|
|
_ASSERTE(pOleColorToSystemColorMD->HasRetBuffArg());
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
ARG_SLOT Args[] =
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
PtrToArgSlot(pDestSysColor),
|
|
|
|
|
PtrToArgSlot(SrcOleColor)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
oleColorToSystemColor.Call(Args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// This method converts a System.Color to an OLE_COLOR.
|
|
|
|
|
OLE_COLOR ConvertSystemColorToOleColor(OBJECTREF *pSrcObj)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Retrieve the method desc to use for the current AD.
|
2019-11-02 06:29:45 -07:00
|
|
|
MethodDesc *pSystemColorToOleColorMD =
|
2019-01-14 15:49:45 -08:00
|
|
|
GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
|
2015-01-30 14:14:42 -08:00
|
|
|
MethodDescCallSite systemColorToOleColor(pSystemColorToOleColorMD);
|
|
|
|
|
|
|
|
|
|
// Set up the args and call the method.
|
|
|
|
|
SYSTEMCOLOR *pSrcSysColor = (SYSTEMCOLOR *)(*pSrcObj)->UnBox();
|
|
|
|
|
return systemColorToOleColor.CallWithValueTypes_RetOleColor((const ARG_SLOT *)&pSrcSysColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
2019-11-02 06:29:45 -07:00
|
|
|
// This method generates a stringized version of a class interface that contains
|
2015-01-30 14:14:42 -08:00
|
|
|
// the signatures of all the methods and fields.
|
|
|
|
|
ULONG GetStringizedClassItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(!InterfaceType.IsNull());
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
LPCWSTR szName;
|
2015-01-30 14:14:42 -08:00
|
|
|
ULONG cchName;
|
|
|
|
|
MethodTable* pIntfMT = InterfaceType.GetMethodTable();
|
|
|
|
|
PREFIX_ASSUME(pIntfMT != NULL);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
MethodTable* pDeclaringMT = NULL;
|
|
|
|
|
DWORD nSlots; // Slots on the pseudo interface.
|
|
|
|
|
mdToken tkMb; // A method or field token.
|
|
|
|
|
ULONG cbCur;
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
|
|
// Should be an actual class.
|
|
|
|
|
_ASSERTE(!pIntfMT->IsInterface());
|
|
|
|
|
|
|
|
|
|
// See what sort of IClassX this class gets.
|
|
|
|
|
TypeHandle thDefItf;
|
|
|
|
|
BOOL bGenerateMethods = FALSE;
|
|
|
|
|
DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pIntfMT), &thDefItf);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// The results apply to this class if the thDefItf is this class itself, not a parent class.
|
|
|
|
|
// A side effect is that [ComVisible(false)] types' guids are generated without members.
|
|
|
|
|
if (thDefItf.GetMethodTable() == pIntfMT && DefItfType == DefaultInterfaceType_AutoDual)
|
|
|
|
|
bGenerateMethods = TRUE;
|
|
|
|
|
|
|
|
|
|
// Get the name of the class.
|
|
|
|
|
DefineFullyQualifiedNameForClassW();
|
|
|
|
|
szName = GetFullyQualifiedNameForClassNestedAwareW(pIntfMT);
|
2023-05-11 14:15:05 -07:00
|
|
|
cchName = (ULONG)u16_strlen(szName);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Start with the interface name.
|
|
|
|
|
cbCur = cchName * sizeof(WCHAR);
|
|
|
|
|
rDef.ReSizeThrows(cbCur + sizeof(WCHAR));
|
|
|
|
|
wcscpy_s(reinterpret_cast<LPWSTR>(rDef.Ptr()), rDef.Size()/sizeof(WCHAR), szName);
|
|
|
|
|
|
|
|
|
|
if (bGenerateMethods)
|
|
|
|
|
{
|
|
|
|
|
ComMTMemberInfoMap MemberMap(pIntfMT); // The map of members.
|
|
|
|
|
|
|
|
|
|
// Retrieve the method properties.
|
|
|
|
|
MemberMap.Init(sizeof(void*));
|
|
|
|
|
|
|
|
|
|
CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
|
|
|
|
|
nSlots = (DWORD)rProps.Size();
|
|
|
|
|
|
|
|
|
|
// Now add the methods to the TypeInfo.
|
|
|
|
|
for (i=0; i<nSlots; ++i)
|
|
|
|
|
{
|
|
|
|
|
ComMTMethodProps *pProps = &rProps[i];
|
|
|
|
|
if (pProps->bMemberVisible)
|
|
|
|
|
{
|
|
|
|
|
if (pProps->semantic < FieldSemanticOffset)
|
|
|
|
|
{
|
|
|
|
|
pDeclaringMT = pProps->pMeth->GetMethodTable();
|
|
|
|
|
tkMb = pProps->pMeth->GetMemberDef();
|
|
|
|
|
cbCur = GetStringizedMethodDef(pDeclaringMT, tkMb, rDef, cbCur);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ComCallMethodDesc *pFieldMeth; // A MethodDesc for a field call.
|
|
|
|
|
FieldDesc *pField; // A FieldDesc.
|
|
|
|
|
pFieldMeth = reinterpret_cast<ComCallMethodDesc*>(pProps->pMeth);
|
|
|
|
|
pField = pFieldMeth->GetFieldDesc();
|
|
|
|
|
pDeclaringMT = pField->GetApproxEnclosingMethodTable();
|
|
|
|
|
tkMb = pField->GetMemberDef();
|
|
|
|
|
cbCur = GetStringizedFieldDef(pDeclaringMT, tkMb, rDef, cbCur);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Return the number of bytes.
|
|
|
|
|
return cbCur;
|
|
|
|
|
} // ULONG GetStringizedClassItfDef()
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Helper to get the GUID of a class interface.
|
|
|
|
|
void GenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(!InterfaceType.IsNull());
|
|
|
|
|
PRECONDITION(CheckPointer(pGuid));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
LPWSTR szName; // Name to turn to a guid.
|
|
|
|
|
ULONG cchName; // Length of the name (possibly after decoration).
|
|
|
|
|
CQuickArray<BYTE> rName; // Buffer to accumulate signatures.
|
|
|
|
|
ULONG cbCur; // Current offset.
|
|
|
|
|
HRESULT hr = S_OK; // A result.
|
|
|
|
|
|
|
|
|
|
cbCur = GetStringizedClassItfDef(InterfaceType, rName);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Pad up to a whole WCHAR.
|
|
|
|
|
if (cbCur % sizeof(WCHAR))
|
|
|
|
|
{
|
|
|
|
|
int cbDelta = sizeof(WCHAR) - (cbCur % sizeof(WCHAR));
|
|
|
|
|
rName.ReSizeThrows(cbCur + cbDelta);
|
|
|
|
|
memset(rName.Ptr() + cbCur, 0, cbDelta);
|
|
|
|
|
cbCur += cbDelta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Point to the new buffer.
|
|
|
|
|
cchName = cbCur / sizeof(WCHAR);
|
|
|
|
|
szName = reinterpret_cast<LPWSTR>(rName.Ptr());
|
|
|
|
|
|
|
|
|
|
// Generate guid from name.
|
|
|
|
|
CorGuidFromNameW(pGuid, szName, cchName);
|
|
|
|
|
} // void GenerateClassItfGuid()
|
|
|
|
|
|
|
|
|
|
HRESULT TryGenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(!InterfaceType.IsNull());
|
|
|
|
|
PRECONDITION(CheckPointer(pGuid));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
GCX_COOP();
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
OBJECTREF pThrowable = NULL;
|
|
|
|
|
|
|
|
|
|
GCPROTECT_BEGIN(pThrowable)
|
|
|
|
|
{
|
|
|
|
|
EX_TRY
|
|
|
|
|
{
|
|
|
|
|
GenerateClassItfGuid(InterfaceType, pGuid);
|
|
|
|
|
}
|
|
|
|
|
EX_CATCH
|
|
|
|
|
{
|
|
|
|
|
pThrowable = GET_THROWABLE();
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH (SwallowAllExceptions);
|
|
|
|
|
|
|
|
|
|
if (pThrowable != NULL)
|
|
|
|
|
hr = SetupErrorInfo(pThrowable);
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
return hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Helper to get the GUID of the typelib that is created from an assembly.
|
|
|
|
|
HRESULT GetTypeLibGuidForAssembly(Assembly *pAssembly, GUID *pGuid)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pAssembly));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pGuid));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
CQuickArray<BYTE> rName; // String for guid.
|
|
|
|
|
ULONG cbData; // Size of the string in bytes.
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2022-01-28 17:00:27 -08:00
|
|
|
// Get GUID from Assembly, else Generate from name.
|
|
|
|
|
hr = pAssembly->GetMDImport()->GetItemGuid(TokenFromRid(1, mdtAssembly), pGuid);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
if (*pGuid == GUID_NULL)
|
|
|
|
|
{
|
|
|
|
|
// Get the string.
|
|
|
|
|
IfFailGo(GetStringizedTypeLibGuidForAssembly(pAssembly, rName, 0, &cbData));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Pad to a whole WCHAR.
|
|
|
|
|
if (cbData % sizeof(WCHAR))
|
|
|
|
|
{
|
|
|
|
|
IfFailGo(rName.ReSizeNoThrow(cbData + sizeof(WCHAR)-(cbData%sizeof(WCHAR))));
|
|
|
|
|
while (cbData % sizeof(WCHAR))
|
|
|
|
|
rName[cbData++] = 0;
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Turn into guid
|
|
|
|
|
CorGuidFromNameW(pGuid, (LPWSTR)rName.Ptr(), cbData/sizeof(WCHAR));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrExit:
|
|
|
|
|
return hr;
|
|
|
|
|
} // HRESULT GetTypeLibGuidForAssembly()
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Helper to get the version of the typelib that is created from an assembly.
|
|
|
|
|
HRESULT GetTypeLibVersionForAssembly(
|
2018-12-13 14:41:08 -08:00
|
|
|
_In_ Assembly *pAssembly,
|
|
|
|
|
_Out_ USHORT *pMajorVersion,
|
|
|
|
|
_Out_ USHORT *pMinorVersion)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pAssembly));
|
|
|
|
|
PRECONDITION(CheckPointer(pMajorVersion));
|
|
|
|
|
PRECONDITION(CheckPointer(pMinorVersion));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
2018-12-13 14:41:08 -08:00
|
|
|
HRESULT hr;
|
|
|
|
|
const BYTE *pbData = nullptr;
|
|
|
|
|
ULONG cbData = 0;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// Check to see if the TypeLibVersionAttribute is set.
|
2022-01-28 17:00:27 -08:00
|
|
|
IfFailRet(pAssembly->GetMDImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_TYPELIBVERSION_TYPE, (const void**)&pbData, &cbData));
|
2018-12-13 14:41:08 -08:00
|
|
|
|
|
|
|
|
// For attribute contents, see https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.typelibversionattribute
|
|
|
|
|
if (cbData >= (2 + 2 * sizeof(UINT32)))
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CustomAttributeParser cap(pbData, cbData);
|
|
|
|
|
IfFailRet(cap.SkipProlog());
|
|
|
|
|
|
|
|
|
|
// Retrieve the major and minor version from the attribute.
|
|
|
|
|
UINT32 u4;
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
*pMajorVersion = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
IfFailRet(cap.GetU4(&u4));
|
|
|
|
|
*pMinorVersion = GET_VERSION_USHORT_FROM_INT(u4);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Use the assembly's major and minor version number.
|
2018-12-13 14:41:08 -08:00
|
|
|
IfFailRet(pAssembly->GetVersion(pMajorVersion, pMinorVersion, nullptr, nullptr));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
2018-12-13 14:41:08 -08:00
|
|
|
// Some system don't handle a typelib with a version of 0.0.
|
|
|
|
|
// When that happens, change it to 1.0.
|
2015-01-30 14:14:42 -08:00
|
|
|
if (*pMajorVersion == 0 && *pMinorVersion == 0)
|
|
|
|
|
*pMajorVersion = 1;
|
2018-12-13 14:41:08 -08:00
|
|
|
|
|
|
|
|
return S_OK;
|
2015-01-30 14:14:42 -08:00
|
|
|
} // HRESULT TypeLibExporter::GetTypeLibVersionFromAssembly()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// This method determines if a member is visible from COM.
|
|
|
|
|
BOOL IsMethodVisibleFromCom(MethodDesc *pMD)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pMD));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
mdProperty pd;
|
2015-01-30 14:14:42 -08:00
|
|
|
LPCUTF8 pPropName;
|
|
|
|
|
ULONG uSemantic;
|
|
|
|
|
mdMethodDef md = pMD->GetMemberDef();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// See if there is property information for this member.
|
|
|
|
|
hr = pMD->GetModule()->GetPropertyInfoForMethodDef(md, &pd, &pPropName, &uSemantic);
|
|
|
|
|
IfFailThrow(hr);
|
|
|
|
|
|
|
|
|
|
if (hr == S_OK)
|
|
|
|
|
{
|
|
|
|
|
return IsMemberVisibleFromCom(pMD->GetMethodTable(), pd, md);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IsMemberVisibleFromCom(pMD->GetMethodTable(), md, mdTokenNil);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
2018-07-20 00:48:07 -07:00
|
|
|
// This method determines if a type is visible from COM or not based on
|
2015-01-30 14:14:42 -08:00
|
|
|
// its visibility. This version of the method works with a type handle.
|
|
|
|
|
// This version will ignore a type's generic attributes.
|
|
|
|
|
//
|
|
|
|
|
// This API should *never* be called directly!!!
|
2018-07-20 00:48:07 -07:00
|
|
|
static BOOL SpecialIsGenericTypeVisibleFromCom(TypeHandle hndType)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
2018-07-20 00:48:07 -07:00
|
|
|
PRECONDITION(!hndType.IsNull());
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2018-07-20 00:48:07 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
DWORD dwFlags;
|
|
|
|
|
mdTypeDef tdEnclosingType;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
const BYTE * pVal;
|
|
|
|
|
ULONG cbVal;
|
2018-07-20 00:48:07 -07:00
|
|
|
MethodTable * pMT = hndType.GetMethodTable();
|
|
|
|
|
_ASSERTE(pMT);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
mdTypeDef mdType = pMT->GetCl();
|
|
|
|
|
IMDInternalImport * pInternalImport = pMT->GetMDImport();
|
|
|
|
|
Assembly * pAssembly = pMT->GetAssembly();
|
2019-05-20 15:15:52 -07:00
|
|
|
Module * pModule = pMT->GetModule();
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// If the type is a COM imported interface then it is visible from COM.
|
|
|
|
|
if (pMT->IsInterface() && pMT->IsComImport())
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
// If the type is an array, then it is not visible from COM.
|
|
|
|
|
if (pMT->IsArray())
|
|
|
|
|
return FALSE;
|
2018-07-20 00:48:07 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Retrieve the flags for the current type.
|
|
|
|
|
tdEnclosingType = mdType;
|
|
|
|
|
if (FAILED(pInternalImport->GetTypeDefProps(tdEnclosingType, &dwFlags, 0)))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2018-07-20 00:48:07 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Handle nested types.
|
|
|
|
|
while (IsTdNestedPublic(dwFlags))
|
|
|
|
|
{
|
|
|
|
|
hr = pInternalImport->GetNestedClassProps(tdEnclosingType, &tdEnclosingType);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2018-07-20 00:48:07 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Retrieve the flags for the enclosing type.
|
|
|
|
|
if (FAILED(pInternalImport->GetTypeDefProps(tdEnclosingType, &dwFlags, 0)))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-20 00:48:07 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// If the outermost type is not visible then the specified type is not visible.
|
|
|
|
|
if (!IsTdPublic(dwFlags))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
// Check to see if the type has the ComVisible attribute set.
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pModule->GetCustomAttribute(mdType, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
|
2015-01-30 14:14:42 -08:00
|
|
|
if (hr == S_OK)
|
|
|
|
|
{
|
|
|
|
|
CustomAttributeParser cap(pVal, cbVal);
|
|
|
|
|
if (FAILED(cap.SkipProlog()))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UINT8 u1;
|
|
|
|
|
if (FAILED(cap.GetU1(&u1)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return (BOOL)u1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check to see if the assembly has the ComVisible attribute set.
|
2019-05-20 15:15:52 -07:00
|
|
|
hr = pModule->GetCustomAttribute(pAssembly->GetManifestToken(), WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
|
2015-01-30 14:14:42 -08:00
|
|
|
if (hr == S_OK)
|
|
|
|
|
{
|
|
|
|
|
CustomAttributeParser cap(pVal, cbVal);
|
|
|
|
|
if (FAILED(cap.SkipProlog()))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UINT8 u1;
|
|
|
|
|
if (FAILED(cap.GetU1(&u1)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return (BOOL)u1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The type is visible.
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
// This method determines if a type is visible from COM or not based on
|
|
|
|
|
// its visibility. This version of the method works with a type handle.
|
|
|
|
|
BOOL IsTypeVisibleFromCom(TypeHandle hndType)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(!hndType.IsNull());
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
CONTRACTL_END;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
// If the type is a generic type, then it is not visible from COM.
|
|
|
|
|
if (hndType.HasInstantiation() || hndType.IsGenericVariable())
|
|
|
|
|
return FALSE;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
return SpecialIsGenericTypeVisibleFromCom(hndType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// Validate that the given target is valid for the specified type.
|
|
|
|
|
BOOL IsComTargetValidForType(REFLECTCLASSBASEREF* pRefClassObj, OBJECTREF* pTarget)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
PRECONDITION(CheckPointer(pRefClassObj));
|
|
|
|
|
PRECONDITION(CheckPointer(pTarget));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
MethodTable* pInvokedMT = (*pRefClassObj)->GetType().GetMethodTable();
|
|
|
|
|
|
2018-11-09 17:49:12 -08:00
|
|
|
MethodTable* pTargetMT = (*pTarget)->GetMethodTable();
|
2015-01-30 14:14:42 -08:00
|
|
|
_ASSERTE(pTargetMT);
|
|
|
|
|
PREFIX_ASSUME(pInvokedMT != NULL);
|
|
|
|
|
|
|
|
|
|
// If the target class and the invoke class are identical then the invoke is valid.
|
|
|
|
|
if (pTargetMT == pInvokedMT)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
// We always allow calling InvokeMember on a __ComObject type regardless of the type
|
|
|
|
|
// of the target object.
|
|
|
|
|
if (IsComObjectClass((*pRefClassObj)->GetType()))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
// If the class that is being invoked on is an interface then check to see if the
|
|
|
|
|
// target class supports that interface.
|
|
|
|
|
if (pInvokedMT->IsInterface())
|
|
|
|
|
return Object::SupportsInterface(*pTarget, pInvokedMT);
|
|
|
|
|
|
|
|
|
|
// Check to see if the target class inherits from the invoked class.
|
|
|
|
|
while (pTargetMT)
|
|
|
|
|
{
|
|
|
|
|
pTargetMT = pTargetMT->GetParentMethodTable();
|
|
|
|
|
if (pTargetMT == pInvokedMT)
|
|
|
|
|
{
|
|
|
|
|
// The target class inherits from the invoked class.
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is no valid relationship between the invoked and the target classes.
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 08:49:08 +02:00
|
|
|
DISPID ExtractStandardDispId(_In_z_ LPWSTR strStdDispIdMemberName)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
// Find the first character after the = in the standard DISPID member name.
|
2023-05-11 14:15:05 -07:00
|
|
|
LPWSTR strDispId = (LPWSTR)u16_strchr(&strStdDispIdMemberName[STANDARD_DISPID_PREFIX_LENGTH], W('=')) + 1;
|
2015-01-30 14:14:42 -08:00
|
|
|
if (!strDispId)
|
|
|
|
|
COMPlusThrow(kArgumentException, IDS_EE_INVALID_STD_DISPID_NAME);
|
|
|
|
|
|
|
|
|
|
// Validate that the last character of the standard member name is a ].
|
2023-05-11 14:15:05 -07:00
|
|
|
LPWSTR strClosingBracket = (LPWSTR)u16_strchr(strDispId, W(']'));
|
2015-01-30 14:14:42 -08:00
|
|
|
if (!strClosingBracket || (strClosingBracket[1] != 0))
|
|
|
|
|
COMPlusThrow(kArgumentException, IDS_EE_INVALID_STD_DISPID_NAME);
|
|
|
|
|
|
|
|
|
|
// Extract the number from the standard DISPID member name.
|
|
|
|
|
return _wtoi(strDispId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT InvokeExHelper(
|
|
|
|
|
IDispatchEx * pDispEx,
|
|
|
|
|
DISPID MemberID,
|
|
|
|
|
LCID lcid,
|
|
|
|
|
WORD flags,
|
|
|
|
|
DISPPARAMS * pDispParams,
|
|
|
|
|
VARIANT* pVarResult,
|
|
|
|
|
EXCEPINFO * pExcepInfo,
|
|
|
|
|
IServiceProvider *pspCaller)
|
|
|
|
|
{
|
|
|
|
|
STATIC_CONTRACT_THROWS;
|
|
|
|
|
STATIC_CONTRACT_GC_TRIGGERS;
|
|
|
|
|
STATIC_CONTRACT_MODE_ANY;
|
|
|
|
|
|
|
|
|
|
_ASSERTE(pDispEx != NULL);
|
|
|
|
|
|
|
|
|
|
struct Param : CallOutFilterParam {
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
IDispatchEx * pDispEx;
|
|
|
|
|
DISPID MemberID;
|
|
|
|
|
LCID lcid;
|
|
|
|
|
WORD flags;
|
|
|
|
|
DISPPARAMS * pDispParams;
|
|
|
|
|
VARIANT* pVarResult;
|
|
|
|
|
EXCEPINFO * pExcepInfo;
|
|
|
|
|
IServiceProvider * pspCaller;
|
|
|
|
|
}; Param param;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
param.OneShot = TRUE; // Inherited from CallOutFilterParam
|
|
|
|
|
param.hr = S_OK;
|
|
|
|
|
param.pDispEx = pDispEx;
|
|
|
|
|
param.MemberID = MemberID;
|
|
|
|
|
param.lcid = lcid;
|
|
|
|
|
param.flags = flags;
|
|
|
|
|
param.pDispParams = pDispParams;
|
|
|
|
|
param.pVarResult = pVarResult;
|
|
|
|
|
param.pExcepInfo = pExcepInfo;
|
|
|
|
|
param.pspCaller = pspCaller;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
PAL_TRY(Param *, pParam, ¶m)
|
|
|
|
|
{
|
|
|
|
|
pParam->hr = pParam->pDispEx->InvokeEx(pParam->MemberID,
|
|
|
|
|
pParam->lcid,
|
|
|
|
|
pParam->flags,
|
|
|
|
|
pParam->pDispParams,
|
|
|
|
|
pParam->pVarResult,
|
|
|
|
|
pParam->pExcepInfo,
|
|
|
|
|
pParam->pspCaller);
|
|
|
|
|
}
|
|
|
|
|
PAL_EXCEPT_FILTER(CallOutFilter)
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
|
|
|
|
|
}
|
|
|
|
|
PAL_ENDTRY;
|
|
|
|
|
|
|
|
|
|
return param.hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT InvokeHelper(
|
|
|
|
|
IDispatch * pDisp,
|
|
|
|
|
DISPID MemberID,
|
|
|
|
|
REFIID riid,
|
|
|
|
|
LCID lcid,
|
|
|
|
|
WORD flags,
|
|
|
|
|
DISPPARAMS * pDispParams,
|
|
|
|
|
VARIANT* pVarResult,
|
|
|
|
|
EXCEPINFO * pExcepInfo,
|
|
|
|
|
UINT *piArgErr)
|
|
|
|
|
{
|
|
|
|
|
STATIC_CONTRACT_THROWS;
|
|
|
|
|
STATIC_CONTRACT_GC_TRIGGERS;
|
|
|
|
|
STATIC_CONTRACT_MODE_ANY;
|
|
|
|
|
|
|
|
|
|
_ASSERTE(pDisp != NULL);
|
|
|
|
|
|
|
|
|
|
struct Param : CallOutFilterParam {
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
IDispatch * pDisp;
|
|
|
|
|
DISPID MemberID;
|
|
|
|
|
REFIID riid;
|
|
|
|
|
LCID lcid;
|
|
|
|
|
WORD flags;
|
|
|
|
|
DISPPARAMS * pDispParams;
|
|
|
|
|
VARIANT * pVarResult;
|
|
|
|
|
EXCEPINFO * pExcepInfo;
|
|
|
|
|
UINT * piArgErr;
|
|
|
|
|
|
|
|
|
|
Param(REFIID _riid) : riid(_riid) {}
|
|
|
|
|
}; Param param(riid);
|
|
|
|
|
|
|
|
|
|
param.OneShot = TRUE; // Inherited from CallOutFilterParam
|
|
|
|
|
param.hr = S_OK;
|
|
|
|
|
param.pDisp = pDisp;
|
|
|
|
|
param.MemberID = MemberID;
|
|
|
|
|
//param.riid = riid;
|
|
|
|
|
param.lcid = lcid;
|
|
|
|
|
param.flags = flags;
|
|
|
|
|
param.pDispParams = pDispParams;
|
|
|
|
|
param.pVarResult = pVarResult;
|
|
|
|
|
param.pExcepInfo = pExcepInfo;
|
|
|
|
|
param.piArgErr = piArgErr;
|
|
|
|
|
|
|
|
|
|
PAL_TRY(Param *, pParam, ¶m)
|
|
|
|
|
{
|
|
|
|
|
pParam->hr = pParam->pDisp->Invoke(pParam->MemberID,
|
|
|
|
|
pParam->riid,
|
|
|
|
|
pParam->lcid,
|
|
|
|
|
pParam->flags,
|
|
|
|
|
pParam->pDispParams,
|
|
|
|
|
pParam->pVarResult,
|
|
|
|
|
pParam->pExcepInfo,
|
|
|
|
|
pParam->piArgErr);
|
|
|
|
|
}
|
|
|
|
|
PAL_EXCEPT_FILTER(CallOutFilter)
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
|
|
|
|
|
}
|
|
|
|
|
PAL_ENDTRY;
|
|
|
|
|
|
|
|
|
|
return param.hr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DispInvokeConvertObjectToVariant(OBJECTREF *pSrcObj, VARIANT *pDestVar, ByrefArgumentInfo *pByrefArgInfo)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
PRECONDITION(CheckPointer(pSrcObj));
|
|
|
|
|
PRECONDITION(IsProtectedByGCFrame (pSrcObj));
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pDestVar));
|
2015-01-30 14:14:42 -08:00
|
|
|
PRECONDITION(CheckPointer(pByrefArgInfo));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if (pByrefArgInfo->m_bByref)
|
|
|
|
|
{
|
|
|
|
|
if (*pSrcObj == NULL)
|
|
|
|
|
{
|
|
|
|
|
V_VT(pDestVar) = VT_VARIANT | VT_BYREF;
|
|
|
|
|
pDestVar->pvarVal = &pByrefArgInfo->m_Val;
|
|
|
|
|
}
|
2020-07-28 16:10:38 -07:00
|
|
|
else if (CoreLibBinder::IsClass((*pSrcObj)->GetMethodTable(), CLASS__VARIANT_WRAPPER))
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
OBJECTREF WrappedObj = (*((VARIANTWRAPPEROBJECTREF*)pSrcObj))->GetWrappedObject();
|
|
|
|
|
GCPROTECT_BEGIN(WrappedObj)
|
|
|
|
|
{
|
|
|
|
|
OleVariant::MarshalOleVariantForObject(&WrappedObj, &pByrefArgInfo->m_Val);
|
|
|
|
|
V_VT(pDestVar) = VT_VARIANT | VT_BYREF;
|
|
|
|
|
pDestVar->pvarVal = &pByrefArgInfo->m_Val;
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OleVariant::MarshalOleVariantForObject(pSrcObj, &pByrefArgInfo->m_Val);
|
|
|
|
|
OleVariant::CreateByrefVariantForVariant(&pByrefArgInfo->m_Val, pDestVar);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OleVariant::MarshalOleVariantForObject(pSrcObj, pDestVar);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
static void DoIUInvokeDispMethod(IDispatchEx* pDispEx, IDispatch* pDisp, DISPID MemberID, LCID lcid,
|
2015-01-30 14:14:42 -08:00
|
|
|
WORD flags, DISPPARAMS* pDispParams, VARIANT* pVarResult)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
UINT iArgErr;
|
|
|
|
|
EXCEPINFO ExcepInfo;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
|
|
memset(&ExcepInfo, 0, sizeof(EXCEPINFO));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
GCX_COOP();
|
|
|
|
|
OBJECTREF pThrowable = NULL;
|
|
|
|
|
GCPROTECT_BEGIN(pThrowable);
|
|
|
|
|
{
|
|
|
|
|
// Call the method
|
2019-11-02 06:29:45 -07:00
|
|
|
EX_TRY
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
// We are about to make call's to COM so switch to preemptive GC.
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
|
|
|
|
|
if (pDispEx)
|
|
|
|
|
{
|
|
|
|
|
hr = InvokeExHelper(pDispEx, MemberID, lcid, flags, pDispParams,
|
|
|
|
|
pVarResult, &ExcepInfo, NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hr = InvokeHelper( pDisp, MemberID, IID_NULL, lcid, flags,
|
|
|
|
|
pDispParams, pVarResult, &ExcepInfo, &iArgErr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the invoke call failed then throw an exception based on the EXCEPINFO.
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
{
|
|
|
|
|
if (hr == DISP_E_EXCEPTION)
|
|
|
|
|
{
|
|
|
|
|
// This method will free the BSTR's in the EXCEPINFO.
|
|
|
|
|
COMPlusThrowHR(&ExcepInfo);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
COMPlusThrowHR(hr);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
}
|
|
|
|
|
EX_CATCH
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
// If we get here we need to throw an TargetInvocationException
|
|
|
|
|
pThrowable = GET_THROWABLE();
|
|
|
|
|
_ASSERTE(pThrowable != NULL);
|
|
|
|
|
}
|
|
|
|
|
EX_END_CATCH(RethrowTerminalExceptions);
|
|
|
|
|
|
|
|
|
|
if (pThrowable != NULL)
|
|
|
|
|
{
|
|
|
|
|
COMPlusThrow(InvokeUtil::CreateTargetExcept(&pThrowable));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FORCEINLINE void DispParamHolderRelease(VARIANT* value)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
if (V_VT(value) & VT_BYREF)
|
|
|
|
|
{
|
|
|
|
|
VariantHolder TmpVar;
|
|
|
|
|
OleVariant::ExtractContentsFromByrefVariant(value, &TmpVar);
|
|
|
|
|
}
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
SafeVariantClear(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DispParamHolder : public Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
DispParamHolder(VARIANT* p = NULL)
|
|
|
|
|
: Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>(p)
|
|
|
|
|
{
|
|
|
|
|
WRAPPER_NO_CONTRACT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FORCEINLINE void operator=(VARIANT* p)
|
|
|
|
|
{
|
|
|
|
|
WRAPPER_NO_CONTRACT;
|
|
|
|
|
Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>::operator=(p);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
// InvokeDispMethod will convert a set of managed objects and call IDispatch. The
|
|
|
|
|
// result will be returned as a CLR Variant pointed to by pRetVal.
|
2018-12-13 14:41:08 -08:00
|
|
|
void IUInvokeDispMethod(
|
|
|
|
|
REFLECTCLASSBASEREF* pRefClassObj,
|
|
|
|
|
OBJECTREF* pTarget,
|
|
|
|
|
OBJECTREF* pName,
|
|
|
|
|
DISPID *pMemberID,
|
|
|
|
|
OBJECTREF* pArgs,
|
|
|
|
|
OBJECTREF* pByrefModifiers,
|
|
|
|
|
OBJECTREF* pNamedArgs,
|
|
|
|
|
OBJECTREF* pRetVal,
|
|
|
|
|
LCID lcid,
|
|
|
|
|
WORD flags,
|
|
|
|
|
BOOL bIgnoreReturn,
|
|
|
|
|
BOOL bIgnoreCase)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
2019-11-02 06:29:45 -07:00
|
|
|
PRECONDITION(CheckPointer(pTarget));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
UINT i;
|
|
|
|
|
UINT iSrcArg;
|
|
|
|
|
UINT iDestArg;
|
|
|
|
|
VARIANT VarResult;
|
|
|
|
|
UINT cArgs = 0;
|
|
|
|
|
UINT cNamedArgs = 0;
|
|
|
|
|
DISPPARAMS DispParams = {0};
|
|
|
|
|
DISPID* aDispID = NULL;
|
|
|
|
|
DISPID MemberID = 0;
|
|
|
|
|
ByrefArgumentInfo* aByrefArgInfos = NULL;
|
|
|
|
|
BOOL bSomeArgsAreByref = FALSE;
|
|
|
|
|
SafeComHolder<IDispatch> pDisp = NULL;
|
|
|
|
|
SafeComHolder<IDispatchEx> pDispEx = NULL;
|
|
|
|
|
VariantPtrHolder pVarResult = NULL;
|
|
|
|
|
NewArrayHolder<DispParamHolder> params = NULL;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Function initialization.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
SafeVariantInit(&VarResult);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// InteropUtil.h does not know about anything other than OBJECTREF so
|
|
|
|
|
// convert the OBJECTREF's to their real type.
|
|
|
|
|
|
|
|
|
|
STRINGREF* pStrName = (STRINGREF*) pName;
|
|
|
|
|
PTRARRAYREF* pArrArgs = (PTRARRAYREF*) pArgs;
|
|
|
|
|
PTRARRAYREF* pArrByrefModifiers = (PTRARRAYREF*) pByrefModifiers;
|
|
|
|
|
PTRARRAYREF* pArrNamedArgs = (PTRARRAYREF*) pNamedArgs;
|
|
|
|
|
MethodTable* pInvokedMT = (*pRefClassObj)->GetType().GetMethodTable();
|
|
|
|
|
PREFIX_ASSUME(pInvokedMT != NULL);
|
|
|
|
|
|
|
|
|
|
// Retrieve the total count of arguments.
|
|
|
|
|
if (*pArrArgs != NULL)
|
|
|
|
|
cArgs = (*pArrArgs)->GetNumComponents();
|
|
|
|
|
|
|
|
|
|
// Retrieve the count of named arguments.
|
|
|
|
|
if (*pArrNamedArgs != NULL)
|
|
|
|
|
cNamedArgs = (*pArrNamedArgs)->GetNumComponents();
|
|
|
|
|
|
|
|
|
|
// Validate that the target is valid for the specified type.
|
|
|
|
|
if (!IsComTargetValidForType(pRefClassObj, pTarget))
|
2023-05-31 15:11:00 -07:00
|
|
|
COMPlusThrow(kTargetException, W("RFLCT_Targ_ITargMismatch"));
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// If the invoked type is an interface, make sure it is IDispatch based.
|
|
|
|
|
if (pInvokedMT->IsInterface())
|
|
|
|
|
{
|
|
|
|
|
CorIfaceAttr ifaceType = pInvokedMT->GetComInterfaceType();
|
|
|
|
|
if (!IsDispatchBasedItf(ifaceType))
|
|
|
|
|
COMPlusThrow(kTargetInvocationException, IDS_EE_INTERFACE_NOT_DISPATCH_BASED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate that the target is a COM object.
|
|
|
|
|
_ASSERTE((*pTarget)->GetMethodTable()->IsComObjectType());
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Initialize the DISPPARAMS structure.
|
|
|
|
|
//
|
|
|
|
|
if (cArgs > 0)
|
|
|
|
|
{
|
|
|
|
|
UINT cPositionalArgs = cArgs - cNamedArgs;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
DispParams.cArgs = cArgs;
|
|
|
|
|
DispParams.rgvarg = (VARIANTARG *)_alloca(cArgs * sizeof(VARIANTARG));
|
|
|
|
|
params = new DispParamHolder[cArgs];
|
|
|
|
|
|
|
|
|
|
// Initialize all the variants.
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
for (i = 0; i < cArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
SafeVariantInit(&DispParams.rgvarg[i]);
|
|
|
|
|
params[i] = &DispParams.rgvarg[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Retrieve the IDispatch interface that will be invoked on.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (pInvokedMT->IsInterface())
|
|
|
|
|
{
|
|
|
|
|
// The invoked type is a dispatch or dual interface so we will make the
|
|
|
|
|
// invocation on it.
|
|
|
|
|
pDisp = (IDispatch *)ComObject::GetComIPFromRCWThrowing(pTarget, pInvokedMT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// A class was passed in so we will make the invocation on the default
|
|
|
|
|
// IDispatch for the COM component.
|
|
|
|
|
|
|
|
|
|
RCWHolder pRCW(GetThread());
|
|
|
|
|
RCWPROTECT_BEGIN(pRCW, *pTarget);
|
|
|
|
|
|
2022-08-02 00:56:33 +03:00
|
|
|
// Retrieve the IDispatch pointer from the wrapper.
|
2015-01-30 14:14:42 -08:00
|
|
|
pDisp = (IDispatch*)pRCW->GetIDispatch();
|
|
|
|
|
if (!pDisp)
|
|
|
|
|
COMPlusThrow(kTargetInvocationException, IDS_EE_NO_IDISPATCH_ON_TARGET);
|
|
|
|
|
|
2019-11-02 06:29:45 -07:00
|
|
|
// If we aren't ignoring case, then we need to try and QI for IDispatchEx to
|
2015-01-30 14:14:42 -08:00
|
|
|
// be able to use IDispatchEx::GetDispID() which has a flag to control case
|
|
|
|
|
// sentisitivity.
|
|
|
|
|
if (!bIgnoreCase && cNamedArgs == 0)
|
|
|
|
|
{
|
|
|
|
|
RCW_VTABLEPTR(pRCW);
|
|
|
|
|
hr = SafeQueryInterface(pDisp, IID_IDispatchEx, (IUnknown**)&pDispEx);
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
pDispEx = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCWPROTECT_END(pRCW);
|
|
|
|
|
}
|
|
|
|
|
_ASSERTE((IUnknown*)pDisp != NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Prepare the DISPID's that will be passed to invoke.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (pMemberID && (*pMemberID != DISPID_UNKNOWN) && (cNamedArgs == 0))
|
|
|
|
|
{
|
|
|
|
|
// The caller specified a member ID and we don't have any named arguments so
|
|
|
|
|
// we can simply use the member ID the caller specified.
|
|
|
|
|
MemberID = *pMemberID;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int strNameLength = (*pStrName)->GetStringLength();
|
|
|
|
|
|
|
|
|
|
// Check if we are invoking on the default member.
|
|
|
|
|
if (strNameLength == 0)
|
|
|
|
|
{
|
|
|
|
|
// Set the DISPID to 0 (default member).
|
|
|
|
|
MemberID = 0;
|
|
|
|
|
|
|
|
|
|
_ASSERTE(cNamedArgs == 0);
|
|
|
|
|
if (cNamedArgs != 0)
|
|
|
|
|
COMPlusThrow(kNotSupportedException,W("NotSupported_IDispInvokeDefaultMemberWithNamedArgs"));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Create an array of strings that will be passed to GetIDsOfNames().
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
UINT cNamesToConvert = cNamedArgs + 1;
|
|
|
|
|
LPWSTR strTmpName = NULL;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Allocate the array of strings to convert, the array of pinned handles and the
|
|
|
|
|
// array of converted DISPID's.
|
|
|
|
|
size_t allocSize = cNamesToConvert * sizeof(LPWSTR);
|
|
|
|
|
if (allocSize < cNamesToConvert)
|
|
|
|
|
COMPlusThrowArgumentOutOfRange(W("namedParameters"), W("ArgumentOutOfRange_Capacity"));
|
|
|
|
|
LPWSTR *aNamesToConvert = (LPWSTR *)_alloca(allocSize);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
allocSize = cNamesToConvert * sizeof(DISPID);
|
|
|
|
|
if (allocSize < cNamesToConvert)
|
|
|
|
|
COMPlusThrowArgumentOutOfRange(W("namedParameters"), W("ArgumentOutOfRange_Capacity"));
|
|
|
|
|
aDispID = (DISPID *)_alloca(allocSize);
|
|
|
|
|
|
|
|
|
|
// The first name to convert is the name of the method itself.
|
|
|
|
|
aNamesToConvert[0] = (*pStrName)->GetBuffer();
|
|
|
|
|
|
|
|
|
|
// Check to see if the name is for a standard DISPID.
|
|
|
|
|
if (SString::_wcsnicmp(aNamesToConvert[0], STANDARD_DISPID_PREFIX, STANDARD_DISPID_PREFIX_LENGTH) == 0)
|
|
|
|
|
{
|
|
|
|
|
// The name is for a standard DISPID so extract it from the name.
|
|
|
|
|
MemberID = ExtractStandardDispId(aNamesToConvert[0]);
|
|
|
|
|
|
|
|
|
|
// Make sure there are no named arguments to convert.
|
|
|
|
|
if (cNamedArgs > 0)
|
|
|
|
|
{
|
|
|
|
|
STRINGREF *pNamedArgsData = (STRINGREF *)(*pArrNamedArgs)->GetDataPtr();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cNamedArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
// The first name to convert is the name of the method itself.
|
|
|
|
|
strTmpName = pNamedArgsData[i]->GetBuffer();
|
|
|
|
|
|
|
|
|
|
// Check to see if the name is for a standard DISPID.
|
|
|
|
|
if (SString::_wcsnicmp(strTmpName, STANDARD_DISPID_PREFIX, STANDARD_DISPID_PREFIX_LENGTH) != 0)
|
|
|
|
|
COMPlusThrow(kArgumentException, IDS_EE_NON_STD_NAME_WITH_STD_DISPID);
|
|
|
|
|
|
|
|
|
|
// The name is for a standard DISPID so extract it from the name.
|
|
|
|
|
aDispID[i + 1] = ExtractStandardDispId(strTmpName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BOOL fGotIt = FALSE;
|
|
|
|
|
BOOL fIsNonGenericComObject = pInvokedMT->IsInterface() || (pInvokedMT != g_pBaseCOMObject && pInvokedMT->IsComObjectType());
|
|
|
|
|
BOOL fUseCache = fIsNonGenericComObject && !(IUnknown*)pDispEx && strNameLength <= ReflectionMaxCachedNameLength && cNamedArgs == 0;
|
|
|
|
|
DispIDCacheElement vDispIDElement;
|
|
|
|
|
|
|
|
|
|
// If the object is not a generic COM object and the member meets the criteria to be
|
|
|
|
|
// in the cache then look up the DISPID in the cache.
|
|
|
|
|
if (fUseCache)
|
|
|
|
|
{
|
|
|
|
|
vDispIDElement.pMT = pInvokedMT;
|
|
|
|
|
vDispIDElement.strNameLength = strNameLength;
|
|
|
|
|
vDispIDElement.lcid = lcid;
|
2022-01-12 15:05:32 +02:00
|
|
|
wcscpy_s(vDispIDElement.strName, ARRAY_SIZE(vDispIDElement.strName), aNamesToConvert[0]);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Only look up if the cache has already been created.
|
|
|
|
|
DispIDCache* pDispIDCache = GetAppDomain()->GetRefDispIDCache();
|
|
|
|
|
fGotIt = pDispIDCache->GetFromCache (&vDispIDElement, MemberID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!fGotIt)
|
|
|
|
|
{
|
|
|
|
|
NewArrayHolder<PinningHandleHolder> ahndPinnedObjs = new PinningHandleHolder[cNamesToConvert];
|
|
|
|
|
ahndPinnedObjs[0] = GetAppDomain()->CreatePinningHandle((OBJECTREF)*pStrName);
|
|
|
|
|
|
|
|
|
|
// Copy the named arguments into the array of names to convert.
|
|
|
|
|
if (cNamedArgs > 0)
|
|
|
|
|
{
|
|
|
|
|
STRINGREF *pNamedArgsData = (STRINGREF *)(*pArrNamedArgs)->GetDataPtr();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cNamedArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
// Pin the string object and retrieve a pointer to its data.
|
|
|
|
|
ahndPinnedObjs[i + 1] = GetAppDomain()->CreatePinningHandle((OBJECTREF)pNamedArgsData[i]);
|
|
|
|
|
aNamesToConvert[i + 1] = pNamedArgsData[i]->GetBuffer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call GetIDsOfNames to convert the names to DISPID's
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// We are about to make call's to COM so switch to preemptive GC.
|
|
|
|
|
GCX_PREEMP();
|
|
|
|
|
|
|
|
|
|
if ((IUnknown*)pDispEx)
|
|
|
|
|
{
|
|
|
|
|
// We should only get here if we are doing a case sensitive lookup and
|
|
|
|
|
// we don't have any named arguments.
|
|
|
|
|
_ASSERTE(cNamedArgs == 0);
|
|
|
|
|
_ASSERTE(!bIgnoreCase);
|
|
|
|
|
|
|
|
|
|
// We managed to retrieve an IDispatchEx IP so we will use it to
|
|
|
|
|
// retrieve the DISPID.
|
|
|
|
|
BSTRHolder bstrTmpName = SysAllocString(aNamesToConvert[0]);
|
|
|
|
|
if (!bstrTmpName)
|
|
|
|
|
COMPlusThrowOM();
|
|
|
|
|
|
|
|
|
|
hr = pDispEx->GetDispID(bstrTmpName, fdexNameCaseSensitive, aDispID);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Call GetIdsOfNames() to retrieve the DISPID's of the method and of the arguments.
|
|
|
|
|
hr = pDisp->GetIDsOfNames(
|
|
|
|
|
IID_NULL,
|
|
|
|
|
aNamesToConvert,
|
|
|
|
|
cNamesToConvert,
|
|
|
|
|
lcid,
|
|
|
|
|
aDispID
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
{
|
|
|
|
|
// Check to see if the user wants to invoke the new enum member.
|
|
|
|
|
if (cNamesToConvert == 1 && SString::_wcsicmp(aNamesToConvert[0], GET_ENUMERATOR_METHOD_NAME) == 0)
|
|
|
|
|
{
|
|
|
|
|
// Invoke the new enum member.
|
|
|
|
|
MemberID = DISPID_NEWENUM;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// The name is unknown.
|
|
|
|
|
COMPlusThrowHR(hr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// The member ID is the first elements of the array we got back from GetIdsOfNames.
|
|
|
|
|
MemberID = aDispID[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the object is not a generic COM object and the member meets the criteria to be
|
|
|
|
|
// in the cache then insert the member in the cache.
|
|
|
|
|
if (fUseCache)
|
|
|
|
|
{
|
|
|
|
|
DispIDCache *pDispIDCache = GetAppDomain()->GetRefDispIDCache();
|
|
|
|
|
pDispIDCache->AddToCache (&vDispIDElement, MemberID);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store the member ID if the caller passed in a place to store it.
|
|
|
|
|
if (pMemberID)
|
|
|
|
|
*pMemberID = MemberID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Fill in the DISPPARAMS structure.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (cArgs > 0)
|
|
|
|
|
{
|
|
|
|
|
// Allocate the byref argument information.
|
|
|
|
|
aByrefArgInfos = (ByrefArgumentInfo*)_alloca(cArgs * sizeof(ByrefArgumentInfo));
|
|
|
|
|
memset(aByrefArgInfos, 0, cArgs * sizeof(ByrefArgumentInfo));
|
|
|
|
|
|
|
|
|
|
// Set the byref bit on the arguments that have the byref modifier.
|
|
|
|
|
if (*pArrByrefModifiers != NULL)
|
|
|
|
|
{
|
|
|
|
|
BYTE *aByrefModifiers = (BYTE*)(*pArrByrefModifiers)->GetDataPtr();
|
|
|
|
|
for (i = 0; i < cArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
if (aByrefModifiers[i])
|
|
|
|
|
{
|
|
|
|
|
aByrefArgInfos[i].m_bByref = TRUE;
|
|
|
|
|
bSomeArgsAreByref = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to protect the temporary object that will be used to convert from
|
|
|
|
|
// the managed objects to OLE variants.
|
|
|
|
|
OBJECTREF TmpObj = NULL;
|
|
|
|
|
GCPROTECT_BEGIN(TmpObj)
|
|
|
|
|
{
|
|
|
|
|
if (!(flags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)))
|
|
|
|
|
{
|
|
|
|
|
// For anything other than a put or a putref we just use the specified
|
|
|
|
|
// named arguments.
|
|
|
|
|
DispParams.cNamedArgs = cNamedArgs;
|
|
|
|
|
DispParams.rgdispidNamedArgs = (cNamedArgs == 0) ? NULL : &aDispID[1];
|
|
|
|
|
|
|
|
|
|
// Convert the named arguments from COM+ to OLE. These arguments are in the same order
|
|
|
|
|
// on both sides.
|
|
|
|
|
for (i = 0; i < cNamedArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
iSrcArg = i;
|
|
|
|
|
iDestArg = i;
|
|
|
|
|
TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
|
2019-11-02 06:29:45 -07:00
|
|
|
DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert the unnamed arguments. These need to be presented in reverse order to IDispatch::Invoke().
|
|
|
|
|
for (iSrcArg = cNamedArgs, iDestArg = cArgs - 1; iSrcArg < cArgs; iSrcArg++, iDestArg--)
|
|
|
|
|
{
|
|
|
|
|
TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
|
2019-11-02 06:29:45 -07:00
|
|
|
DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// If we are doing a property put then we need to set the DISPID of the
|
|
|
|
|
// argument to DISP_PROPERTYPUT if there is at least one argument.
|
|
|
|
|
DispParams.cNamedArgs = cNamedArgs + 1;
|
|
|
|
|
DispParams.rgdispidNamedArgs = (DISPID*)_alloca((cNamedArgs + 1) * sizeof(DISPID));
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Fill in the array of named arguments.
|
|
|
|
|
DispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
|
|
|
|
|
for (i = 1; i < cNamedArgs; i++)
|
|
|
|
|
DispParams.rgdispidNamedArgs[i] = aDispID[i];
|
|
|
|
|
|
|
|
|
|
// The last argument from reflection becomes the first argument that must be passed to IDispatch.
|
|
|
|
|
iSrcArg = cArgs - 1;
|
|
|
|
|
iDestArg = 0;
|
|
|
|
|
TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
|
2019-11-02 06:29:45 -07:00
|
|
|
DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// Convert the named arguments from COM+ to OLE. These arguments are in the same order
|
|
|
|
|
// on both sides.
|
|
|
|
|
for (i = 0; i < cNamedArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
iSrcArg = i;
|
|
|
|
|
iDestArg = i + 1;
|
|
|
|
|
TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
|
2019-11-02 06:29:45 -07:00
|
|
|
DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert the unnamed arguments. These need to be presented in reverse order to IDispatch::Invoke().
|
|
|
|
|
for (iSrcArg = cNamedArgs, iDestArg = cArgs - 1; iSrcArg < cArgs - 1; iSrcArg++, iDestArg--)
|
|
|
|
|
{
|
|
|
|
|
TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
|
2019-11-02 06:29:45 -07:00
|
|
|
DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// There are no arguments.
|
|
|
|
|
DispParams.cArgs = cArgs;
|
|
|
|
|
DispParams.cNamedArgs = 0;
|
|
|
|
|
DispParams.rgdispidNamedArgs = NULL;
|
|
|
|
|
DispParams.rgvarg = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we're calling on DISPID=-4, then pass both METHOD and PROPERTYGET
|
|
|
|
|
if (MemberID == DISPID_NEWENUM)
|
|
|
|
|
{
|
|
|
|
|
_ASSERTE((flags & DISPATCH_METHOD) && "Expected DISPATCH_METHOD to be set.");
|
|
|
|
|
flags |= DISPATCH_METHOD | DISPATCH_PROPERTYGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Call invoke on the target's IDispatch.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (!bIgnoreReturn)
|
|
|
|
|
pVarResult = &VarResult;
|
|
|
|
|
|
|
|
|
|
DoIUInvokeDispMethod(pDispEx, pDisp, MemberID, lcid, flags, &DispParams, pVarResult);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Return value handling and cleanup.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Back propagate any byref args.
|
|
|
|
|
if (bSomeArgsAreByref)
|
|
|
|
|
{
|
|
|
|
|
OBJECTREF TmpObj = NULL;
|
|
|
|
|
GCPROTECT_BEGIN(TmpObj)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < cArgs; i++)
|
|
|
|
|
{
|
|
|
|
|
if (aByrefArgInfos[i].m_bByref)
|
|
|
|
|
{
|
|
|
|
|
// Convert the variant back to an object.
|
|
|
|
|
OleVariant::MarshalObjectForOleVariant(&aByrefArgInfos[i].m_Val, &TmpObj);
|
|
|
|
|
(*pArrArgs)->SetAt(i, TmpObj);
|
2019-11-02 06:29:45 -07:00
|
|
|
}
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GCPROTECT_END();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bIgnoreReturn)
|
|
|
|
|
{
|
|
|
|
|
if (MemberID == DISPID_NEWENUM)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Use a custom marshaler to convert the IEnumVARIANT to an IEnumerator.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Start by making sure that the variant we got back contains an IP.
|
|
|
|
|
if ((VarResult.vt != VT_UNKNOWN) || !VarResult.punkVal)
|
|
|
|
|
COMPlusThrow(kInvalidCastException, IDS_EE_INVOKE_NEW_ENUM_INVALID_RETURN);
|
|
|
|
|
|
|
|
|
|
// Have the custom marshaler do the conversion.
|
|
|
|
|
*pRetVal = ConvertEnumVariantToMngEnum((IEnumVARIANT *)VarResult.punkVal);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Convert the return variant to a COR variant.
|
|
|
|
|
OleVariant::MarshalObjectForOleVariant(&VarResult, pRetVal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-18 22:09:19 -07:00
|
|
|
#if defined(FEATURE_COMINTEROP_UNMANAGED_ACTIVATION) && defined(FEATURE_COMINTEROP)
|
2018-12-13 14:41:08 -08:00
|
|
|
|
2020-09-22 18:08:15 -07:00
|
|
|
static void GetComClassHelper(
|
2018-12-13 14:41:08 -08:00
|
|
|
_Out_ OBJECTREF *pRef,
|
|
|
|
|
_In_ EEClassFactoryInfoHashTable *pClassFactHash,
|
2020-09-22 18:08:15 -07:00
|
|
|
_In_ ClassFactoryInfo *pClassFactInfo)
|
2018-12-13 14:41:08 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
2020-09-22 18:08:15 -07:00
|
|
|
MODE_COOPERATIVE;
|
2018-12-13 14:41:08 -08:00
|
|
|
INJECT_FAULT(ThrowOutOfMemory());
|
|
|
|
|
PRECONDITION(CheckPointer(pRef));
|
|
|
|
|
PRECONDITION(CheckPointer(pClassFactHash));
|
|
|
|
|
PRECONDITION(CheckPointer(pClassFactInfo));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
OBJECTHANDLE hRef;
|
|
|
|
|
AppDomain *pDomain = GetAppDomain();
|
|
|
|
|
|
|
|
|
|
CrstHolder ch(pDomain->GetRefClassFactCrst());
|
|
|
|
|
|
|
|
|
|
// Check again.
|
|
|
|
|
if (pClassFactHash->GetValue(pClassFactInfo, (HashDatum *)&hRef))
|
|
|
|
|
{
|
|
|
|
|
*pRef = ObjectFromHandle(hRef);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There is no managed class for this CLSID
|
|
|
|
|
// so we will create a ComClassFactory to
|
|
|
|
|
// represent it.
|
|
|
|
|
//
|
|
|
|
|
|
2020-09-22 18:08:15 -07:00
|
|
|
NewHolder<ComClassFactory> pComClsFac = new ComClassFactory(pClassFactInfo->m_clsid);
|
2018-12-13 14:41:08 -08:00
|
|
|
pComClsFac->SetManagedVersion();
|
|
|
|
|
|
|
|
|
|
NewArrayHolder<WCHAR> wszRefServer = NULL;
|
|
|
|
|
if (pClassFactInfo->m_strServerName)
|
|
|
|
|
{
|
2023-05-11 14:15:05 -07:00
|
|
|
size_t len = u16_strlen(pClassFactInfo->m_strServerName)+1;
|
2018-12-13 14:41:08 -08:00
|
|
|
wszRefServer = new WCHAR[len];
|
|
|
|
|
wcscpy_s(wszRefServer, len, pClassFactInfo->m_strServerName);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-22 18:08:15 -07:00
|
|
|
pComClsFac->Init(wszRefServer, NULL);
|
2018-12-13 14:41:08 -08:00
|
|
|
AllocateComClassObject(pComClsFac, pRef);
|
|
|
|
|
|
|
|
|
|
// Insert to hash.
|
|
|
|
|
hRef = pDomain->CreateHandle(*pRef);
|
|
|
|
|
pClassFactHash->InsertValue(pClassFactInfo, (LPVOID)hRef);
|
|
|
|
|
|
|
|
|
|
// Make sure the hash code is working.
|
|
|
|
|
_ASSERTE (pClassFactHash->GetValue(pClassFactInfo, (HashDatum *)&hRef));
|
|
|
|
|
|
|
|
|
|
wszRefServer.SuppressRelease();
|
|
|
|
|
pComClsFac.SuppressRelease();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
//-------------------------------------------------------------
|
|
|
|
|
// returns a ComClass reflect class that wraps the IClassFactory
|
2020-09-22 18:08:15 -07:00
|
|
|
void GetComClassFromCLSID(REFCLSID clsid, _In_opt_z_ PCWSTR wszServer, OBJECTREF *pRef)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
INJECT_FAULT(COMPlusThrowOM());
|
|
|
|
|
PRECONDITION(pRef != NULL);
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
//
|
2020-06-18 22:09:19 -07:00
|
|
|
// See if we can find the well known managed class for this CLSID.
|
2015-01-30 14:14:42 -08:00
|
|
|
//
|
|
|
|
|
|
2020-06-18 22:09:19 -07:00
|
|
|
// Check if we have in the hash.
|
|
|
|
|
OBJECTHANDLE hRef;
|
|
|
|
|
ClassFactoryInfo ClassFactInfo;
|
|
|
|
|
ClassFactInfo.m_clsid = clsid;
|
|
|
|
|
ClassFactInfo.m_strServerName = wszServer;
|
|
|
|
|
EEClassFactoryInfoHashTable *pClassFactHash = GetAppDomain()->GetClassFactHash();
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2020-06-18 22:09:19 -07:00
|
|
|
if (pClassFactHash->GetValue(&ClassFactInfo, (HashDatum*) &hRef))
|
2019-11-02 06:29:45 -07:00
|
|
|
{
|
2020-06-18 22:09:19 -07:00
|
|
|
*pRef = ObjectFromHandle(hRef);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-09-22 18:08:15 -07:00
|
|
|
GetComClassHelper(pRef, pClassFactHash, &ClassFactInfo);
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we made it this far *pRef better be set.
|
|
|
|
|
_ASSERTE(*pRef != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-18 22:09:19 -07:00
|
|
|
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION && FEATURE_COMINTEROP
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
//-------------------------------------------------------------
|
|
|
|
|
// check if a ComClassFactory has been setup for this class
|
|
|
|
|
// if not set one up
|
|
|
|
|
ClassFactoryBase *GetComClassFactory(MethodTable* pClassMT)
|
|
|
|
|
{
|
|
|
|
|
CONTRACT (ClassFactoryBase*)
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
INJECT_FAULT(ThrowOutOfMemory());
|
|
|
|
|
PRECONDITION(CheckPointer(pClassMT));
|
2020-05-29 17:37:12 -07:00
|
|
|
PRECONDITION(pClassMT->IsComObjectType());
|
2015-01-30 14:14:42 -08:00
|
|
|
POSTCONDITION(CheckPointer(RETVAL));
|
|
|
|
|
}
|
|
|
|
|
CONTRACT_END;
|
|
|
|
|
|
2022-08-02 00:56:33 +03:00
|
|
|
// Work our way up the hierarchy until we find the first COM import type.
|
2020-05-29 17:37:12 -07:00
|
|
|
while (!pClassMT->IsComImport())
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
pClassMT = pClassMT->GetParentMethodTable();
|
|
|
|
|
_ASSERTE(pClassMT != NULL);
|
|
|
|
|
_ASSERTE(pClassMT->IsComObjectType());
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if com data has been setup for this class
|
|
|
|
|
ClassFactoryBase *pClsFac = pClassMT->GetComClassFactory();
|
|
|
|
|
|
|
|
|
|
if (pClsFac == NULL)
|
|
|
|
|
{
|
|
|
|
|
NewHolder<ClassFactoryBase> pNewFactory;
|
|
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
GUID guid;
|
|
|
|
|
pClassMT->GetGuid(&guid, TRUE);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-09-22 18:08:15 -07:00
|
|
|
ComClassFactory *pComClsFac = new ComClassFactory(guid);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-05-29 17:37:12 -07:00
|
|
|
pNewFactory = pComClsFac;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2020-09-22 18:08:15 -07:00
|
|
|
pComClsFac->Init(NULL, pClassMT);
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
// store the class factory in EE Class
|
|
|
|
|
if (!pClassMT->SetComClassFactory(pNewFactory))
|
|
|
|
|
{
|
|
|
|
|
// another thread beat us to it
|
|
|
|
|
pNewFactory = pClassMT->GetComClassFactory();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pClsFac = pNewFactory.Extract();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RETURN pClsFac;
|
|
|
|
|
}
|
|
|
|
|
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
2018-12-13 14:41:08 -08:00
|
|
|
// void InitializeComInterop()
|
2019-11-02 06:29:45 -07:00
|
|
|
// Called from EEStartup, to initialize com Interop specific data
|
2015-01-30 14:14:42 -08:00
|
|
|
// structures.
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
void InitializeComInterop()
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
InitializeSListHead(&RCW::s_RCWStandbyList);
|
|
|
|
|
ComCall::Init();
|
2020-01-31 19:36:44 -05:00
|
|
|
#ifdef TARGET_X86
|
2015-01-30 14:14:42 -08:00
|
|
|
ComPlusCall::Init();
|
|
|
|
|
#endif
|
|
|
|
|
CtxEntryCache::Init();
|
|
|
|
|
ComCallWrapperTemplate::Init();
|
|
|
|
|
#ifdef _DEBUG
|
2022-07-17 08:11:11 +03:00
|
|
|
InitializeInteropLogging();
|
2015-01-30 14:14:42 -08:00
|
|
|
#endif //_DEBUG
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// LOGGING APIS
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static int g_TraceCount = 0;
|
2021-03-29 13:58:50 -07:00
|
|
|
static IUnknown* g_pTraceIUnknown = NULL;
|
2015-01-30 14:14:42 -08:00
|
|
|
|
2022-07-17 08:11:11 +03:00
|
|
|
VOID InitializeInteropLogging()
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
WRAPPER_NO_CONTRACT;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
g_TraceCount = g_pConfig->GetTraceWrapper();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 08:49:08 +02:00
|
|
|
VOID LogInterop(_In_z_ LPCSTR szMsg)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
|
|
|
|
LIMITED_METHOD_CONTRACT;
|
|
|
|
|
LOG( (LF_INTEROP, LL_INFO10, "%s\n",szMsg) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogRCWCreate(RCW* pWrap, IUnknown* pUnk)
|
|
|
|
|
// log wrapper create
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
VOID LogRCWCreate(RCW* pWrap, IUnknown* pUnk)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
static int count = 0;
|
|
|
|
|
LPVOID pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
|
|
|
|
|
// pre-increment the count, so it can never be zero
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
if (count == g_TraceCount)
|
|
|
|
|
{
|
|
|
|
|
g_pTraceIUnknown = pUnk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
LOG( (LF_INTEROP,
|
|
|
|
|
LL_INFO10,
|
|
|
|
|
"Create RCW: Wrapper %p #%d IUnknown:%p Context %p\n",
|
|
|
|
|
pWrap, count,
|
|
|
|
|
pUnk,
|
|
|
|
|
pCurrCtx) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogRCWMinorCleanup(RCW* pWrap)
|
|
|
|
|
// log wrapper minor cleanup
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
VOID LogRCWMinorCleanup(RCW* pWrap)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pWrap));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
static int dest_count = 0;
|
|
|
|
|
dest_count++;
|
|
|
|
|
|
|
|
|
|
IUnknown *pUnk = pWrap->GetRawIUnknown_NoAddRef_NoThrow();
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
LPVOID pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
LOG( (LF_INTEROP,
|
|
|
|
|
LL_INFO10,
|
|
|
|
|
"Minor Cleanup RCW: Wrapper %p #%d IUnknown %p Context: %p\n",
|
|
|
|
|
pWrap, dest_count,
|
|
|
|
|
pUnk,
|
|
|
|
|
pCurrCtx) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogRCWDestroy(RCW* pWrap, IUnknown* pUnk)
|
|
|
|
|
// log wrapper destroy
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
VOID LogRCWDestroy(RCW* pWrap)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pWrap));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
static int dest_count = 0;
|
|
|
|
|
dest_count++;
|
|
|
|
|
|
|
|
|
|
IUnknown *pUnk = pWrap->GetRawIUnknown_NoAddRef_NoThrow();
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
LPVOID pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
STRESS_LOG4(
|
|
|
|
|
LF_INTEROP,
|
|
|
|
|
LL_INFO10,
|
|
|
|
|
"Destroy RCW: Wrapper %p #%d IUnknown %p Context: %p\n",
|
|
|
|
|
pWrap, dest_count,
|
|
|
|
|
pUnk,
|
|
|
|
|
pCurrCtx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogInteropLeak(IUnkEntry * pEntry)
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
VOID LogInteropLeak(IUnkEntry * pEntry)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pEntry));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
IUnknown *pUnk = pEntry->GetRawIUnknown_NoAddRef_NoThrow();
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
LOG( (LF_INTEROP,
|
|
|
|
|
LL_INFO10,
|
|
|
|
|
"IUnkEntry Leak: %p Context: %p\n",
|
|
|
|
|
pUnk,
|
|
|
|
|
pEntry->GetCtxCookie()) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogInteropLeak(IUnknown* pItf)
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
VOID LogInteropLeak(IUnknown* pItf)
|
|
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
LPVOID pCurrCtx = NULL;
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pItf)
|
|
|
|
|
{
|
|
|
|
|
pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
LOG((LF_INTEROP,
|
|
|
|
|
LL_EVERYTHING,
|
|
|
|
|
"Leak: Itf = %p, CurrCtx = %p\n",
|
|
|
|
|
pItf, pCurrCtx));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogInteropQI(IUnknown* pItf, REFIID iid, HRESULT hr, LPCSTR szMsg)
|
|
|
|
|
//-------------------------------------------------------------------
|
2022-01-06 08:49:08 +02:00
|
|
|
VOID LogInteropQI(IUnknown* pItf, REFIID iid, HRESULT hrArg, _In_z_ LPCSTR szMsg)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pItf));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
|
|
|
|
|
|
|
|
|
LPVOID pCurrCtx = NULL;
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
SafeComHolder<IUnknown> pUnk = NULL;
|
|
|
|
|
int cch = 0;
|
2022-10-24 17:41:20 -07:00
|
|
|
CHAR szIID[GUID_STR_BUFFER_LEN];
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
hr = SafeQueryInterface(pItf, IID_IUnknown, &pUnk);
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
|
2022-10-07 10:31:23 -07:00
|
|
|
cch = GuidToLPSTR(iid, szIID);
|
2015-01-30 14:14:42 -08:00
|
|
|
_ASSERTE(cch > 0);
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hrArg))
|
|
|
|
|
{
|
|
|
|
|
LOG((LF_INTEROP,
|
|
|
|
|
LL_EVERYTHING,
|
2022-10-07 10:31:23 -07:00
|
|
|
"Succeeded QI: Unk = %p, Itf = %p, CurrCtx = %p, IID = %s, Msg: %s\n",
|
|
|
|
|
(IUnknown*)pUnk, pItf, pCurrCtx, szIID, szMsg));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG((LF_INTEROP,
|
|
|
|
|
LL_EVERYTHING,
|
2022-10-07 10:31:23 -07:00
|
|
|
"Failed QI: Unk = %p, Itf = %p, CurrCtx = %p, IID = %s, HR = %p, Msg: %s\n",
|
|
|
|
|
(IUnknown*)pUnk, pItf, pCurrCtx, szIID, hrArg, szMsg));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogInteropAddRef(IUnknown* pItf, ULONG cbRef, LPCSTR szMsg)
|
|
|
|
|
//-------------------------------------------------------------------
|
2022-01-06 08:49:08 +02:00
|
|
|
VOID LogInteropAddRef(IUnknown* pItf, ULONG cbRef, _In_z_ LPCSTR szMsg)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pItf));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
LPVOID pCurrCtx = NULL;
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
SafeComHolder<IUnknown> pUnk = NULL;
|
|
|
|
|
|
|
|
|
|
hr = SafeQueryInterface(pItf, IID_IUnknown, &pUnk);
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
|
|
|
|
|
{
|
|
|
|
|
pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
LOG((LF_INTEROP,
|
|
|
|
|
LL_EVERYTHING,
|
|
|
|
|
"AddRef: Unk = %p, Itf = %p, CurrCtx = %p, RefCount = %d, Msg: %s\n",
|
|
|
|
|
(IUnknown*)pUnk, pItf, pCurrCtx, cbRef, szMsg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
// VOID LogInteropRelease(IUnknown* pItf, ULONG cbRef, LPCSTR szMsg)
|
|
|
|
|
//-------------------------------------------------------------------
|
2022-01-06 08:49:08 +02:00
|
|
|
VOID LogInteropRelease(IUnknown* pItf, ULONG cbRef, _In_z_ LPCSTR szMsg)
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2019-11-02 06:29:45 -07:00
|
|
|
if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
|
2015-01-30 14:14:42 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
NOTHROW;
|
|
|
|
|
GC_NOTRIGGER;
|
|
|
|
|
MODE_ANY;
|
|
|
|
|
PRECONDITION(CheckPointer(pItf, NULL_OK));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
LPVOID pCurrCtx = NULL;
|
|
|
|
|
|
|
|
|
|
if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pItf)
|
|
|
|
|
{
|
|
|
|
|
pCurrCtx = GetCurrentCtxCookie();
|
|
|
|
|
LOG((LF_INTEROP,
|
|
|
|
|
LL_EVERYTHING,
|
|
|
|
|
"Release: Itf = %p, CurrCtx = %p, RefCount = %d, Msg: %s\n",
|
|
|
|
|
pItf, pCurrCtx, cbRef, szMsg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // _DEBUG
|
|
|
|
|
|
|
|
|
|
IUnknown* MarshalObjectToInterface(OBJECTREF* ppObject, MethodTable* pItfMT, MethodTable* pClassMT, DWORD dwFlags)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// When an interface method table is specified, fDispIntf must be consistent with the
|
|
|
|
|
// interface type.
|
|
|
|
|
BOOL bDispatch = (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF);
|
|
|
|
|
BOOL bUseBasicItf = (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
_ASSERTE(!pItfMT || (!pItfMT->IsInterface() && bDispatch) ||
|
2020-05-29 17:37:12 -07:00
|
|
|
(!!bDispatch == IsDispatchBasedItf(pItfMT->GetComInterfaceType())));
|
2015-01-30 14:14:42 -08:00
|
|
|
|
|
|
|
|
if (pItfMT)
|
|
|
|
|
{
|
|
|
|
|
return GetComIPFromObjectRef(ppObject, pItfMT);
|
|
|
|
|
}
|
|
|
|
|
else if (!bUseBasicItf)
|
|
|
|
|
{
|
|
|
|
|
return GetComIPFromObjectRef(ppObject, pClassMT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
ComIpType ReqIpType = bDispatch ? ComIpType_Dispatch : ComIpType_Unknown;
|
2015-01-30 14:14:42 -08:00
|
|
|
return GetComIPFromObjectRef(ppObject, ReqIpType, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UnmarshalObjectFromInterface(OBJECTREF *ppObjectDest, IUnknown **ppUnkSrc, MethodTable *pItfMT, MethodTable *pClassMT, DWORD dwFlags)
|
|
|
|
|
{
|
|
|
|
|
CONTRACTL
|
|
|
|
|
{
|
|
|
|
|
THROWS;
|
|
|
|
|
MODE_COOPERATIVE;
|
|
|
|
|
GC_TRIGGERS;
|
|
|
|
|
PRECONDITION(IsProtectedByGCFrame(ppObjectDest));
|
|
|
|
|
}
|
|
|
|
|
CONTRACTL_END;
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
_ASSERTE(!pClassMT || !pClassMT->IsInterface());
|
|
|
|
|
|
|
|
|
|
DWORD dwObjFromComIPFlags = ObjFromComIP::FromItfMarshalInfoFlags(dwFlags);
|
|
|
|
|
GetObjectRefFromComIP(
|
|
|
|
|
ppObjectDest, // Object
|
|
|
|
|
ppUnkSrc, // Interface pointer
|
|
|
|
|
pClassMT, // Class type
|
|
|
|
|
dwObjFromComIPFlags // Flags
|
|
|
|
|
);
|
2019-11-02 06:29:45 -07:00
|
|
|
|
2015-01-30 14:14:42 -08:00
|
|
|
// Make sure the interface is supported.
|
|
|
|
|
_ASSERTE(!pItfMT || pItfMT->IsInterface() || pItfMT->GetComClassInterfaceType() != clsIfNone);
|
|
|
|
|
|
2021-08-12 10:47:58 -07:00
|
|
|
bool fIsInterface = (pItfMT != NULL && pItfMT->IsInterface());
|
2015-01-30 14:14:42 -08:00
|
|
|
if (fIsInterface)
|
|
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
// We only verify that the object supports the interface for non-WinRT scenarios because we
|
|
|
|
|
// believe that the likelihood of improperly constructed programs is significantly lower
|
|
|
|
|
// with WinRT and the Object::SupportsInterface check is very expensive.
|
|
|
|
|
if (!Object::SupportsInterface(*ppObjectDest, pItfMT))
|
2015-01-30 14:14:42 -08:00
|
|
|
{
|
2020-05-29 17:37:12 -07:00
|
|
|
COMPlusThrowInvalidCastException(ppObjectDest, TypeHandle(pItfMT));
|
2015-01-30 14:14:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // FEATURE_COMINTEROP
|