diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/utilcode/tlbutils.cpp | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/utilcode/tlbutils.cpp')
-rw-r--r-- | src/utilcode/tlbutils.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/utilcode/tlbutils.cpp b/src/utilcode/tlbutils.cpp new file mode 100644 index 0000000000..88906bac64 --- /dev/null +++ b/src/utilcode/tlbutils.cpp @@ -0,0 +1,222 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// Utilities used to help manipulating typelibs. + +#include "stdafx.h" // Precompiled header key. + +#include "tlbutils.h" +#include "dispex.h" +#include "posterror.h" +#include "ndpversion.h" + +#define CUSTOM_MARSHALER_ASM ", CustomMarshalers, Version=" VER_ASSEMBLYVERSION_STR ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" + +static const LPCWSTR DLL_EXTENSION = {W(".dll")}; +static const int DLL_EXTENSION_LEN = 4; +static const LPCWSTR EXE_EXTENSION = {W(".exe")}; +static const int EXE_EXTENSION_LEN = 4; + +const StdConvertibleItfInfo aStdConvertibleInterfaces[] = +{ + { "System.Runtime.InteropServices.Expando.IExpando", (GUID*)&IID_IDispatchEx, + "System.Runtime.InteropServices.CustomMarshalers.ExpandoToDispatchExMarshaler" CUSTOM_MARSHALER_ASM, "IExpando" }, + + { "System.Reflection.IReflect", (GUID*)&IID_IDispatchEx, + "System.Runtime.InteropServices.CustomMarshalers.ExpandoToDispatchExMarshaler" CUSTOM_MARSHALER_ASM, "IReflect" }, + + { "System.Collections.IEnumerator", (GUID*)&IID_IEnumVARIANT, + "System.Runtime.InteropServices.CustomMarshalers.EnumeratorToEnumVariantMarshaler" CUSTOM_MARSHALER_ASM, "" }, + + { "System.Type", (GUID*)&IID_ITypeInfo, + "System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler" CUSTOM_MARSHALER_ASM, "" }, +}; + +// This method returns the custom marshaler info to convert the native interface +// to its managed equivalent. Or null if the interface is not a standard convertible interface. +const StdConvertibleItfInfo *GetConvertionInfoFromNativeIID(REFGUID rGuidNativeItf) +{ + CONTRACT (const StdConvertibleItfInfo*) + { + NOTHROW; + POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); + } + CONTRACT_END; + + // Look in the table of interfaces that have standard convertions to see if the + // specified interface is there. + for (int i = 0; i < sizeof(aStdConvertibleInterfaces) / sizeof(StdConvertibleItfInfo); i++) + { + if (IsEqualGUID(rGuidNativeItf, *(aStdConvertibleInterfaces[i].m_pNativeTypeIID))) + RETURN &aStdConvertibleInterfaces[i]; + } + + // The interface is not in the table. + RETURN NULL; +} + +//***************************************************************************** +// Given a typelib, determine the managed namespace name. +//***************************************************************************** +HRESULT GetNamespaceNameForTypeLib( // S_OK or error. + ITypeLib *pITLB, // [IN] The TypeLib. + BSTR *pwzNamespace) // [OUT] Put the namespace name here. +{ + CONTRACTL + { + DISABLED(NOTHROW); // PostError goes down a throwing path right now. Revisit this when fixed. + PRECONDITION(CheckPointer(pITLB)); + PRECONDITION(CheckPointer(pwzNamespace)); + } + CONTRACTL_END; + + HRESULT hr = S_OK; // A result. + ITypeLib2 *pITLB2=0; //For getting custom value. + TLIBATTR *pAttr=0; // Typelib attributes. + BSTR szPath=0; // Typelib path. + + // If custom attribute for namespace exists, use it. + if (pITLB->QueryInterface(IID_ITypeLib2, (void **)&pITLB2) == S_OK) + { + VARIANT vt; + VariantInit(&vt); + if (pITLB2->GetCustData(GUID_ManagedName, &vt) == S_OK) + { + if (V_VT(&vt) == VT_BSTR) + { + // If the namespace ends with .dll then remove the extension. + LPWSTR pDest = wcsstr(vt.bstrVal, DLL_EXTENSION); + if (pDest && (pDest[DLL_EXTENSION_LEN] == 0 || pDest[DLL_EXTENSION_LEN] == ' ')) + *pDest = 0; + + if (!pDest) + { + // If the namespace ends with .exe then remove the extension. + pDest = wcsstr(vt.bstrVal, EXE_EXTENSION); + if (pDest && (pDest[EXE_EXTENSION_LEN] == 0 || pDest[EXE_EXTENSION_LEN] == ' ')) + *pDest = 0; + } + + if (pDest) + { + // We removed the extension so re-allocate a string of the new length. + *pwzNamespace = SysAllocString(vt.bstrVal); + SysFreeString(vt.bstrVal); + } + else + { + // There was no extension to remove so we can use the string returned + // by GetCustData(). + *pwzNamespace = vt.bstrVal; + } + + goto ErrExit; + } + else + { + VariantClear(&vt); + } + } + } + + // No custom attribute, use library name. + IfFailGo(pITLB->GetDocumentation(MEMBERID_NIL, pwzNamespace, 0, 0, 0)); + +ErrExit: + if (szPath) + ::SysFreeString(szPath); + if (pAttr) + pITLB->ReleaseTLibAttr(pAttr); + if (pITLB2) + pITLB2->Release(); + + return hr; +} // HRESULT GetNamespaceNameForTypeLib() + +//***************************************************************************** +// Given an ITypeInfo, determine the managed name. Optionally supply a default +// namespace, otherwise derive namespace from containing typelib. +//***************************************************************************** +HRESULT GetManagedNameForTypeInfo( // S_OK or error. + ITypeInfo *pITI, // [IN] The TypeInfo. + LPCWSTR wzNamespace, // [IN, OPTIONAL] Default namespace name. + LPCWSTR wzAsmName, // [IN, OPTIONAL] Assembly name. + BSTR *pwzName) // [OUT] Put the name here. +{ + CONTRACTL + { + DISABLED(NOTHROW); + PRECONDITION(CheckPointer(pITI)); + PRECONDITION(CheckPointer(wzNamespace, NULL_OK)); + PRECONDITION(CheckPointer(wzAsmName, NULL_OK)); + PRECONDITION(CheckPointer(pwzName)); + } + CONTRACTL_END; + + HRESULT hr = S_OK; // A result. + ITypeInfo2 *pITI2=0; // For getting custom value. + ITypeLib *pITLB=0; // Containing typelib. + + BSTR bstrName=0; // Typeinfo's name. + BSTR bstrNamespace=0; // Typelib's namespace. + int cchFullyQualifiedName; // Size of namespace + name buffer. + int cchAsmName=0; // The size of the assembly name. + int cchAsmQualifiedName=0; // The size of the assembly qualified name buffer. + CQuickArray<WCHAR> qbFullyQualifiedName; // The fully qualified type name. + + // Check for a custom value with name. + if (pITI->QueryInterface(IID_ITypeInfo2, (void **)&pITI2) == S_OK) + { + VARIANT vt; // For getting custom value. + ::VariantInit(&vt); + if (pITI2->GetCustData(GUID_ManagedName, &vt) == S_OK && vt.vt == VT_BSTR) + { // There is a custom value with the name. Just believe it. + *pwzName = vt.bstrVal; + vt.bstrVal = 0; + vt.vt = VT_EMPTY; + goto ErrExit; + } + } + + // Still need name, get the namespace. + if (wzNamespace == 0) + { + IfFailGo(pITI->GetContainingTypeLib(&pITLB, 0)); + IfFailGo(GetNamespaceNameForTypeLib(pITLB, &bstrNamespace)); + wzNamespace = bstrNamespace; + } + + // Get the name, and combine with namespace. + IfFailGo(pITI->GetDocumentation(MEMBERID_NIL, &bstrName, 0,0,0)); + cchFullyQualifiedName = (int)(wcslen(bstrName) + wcslen(wzNamespace) + 1); + IfFailGo(qbFullyQualifiedName.ReSizeNoThrow(cchFullyQualifiedName + 1)); + ns::MakePath(qbFullyQualifiedName.Ptr(), cchFullyQualifiedName + 1, wzNamespace, bstrName); + + // If the assembly name is specified, then add it to the type name. + if (wzAsmName) + { + cchAsmName = (int)wcslen(wzAsmName); + cchAsmQualifiedName = cchFullyQualifiedName + cchAsmName + 3; + IfNullGo(*pwzName = ::SysAllocStringLen(0, cchAsmQualifiedName)); + ns::MakeAssemblyQualifiedName(*pwzName, cchAsmQualifiedName, qbFullyQualifiedName.Ptr(), cchFullyQualifiedName, wzAsmName, cchAsmName); + } + else + { + IfNullGo(*pwzName = ::SysAllocStringLen(qbFullyQualifiedName.Ptr(), cchFullyQualifiedName)); + } + +ErrExit: + if (bstrName) + ::SysFreeString(bstrName); + if (bstrNamespace) + ::SysFreeString(bstrNamespace); + if (pITLB) + pITLB->Release(); + if (pITI2) + pITI2->Release(); + + return (hr); +} // HRESULT GetManagedNameForTypeInfo() |