Feel like a geek and get yourself Ema Personal Wiki for Android and Windows

16 June 2009

Registration-free COM components try-out (continued)

As described in the previous post, I am trying out Side By Side (reg free) COM, trying to solve versioning and deployment issues we have with our software. In the previous post, I looked at VB6 and COM, this post is about my adventures with .NET and COM. The conclusion is: don't use the walkthrough as is, you won't be able to get a successful regfree installation.

.NET and COM



Step 1 Read the walkthrough.

Step 2 Create the COM enabled .NET dll and the VB6 client app
Use Guid.NewGuid().ToString() to create GUIDs for the .NET assembly, class and interface if guidgen is not working for some reason. I created a new windows forms exe which copies a new Guid to the clipboard and exits. Start the vb6 exe to see if it works.

Step 3 unregister the .NET dll
with c:\windows\Microsoft.NET\Framework\v2.0.50727\regasm /u SideBySide.dll. Start the vb6 exe and see that it doesn't work any more.

Step 4 Create the manifest files for the dll and the client exe.
The example manifest in the walkthrough contains errors. FAIL. For example: //assemblyIdentity/@name=" SideBySide" should be "SideBySide", without the space. And //clrClass/@progid="SideBySide.SideBySide" should be "SideBySide.SideBySideClass".

Step 5 Do voodoo magic to embed the manifest into the dll
- Create a resource definition file which references the SideBySide.manifest file
- Create a build.cmd file which creates the resource file and compiles it into SideBySide.dll
Run build.cmd in a VS command prompt (%comspec% /k ""C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86)

Step 6 Start client.exe
Now it should work... gaaah! Automation error!

Step 7 Take hours to troubleshoot
- The error is 80070002, which is supposed to mean "file not found". There are however no entries in the windows event log, and no entries in fuslogvw by which i could get a diagnosis of the problem.
- Googling on the error is not helpful.
- The assembly should have an embedded manifest. Open the file in VS, check: obviously has the right manifest file.
- Manifest files seem to be correct. But because the example in the walkthrough had errors, i feel uncertain about it.
- Because the dll has no version information if you view the properties in Windows Explore, i though that might have to do with the problem. I tried to embed the manifest using Visual Studio. After that, it works, but that is because "register for COM interop" was still checked. Regasm-ing /u and it won't work any more. The file still has no file version properties - but i'm not sure if that is a problem.
- Tried adding the interface to the manifest file also, still fails.
- Tried to build everything from scratch: same automation error occurs.
- I was thinking: we had issues with our own software that appeared after building VB6 exe's against .NET COM dll's and then rebuilding the COM dll's. That could be a problem, so i will test it: build the .NET dll with embedded manifest file and after that rebuild the vb6 exe. Still fails.
- Ok starting from scratch again.
- Tried all variations of the manifest files i could think of: Still fails with the automation error

Step 8 Give up for now.
I have no ideas left. Do some hopeless i-give-up-but-i-dont-want-to-admit-it-browsing and hey, a tool to generate the manifest files instead of having to make them yourself. The tool is called genman32, and is made by Junfeng Zhang, who has some articles about SxS / RegFree com.

Step 9 Having new hope, try again with the genman32 tool
The tool generates a manifest using reflection and is able to embed it in the dll. The generated manifest is unfortunately not correct.. But i could correct the errors and then use the tool to embed the corrected manifest.
- Create manifest with "genman32 <dll>"
- Correct the manifest (<dll>.manifest): Remove /assembly/assemblyIdentity/@processorArchitecture and add /assembly/assemblyIdentity/@type='win32'.
- Embed the manifest in the dll with "genman32 <dllname> /add /manifest:<manifestname>

Step 10 Start the Vb6 exe
Ha! Now it works!! Double check by regasm-ing /u the assembly... still works!! The only difference with my "manual" tries is that the dll now has version information embedded as well. It seems that having this version information is not optional. The manual process described in the walkthrough removes this information, while the genman32 tool preserves it (which is compiled into the dll by Visual Studio automatically).

Conclusion


The document "Registration-Free Activation of .NET-Based Components: A Walkthrough" is not correct and it cost me time and frustration. And i am probably not the only person with this experience. I will provide this story as feedback on the article and i hope the article will be corrected.

But apart from that, the good news is: I do have a way of using .NET COM components in VB6 regfree. I should try this with .NET OCX files too...

3 comments:

Moran Lefler said...

Gah!

My working desk has marks in the shape of my forehead for not reading your post earlier. I'm messing around with that MSDN article for two whole weeks, trying different manifest files as you mentioned. I'm gonna try your solution right now. keep your fingers crossed!

James said...

Thanks for a really useful post - which ALMOST got me to a working solution. Basically I have a C# .Net component exposed to COM that needs to be accessed from another program that was previously created in VB6. Some things that I found that don't match with your post:

1. On Windows Server 2003 I did not need to actually bind the .Net dll's manifest into the dll itself - it worked ok as a separate manifest file for the component but the naming is critical - in my case I had an assembly called "my.net.comp" in "my.net.comp.dll" with the "name" attribute in the manifests assemblyidentity set to just "my.net.comp". In this I found the component manifest must be "my.net.comp.manifest" NOT "my.net.comp.dll.manifest"

2. For Windows XP I could only get it working with the component manifest bound into the dll - but when I tried to do this with genman32 it just would not work. Neither would a simulation of the .rc method in the walk through - I eventually found this is due to my dll being strong named signed as part of the build step in VS 2008 IDE - this meant I needed to add the publicKeyToken attribute in the two assemblyidentity parts (.exe and .dll's manifests) but even with that it failed - what happens is when you bind in the manifest it breaks the SHA1 hash tag that is given to the strong named dll because it add some stuff to it.

The trick was this:

1. Add the .rc file to my original C# project and set a build event to compile it to a .res file
2. In C# project properties on the Application tab set it to use a resource (down by the icon bit - specifying the .res file made from .rc

Then the bind of .res and strong naming all happened together and worked fine

Jan Willem said...

Thanks for the update!