1

このチュートリアルに従って、マネージド 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 リンクによると、ダイアログ ボックスが表示されているはずですが、私の場合は何も表示されていません。

私は問題について確信が持てません。どんな提案/ポインタも役に立ちます。ありがとう。

4

1 に答える 1

3

ホスティング API は COM を使用し、GetLastError() を通じてエラーを報告しません。メソッドの戻り値はエラー コードです。これは HRESULT であり、ホスティング API は通常、0x8013xxxx などのエラー コードを返します。xxxx の値は、CorError.h SDK ヘッダーにあります。

次のようなものが必要です。

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

そして、あなたが行うすべての呼び出しにこのチェックを追加してください。これを行わないと、診断が困難な方法でプログラムがクラッシュする可能性があります。そして、得ることができるすべての助けが必要です。何が問題なのかを知らせるフレンドリーな .NET 例外はもうありません。

他のサバイバル戦略では混合モードのデバッグを使用しているため、マネージ例外が HRESULT になる前に診断し、マネージ コードに AppDomain.CurrentDomain.UnhandledException イベント ハンドラーを記述し、IErrorInfo を使用して例外メッセージを取得できます。ホスト、適切なメソッド名を使用して、それは L"EntryPoint" であり、必要に応じて静的にします。

于 2014-02-02T13:26:48.193 に答える