Exact steps for registration-free COM interop in .NET (invoke copied COM dll without regsvr32) - com-interop

I want to add a registration-free COM reference to my .NET app. Registration-free means users can run the app without registering the COM component to their system.
I found a number of articles on this topic (e.g. MSDN, this S/O question, etc.) but none contains concrete steps. Here's what I have tried and did not work:
Generate manifest for the COM dll (say foo.dll) using mt.exe as described in this answer.
Add foo.dll and foo.dll.manifest to my app as "Build Action" = "Content" and "Copy to Output Directory" = "Copy Always".
Add reference to interop.foo.dll that came with foo.dll.
Add app manifest file with this section:
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="foo" />
</dependentAssembly>
</dependency>
Build and run.
There's an error saying application configuration is not correct. Tried different values in <assemblyIdentity> without luck.
Could someone share experience? Thanks.

Hans's answer has the right information, but I wasn't clear what to do when I first read it. After trying many different things I finally got it working and it's very simple:
Register the COM class on the developer machine.
In the app project, add the COM reference.
In reference properties, set these:
Isolated = True
Copy Local = True
Embed Interop Types = False (Hans pointed out in the comments that this is unnecessary but I haven't verified)
By following these steps, the interop.foo.dll and app manifest are automatically generated. This allows users to use the COM component without registration.
On the opposite, if you don't register the COM on the dev machine, you can still develop and build the app by adding reference to interop.foo.dll (which can be generated on a machine with the COM class registered and then copied around), but the build result can only run on machines with the COM component registered. There might be a solution around this but requires deeper knowledge of how MSBuild work with COM references, which I did not spend time investigating.
So in short, the key to runtime registration-free COM is to register the COM class on the dev machine.

Your manifest is not correct. It should contain the <file> element instead of the <dependentAssembly> element. With <comClass> elements that declare the creatable co-classes.
Generating the manifest is a built-in feature in the VS build system. To make it work, the COM component needs to be installed correctly on your dev machine. Do not try a reg-free COM manifest unless you can make it work without one on your machine, you'll fight two problems instead of one. So for starters make sure that the server is properly installed, using the vendor's installer or deployment instructions. And make sure that a test program that creates an object and call a method operates correctly.
Exercising this is useful, with a known-good COM server that's available on any machine. Create a new project from the Console Application project template. Project + Add Reference, Browse tab, select c:\windows\system32\shell32.dll. Select the added Shell32 reference and change its Isolated property to True. Build + Rebuild.
Look in the bin\Debug build directory of your project and open the app.exe.manifest file with Notepad. Observe the file and comClass elements, that's what you'll need in yours as well. If this doesn't help then turn to the owner of the COM server, he should be able to provide you with the manifest you need.

Related

How to call IVsBuildableProjectCfg.StartBuild in extension

I called IVsBuildableProjectCfg.StartBuild in a Visual Studio extension to build a project.
var ret= cfg.StartBuild(pane, VSConstants.VS_BUILDABLEPROJECTCFGOPTS_REBUILD);
But it doesn't start building. Instead it just produced exceptions.
System.InvalidOperationException: 'The operation cannot be completed because BeginBuild has not yet been called.'
How can it be called correctly?
background
Originally I called IVsSolutionBuildManager2.StartUpdateProjectConfigurations, but when projects are configured not to be built in Configuration Manager in a solution, StartUpdateProjectConfigurations doesn't build them.
Of course this is ideal behavior because IVsSolutionBuildManager is based on solution configurations including Configuration Manager.
But even in such a case, I want to build specific projects. Actually some of the extension users wanted that and I also think it's useful.
https://github.com/Wakusei/BuildStartProject/issues/2

How to create a manifest file for TLBs which are used for remote COM objects only?

My Delphi application Client.exe needs a couple of .tlb files to work. These files define server interfaces. The corresponding object instances are created with System.Win.ComObj.CreateRemoteComObject.
What is the problem?
For now the .tlb files are registered globally during the installation using regtlibv12.exe and are unregistered on uninstalling the software. This makes it impossible to install and uninstall multiple instances of the same software since it can break the TLB registrations.
Attempt to solve it with Registration Free COM
The idea is to use the .tlb files without registration but with a .manifest file.
I know how to use a customized Windows application manifest file with Delphi. But I don't know how to extract the information from the .tlb files and create the correct .manifest file.
I have found Mt.exe which can be used to generate .manifest files but it doesn't help me because
it's asking for a corresponding DLL file when the -tlb parameter is set but there are no .dll files shipped with the application since the COM objects are created on remote machines
it doesn't accept multiple .tlb files in the parameter list.
Other tools like Make My Manifest or Unattended Make My Manifest aren't available anymore or don't help me either.
What is the right way to create a manifest file in this case?
AFAIK RegFree COM does only support registration of local instances, via a dll. There is no way of using it with DCOM, which is something much more complex than local COM.
From my own experiment, DCOM could be a real PITA, especially in terms of registration. IMHO you should either use local COM objects, or switch to another much standard approach, like REST services. You may be able to re-use almost the same interfaces using e.g. an SOA approach over REST/JSON - see especially sicClientDriven mode to emulate DCOM objects.

Developing Reg-Free COM application with VB6

I'm maintaining a VB6 application with many COM components (DLLs and OCXs). In order to streamline development and deployment I'd like to use reg-free com. The problem with development is that the application runs within the VB6.EXE instance. How can I trick VB6 to use my (unregistered) components? It is very important for me to not have to go through registering/unregistering components when switching between branches. Generating a .manifest file for VB6 is not out of the question but is there some other, more optimal way, to specify a .manifest file when launching VB6.EXE?
Note: The Activation Context API doesn't seem to help, even if used from within the development environment.
Solutions I've thought:
A utility application that activates a context from a manifest and launches VB6 as a child process (doesn't work; processes don't inherit activation context)
Injecting context activation into the VB6 process at startup (too complicated; must hack the executable to do this)
Hosting VB6 in my own process after activating the right context (can't even find out if this is possible)
Using a VB6 Add-In or other utility that runs within VB6 to activate a context (tried that but it doesn't seem to work)
Update Jan. 16
As suggested by wqw, I did some testing with a VB.exe.manifest. The VB6.exe.manifest worked, with some caveats:
The SxS dll specified in the manifest would not appear in the references window on projects that didn't actually reference the component
On projects that did reference the component it would be shown to reside in the directory according to the following order:
The pathname recorded in the project file (if the file was still present)
A pathname as if it resided in the same folder as the project (vbp)
If the file was not in any of these folders, the project would not compile (just running the code causes an internal compile in VB6) with the message "Can't find project or library".
Obviously, VB6 actualy scans the registry to find COM components and verifies, during compilation, that they exist where they say they exist. I'm not sure what that might mean if I actually want to use VB6.exe.manifest to redirect COM component instantiation. Perhaps having dummy component files at some predefined location might trick VB6 into believing that everything is as it should be, although an entirely different set of components got loaded for use.
Further update:
I did a test on that last assumption and it proved to be false. The component has to actually be there in order for the project to compile. It must even properly load (no dummy, zero-length files accepted!). Now I'm not even sure if the manifest works. That's a more time-consuming test (requires a component with two versions that produce different results, one with the project, and one for the manifest).
Our approach to this problem was to write a build assist program that registered and unregistered components, run the VB6 compiler, and would even rewrite project files with updated GUIDs when interfaces changed. You would hand it a VBG project group and it would do the rest.
I suppose we could also have added a mode that unregistered components when you switched branches.
Are you following the practice of using "compatibility" binaries? You shouldn't use the binary at your build location for compatibility references - you should commit a separate copy to version control and configure your project to consider that the "compatible" version - only change this file when you break interfaces.

Problem with VSTS UnitTesting. Can't supply C++ DLLs

I am using VSTS Unitesting platform. I am trying to test a method which got references to assemblies which in turn contain DllImport to C++ DLLs.
In order for it to work I need to copy C++ DLLs to reside on the same directory the EXE and DLLs are running.
Of course when I use the same code with Unittest I also need to supply those DLLs.
I found out that the Unittest framework us using the $(Solution)\TestResults[WorkSpace] [DateTime]\Out as a working directory.
If I manually copy the C++ DLLs to this directory the unit test is is working like a charm.
The problem is that every time the Unitest is running it creates a new directory.
Has anybody encountered it? do you have a solution?
Thanks,
Ariel
As Steve D mentions, deployment items are the answer here. You can either put them on the class, or test method using the attribute, or use the Test Run Configuration to add them so that when any tests are run from that solution they will be deployed.
The other option is to make sure they're in the path somewhere so that the standard windows look up rules for DLLs will apply, and the runtime will be able to locate them.
Why is this a problem? because theres little to no metadata from the project to the Native DLL -- we don't know to pick it up. The only option really would be to dive all types in the deployed managed dlls looking for the DllImport attrib. This would, however, fail, if you are doing explicit DLLLoads in the managed code.
You could try using a [DeploymentItem] attribute. It allows you to specify a relative path from the solution file which will get copied to the test output directory.

VB6 install on Windows Vista as a Standard User

I have a VB6 application that needs to be installed on Windows Vista as a Standard User. Using Visual Studio 2005 I have created a setup project that will place the application in a standard user safe place or folder. I also have a dll that I want to install and register to the users application data folder. Once my windows installer is created in VS'05 I flipped the word count properties' 3rd bit using msiinfo.exe so that Vista will not prompt Admin credentials when it runs the msi. The application installs without any problems until it tries to register the dll to the users application data folder. When it reaches that point it throws an error stating that it cannot register the type library for the dll. It appears the installer does not have the authority to register a dll to the users folder. Is this correct? My understanding was that Vista only complained about standard users updating or changing items that affected all users of a machine. Any ideas? Thoughts? Suggestions?
Steve
My suggestion is, if you are able, to use regfree com / manifest files instead of registering the ocx/dll files, which as you mention is a real chore under a basic user account.
There is an excellent free app you can use to build the manifest for you as well here: http://mmm4vb6.atom5.com/
We have been using this for a few years now, with no issues.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
Instead of registering your DLL files directly, you can use RegFree COM.
This involves creating an XML manifest file for your app, so Windows will look for your DLL files in the application folder, instead of using the system registry to find them.
This means your app will run properly without your installer having to register DLLs.
These links have more info:
http://msdn.microsoft.com/en-us/magazine/cc188708.aspx
http://www.devx.com/vb/Article/32888/1954
You can use the free Make My Manifest software to create the manifest files you need:
http://mmm4vb6.atom5.com/
Generally I agree to what Joel Coehoorn says in his answer.
However, knowing how the registry works in this regard, I can make the suggestion that you try to manually register your DLL to HKEY_CURRENT_USER\SOFTWARE\Classes, basically repeating what regsvr32.exe would do to HKEY_LOCAL_MACHINE\SOFTWARE\Classes.
It's a bit of a hack, and maybe it won't work, but you can try it.
related post on MSDN: http://msdn.microsoft.com/en-us/library/ms693350.aspx (thanks to MarkJ pointing this out in the comments)
related post on vbforums.com: http://www.vbforums.com/showthread.php?t=507228
Unattended Make My Manifest is a remake of MMM that can be used to generate manifests in automated builds. It uses a script file to add depended COM components.
Registry-free COM: MakeMyManifest is well spoken of. It is an automatic tool for creating manifests for VB6 projects: I haven't tried it myself.
DirectCOM is an alternative to registry-free COM. It also has fans, again I haven't tried it.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
There is a semi-automatic technique for creating manifests for registry-free COM. You can create the manifests with Visual Studio 2008 (you can use a free version like Visual Basic Express Edition). Then make a couple of edits by hand to make the manifests suitable for use from VB6. See this section of this MSDN article for step-by-step instructions - ignore the rest of the article which is about ClickOnce.
Registering a DLL does impact all users (DLLs are registered globally) and therefore requires Admin permissions. There is no way around that.
The solution for newer programming environments is that the DLL doesn't need to be registered to be used. However, since vb6 relies on COM you're probably out of luck.

Resources