【问题标题】:Configuring .NET library from unmanaged C++从非托管 C++ 配置 .NET 库
【发布时间】:2011-01-20 19:39:41
【问题描述】:

我有一个名为 Foo 的 C# .NET 库,它生成一个 Foo.dll 文件。它也可以通过如下所示的 .config 文件进行配置:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="Foo.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <Foo.Properties.Settings>
      <setting name="Server" serializeAs="String">
        <value>localhost</value>
      </setting>
    </Foo.Properties.Settings>
  </applicationSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

我想做的是从名为 Bar 的非托管 C++ 程序调用此 .NET 库中的函数,并能够从非托管 C++ 应用程序更改其配置。通过在 Foo 中将类/接口属性 ComVisible 设置为 true,我可以从 Bar 调用 Foo 函数。但是,我无法从非托管 C++ 应用程序更改 .config 文件的值 -- 服务器始终是“localhost”。

我正在尝试做的事情——从非托管 C++ 配置 .NET 库——甚至可能吗?

【问题讨论】:

    标签: c# c++ com configuration unmanaged


    【解决方案1】:

    嗯,这是可能的,但不是少量的工作。通常更容易从托管世界创建 appdomain 和设置配置,然后在托管代码中创建一个小的“thunking”层来为非托管客户端包装它。但由于这不是您所要求的,因此您可以通过以下方式实现目标:

    首先您需要导入 mscorelib:

    #include <mscoree.h>
    #import <mscorlib.tlb> raw_interfaces_only no_smart_pointers high_property_prefixes("_get","_put","_putref")
    

    然后绑定到运行时:

    ICorRuntimeHost runtimeHost;
    hr = CorBindToRuntimeEx(
        NULL,   //Retrieve latest version by default
        L"wks", //Request a WorkStation build of the CLR
        STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC, 
        CLSID_CorRuntimeHost,
        IID_ICorRuntimeHost,
        (void**)&runtimeHost
    );
    

    现在启动 CLR 并创建一个 AppDomainSetup 实例。

    hr = runtimeHost->Start();
    IAppDomainSetup pSetup;
    hr = runtimeHost->CreateDomainSetup(&pSetup);
    

    现在根据需要填写设置信息:

    hr = pSetup->put_ApplicationBase(_bstr_t(thisFile));
    hr = pSetup->put_ConfigurationFile(_bstr_t(configFile));
    

    最后创建域:

    hr = __gRuntimeHost->CreateDomainEx(L"ISAPI.Net", pSetup, NULL, &pDomain);
    

    现在您可以选择实例化一个对象并调用方法:

    hr = pDomain->CreateInstanceFrom(_bstr_t(assemblyFile), _bstr_t("Namespace.ClassName"), &pObjectHandle);
    VARIANT vtUnwrapped;
    hr = spObjectHandle->Unwrap(&vtUnwrapped);
    IDispatch pDisp = vtUnwrapped.pdispVal;
    DISPID dispid;
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    hr = pDisp->GetIDsOfNames (
            IID_NULL, 
            szMemberName,
            1,
            LOCALE_SYSTEM_DEFAULT,
            &dispid
        );
    
    hr = pDisp->Invoke (
              dispid,
              IID_NULL,
              LOCALE_SYSTEM_DEFAULT,
              DISPATCH_METHOD,
              &dispparamsNoArgs,
              NULL,
              NULL,
              NULL
          );
    

    显然上面的代码片段是不完整的;但是,如果您对 C++ COM 足够熟练,以上内容应该为您提供足够的信息来解决问题。您应该注意,这是我可以证明在 3.5 中继续工作的“旧”(1.x)托管接口,我不知道这些接口如何/是否在 4.0 上工作。从.Net 2.0 new hosting interfaces 开始介绍。除了 1.x 版本之外,我从不需要任何东西,所以我从不费心升级任何托管代码。

    另见:Hosting Overview

    【讨论】:

    • @csharptest.net:谢谢,目前正在尝试这个,并且还在考虑thunking 解决方案。我一定会让你知道我最终会采用哪种解决方案。
    • 我都做过,我现在告诉你我更喜欢托管代码中的thunking layer;但是,两者都是可行的解决方案。
    • 非常有趣。恐怕我不熟悉创建这个托管的 thunking 层。如果我创建一个包含托管配置的 C++/CLI 层(然后从非托管 C++ 调用该 C++/CLI 层上的方法),是否会被认为是 thunking,或者我只是错了这个?
    • @GP 您目前如何通过 COM InterOp 或其他方式从 C++ 激活托管代码?
    • 通过 COM 互操作。你给了我一个想法。我目前正在将您上面的代码转换为 C# 方法,该方法将共享 C# 程序集加载到临时 AppDomain 中,提供编辑后的配置文件等。这将是从非托管 C++ 调用的那个方法。我希望这行得通。
    【解决方案2】:

    .Net 配置系统为 EXE 加载 .config 文件; DLL 没有配置文件。

    你需要找到不同的方法。

    编辑:您还可以创建HostApp.exe.config 形式的配置文件,其中HostApp 是您的本地EXE 的完整路径。

    【讨论】:

    • 相反,dll 确实有配置文件。例如,如果我在上面给出的示例中的 .NET 库的使用者从非托管 C++ exe 更改为托管 C# exe,则可以通过复制 .config 值来更新共享库 Foo.dll 的服务器Foo 进入 Bar.exe.config。因此,我最初的问题是:如果 .NET 使用者可以更新 .NET dll 的配置文件,那么非托管 C++ 使用者是否能够更新 .NET dll 的配置文件?
    • @GP:这是一个 EXE 的配置文件。 DLL 本身没有配置文件。 .Net 框架将从不查看Foo.dll.config。
    • 我明白你想说什么,虽然我同意共享库 dll 的配置文件不会加载到 AppDomain 中,但这并不是我在评论中所建议的。我要说的是,如果您将 C# Foo 的配置移植(重新:复制和粘贴)到 C# Bar 的 exe.config 文件中,那么这使得 C# Bar 能够在运行时更新 C# Foo 的配置值。 (我会留给你自己测试。)所以,如果可以通过 C# Bar 配置 C# Foo 的配置,非托管 C++ Bar 也可以吗?
    • 我很困惑你在上面的编辑中所说的“完整路径”是什么意思,看到文件名不能包含路径字符。无论如何,我认为它是 HostApp 的名称,但我不敢说您在上面编辑中的建议在非托管 C++ 主机调用 C# .NET 库的情况下不起作用。服务器仍然是本地主机。
    猜你喜欢
    • 1970-01-01
    • 2011-08-31
    • 2013-01-07
    • 1970-01-01
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多