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

C# 如何调试使用自定义.NET Core 2主机加载的程序集?,c#,c++,debugging,.net-core,visual-studio-debugging,C#,C++,Debugging,.net Core,Visual Studio Debugging,为了扩展具有托管附加功能的本机应用程序,我创建了一个自定义的.NET Core 2.0主机,与中描述的非常类似 到目前为止,它运行良好并加载我的程序集。它还成功地运行了ICLRRuntimeHost2.CreateDelegate所委托的方法;在一次测试中,我用System.IO.file.writealText将一个“Hello World”写入一个新文件,该文件与预期内容一起出现 然而,我有点困惑于如何在我加载的程序集中调试托管代码 简单地在那里设置断点不会触发 我还尝试搜索特定的与调试相

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

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

然而,我有点困惑于如何在我加载的程序集中调试托管代码

  • 简单地在那里设置断点不会触发
  • 我还尝试搜索特定的与调试相关的属性值对,以传递给
    ICLRRuntimeHost2.CreateAppDomainWithManager
    方法,但没有找到任何属性值对
  • 调用
    Debugger.Break
    会导致MSVC++调试器中断(“bla.exe已触发断点”),但不会进入我的托管代码或理解其中的任何内容。我想这只是一种破坏调试器的常见系统本机方法
  • 或者有类似于Python中的“鸡蛋文件”的东西让VisualStudio将托管代码与调试器“连接”起来吗
如上所述,我的代码与文档非常相似,这里仅供参考
Run
基本上加载coreclr库,从中获取GetClrRuntimeHost函数,实例化应用程序域并运行委派的托管代码。如果少数被调用的额外方法或使用的成员的实现有任何问题,我将根据请求添加它们

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)();
}
void ClrHost::Run(wstring const&assembly、wstring const&type、wstring const&method)
{
//加载CoreCLR.dll并检索GetCLRRuntimeHost函数。
wstring corecrlfilepath=\u runtimeFolder/“coreclr.dll”;
HMODULE coreClr=LoadLibraryExW(coreClrFilePath.c_str(),NULL,0);
如果(!coreClr)
抛出新的ClrHostException(L“无法加载CoreCLR.dll”);
FngGetClrRuntimeHost FngGetClrRuntimeHost=(FngGetClrRuntimeHost)GetProcAddress(coreClr,“GetCLRRuntimeHost”);
如果(!fnGetClrRuntimeHost)
抛出新的ClrHostException(L“找不到GetCLRRuntimeHost函数”);
//实例化并设置运行时主机。
if(失败(fnGetClrRuntimeHost(IID_ICLRRuntimeHost2,(IUnknown**)和_runtimeHost)))
抛出新的ClrHostException(L“无法检索ICLRRuntimeHost2实例”);
STARTUP\u FLAGS startupFlags=静态\u转换(
启动\u标志::启动\u并发\u GC
|启动标志::启动单个应用域
|启动\u标志::启动\u加载程序\u优化\u单个\u域);
if(失败(_runtimeHost->SetStartupFlags(startupFlags)))
抛出新的ClrHostException(L“无法设置运行时主机启动标志”);
if(失败(\u runtimeHost->Start())
抛出新的ClrHostException(L“无法启动运行时主机”);
//使用配置的设置实例化AppDomain。
int appDomainFlags=APPDOMAIN\u启用\u平台\u特定的\u应用
|APPDOMAIN\u启用\u PINVOKE\u和\u CLASSIC\u COMINTEROP
|APPDOMAIN\u禁用\u透明度\u强制执行;
wstring tpassemblies=concatenatePath(GetAssembliesFromFolder(_runtimeFolder));
wstring assemblyFolders=连接路径(_assemblyFolders);
wstring nativeLibFolders=连接路径(_nativeLibFolders);
LPCWSTR propertyKeys[]={
L“受信任的平台组件”,
L“应用程序路径”,
L“应用程序路径”,
L“本机DLL搜索目录”,
L“平台资源根”,
L“AppDomainCompatinSwitch”
};
LPCWSTR属性值[]={
tpassemblies.c_str(),
assemblyFolders.c_str(),
assemblyFolders.c_str(),
nativeLibFolders.c_str(),
assemblyFolders.c_str(),
L“未指定时使用最新行为”
};
如果(失败)(运行时主机->CreateAppDomainWithManager(L“IDA.NET AppDomain”),appDomainFlags,NULL,NULL,
sizeof(propertyKeys)/sizeof(LPCWSTR)、propertyKeys、propertyvalue和appDomainID)
{
抛出新的ClrHostException(L“无法创建AppDomain”);
}
//获取托管静态方法的委托。
void*fnlegate=NULL;
HRESULT hr=\u runtimeHost->CreateDelegate(\u appDomainID,assembly.c\u str(),type.c\u str(),method.c\u str(),
(INT_PTR*)和FN代表);
如果(失败(小时))
抛出新的ClrHostException(L“无法运行“+程序集+L.”中的“+类型+L.”+方法+L”);
//执行托管代码。
((RunSignature*)fnDelegate)();
}

我刚刚意识到它比预期的要简单

现在,我总是使用我的本地C++项目(主机.NETCore)作为VisualStudio./P>中的启动项目。 但是,通过创建启动配置文件,启动外部本机可执行文件而不是“启动”我的库,将启动项目更改为托管C#库,可以调试和单步执行托管代码

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

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