GP.*_*GP. 1 c# c++ com configuration unmanaged
我有一个名为 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>
Run Code Online (Sandbox Code Playgroud)
我想要做的是从名为 Bar 的非托管 C++ 程序调用此 .NET 库中的函数,并能够从非托管 C++ 应用程序更改其配置。通过在 Foo 中将类/接口属性 ComVisible 设置为 true,我能够从 Bar 调用 Foo 函数。但是,我无法从非托管 C++ 应用程序更改 .config 文件值——服务器始终为 "localhost"。
我正在尝试做什么——从非托管 C++ 配置 .NET 库——甚至可能吗?
嗯,这是可能的,但工作量不小。从托管世界创建应用程序域和设置配置,然后在托管代码中创建一个小的“thunking”层来为非托管客户端包装它通常更容易。但由于这不是您所要求的,以下是您实现目标的方法:
首先,您需要导入 mscorelib:
#include <mscoree.h>
#import <mscorlib.tlb> raw_interfaces_only no_smart_pointers high_property_prefixes("_get","_put","_putref")
Run Code Online (Sandbox Code Playgroud)
然后绑定到运行时:
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
);
Run Code Online (Sandbox Code Playgroud)
现在启动 CLR 并创建一个 AppDomainSetup 实例。
hr = runtimeHost->Start();
IAppDomainSetup pSetup;
hr = runtimeHost->CreateDomainSetup(&pSetup);
Run Code Online (Sandbox Code Playgroud)
现在根据需要填写设置信息:
hr = pSetup->put_ApplicationBase(_bstr_t(thisFile));
hr = pSetup->put_ConfigurationFile(_bstr_t(configFile));
Run Code Online (Sandbox Code Playgroud)
最后创建域:
hr = __gRuntimeHost->CreateDomainEx(L"ISAPI.Net", pSetup, NULL, &pDomain);
Run Code Online (Sandbox Code Playgroud)
现在您可以选择实例化一个对象并调用方法:
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
);
Run Code Online (Sandbox Code Playgroud)
显然上面的代码片段是不完整的;但是,如果您对 C++ COM 足够熟练,上述内容应该为您提供足够的信息来解决它。您应该注意,这是我可以证明在 3.5 中继续工作的“旧”(1.x)托管接口,我不知道这些接口如何/是否在 4.0 上工作。从.Net 2.0 开始,引入了新的托管接口。我从来不需要 1.x 版本以外的任何东西,所以我从不费心升级任何托管代码。
另请参阅:托管概述