Can I control version number assigned to interop assembly? - c#

I have a C# program that uses a native C++ COM object. Visual Studio generates an interop assembly with wrappers for the types in the COM object. Each time I recompile the C# program interop assembly has version 1.0.0.0.
This is bad for the installer - sometimes we extend the COM object interfaces (add new methods at the end of some interface) so the interop assembly has to be changed. when the installer tries to update an existing installation it thinks that the interop assembly hasn't changed (since it still has version 1.0.0.0) and skips updating it and the program doesn't work.
How can I control the version number assigned to the interop assembly?

It's been a little while so I might be remembering incorrectly how this works but I think that you might be able to do what you want if you use Tlbimp rather than having VS create the wrappers.
Possibly you could do it using the asmversion parameter and otherwise it might be possible if you give it a strong name using the keyfile parameter.

Related

How can I add a reference to a project of a Windows native DLL?

I'm trying to add Windows/System32/Shell32.dll DLL to my project. The issue is, it copies the reference to the directory! Since this is a windows file, it shouldn't have to come with me if I were to deploy my application.
I have tried stopping it from copying to the directory, tried looking for how to embed the resource in the application and even added reference paths to System32. It seems so much more challenging than the program just using the local DLL from the system...
What can I do?
Shell32.dll is a COM component. You should not get a copy of it in your project. What you get instead is Interop.Shell32.dll. Which is a .NET assembly, not a copy of Shell32.dll. It contains the COM interface and class declarations, converted from the type library definition inside Shell32.dll to friendly .NET declarations that the CLR knows how to easily handle.
This is an optimization, it avoids having to make the conversion at runtime. Which is expensive, subject to various options (check the MSDN docs for Tlbimp.exe) and may easily fail because there is no general requirement that the type library is also available on the target machine.
You must deploy Interop.Shell32.dll to the target machine, just like you do with any .NET class libraries you'd use.
Do note that this interop library is no longer needed on .NET 4 and VS2010. Which acquired the "Embed Interop Types" feature. In other words, instead of keeping the interop types in a separate assembly, the C# and VB.NET compilers can now embed them in your program. Very highly recommended, just set the option to True in the Properties window view of the Shell32 reference.

How can a C# program use a COM dll of any version?

This question is a sequel of this question
We're creating a dll, written in C++, providing access to some hardware. This dll implements and is accessed using COM interfaces. We also have a C# program that uses this dll through the COM objects.
We're having an issue with the versions. Indeed, when running the C# program, it absolutely wants to use the exact COM/C++ dll version it used when compiling. I.e. if the C# program was compiled using COM/C++ dll 1.2.3.4, then the program will refuse to run with COM/C++ dll 1.2.3.5.
Unhandled Exception: System.TypeInitializationException: The type initializer for 'MyDllVerify.App' threw an exception. ---> System.IO.FileNotFoundException: Could not load file or assembly 'MyCorp.MyDll.Interop, Version=1.2.3.4, Culture
=neutral, PublicKeyToken=ced78d295d1e0f2b' or one of its dependencies. The system cannot find the file specified.
File name: 'MyCorp.MyDll.Interop, Version=1.2.3.4, Culture=neutral, PublicKey Token=ced78d295d1e0f2b' at MyDllVerify.App..cctor()
I'd like to instruct the C# program to use any COM/C++ dll with version 1.2.anything.
Where can I configure this in the C# project?
I would suggest you to not directly reference to the COM-dll in your C# project. If you do that, at build time there is always a new COM-interop-dll generated. This can lead to a lot of problems.
It would be a better approach to create a COM-interop-dll, store it in your library folder and reference this library in your C# project. Keep this COM-interop-dll as static as possible. If you do it like that, you can replace the used COM-dll as much as you want, as long as your interfaces do not change.
You could try to manipulate this interop assembly and make the version checking for 1.2.* there, if you realy want that (I would not recommend to that, it could cause serious confusion).
Explanation:
The COM-interop-dll is a regular .NET assembly. It works like a wrapper between your C# code and the COM-C++-code you want to use in the C# code.
The COM-interop-dll don't have to be registered for COM. You can install this assembly so many times you like. But it requires that your COM-dll is registered for COM.
Useful tools:
tlbimp
regasm
sn
Nothing is different from the way I documented it in your previous question. You still use <bindingRedirect> to allow the wrong version of the interop assembly to be loaded.
It is fairly unlikely to work in practice, messing with DLL Hell when you use COM is extremely unwise. If you use early binding then COM has no way to verify that you are calling the correct method. Very unlike .NET where the jitter can make checks like these at runtime from the metadata in the assembly. If the C++ programmer did it right then he changed the guids of the types that he changed. Which will make your code bomb with E_NOINTERFACE since you'll use the guid of the old version.
If he didn't, unfortunately way too common, then your program is liable to crash with something nasty like an AccessViolationException. Or worse, it won't crash but will call the completely wrong method.
The failure mode is more benign when you use late binding, you'll get one of the IDispatch errors when the method doesn't exist or if its arguments have changed. Not that this ultimately solves anything, you still have a program that doesn't work. Mess with DLL Hell like this only if you like to live dangerously.

How to latebind COM event without interface

I need to late bind to a 3rd party VB6 COM object in a 3.5 C# application (to avoid version dependencies that we currently have). The dll that was provided is not consumable in most non-latebound ways due to some bug that causes errors when we try to consume it normally. Currently, we are using a custom VB6 wrapper that makes things VERY version specific, however I have found that I can use late-binding to access properties and methods. Now, I am trying to late-bind to events, however everything I have read says that I need to inherit from the COM wrapper's interface to create the event sinks that are needed. Here is one such article.
So, my question is whether it is possible to perform late-bound event handling without having any reference to the dll at compile time?
UPDATE
Here are the errors I have with the VB6 wrapper (Which is still being actively updated).
In OleViewer, I get
Could not decompile selected item Error loading type library/DLL.
TYPE_E_CANTLOADLIBRARY ($80029C4A)
In Visual Studio I get:
Could not determine the dependencies of the COM reference
"3rdPartyDLL". Error loading type library/DLL. (Exception from
HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))
From here:
I found that the problem is caused when the IDL contains an importlib
to another project's .tlb typelib.
This seems to create a dependency between one dll and the other.
If dependant dll is missing OLEView refuses to display the dependent
dll, which also manifests itself by not allowing #import from C++
code.
Therefore I would look carefully at the COM dependencies of the DLL in question and make sure they are all registered as well.
It also goes on to add:
...because both dlls are co-dependent,
components from each interact (via interface declarations on method
signatures) and use #import from each others typelib.
Therefore, unless both target dlls are present, neither can be
rebuilt. As you can imagine, this causes a terrible problem when you
try to completely rebuild the project's from scratch.
I've experimented with separating the interface definitions into
smaller IDL files...
Edit: here's a recent example of this problem coming about (I believe). I had a C# library exported to COM. Modifications to that library were made which changed the interface of several classes, but the library GUID was not changed. Also see here about risks of AutoDual which was in use.
Here's the odd part - the VB6 DLL was rebuilt referencing the modified C# DLL. It compiled fine. no errors. But its typelib was corrupt - OleView couldn't open it, failing with TYPE_E_CANTLOADLIBRARY. Changing the C# DLL GUID was necessary to get the VB6 DLL recompiled successfully.
Clearly a pitfall of VB6 / C# interop.
The problem is most probably caused by the platform you are using. I just had a similar problem yesterday. Make sure that you are setting your project platform to x86 / x64 when you are late binding a x86/x64 COM type library.
The same applies to oleview. Use the x86/x64 version to view x86/x64 type libraries. (Possibly you need to install the x64 Windows SDK if you are on an x64 system to get the correct executeable).

How do I create and use a .NET metadata-only 'Reference Assembly'?

Since version 3.0, .NET installs a bunch of different 'reference assemblies' under C:\Program Files\Reference Assemblies\Microsoft...., to support different profiles (say .NET 3.5 client profile, Silverlight profile). Each of these is a proper .NET assembly that contains only metadata - no IL code - and each assembly is marked with the ReferenceAssemblyAttribute. The metadata is restricted to those types and member available under the applicable profile - that's how intellisense shows a restricted set of types and members. The reference assemblies are not used at runtime.
I learnt a bit about it from this blog post.
I'd like to create and use such a reference assembly for my library.
How do I create a metadata-only assembly - is there some compiler flag or ildasm post-processor?
Are there attributes that control which types are exported to different 'profiles'?
How does the reference assembly resolution at runtime - if I had the reference assembly present in my application directory instead of the 'real' assembly, and not in the GAC at all, would probing continue and my AssemblyResolve event fire so that I can supply the actual assembly at runtime?
Any ideas or pointers to where I could learn more about this would be greatly appreciated.
Update: Looking around a bit, I see the .NET 3.0 'reference assemblies' do seem to have some code, and the Reference Assembly attribute was only added in .NET 4.0. So the behaviour might have changed a bit with the new runtime.
Why? For my Excel-DNA ( http://exceldna.codeplex.com ) add-in library, I create single-file .xll add-in by packing the referenced assemblies into the .xll file as resources. The packed assemblies include the user's add-in code, as well as the Excel-DNA managed library (which might be referenced by the user's assembly).
It sounds rather complicated, but works wonderfully well most of the time - the add-in is a single small file, so no installation of distribution issues. I run into (not unexpected) problems because of different versions - if there is an old version of the Excel-DNA managed library as a file, the runtime will load that instead of the packed one (I never get a chance to interfere with the loading).
I hope to make a reference assembly for my Excel-DNA managed part that users can point to when compiling their add-ins. But if they mistakenly have a version of this assembly at runtime, the runtime should fail to load it, and give me a chance to load the real assembly from resources.
To create a reference assembly, you would add this line to your AssemblyInfo.cs file:
[assembly: ReferenceAssembly]
To load others, you can reference them as usual from your VisualStudio project references, or dynamically at runtime using:
Assembly.ReflectionOnlyLoad()
or
Assembly.ReflectionOnlyLoadFrom()
If you have added a reference to a metadata/reference assembly using VisualStudio, then intellisense and building your project will work just fine, however if you try to execute your application against one, you will get an error:
System.BadImageFormatException: Cannot load a reference assembly for execution.
So the expectation is that at runtime you would substitute in a real assembly that has the same metadata signature.
If you have loaded an assembly dynamically with Assembly.ReflectionOnlyLoad() then you can only do all the reflection operations against it (read the types, methods, properties, attributes, etc, but can not dynamically invoke any of them).
I am curious as to what your use case is for creating a metadata-only assembly. I've never had to do that before, and would love to know if you have found some interesting use for them...
If you are still interested in this possibility, I've made a fork of the il-repack project based on Mono.Cecil which accepts a "/meta" command line argument to generate a metadata only assembly for the public and protected types.
https://github.com/KarimLUCCIN/il-repack/tree/xna
(I tried it on the full XNA Framework and its working afaik ...)
Yes, this is new for .NET 4.0. I'm fairly sure this was done to avoid the nasty versioning problems in the .NET 2.0 service packs. Best example is the WaitHandle.WaitOne(int) overload, added and documented in SP2. A popular overload because it avoids having to guess at the proper value for *exitContext" in the WaitOne(int, bool) overload. Problem is, the program bombs when it is run on a version of 2.0 that's older than SP2. Not a happy diagnostic either. Isolating the reference assemblies ensures that this can't happen again.
I think those reference assemblies were created by starting from a copy of the compiled assemblies (like it was done in previous versions) and running them through a tool that strips the IL from the assembly. That tool is however not available to us, nothing in the bin/netfx 4.0 tools Windows 7.1 SDK subdirectory that could do this. Not exactly a tool that gets used often so it is probably not production quality :)
You might have luck with the Cecil Library (from Mono); I think the implementation allows ILMerge functionality, it might just as well write metadata only assemblies.
I have scanned the code base (documentation is sparse), but haven't found any obvious clues yet...
YYMV

Loose coupling of COM in C# or How to avoid COMException 0x80040154

I have a .Net 2 C# application I am developing which uses a VB 6 generated COM DLL. The VB DLL is updated frequently any my application crashes with a System.Runtime.InteropServices.COMException (0x80040154). The part of the COM DLL I use does not change but the version (and CLSID) will.
The "Specific Version" option for the reference is false. The WrapperTool is tlbimp.
How do I tell my application not to worry about changes in the DLL? Is there any way of checking just the functions I am using?
It is one of the most common COM errors, "Class not registered". It starts at VB6, it has an option to control binary compatibility. I forgot exactly what that looks like, it's been too long. If you don't control this, VB6 is going to create a new COM server with different CLSID values. That requires re-registering the DLL with Regsvr32.exe. And re-generating the interop library with Tlbimp.exe. The latter step is probably the one you missed.
Note that using different CLSID values is a hard requirement for COM, it must be done when the public interface changes. But not when only the implementation changes.

Categories

Resources