2
votes

I'm having trouble loading configuration settings in .NET whilst using an assembly over COM interop.

Background: We use lots of VBScript scripts on some servers, that perform various tasks. Commonly, they perform functions such as sending Emails. To facilitate this, I wanted to create a COM object that was creatable from the VBScript, which would help with some of these common featuresets.

Thus, I'm trying to create a .NET assembly that exposes some COM interfaces via interop. I managed to get this working, but then wanted to externalise (rather than hard code) some of the configuration settings.

I'm using this line to retrieve the configuration:

ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location)

This seems to work without issue when I'm testing it from a test project, and referencing it as a .NET project, but if I test it as a COM object, it fails.

The reason for the failure is that in my config file, I have a custom section:

<section name="CustomSection" type="COMObjects.CustomSection, COMObject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9e8071519bd2f04"/>

However when it tries to load the custom section, it fails to load the assembly "COMObject". To me, this makes sense, as I haven't placed the assembly in the GAC (nor do I want to), so it's struggling to locate it.

Is there a way to help the .NET framework locate the assembly referenced in the config file for a scenario such as this?

Below is the fuslogvw.exe output for the binding:

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable  C:\Windows\SysWOW64\cscript.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: User = My-MACHINE\ME
LOG: DisplayName = COMObject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9e8071519bd2f03
 (Fully-specified)
LOG: Appbase = file:///C:/Windows/SysWOW64/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.

LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: The same bind was seen before, and was failed with hr = 0x80070002.
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

Thanks

1
This question is too poorly documented to make the call. Knowing exactly what the failure looks like is important. A common mistake with assemblies that contain [ComVisible] types is to forget to use the Regasm.exe /codebase option. Use Fuslogvw.exe to diagnose problems with finding the interop assembly.Hans Passant
Hans, I think I've explained in the question why it's failing. I've added the fuslogvw.exe output to the question, regardless.dark_perfect
Have you considered switching to PowerShell scripts?Holistic Developer
Yes, in fact, PowerShell would be my preference, but it's for a client who have said we can't install Powershell on the server.dark_perfect

1 Answers

3
votes

Running under executable C:\Windows\SysWOW64\cscript.exe

This code is activated by the 32-bit version of the script interpreter. Where the CLR will look for assemblies is affected by the startup EXE location. It sets the value of AppBase which inevitably point to the Windows directory because that's where cscript.exe is stored. The only way it could find your assembly is by you copying it into c:\Windows\SysWow64. That's not a reasonable thing to do, this directory is owned by the operating system.

The private path can be configured by a app.exe.config file, <probing> element. It is limited, you can only select a subdirectory of the AppBase. Creating a subdirectory in c:\Windows\SysWOW64 is not a reasonable thing to do. Creating a script.exe.config file is going to affect all scripts that are executed by cscript. That's not a reasonable thing to do.

The .NET framework offers a very reasonable alternative to assembly resolution problems like this. You already know it, it is the thing you don't want to do. This assembly belongs in the GAC.