My question is whether there are certain limitations to accessing COM objects when you're dealing with an MSIX-packaged app.
I've created a blank WinUI 3 C++ project, using the Visual Studio project template. In the project, I've created a traditional COM class that's registered at runtime using CoRegisterClassObject. I do not otherwise register the object in the registry. It's a singleton that's supposed to be accessible only when the .exe is already launched.
Now when I modify the project to be unpackaged, and the .exe is launched, I'm able to access the singeton class from another process, by calling CoCreateInstance. Everything works as designed.
But when I change the MSIX project back to the packaged setup, the call to CoCreateInstance from the unpackaged process now fails, with code REGDB_E_CLASSNOTREG.
It's like trying to connect to a COM object when there's an unelevated/elevated mismatch. Same error.
So are unpackaged processes unable to access COM objects registered with CoRegisterClassObject in MSIX-packaged apps? Is there a workaround or anything? Thanks in advance.
Related
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.
http://s4.postimg.org/bkprrelpp/6210.gif
Can someone explain this to me? I set my MCMS.Primary output as instructed by this page.
http://mdc.custhelp.com/app/answers/detail/a_id/19889/~/using-visual-studio-2013-professional-to-build-a-microsoft-visual-basic
I set the registration type to Extract COM information, the Scan At Build to Dependencies and Properties, and checked the COM Interop. But I'm getting an error and a warning after trying to build the project. I tried the help page that pops out after clicking the error message. But I can't find the components view it was referring to. What I want to know is how much important this COM Interop is. And also why sometimes when I build the project the error does not appear. But mostly it does.
One suggestion of that help page told me to register the item mentioned in the error message. An .exe file.
COM extraction is useful for turning self-registration routines into Windows Installer table data. COM Interop is the equivalent for registering managed assemblies for use via COM Interop. In both cases, the resulting registry keys are used to allow other DLLs to instantiate your COM server.
So the fundamental question you have to answer here is whether MCMS.exe is a COM server and registers any such data. If it is and does, then something is wrong with the extraction, and this is a problem. However if MCMS.exe is not a COM server, or does not actually register any relevant COM data, you may need to disable COM extraction.
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.
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.
I have a unmanaged C++/ATL in-process COM object (in Unmanaged.dll) that I'm trying to use from a managed C# DLL (Managed.dll). However, I want I want to use registration free COM. I have it down to these steps:
Register the COM object on the development machine. The in-process server must have a properly registered type library.
Add a reference to the COM object within the C# project, and then set the Reference Properties to Isolated = True.
This produces Unmanaged.dll, Managed.dll, and Native.Managed.manifest. Opening the manifest, it's pretty clear how the system uses it to load the COM object in a registration-free way.
Here's the rub. I have a managed EXE (Managed.exe) which dynamically loads Managed.dll to access public types. What I mean by "dynamically" is, it uses Assembly.LoadFrom("Managed.dll"). When the code inside Managed.dll tries to create the COM object, it gets a "class not registered" exception. It appears the activation context doesn't get setup correctly when Managed.dll gets loaded.
Is there a way to get registration free COM to work in this scenario?
Two days without an answer, so here's what I've come up with in that time...
It does indeed look like the activation context is setup by the OS at process launch based on the manifest associated with the main EXE. That means all registration-free COM related elements must be in the Main.exe.manifest at the time the process is started. This breaks the isolation between EXE and DLLs. If a DLL is responsible for creating COM objects, you wouldn't expect the EXE manifest to have to contain the reg-free COM information. You might have expected the manifest associated with the DLL to be merged into the process activation context at the time the DLL gets loaded, but it does not.
To work around this, the DLL must configure a new activation context before creating the COM object. To make things worse, there is currently (as of .NET 4.0) no managed way to do this. So, the DLL will have to PInvoke the following Win32 functions:
CreateActCtx
ActivateActCtx
DeactivateActCtx
ReleaseActCtx
I wrapped these calls with a managed class that calls CreateActCtx and ActivationActCtx in the constructor and DeativateActCtx and ReleaseActCtx in IDisposable::Dispose.