c# - 为什么即使 GetLastError 为 0,CLRHosting API 也无法正常工作?

标签 c# c++ .net dll-injection clr-hosting

我正在尝试按照此 tutorial 将托管 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;
}

问题

现在的问题是,当我执行 native 代码时,GetLastError() 返回 0。那是在调用 ExecuteInDefaultAppDomain() 之后。根据 Codeproject 链接,它应该显示对话框,但在我的例子中它没有显示任何内容。

我不确定这个问题,任何建议/指针都会有所帮助。谢谢。

最佳答案

托管 api 使用 COM,它不会通过 GetLastError() 报告错误。该方法的返回值是错误代码。它是一个 HRESULT,托管 api 通常返回错误代码,如 0x8013xxxx。您将在 CorError.h SDK header 中找到 xxxx 值。

你需要这样的东西:

hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(...);
if (FAILED(hr)) ErrorExit(L"Execute", hr);

并将此检查添加到您调用的每个电话中。不这样做可能会使您的程序以难以诊断的方式崩溃。您需要获得所有帮助,您不再有友好的 .NET 异常来告诉您哪里出了问题。

其他生存策略使用混合模式调试,因此您可以在托管异常变成 HRESULT 之前对其进行诊断,在托管代码中编写 AppDomain.CurrentDomain.UnhandledException 事件处理程序,使用 IErrorInfo 获取异常在您的主机中使用正确的方法名称消息,它是 L"EntryPoint",并根据需要将其设为静态

关于c# - 为什么即使 GetLastError 为 0,CLRHosting API 也无法正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21510919/

相关文章:

c# - 本地化在通过 QueryString 设置文化时起作用,但在文化在途中时不起作用

C++程序结束得太早

c++ - 如何获取连接到 mysql 服务器的主机列表

c# - 创建TextBlock时我可以知道它的宽度吗?

c# - 以无边界形式绘制夹具

c# - 为什么同一设计会得到两种不同的结果?

c# - 带有 C++ 的图形用户界面?还是 C# 和 Java 的路要走?

javascript - 如何将 C# 变量传递给 JavaScript 函数

c++ - 如何生成不与父进程一起死亡的子进程?

c# - .NET winforms 应用程序在不使用 ClickOnce 的情况下更新自身的最佳方式是什么?