我有一组现有的.net库,我希望从Excel VBA调用(该部分工作正常)。这些库依赖于app.config中的设置。我知道我可以在excel.exe.config文件中输入这些设置(放在与excel.exe相同的目录中),但这对我来说似乎不是一个非常易于管理的解决方案,因为我可以看到导致冲突,如果不止一个应用程序想要这样做。
我的问题很简单:COM暴露的dll是否有任何方式引用它们各自的配置文件?
示例app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="test" value="Hello world!" />
</appSettings>
</configuration>
示例c#:
namespace ExcelVbaFacingCode
{
public class SimpleAppSettingReader
{
public string GetValue(string key)
{
return ConfigurationManager.AppSettings[key];
}
}
}
示例VBA:
Public Sub Test()
Dim Test As New SimpleAppSettingReader
Dim sampleValue As String
sampleValue = Test.GetValue("test")
MsgBox "Value: '" + sampleValue + "'", vbOKOnly
End Sub
答案 0 :(得分:3)
每当调用ConfigurationManager.AppSettings
时,它会自动打开执行程序集的配置文件。在您的情况下,Excel是正在执行的应用程序,因此您无法打开.Net DLL的配置文件。
这是有原因的。可以从多种类型的应用程序调用单个DLL,每个应用程序可能具有不同的要求(例如,可能具有不同的数据库)。因此,应用程序指定设置,而不是引用的程序集。
我认为您已经建议的是最好的方法。我知道你似乎在复制你的配置文件,这意味着你有重复的东西担心代码何时发生变化,但这是最好的事情。
答案 1 :(得分:3)
我遇到了与web.config类似的问题....我找到了一个有趣的解决方案。您可以封装配置读取功能,例如。像这样的东西:
public class MyClass {
public static Func<string, string> GetConfigValue = s => ConfigurationManager.AppSettings[s];
//...
}
然后通常使用
string connectionString = MyClass.GetConfigValue("myConfigValue");
但在特殊情况下,首先“覆盖”这样的函数:
MyClass.GetConfigValue = s => s == "myConfigValue" ? "Hi", "string.Empty";
更多信息:
http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/
答案 2 :(得分:1)
尝试:
ConfigurationManager.OpenExeConfiguration("foo.config");
答案 3 :(得分:1)
您确实可以指定.NET配置API将使用的配置文件,但您必须在创建AppDomain之前执行此操作(这并不像听起来那么简单。)这就是ASP.NET的工作原理例。它将AppDomain设置为使用位于虚拟目录中的“web.config”文件,而不是需要w3p.exe.config或不需要。
您也可以执行此操作,但需要创建辅助AppDomain。由于与多个加载项和程序集引用有关的许多原因,这本身就是一个好主意。但是你可以放在AppDomain's setup中的一件事就是“app.config”文件的名称/路径。
要创建新的AppDomain,您可以使用“shim”,它是一些用于配置和启动AppDomain的样板C ++代码,从那一点开始的其余代码可以是托管代码。
有一篇关于MSDN的文章,由Andrew Whitechapel撰写并称为Isolating Office Extensions with the COM Shim Wizard。我不会撒谎,这不是一个微不足道的概念,但它也不是太糟糕。有一个为您创建C ++项目的向导,它将.NET插件加载到新的AppDomain中。 AppDomain的配置必须在加载之前完成,因此您需要将以下内容放在向导创建的代码中。
// CLRLoader.cpp
HRESULT CCLRLoader::CreateLocalAppDomain()
{
... snip ...
// Configure the AppDomain to use a specific configuration file
pDomainSetup->put_ConfigurationFile(CComBSTR(szConfigFile));
... snip ...
}
值得注意的是,如果/当您转换为VSTO项目时,VSTO运行时会为您执行所有此AppDomain配置。每个VSTO插件都在自己的AppDomain中运行,并带有自己的私有app.config文件。
答案 4 :(得分:0)
据我了解,您希望配置对于安装dll的计算机是全局的。有一个机器全局配置选项的machine.config文件。我自己从未使用它,所以我没有更详细的信息,但可能值得研究。 http://msdn.microsoft.com/en-us/library/ms229697(VS.71).aspx。谷歌搜索“machine.config”会提供更多看似有用的点击。
另一种方法是将自定义xml文件放在dll文件的安装目录中。要获取文件的路径,请使用System.Reflection.Assembly.GetExecutingAssembly.Location(或CodeBase而不是Location)。不幸的是,你必须在xml文件之上构建自己的配置管理,但是由于Linq to XML,我认为XML比以往任何时候都更加轻松。
答案 5 :(得分:0)
还有另一种从COM组件加载.config文件的方法,我已经使用了好几年。
它的工作原理如下:
将名为“Application.manifest”的文件放在该文件夹中。该文件必须包含:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" />
将配置文件放在同一个文件夹中。配置文件的名称必须是“Application.config”,即不是“myapp.config”
您可以在application.config中使用所有普通标记(例如runtime,system.diagnostics等)
我使用vbscript创建COM +应用程序:
Dim allapps, newapp
Set allapps = objCatalog.GetCollection("Applications")
Set newapp = allapps.Add()
newapp.Value("Name") = MyComAppName
newapp.Value("ApplicationAccessChecksEnabled") = False
newapp.Value("Activation") = 1 ' own process
newapp.Value("ApplicationDirectory") = WScript.CreateObject("WScript.Shell").CurrentDirectory
allapps.SaveChanges
WScript.Echo "Created application " & ComAppName
objCatalog.ImportComponent ComAppName, MyComName
WScript.Echo "Installed component " & MyComName