从非托管 C++ 配置 .NET 库

Posted

技术标签:

【中文标题】从非托管 C++ 配置 .NET 库【英文标题】:Configuring .NET library from unmanaged C++ 【发布时间】: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”

我正在尝试做的事情————甚至可能吗?

【问题讨论】:

【参考方案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 库的情况下不起作用。服务器仍然是本地主机。

以上是关于从非托管 C++ 配置 .NET 库的主要内容,如果未能解决你的问题,请参考以下文章

从非托管 c++ 调用托管 c# 函数

从非托管 c++ 调用托管 c# 函数

从非托管 c++ 调用 C# 函数(通过托管包装器)

从非托管 C++ 调用 WCF 服务会导致访问冲突

从非托管 C++ mfc active x dll 启动 C# 对话框

将数组从非托管 C++ 传递到 C#