Почему CLRHosting API не работает, даже если GetLastError равен 0?
Я пытаюсь загрузить управляемую C# dll в управляемый процесс C#, следуя этому руководству. Я немного потрудился на C/C++ и имею практические знания по MS COM, но C# и управляемый код - это совершенно новый для меня зверь, так что будьте добры, если я что-то делаю не так. У меня есть.NET 4.5 в моей системе, и это та же среда выполнения, которая используется по умолчанию (я думаю). Код на данный момент (в основном, скопирован из ссылки выше):
Код - C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace InjectSample
{
public class Program
{
int EntryPoint(String pwzArgument)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show(
"I am a managed app.\n\n" +
"I am running inside: [" +
System.Diagnostics.Process.GetCurrentProcess().ProcessName +
"]\n\n" + (String.IsNullOrEmpty(pwzArgument) ?
"I was not given an argument" :
"I was given this argument: [" + pwzArgument + "]"));
return 0;
}
static void Main(string[] args)
{
Program prog = new Program();
prog.EntryPoint("hello world");
}
}
}
Родной код
#include <metahost.h>
#pragma comment(lib, "mscoree.lib")
#import "mscorlib.tlb" raw_interfaces_only \
high_property_prefixes("_get","_put","_putref") \
rename("ReportEvent", "InteropServices_ReportEvent")
#include <strsafe.h>
void ErrorExit(LPCWSTR lpszFunction, DWORD dwLastError)
{
if(dwLastError == 0) return;
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dwFlag = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
FormatMessage( dwFlag, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dwLastError, lpMsgBuf);
::MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
int wmain(int argc, wchar_t* argv[])
{
HRESULT hr;
ICLRMetaHost *pMetaHost = NULL;
ICLRRuntimeInfo *pRuntimeInfo = NULL;
ICLRRuntimeHost *pClrRuntimeHost = NULL;
// build runtime
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost,
IID_PPV_ARGS(&pClrRuntimeHost));
// start runtime
hr = pClrRuntimeHost->Start();
// execute managed assembly
DWORD pReturnValue;
SetLastError(0);
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(
L"C:\\Temp\\InjectSample.exe",
L"InjectExample.Program",
L"int EntryPoint(String pwzArgument)",
L"hello .net runtime",
&pReturnValue);
ErrorExit(L"ExecuteInDefaultAppDomain()", GetLastError());
// free resources
pMetaHost->Release();
pRuntimeInfo->Release();
pClrRuntimeHost->Release();
return 0;
}
проблема
Теперь проблема в том, что когда я выполняю нативный код, GetLastError()
возвращается 0
, Это сразу после звонка ExecuteInDefaultAppDomain()
, По ссылке Codeproject, он должен был показать диалоговое окно, но в моем случае он ничего не показывает.
Я не уверен в проблеме, любое предложение / указатель будет полезно. Благодарю.
1 ответ
API хостинга использует COM, он не сообщает об ошибках через GetLastError(). Возвращаемым значением метода является код ошибки. Это HRESULT, API-интерфейс хостинга обычно возвращает коды ошибок, например 0x8013xxxx. Вы найдете значения xxxx в заголовке SDK CorError.h.
Вам понадобится что-то вроде этого:
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(...);
if (FAILED(hr)) ErrorExit(L"Execute", hr);
И добавьте эту проверку к каждому звонку. Несоблюдение этого требования может привести к аварийному завершению вашей программы. И вам нужна вся помощь, которую вы можете получить, у вас больше нет дружественных исключений.NET, чтобы сообщить вам, что пошло не так.
В других стратегиях выживания используется отладка в смешанном режиме, поэтому у вас есть шанс диагностировать управляемые исключения, прежде чем они превратятся в HRESULT, написав обработчик событий AppDomain.CurrentDomain.UnhandledException в вашем управляемом коде, используя IErrorInfo, чтобы вы могли получить сообщение об исключении в своем host, используя правильное имя метода, это L"EntryPoint", и делает его статическим, как требуется.