如何调试使用自定义.NET Core 2主机加载的程序集?

时间:2018-04-20 16:05:12

标签: c# c++ debugging .net-core visual-studio-debugging

为了扩展具有托管附加功能的本机应用程序,我创建了一个自定义.NET Core 2.0主机,与official docs中描述的内容非常相似。

到目前为止它运行良好并加载我的程序集。它还成功运行ICLRRuntimeHost2.CreateDelegate委派的方法;为了测试,我在一个带有System.IO.File.WriteAllText的新文件中写了一个“Hello World”,该文件与预期的内容一起出现。

但是,我对我如何调试我加载的程序集中的托管代码感到有点困惑。

  • 只需设置断点就不会触发。
  • 我还尝试搜索特定的与调试相关的属性 - 值对,以传递给ICLRRuntimeHost2.CreateAppDomainWithManager方法,但没有找到任何方法。
  • 调用Debugger.Break 会导致MSVC ++调试程序中断(“bla.exe已触发断点。”),但不会进入我的托管代码或了解其中的任何内容。我想这只是打破调试器的常见系统原生方式。
  • 或者是否有像Python中所知的“egg文件”,以使Visual Studio将托管代码与调试器“连接”?

如上所述,我的代码与文档非常相似,仅供参考。 Run基本上加载coreclr库,从中获取GetClrRuntimeHost函数,实例化app域并运行委托的托管代码。如果少数几个被称为额外方法或使用过的成员的实现有任何问题,我会根据要求添加它们。

void ClrHost::Run(wstring const& assembly, wstring const& type, wstring const& method)
{
    // Load the CoreCLR.dll and retrieve the GetCLRRuntimeHost function.
    wstring coreClrFilePath = _runtimeFolder / "coreclr.dll";
    HMODULE coreClr = LoadLibraryExW(coreClrFilePath.c_str(), NULL, 0);
    if (!coreClr)
        throw new ClrHostException(L"Could not load CoreCLR.dll.");
    FnGetCLRRuntimeHost fnGetClrRuntimeHost = (FnGetCLRRuntimeHost)GetProcAddress(coreClr, "GetCLRRuntimeHost");
    if (!fnGetClrRuntimeHost)
        throw new ClrHostException(L"Could not find GetCLRRuntimeHost function.");

    // Instantiate and set up a runtime host.
    if (FAILED(fnGetClrRuntimeHost(IID_ICLRRuntimeHost2, (IUnknown**)&_runtimeHost)))
        throw new ClrHostException(L"Could not retrieve ICLRRuntimeHost2 instance.");
    STARTUP_FLAGS startupFlags = static_cast<STARTUP_FLAGS>(
        STARTUP_FLAGS::STARTUP_CONCURRENT_GC
        | STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN
        | STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN);
    if (FAILED(_runtimeHost->SetStartupFlags(startupFlags)))
        throw new ClrHostException(L"Could not set runtime host startup flags.");
    if (FAILED(_runtimeHost->Start()))
        throw new ClrHostException(L"Could not start runtime host.");

    // Instantiate the AppDomain with the configured settings.
    int appDomainFlags = APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
        | APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
        | APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT;
    wstring tpaAssemblies = ConcatenatePaths(GetAssembliesFromFolder(_runtimeFolder));
    wstring assemblyFolders = ConcatenatePaths(_assemblyFolders);
    wstring nativeLibFolders = ConcatenatePaths(_nativeLibFolders);
    LPCWSTR propertyKeys[] = {
        L"TRUSTED_PLATFORM_ASSEMBLIES",
        L"APP_PATHS",
        L"APP_NI_PATHS",
        L"NATIVE_DLL_SEARCH_DIRECTORIES",
        L"PLATFORM_RESOURCE_ROOTS",
        L"AppDomainCompatSwitch"
    };
    LPCWSTR propertyValues[] = {
        tpaAssemblies.c_str(),
        assemblyFolders.c_str(),
        assemblyFolders.c_str(),
        nativeLibFolders.c_str(),
        assemblyFolders.c_str(),
        L"UseLatestBehaviorWhenTFMNotSpecified"
    };
    if (FAILED(_runtimeHost->CreateAppDomainWithManager(L"IDA.NET AppDomain", appDomainFlags, NULL, NULL,
        sizeof(propertyKeys) / sizeof(LPCWSTR), propertyKeys, propertyValues, &_appDomainID)))
    {
        throw new ClrHostException(L"Could not create AppDomain.");
    }

    // Get a delegate for the managed static method.
    void *fnDelegate = NULL;
    HRESULT hr = _runtimeHost->CreateDelegate(_appDomainID, assembly.c_str(), type.c_str(), method.c_str(),
        (INT_PTR*)&fnDelegate);
    if (FAILED(hr))
        throw new ClrHostException(L"Could not run " + type + L"." + method + L" in " + assembly + L".");

    // Execute the managed code.
    ((RunSignature*)fnDelegate)();
}

1 个答案:

答案 0 :(得分:0)

我刚才意识到这比预期的要简单!

现在,我总是使用我的原生C ++项目(承载.NET Core的项目)作为Visual Studio中的启动项目。

但是,通过创建启动配置文件来启动外部本机可执行文件而不是&#34;启动&#34;将启动项目更改为托管C#库。我的库,可以调试和逐步执行托管代码。

您可以在&#34; Debug&#34;下的项目属性中设置这样的启动配置文件,或者将典型的.NET Core Properties\launchSettings.json添加到您的托管项目根目录,存储如下内容:

{
"profiles": {
    "Any profile name (typically the project name)": {
    "commandName": "Executable",
    "executablePath": "C:\\FullNativeExecutablePath\\AndFileName.exe",
    "workingDirectory": "C:\\FullNativeExecutablePath"
    }
}
}