Visual Studio - Register for COM interop manually on a second PC? - visual-studio

In Visual Studio (C#), ticking 'Register for COM interop' updates the Windows environment such that my Visual Studio project, its dependent Visual Studio projects (in same solution) & dependent DLL files are all available for another COM-consuming application on the same machine. This COM-consuming application works with no issue.
If I want the same COM objects to be available to a consuming application on another machine, what must I do?
I assume I still build with the same flag set (so that the DLL files have COM content)? I assume I must register the COM DLL file (e.g. regasm) - Unfortunately this doesn't work - do I register every DLL file that I am constructing & every DLL file library they reference?
Please make no assumptions about my COM knowledge.

You don't quite provide enough information to answer with certainty, but there are enough hints to guess at what you are doing.
When your client app asks for the COM object, the .NET runtime is invoked and it locates the COM-exposing assembly DLL from the information stored by RegAsm (specifically by the /codebase parameter). But after that, it's all .NET assembly loading rules - including the loading of dependencies.
If your COM assembly has dependencies, the dependent assemblies must be locatable from the client process. It doesn't matter whether the dependencies are in the same folder as the COM DLL - the one loading those dependencies is the process, not your COM DLL. The .NET runtime uses a process called Fusion to decide where to look for .NET assemblies.
You have two practical choices:
Put the COM DLL, its dependencies and the client EXE all in the same folder. This works if there is only one client, and you control the client (so, don't do this if the client is IIS, for example). It's the simplest solution.
Give all the .NET components a strong name and deploy them to the GAC1. You still have to run RegAsm; but don't use the /codebase argument.
It is also possible to customize the Fusion rules by giving the client app a manifest with the proper entries, but that's too much of a hassle. The other options are more practical.
If this doesn't describe your problem, then I would use a combination of SysInternals' (now Microsoft's) Process Monitor and the .NET fusion log functionality to look into where the process is seeking the different DLLs.
1Technically you don't have to put the main COM DLL in the GAC, but it makes no sense to use /codebase for the COM DLL when you have to deal with GAC anyway. At that point you might as well put them all in the GAC

Related

COM References and TFS build definition

I have a C# project in which I have a COM Reference. It compiles fine when opened in VS 2013. But, it fails as part of TFS build definition.
TFS version : 2013
TFS Build Controller & Agent : 2013
VS version : 2013
The failure message says that it could not find the Interop dll. I cannot manually create the Interop dll and check-in into TFS because it would keep changing and I want my C# project to always take the udpated COM reference.
I tried the COMFileReference suggestion but it did not solve my issue. I even manually registered the COM dll using regsvr32 but still I am facing the issue.
Any help is highly appreciated.
Regards,
kvk1985
A COM reference is the safest way to ensure that your program matches the actual installed component when you test your code. The compiler will read the type library of the component, a very similar mechanism that's used for normal .NET assembly references. Except that the type definitions come from the type library instead of .NET metadata.
But has a disadvantage in your case, it can only work when the component is actually installed on the machine. That probably did not happen on that build server. That's fairly normal, the people that maintain build servers don't particularly like anybody messing with it. And it is a maintenance headache, the build breaks when the devs update their machine with the latest version but forget to update the build server as well. And old builds get to be hard to reproduce.
So installing the component on the build server is the Quick Fix. If that's an insurmountable obstacle then somebody needs to run Tlbimp.exe on their machine. That generates the interop assembly, it needs to be checked-in to source control. And the project must be modified, remove the COM reference and add the reference to the generated interop library. It will now build the same way on the build server and the dev machines.
That's of course brittle the other way, if a dev updates the component on his machine then there will be a mismatch with the interop assembly. That can be a very ugly one, an E_NOINTERFACE runtime error if the COM vendor did it right, something excessively nasty like calling the wrong method, a stack imbalance or an AVE if he didn't. Otherwise the exact same kind of failures that can occur if the user's machine doesn't have the right version of the component installed. Standard DLL Hell.
You'll have to make the call yourself, there's no One Right Answer.

How to fully publish a Visual C# project?

I have a Visual C# Project that is fairly basic (no more than 100 lines) but it includes some 3rd party DLL references. Running the project on the computer it was developed on has it run just fine.
In Microsoft Visual C# 2010 Express, I go to Project->Publish <project name> and it builds some files including a setup.exe installer.
When I move those files to another computer and run the setup.exe, it correctly installs the program.
But when I run the program, it simply closes out saying:
ProjectName.exe has encountered a problem and needs to close. We are sorry for the inconvenience.
The command window also appears for a brief second with some errors, but it's hard to make out what it is saying. It looks something like:
Unhandled Exception: System.Runtime.InteropServices.COMException: Retrieving the COM class factory for the component with CLSID { ....... } failed due to the following error: .....
I'm unable to get the command window to stay, so I cannot get the full message. But I assume this is due to the other computer not having those 3rd party DLLS.
How can I have Visual C# 2010 package everything including DLLs so this error does not appear? Or if that may not be the actual issue, how can I stop the command window from instantly vanishing? (I do not know the full list of DLLs required)
Or if the DLL is a registered DLL under C:\Windows\system32, is the project never going to build that into the package? Is there a way to see what it depends on?
Visual Studio 2010 Express doesn't create fully functional installers, but only ClickOnce installers, and those also with limited functions. This kind of installer can't register COM DLLs.
What seems to be wrong in your case is that you are using a COM DLL which isn't registered on the target system. You could try to check that in your own program (like trying to create the class and catch any exceptions that are thrown by the CreateObject function), and call RegSvr32.exe /s in order to register it. Or you just do this when the program starts the first time, before you create any object from the DLL... haven't tried that, though.
You could also make sure that you register the DLL manually on the target system before you run your program.
Moreover, when .Net uses a COM DLL, it usually creates a compatibility assembly which wraps the COM DLL and makes it accessibly to .Net. In case the DLL you use is only this compatibility assembly, you might have to locate the COM DLL it depends on manually on your system and to include it explicitly in your project's files.
In order to debug, it should be enough to put try / catch blocks around CreateObject. If that doesn't help, try adding an eventhandler for the event that is raised when an exception isn't handled by the application (this might be different according to the kind of application you create).

Automating Com DLL interop version

So when visual studio build the interop dll it gets 4.0.0.0.
The TypeLib version is 4.0
But the actuall DLL version is 4.0.1.112
Is there anyway I can get visual studio to automatically build the interop DLL to assume the actuall DLL version?
Could I alternatively get the interop DLL to use the version stamp from my app.
I just need to keep the interop DLL current with the app so the installer doesn't leave old interops behind.
I really don't want to do tlbimp manually, but I guess when I get to the point of automating the installer, I could automate that step.
Well, it did consider the DLL version. A type library can only have a major and a minor version number. You'll need to bump your DLL version to, say, 4.1.x.x
This is otherwise appropriate behavior. One hard rule of COM is that you must change the GUIDs if you make a change to a publicly visible interface. Not doing so causes the worst kind of DLL Hell, the kind that crashes the client app without any good way to diagnose the reason.
That's no longer a revision change, that's a non-so-minor version change. The clients of the COM server have to be rebuilt. If you didn't actually change a public interface then having a type library version of 4.0 is still quite appropriate. It didn't change.
I don't believe this is possible. Visual Studio will prefer the TypeLib version when building the the interop DLL. I think you're only recourse is to use a hand crafted DLL with tlbimp and taking advantage of the /asmversion switch
http://msdn.microsoft.com/en-us/library/tt0cf3sx(VS.80).aspx

What does "Register for COM Interop" actually do?

What exactly does the VS project option "Register for COM interop" actually do? Because when I build my library with this option enabled I can call CreateObject on my library from VBScript. But if I build without this and then run regasm manually CreateObject fails. So I'm wondering -- what does VS2010 do that I'm not doing?
It does the same thing as running Regasm.exe with the /tlb and /codebase options. The /codebase option is probably the one you forgot. Regasm likes assuming you put the DLL in the GAC and generates a warning when you don't. The GAC is indeed a very good way to avoid DLL Hell, always a COM problem. But not appropriate on your dev machine, you don't want to pollute the GAC while developing and testing the code. It only matters on your user's machine, the one that's likely to be exposed to multiple versions.
Using the wrong version of Regasm.exe on a 64-bit machine is another way to get in trouble, there are usually 4 versions on your machine. Be sure to distinguish the 32-bit and 64-bit versions (c:\windows\microsoft\framework vs framework64), they write different registry keys. You want to pick the one that's compatible with the client app. Using both is okay too, .NET code can run in either mode, but pretty unusual. And distinguish between the v2.0.50727 (.NET 2.0 through 3.5SP1) and the v4.0 versions. Picking the right Visual Studio Command Prompt is half the battle.

Installing a shared assembly to the GAC with COM interop

Specifically, I am using Wise Installation Studio to install several shared .NET 2.0 assemblies into the GAC. These are being used by some legacy COM application files as well as other application assemblies.
I have the flag for "Generate COM interop registry keys for .NET assembly" set.
Reference counting appears to be working for removing the actual assembly from the GAC, but the COM registration information is getting removed with the first uninstall via ARP.
I am wondering if there is some work around for this, if I would be better off installing the assembly to Common Files, or if there are any other suggestions out there?
How I could read on the http://www.ssw.com.au/ssw/standards/wisesetup/WiseStandards.aspx page using of "Generate COM interop registry keys for .NET assembly" allow you just add a set of registry keys to MSI. As in all Windows Installer Setups it is important to define to which MSI component a registry key or a file belong. If you make these registry keys as a part of the same components as the file and the assembly, the keys will be removed always together with the assembly. If multiple setups use the same component GUID, then only if you uninstall the last setup used the component, the component will be uninstalled.

Resources