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

发布于 2024-10-13 02:10:54 字数 1251 浏览 4 评论 0原文

我有一个名为 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 库)是否可能?

I have a C# .NET library called Foo that produces a Foo.dll file. It is also configurable via a .config file which looks like this:

<?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>

What I want to do is call functions in this .NET library from an unmanaged C++ program called Bar and be able to change its configuration from the unmanaged C++ application. I was able to call Foo functions from Bar by setting classes/interface attributes ComVisible to true in Foo. However, I was not able to change the .config file values from the unmanaged C++ application -- Server is always "localhost".

Is what I'm trying to do -- configuring a .NET library from unmanaged C++ -- even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神经暖 2024-10-20 02:10:54

嗯,这是可能的,但工作量并不小。通常,从托管世界创建应用程序域并设置配置,然后在托管代码中创建一个小的“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,上面的内容应该为您提供了足够的信息来解决这个问题。您应该注意,这是“旧”(1.x)托管接口,我可以证明它可以在 3.5 中继续工作,我不知道这些接口如何/是否在 4.0 上工作。自.Net 2.0 新托管接口 进行了介绍。我从来不需要 1.x 版本之外的任何东西,所以我从来没有费心去升级任何托管代码。

另请参阅:托管概述

Well this is possible, but not a small amount of work. It's generally easier to create the appdomain and set configuration from the managed world and then create a small 'thunking' layer in managed code to wrap it all up for unmanaged clients. But since that isn't what you asked for, here is how you could accomplish your goal:

First you will need to import the mscorelib:

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

Then bind to the runtime:

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
);

Now startup the CLR and create an AppDomainSetup instance.

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

Now fill in the setup information as appropriate:

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

Finally create the domain:

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

Now you can optionally instantiate an object and call methods:

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
      );

Obviously the code fragments above are incomplete; however, if your adept enough at C++ COM the above should provide you with enough information to work it out. You should note that this is the 'old' (1.x) hosting interfaces which I can attest continue to work through 3.5, I have no idea how/if these work on 4.0. As of .Net 2.0 new hosting interfaces were introduced. I've never had need of anything beyond the 1.x versions, so I never bothered to upgrade any hosting code.

see also: Hosting Overview

陌伤ぢ 2024-10-20 02:10:54

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

你需要找到一种不同的方法。

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

The .Net config system loads .config files for EXEs; DLLs do not have config files.

You need to find a different approach.

EDIT: You can also create a config file of the form HostApp.exe.config, where HostApp is the full path to your native EXE.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文