Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use .NET 4 CLR hosting API #18

Open
wants to merge 13 commits into
base: master
from
Next

Use CLR version 4 hosting API.

Still use CLR version 2 hosting API when starting CLR version 2.
Report errors for any failed hosting call.
Fix warnings.
Use Microsoft.NET.Sdk-style project for wwDotNetBridge.
  • Loading branch information
breyed committed Apr 20, 2018
commit 307e70ac70c17be5744ce6cc0cd1b0a0ee947758
@@ -1,5 +1,6 @@
#include <atlbase.h>
#include <mscoree.h>
#include <metahost.h>

#import "mscorlib.tlb" raw_interfaces_only no_smart_pointers high_property_prefixes("_get","_put","_putref")

@@ -13,82 +14,94 @@ CComPtr<ICorRuntimeHost> spRuntimeHost = NULL;
CComPtr<_AppDomain> spDefAppDomain = NULL;
CComPtr<_Object> spDefObject = NULL;

BSTR ClrVersion = NULL;
// .NET Framework 4
CComPtr<ICLRMetaHost> pMetaHost;
CComPtr<ICLRRuntimeInfo> pRuntimeInfo;

CComBSTR ClrVersion;

DWORD WINAPI SetClrVersion(char *version)
{
ClrVersion = CComBSTR(version);
ClrVersion = version;
return 1;
}

/// Assigns an error message
DWORD WINAPI SetError(HRESULT hr, char *ErrorMessage)
class HresultException
{
if (ErrorMessage)
{
int len= strlen(ErrorMessage);
LoadStringRC(hr & 0xffff,(LPWSTR)ErrorMessage,len/2,0);
sprintf((char *)ErrorMessage,"%ws",ErrorMessage);

return strlen(ErrorMessage);
char const* const error;
HRESULT const hr;

public:
HresultException(char const* error) : error(error), hr(0) {}
HresultException(HRESULT hr) : error(nullptr), hr(hr) {}

DWORD GetMessage(char* errorMessage)
{
auto outputSize = strlen(errorMessage);
if (error) {
strcpy_s(errorMessage, outputSize, error);
} else {
#pragma warning(push)
#pragma warning(disable: 4996) // LoadStringRC is deprecated, but no alternative is suggested.
LoadStringRC(hr & 0xffff, (LPWSTR)errorMessage, outputSize / 2, 0);
#pragma warning(pop)
sprintf_s((char *)errorMessage, outputSize, "%ws", (LPWSTR)errorMessage);
}
return strlen(errorMessage);
}

strcpy(ErrorMessage,"");
return 0;
};

void VerifyHresult(HRESULT hr)
{
if (FAILED(hr))
throw HresultException(hr);
}

/// Starts up the CLR and creates a Default AppDomain
DWORD WINAPI ClrLoad(char *ErrorMessage, DWORD *dwErrorSize)
void WINAPI ClrLoadLegacyVersion2()
{
if (spDefAppDomain)
return 1;


#pragma warning(push)
#pragma warning(disable: 4996) // CorBindToRuntimeEx is deprecated, but we need to use it to start CLR version 2.
//Retrieve a pointer to the ICorRuntimeHost interface
HRESULT hr = CorBindToRuntimeEx(
ClrVersion, //Retrieve latest version by default
L"wks", //Request a WorkStation build of the CLR
STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN | STARTUP_CONCURRENT_GC,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(void**)&spRuntimeHost
);

if (FAILED(hr))
{
*dwErrorSize = SetError(hr,ErrorMessage);
return hr;
}
VerifyHresult(CorBindToRuntimeEx(
ClrVersion, //Retrieve latest version by default
L"wks", //Request a WorkStation build of the CLR
STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN | STARTUP_CONCURRENT_GC,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(void**)&spRuntimeHost
));
#pragma warning(pop)

//Start the CLR
hr = spRuntimeHost->Start();

if (FAILED(hr))
return hr;
VerifyHresult(spRuntimeHost->Start());

CComPtr<IUnknown> pUnk;

//Retrieve the IUnknown default AppDomain
//hr = spRuntimeHost->GetDefaultDomain(&pUnk);
//if (FAILED(hr))
// return hr;


WCHAR domainId[50];
swprintf(domainId,L"%s_%i",L"wwDotNetBridge",GetTickCount());
hr = spRuntimeHost->CreateDomain(domainId,NULL,&pUnk);

//spRuntimeHost->CreateDomainSetup(&pUnk);
//

hr = pUnk->QueryInterface(&spDefAppDomain.p);
if (FAILED(hr))
return hr;

return 1;
swprintf(domainId, 50, L"%s_%i", L"wwDotNetBridge", GetTickCount());
VerifyHresult(spRuntimeHost->CreateDomain(domainId, NULL, &pUnk));
VerifyHresult(pUnk->QueryInterface(&spDefAppDomain.p));
}

void WINAPI ClrLoad()
{
if (ClrVersion.Length() >= 2 && ClrVersion[0] == 'v' && ClrVersion[1] == '2') {
ClrLoadLegacyVersion2();
return;
}

// Tutorial on how this works: https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0
VerifyHresult(CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)));
VerifyHresult(pMetaHost->GetRuntime(ClrVersion, IID_PPV_ARGS(&pRuntimeInfo)));
BOOL fLoadable;
VerifyHresult(pRuntimeInfo->IsLoadable(&fLoadable));
if (!fLoadable) throw HresultException("CLR is not loadable.");
VerifyHresult(pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&spRuntimeHost)));
VerifyHresult(spRuntimeHost->Start());
CComPtr<IUnknown> spAppDomainThunk;
VerifyHresult(spRuntimeHost->GetDefaultDomain(&spAppDomainThunk));
VerifyHresult(spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefAppDomain)));
}

// *** Unloads the CLR from the process
DWORD WINAPI ClrUnload()
@@ -99,95 +112,46 @@ DWORD WINAPI ClrUnload()
spDefAppDomain.Release();
spDefAppDomain = NULL;

spRuntimeHost->Stop();
spRuntimeHost->Stop();
spRuntimeHost.Release();
spRuntimeHost = NULL;
}

return 1;
}


// *** Creates an instance by Name (ie. local path assembly without extension or GAC'd FullName of
// any signed assemblies.
DWORD WINAPI ClrCreateInstance( char *AssemblyName, char *className, char *ErrorMessage, DWORD *dwErrorSize)
IDispatch* WINAPI ClrCreateInstance(char *AssemblyName, char *className, char *ErrorMessage, DWORD *dwErrorSize)
{
CComPtr<_ObjectHandle> spObjectHandle;

if (!spDefAppDomain)
{
if (ClrLoad(ErrorMessage,dwErrorSize) != 1)
return -1;
}

DWORD hr;

//Creates an instance of the type specified in the Assembly
hr = spDefAppDomain->CreateInstance(
_bstr_t(AssemblyName),
_bstr_t(className),
&spObjectHandle
);



*dwErrorSize = 0;

if (FAILED(hr))
{
*dwErrorSize = SetError(hr,ErrorMessage);
return -1;
try {
if (!spDefAppDomain)
ClrLoad();
CComPtr<_ObjectHandle> spObjectHandle;
VerifyHresult(spDefAppDomain->CreateInstance(_bstr_t(AssemblyName), _bstr_t(className), &spObjectHandle));
CComVariant VntUnwrapped;
VerifyHresult(spObjectHandle->Unwrap(&VntUnwrapped));
return VntUnwrapped.pdispVal;
} catch (HresultException ex) {
*dwErrorSize = ex.GetMessage(ErrorMessage);
return NULL;
}

CComVariant VntUnwrapped;
hr = spObjectHandle->Unwrap(&VntUnwrapped);
if (FAILED(hr))
return -1;


CComPtr<IDispatch> pDisp;
pDisp = VntUnwrapped.pdispVal;

return (DWORD) pDisp.p;
}

/// *** Creates an instance of a class from an assembly referenced through it's disk path
DWORD WINAPI ClrCreateInstanceFrom( char *AssemblyFileName, char *className, char *ErrorMessage, DWORD *dwErrorSize)
/// *** Creates an instance of a class from an assembly referenced through its disk path
IDispatch* WINAPI ClrCreateInstanceFrom(char *AssemblyFileName, char *className, char *ErrorMessage, DWORD *dwErrorSize)
{
CComPtr<_ObjectHandle> spObjectHandle;

if (!spDefAppDomain)
{
if (ClrLoad(ErrorMessage,dwErrorSize) != 1)
return -1;
}

DWORD hr;

//Creates an instance of the type specified in the Assembly
hr = spDefAppDomain->CreateInstanceFrom(
_bstr_t(AssemblyFileName),
_bstr_t(className),
&spObjectHandle
);

*dwErrorSize = 0;

if (FAILED(hr))
{
*dwErrorSize = SetError(hr,ErrorMessage);
return -1;
try {
if (!spDefAppDomain)
ClrLoad();
CComPtr<_ObjectHandle> spObjectHandle;
VerifyHresult(spDefAppDomain->CreateInstanceFrom(_bstr_t(AssemblyFileName), _bstr_t(className), &spObjectHandle));
CComVariant VntUnwrapped;
VerifyHresult(spObjectHandle->Unwrap(&VntUnwrapped));
return VntUnwrapped.pdispVal;
} catch (HresultException ex) {
*dwErrorSize = ex.GetMessage(ErrorMessage);
return NULL;
}

CComVariant VntUnwrapped;
hr = spObjectHandle->Unwrap(&VntUnwrapped);
if (FAILED(hr))
return -1;

CComPtr<IDispatch> pDisp;
pDisp = VntUnwrapped.pdispVal;

// *** pass the raw COM pointer back
return (DWORD) pDisp.p;
}

@@ -1,10 +1,7 @@
LIBRARY wwipstuff
LIBRARY ClrHost
EXPORTS DllMain @1
ClrLoad @105
ClrUnload @106
ClrCreateInstance @108
ClrCreateInstanceFrom @109
SetClrVersion @110



@@ -47,7 +47,6 @@
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;


namespace Westwind.WebConnection
@@ -66,7 +65,6 @@ namespace Westwind.WebConnection
[ProgId("Westwind.wwDotNetBridge")]
public class wwDotNetBridge
{

private static bool _firstLoad = true;

/// <summary>
@@ -436,7 +434,7 @@ protected object CreateInstanceFromFile_Internal(string AssemblyFileName, string
if (args == null)
server = AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(AssemblyFileName, TypeName);
else
server = AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(AssemblyFileName, TypeName, false, BindingFlags.Default, null, args, null, null, null);
server = AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(AssemblyFileName, TypeName, false, BindingFlags.Default, null, args, null, null);
}
catch (Exception ex)
{
@@ -642,7 +640,6 @@ public bool SetStaticProperty(string typeName, string property, object value)
value = FixupParameter(value);

ErrorMessage = "";
object result = null;
try
{
type.InvokeMember(property, BindingFlags.Static | BindingFlags.Public | BindingFlags.SetField | BindingFlags.SetProperty, null, type, new object[1] { value });
@@ -677,8 +674,6 @@ public string GetEnumString(string EnumTypeName, object Value)
SetError(ex.GetBaseException());
throw ex.GetBaseException();
}

return null;
}

public Type GetType(object value)
@@ -1,24 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
#if SHAREWARE
[assembly: AssemblyTitle("Unregistered: West Wind .NET Bridge Connector (.NET). --- Please register your copy at www.west-wind.com/wwstore")]
#else
[assembly: AssemblyTitle("West Wind .NET Bridge Connector (.NET)")]
#endif
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("West Wind Technologies")]
[assembly: AssemblyProduct("West Wind Client Tools")]
[assembly: AssemblyCopyright("Copyright 漏 2007-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

//[assembly: AllowPartiallyTrustedCallers]
using System.Runtime.InteropServices;

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
@@ -28,15 +8,3 @@

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0cc053c9-1cdd-4595-b236-e06b32aafec4")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.19.0")]

ProTip! Use n and p to navigate between commits in a pull request.
You can鈥檛 perform that action at this time.