C++ CLR主机没有';不执行WPF应用程序,但它不执行WinForms
我制作了一个非常类似于的代码。两者的区别在于,我从内存加载可执行文件,而他从文件加载。另一个区别是他调用了一些随机方法,而我想调用Main方法 我的目标是成为.NETreactor的本地加载程序 该代码适用于控制台应用程序和WinForms。唯一的问题是它不会加载WPF应用程序,更具体地说,它在这一行失败:C++ CLR主机没有';不执行WPF应用程序,但它不执行WinForms,c++,wpf,clr,C++,Wpf,Clr,我制作了一个非常类似于的代码。两者的区别在于,我从内存加载可执行文件,而他从文件加载。另一个区别是他调用了一些随机方法,而我想调用Main方法 我的目标是成为.NETreactor的本地加载程序 该代码适用于控制台应用程序和WinForms。唯一的问题是它不会加载WPF应用程序,更具体地说,它在这一行失败:pMethodInfo->Invoke_3(v2、p2和v)与hr=0x8013164(COR_E__targetinthival)。WPF项目创建于VS2019,目标体系结构(x86)和.N
pMethodInfo->Invoke_3(v2、p2和v)代码>与hr=0x8013164(COR_E__targetinthival)
。WPF项目创建于VS2019,目标体系结构(x86)和.NET Framework(4.0)与loader的相匹配
下图显示了WPF应用程序的主要功能。我真的不知道它为什么会引起TargetInvestment
代码如下:
int LoadAssembly(LPVOID bytes, DWORD size)
{
HRESULT hr;
ICLRMetaHost* pMetaHost = NULL;
ICLRRuntimeInfo* pRuntimeInfo = NULL;
ICorRuntimeHost* pCorRuntimeHost = NULL;
IUnknownPtr UnkAppDomain = NULL;
_AppDomainPtr AppDomain = NULL;
_AssemblyPtr pAssembly = NULL;
_MethodInfoPtr pMethodInfo = NULL;
SAFEARRAY* params = NULL;
SAFEARRAY* sa = NULL;
bool bSuccess = false;
while (!bSuccess)
{
// STAThread
CoInitialize(NULL);
// Load and start the .NET runtime.
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
if (FAILED(hr))
break;
// Get the ICLRRuntimeInfo corresponding to a particular CLR version. It
// supersedes CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE.
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
if (FAILED(hr))
break;
// Check if the specified runtime can be loaded into the process. This
// method will take into account other runtimes that may already be
// loaded into the process and set pbLoadable to TRUE if this runtime can
// be loaded in an in-process side-by-side fashion.
BOOL fLoadable;
hr = pRuntimeInfo->IsLoadable(&fLoadable);
if (FAILED(hr) || !fLoadable)
break;
// Load the CLR into the current process and return a runtime interface
// pointer. ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting
// interfaces supported by CLR 4.0. Here we demo the ICorRuntimeHost
// interface that was provided in .NET v1.x, and is compatible with all
// .NET Frameworks.
hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&pCorRuntimeHost));
if (FAILED(hr))
break;
// Start the CLR
hr = pCorRuntimeHost->Start();
if (FAILED(hr))
break;
// Get a pointer to the default AppDomain in the CLR
hr = pCorRuntimeHost->GetDefaultDomain(&UnkAppDomain);
if (FAILED(hr))
break;
hr = UnkAppDomain->QueryInterface(IID_PPV_ARGS(&AppDomain));
if (FAILED(hr))
break;
SAFEARRAYBOUND sab[1];
sab[0].lLbound = 0;
sab[0].cElements = size;
sa = SafeArrayCreate(VT_UI1, 1, sab);
if (!sa)
break;
void* sa_raw;
hr = SafeArrayAccessData(sa, &sa_raw);
if (FAILED(hr))
break;
memcpy(sa_raw, bytes, size);
SafeArrayUnaccessData(sa);
hr = AppDomain->Load_3(sa, &pAssembly);
if (FAILED(hr))
break;
hr = pAssembly->get_EntryPoint(&pMethodInfo);
if (FAILED(hr))
break;
SAFEARRAY* mtd_params;
hr = pMethodInfo->GetParameters(&mtd_params);
if (FAILED(hr))
break;
SAFEARRAY* p2;
if (mtd_params->rgsabound->cElements != 0)
{
INT argc;
WCHAR** _argv = CommandLineToArgvW(GetCommandLineW(), &argc);
params = SafeArrayCreateVector(VT_BSTR, 0, argc);
if (!params)
break;
for (int i = 0; i < argc; i++)
{
long lIndex = i;
hr = SafeArrayPutElement(params, &lIndex, SysAllocString(_argv[i]));
if (FAILED(hr))
break;
}
p2 = SafeArrayCreateVector(VT_VARIANT, 0, 1);
LONG l2 = 0;
VARIANT vp2;
vp2.vt = VT_ARRAY | VT_BSTR;
vp2.parray = params;
hr = SafeArrayPutElement(p2, &l2, &vp2);
if (FAILED(hr))
break;
}
else
{
SAFEARRAYBOUND sabc[1];
sabc[0].cElements = 0;
sabc[0].lLbound = 0;
p2 = SafeArrayCreate(VT_VARIANT, 1, sabc);
}
VARIANT v;
VARIANT v2;
VariantInit(&v);
VariantInit(&v2);
hr = pMethodInfo->Invoke_3(v2, p2, &v);
VariantClear(&v);
VariantClear(&v2);
if (FAILED(hr))
break;
bSuccess = true;
}
if (pMetaHost)
pMetaHost->Release();
if (pRuntimeInfo)
pRuntimeInfo->Release();
if (pCorRuntimeHost)
{
// Please note that after a call to Stop, the CLR cannot be
// reinitialized into the same process. This step is usually not
// necessary. You can leave the .NET runtime loaded in your process.
pCorRuntimeHost->Stop();
pCorRuntimeHost->Release();
}
if (sa)
SafeArrayDestroy(sa);
if (params)
SafeArrayDestroy(params);
return hr;
}
这与我在C++代码中收到的错误相同,只是我不太确定如何检查其中的内部异常
我做了一些研究,我意识到我必须改变ResourceAssembly
,就像他们在这里做的那样:。新代码如下所示:
byte[] data = File.ReadAllBytes("Test2.exe");
Assembly assembly = Assembly.Load(data);
Type type = typeof(Application);
FieldInfo field = type.GetField("_resourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
field.SetValue(null, assembly);
Type helper = typeof(BaseUriHelper);
PropertyInfo property = helper.GetProperty("ResourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
property.SetValue(null, assembly, null);
assembly.EntryPoint.Invoke(null, new object[0]);
结果是代码加载了WPF应用程序。现在,问题是我如何在C++代码中实现这一点?似乎没有人处理过这个问题。我找到的唯一解决方案是从磁盘而不是内存加载文件-。我找到了这个示例:它适用于WPF,但问题是他们是从文件而不是内存加载文件。我想从内存中加载它。你知道怎么做吗?
byte[] data = File.ReadAllBytes("Test2.exe");
Assembly assembly = Assembly.Load(data);
Type type = typeof(Application);
FieldInfo field = type.GetField("_resourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
field.SetValue(null, assembly);
Type helper = typeof(BaseUriHelper);
PropertyInfo property = helper.GetProperty("ResourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
property.SetValue(null, assembly, null);
assembly.EntryPoint.Invoke(null, new object[0]);