代码之家  ›  专栏  ›  技术社区  ›  Ray Brian Agnew

如何调试加载了自定义的程序集。NET Core 2主机?

  •  1
  • Ray Brian Agnew  · 技术社区  · 7 年前

    为了使用托管附加功能扩展本机应用程序,我创建了一个自定义。NET Core 2.0主机,与 official docs

    到目前为止,它运行良好并加载我的程序集。它还成功运行委托给的方法 ICLRRuntimeHost2.CreateDelegate ;在一次测试中,我用 System.IO.File.WriteAllText 与预期内容一起显示。

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

    • 简单地在那里设置断点不会触发。
    • 我还尝试搜索特定的与调试相关的属性值对,以传递给 ICLRRuntimeHost2.CreateAppDomainWithManager 方法,但未找到任何。
    • 使命感 Debugger.Break 导致MSVC++调试器中断(“bla.exe已触发断点”),但不进入我的托管代码,也不理解其中的任何内容。我想这只是破坏调试器的常见系统原生方式。
    • 或者,是否有类似Python中所说的“egg文件”的东西可以让Visual Studio将托管代码与调试器“连接”起来?

    如上所述,我的代码与文档非常相似,这里仅供参考。 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)();
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Ray Brian Agnew    7 年前

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

    现在,我总是使用我的原生C++项目(托管.NETCore的项目)作为Visual Studio中的启动项目。

    但是,通过创建启动概要文件,启动外部本机可执行文件,而不是“启动”我的库,将启动项目更改为托管C#库,可以调试和单步执行托管代码。

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

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