views:

491

answers:

5

I have an existing set of .net libraries that I wish to call from Excel VBA (that part is working fine). These libraries rely on settings in the app.config. I know I can enter these settings in a excel.exe.config file (placed in the same directory as the excel.exe), but this doesn't really seem like a very manageable solution to me, as I can see causing conflicts if more than one application wants to do this.

My question is simple: is there any way of COM exposed dlls referring to their respective config files?

Sample app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="test" value="Hello world!" />
  </appSettings>
</configuration>

Sample c#:

namespace ExcelVbaFacingCode
{
    public class SimpleAppSettingReader
    {
        public string GetValue(string key)
        {
            return ConfigurationManager.AppSettings[key];
        }
    }
}

Sample VBA:

Public Sub Test()
    Dim Test As New SimpleAppSettingReader
    Dim sampleValue As String
    sampleValue = Test.GetValue("test")
    MsgBox "Value: '" + sampleValue + "'", vbOKOnly
End Sub
+1  A: 

Try:

ConfigurationManager.OpenExeConfiguration("foo.config");
Gary McGill
OpenExeConfiguration needs to have the path of the exe passed to it, not the path of the config file. But even if I use this, it will just give me a Configuration object, and not load it into my current configuration. So I'll need to rewrite all existing calls to ConfigurationManager.AppSettings for this to work - not an option for these shared binaries.
MPritch
+2  A: 

Whenever ConfigurationManager.AppSettings is called, it automatically opens the configuration file of the executing assembly. In your case, Excel is the executing application, so you cannot open the config file of the .Net DLL.

This was done for a reason. A single DLL can be called from multiple types of application, each of which might have different requirements (and possibly different databases, for example). For this reason, the application specifies the settings, not the referenced assembly.

I think that what you already suggested is the best way to do this. I know it seems like you are copying your config file, and that it means that you have duplicates out there to worry about when code changes, but its the best thing to do.

Gabriel McAdams
+1 I was clinging on to the hope that wouldn't apply to COM dlls! Unfortunately the company I work at is a big fan of Excel 'apps', so I really don't want to get into the situation where I have to start worrying about settings conflicts with other apps. I suspect I'm going to have to introduce some new settings managment layer into the app :(
MPritch
If they're that into excel apps, you should look into VSTO. It allows you more control (and the .net framework). It's much better than VBA, but a really easy addition/conversion.
Gabriel McAdams
Definitely agree on VSTO, but this I've inherited the VBA macro and want to benefit from some of our existing .net code without a rewrite. VSTO is definitely the long term strategy! Don't worry, will mark the best answer before the bounty expires :)
MPritch
With VSTO, you don't have to lose your existing code. You can easily call VSTO functions from VBA and vice versa. read this page: http://msdn.microsoft.com/en-us/magazine/cc163373.aspx#S4
Gabriel McAdams
and this page: http://www.craigbailey.net/vsto-vba-and-vsto/
Gabriel McAdams
Ooh ta! Will read those later on
MPritch
Looks like you can only call VSTO code from VBA in Office 2007+ :(
MPritch
A: 

As I understand it, you want the configuration to be global to the machine where the dll is installed. There is a machine.config file for machine global configuration options. I have never used it myself, so I don't have any more detailed information, but it might be worth looking into. http://msdn.microsoft.com/en-us/library/ms229697(VS.71).aspx. A Google search for "machine.config" gives more hits which look informative.

Another way is to put a custom xml file in the installation directory of the dll file. To get the path to the file, use System.Reflection.Assembly.GetExecutingAssembly.Location (or maybe CodeBase instead of Location). Unfortunately you will have to build your own config management on top of the xml file, but thanks to Linq to XML I think that XML is more painless than ever.

Anders Abel
Unfortunately using machine.config is offers even less granularity than using the Excel.config! Thanks for the thought though
MPritch
What level of granularity are you looking for? Maybe I misunderstood the question - I thought you wanted machine wide config, but not having to put it together with Excel. Should the settings be machine wide? Or do you want different settings for different cases when the COM-object is invoked?
Anders Abel
Nope. Settings should be app (ie macro) specific
MPritch
Do you mean that it is not enough with one setting file for each dll, but that you rather would like to have the setting files to be per macro file?
Anders Abel
Sorry, missed the part where you suggested the xml config file. Have commented upon this approach in my responses to other answers.
MPritch
+3  A: 

I was facing similar problems with web.config.... I find an interesting solution. You can capsulate configuration reading function, eg. something like this:

public class MyClass {

public static Func<string, string> GetConfigValue = s => ConfigurationManager.AppSettings[s];

//...

}

And then normally use

string connectionString = MyClass.GetConfigValue("myConfigValue");

but in a special case first "override" the function like this:

MyClass.GetConfigValue = s =>  s == "myConfigValue" ? "Hi", "string.Empty";

More about it:

http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/

Tuomas Hietanen
+1 for the idea - very similiar to what I had alluded to in my comment response to Gabriel McAdams's answer
MPritch
+1  A: 

You can indeed specify the configuration file that will be used by the .NET configuration API's but you have to do it before the AppDomain is created (which is not as easy as it sounds.) This is how ASP.NET works for example. It sets up the AppDomain to use a "web.config" file located in the virtual directory as opposed to requiring an w3p.exe.config or what not.

You can do this too but you need to create a secondary AppDomain. This in itself is a good idea for a lot of reasons that have to do with multiple add-ins and assembly references. But one of the things you can put in the AppDomain's setup is the name/path of the "app.config" file.

To create the new AppDomain you can use a "shim" which is a bit of boilerplate C++ code that configures and starts the AppDomain and the rest of the code from that point on can be managed code.

There's an article on MSDN written by Andrew Whitechapel and called Isolating Office Extensions with the COM Shim Wizard. I won't lie, it's not a trivial concept, but it's also not too bad. There's a wizard that creates the C++ project for you which loads the .NET addin into a new AppDomain. The configuration of the AppDomain must be done before it is loaded so you'll want to put the following in the wizard-created code.

// CLRLoader.cpp
HRESULT CCLRLoader::CreateLocalAppDomain()
{

    ... snip ...

    // Configure the AppDomain to use a specific configuration file
    pDomainSetup->put_ConfigurationFile(CComBSTR(szConfigFile));

    ... snip ...

}

It's also worth noting that if/when you convert to a VSTO project, the VSTO runtime does all this AppDomain configuration for you. Each VSTO addin runs in its own AppDomain with its own private app.config file.

Josh Einstein
On the face of it, this is exactly what I'm after. Will review the implementation to confirm.Thanks for the tip on VSTO too
MPritch
Haven't had a full opportunity to review this to check it works, but from reading around it it sounds like it will do what I want. On that basis will mark this as the answer. Thanks Josh!
MPritch
No problem. Feel free to contact me about it as I was completely new to COM via C++ when I first got involved with shimming but after stumbling around a bit it turned out to really improve the stability of my add-in.
Josh Einstein
Looks like the COM shim wizard v2.3.1.0 supports config files out of box (http://msdn.microsoft.com/en-us/library/bb508939.aspx). Things going nicely :)
MPritch