What Is Reg-Free COM - Using COM Without Registration
· Updated: · Go Komura · COM, Reg-Free COM, Registration-Free COM, Windows Development, Legacy Technology
Revision history (1 updates, last updated Sep 1, 2026)
A log of the changes made to this article. Where a pre-update version was archived, it stays readable at a permanent DOI link.
- Retranslated as a full translation of the Japanese original. The previous English version was an abridgement that carried only part of the source, so sections, tables, Mermaid diagrams, figure captions and FAQ entries were missing. All of them have been restored to match the Japanese original, and the technical claims are the same as in the Japanese version. Read the version before this update (DOI: 10.5281/zenodo.21614527)
- First published
Cite this article(DOI: 10.5281/zenodo.21614526)
This article is archived on Zenodo. Below are both the DOI that always resolves to the latest version and the DOI pinned to the version you are reading.
Go Komura (2026). What Is Reg-Free COM - Using COM Without Registration. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21614526 https://comcomponent.com/en/blog/2026/03/16/011-what-is-reg-free-com/
- DOI (latest version)
- 10.5281/zenodo.21614526
- DOI (this version)
- 10.5281/zenodo.22217163
COM / ActiveX / OCX projects run into the same problems with every deployment and every update.
regsvr32is required- Administrator privileges tend to become necessary
- It collides with a different version installed by another app
- Uninstalling it drags other products down with it
- It works on the development machine but not in a clean environment
Reg-Free COM can cut that overhead down considerably. Despite the name, though, it is not magic that makes every COM headache disappear. What it removes is mainly the overhead that comes with global registration. It does not erase the difficulties of bitness, dependent DLLs, type libraries, or threading models.
flowchart TB
accTitle: What Reg-Free COM removes and what it leaves behind
accDescr: A diagram showing that what Reg-Free COM removes is mainly the overhead that comes with global registration, while the difficulties of bitness, dependent DLLs, type libraries, and threading models remain.
rf1["Reg-Free COM"] --> rf2["Less global registration overhead"]
rf1 --> rf3["Some difficulties remain"]
rf3 -.-> rf4["bitness / dependent DLLs / type libraries"]
Figure 1: Expect it to split the headaches into the ones that go away and the ones that stay, not to work magic.
This article looks at Reg-Free COM mainly in the context of keeping COM DLLs / OCXs application-local inside a Windows desktop app.
Who This Is For and What It Assumes
This is written for developers who ship a Windows desktop app that uses an existing COM DLL / OCX and want to get out from under regsvr32 and administrator privileges. It assumes you have worked with the basics of COM at least once: CLSID, ProgID, CoCreateInstance, and in-proc servers. If that ground is still shaky, it is faster to read What Are COM / ActiveX / OCX? - The Differences and Relationships Explained first.
The step-by-step parts use mt.exe and sxstrace from the Windows SDK, so they assume a machine with Visual Studio or the Windows SDK installed.
1. The Conclusion First, in One Line
Here is a rough but useful way to put it up front.
- Reg-Free COM is a way of holding COM registration information in a manifest instead of the registry
- At runtime, the activation context is consulted first when
CoCreateInstanceorCLSIDFromProgIDresolves a class - That is what lets you keep a COM DLL / OCX private to each application
- The main benefits are that it is easy to deploy by XCOPY, that version conflicts are easier to avoid, and that uninstalls are harder to break
- However, the 32-bit / 64-bit problem does not go away. No way of writing the manifest gets around it
- You also need to think separately about dependent DLLs, type libraries, design-time references, and dependencies on non-standard registration data
- In practice it is a very good fit when you want to ship an app-specific COM component alongside the app
In short, Reg-Free COM is a mechanism that pulls COM activation back to the per-application level.
flowchart TB
accTitle: Where registration information lives changes
accDescr: A diagram showing that Reg-Free COM holds COM registration information in a manifest instead of the registry, that the activation context is consulted first when calls such as CoCreateInstance resolve a class, and that COM components can therefore be kept private to each application.
mg1["Hold registration information in a manifest"] --> mg2["Activation context comes first during resolution"]
mg2 --> mg3["COM components can be private per application"]
mg3 -.-> mg4["Easier XCOPY deployment and conflict avoidance"]
Figure 2: The essence is that the entry point for resolution moves from the registry to the manifest.
Knowledge map for this article
Reg-Free COM is a mechanism that keeps COM registration information in manifests rather than the registry and, at run time, consults the activation context first to resolve the DLL. The application manifest declares the side-by-side assemblies it depends on while the component manifest holds the information that originally lived in the registry, such as the CLSID and the ProgID; the manifests are embedded with mt.exe, and resolution failures are traced with sxstrace. The 32bit/64bit match requirement is not lifted, however, and the handling of dependent DLLs and type libraries remains a separate issue, so the approach suits making existing desktop assets such as VB6, MFC, and WinForms app-local, but does not suit situations that require COM to be shared machine-wide. On .NET 5+ and .NET 8, EnableComHosting produces a comhost, and enabling EnableRegFreeCom emits the side-by-side manifest for Reg-Free COM.
flowchart LR
accTitle: Reg-Free COM
accDescr: Diagram showing how Reg-Free COM keeps COM registration information per application through the activation context and side-by-side assembly mechanisms, how the application manifest and the component manifest divide the roles between them, how mt.exe builds the configuration and sxstrace investigates failures, and how all of this relates to comhost in .NET 5 and later
reg_free_com["Registration-Free COM"]
activation_context["Activation Context"]
win32_application_manifest["Win32 Application Manifest"]
component_manifest["Component manifest (assembly manifest)"]
side_by_side_assembly["Side-by-Side Assembly"]
bitness_match_requirement["Bitness Match Requirement"]
regsvr32["regsvr32"]
type_library["Type Library (TLB)"]
mt_exe["mt.exe (Manifest Tool)"]
sxstrace["sxstrace"]
assembly_searching_sequence["Private Assembly Searching Sequence"]
dotnet[".NET (Core and Later)"]
comhost["COM host (*.comhost.dll)"]
enable_com_hosting["EnableComHosting"]
enable_regfreecom["EnableRegFreeCom"]
vb6["Visual Basic 6.0 (VB6)"]
clsid["CLSID (Class ID)"]
progid["ProgID (Programmatic Identifier)"]
com["COM (Component Object Model)"]
activex["ActiveX"]
ocx["OCX"]
mfc["MFC (Microsoft Foundation Classes)"]
windows_forms["Windows Forms"]
machine_wide_com_sharing["Machine-Wide COM Sharing"]
reg_free_com -->|"uses"| activation_context
reg_free_com -->|"uses"| win32_application_manifest
reg_free_com -->|"uses"| component_manifest
win32_application_manifest -->|"requires"| side_by_side_assembly
component_manifest -->|"implements"| side_by_side_assembly
reg_free_com -->|"requires"| bitness_match_requirement
reg_free_com -.->|"successor to"| regsvr32
component_manifest -.->|"uses"| type_library
reg_free_com -->|"configured by"| mt_exe
reg_free_com -->|"verified by"| sxstrace
component_manifest -->|"configured by"| mt_exe
reg_free_com -->|"requires"| assembly_searching_sequence
dotnet -.->|"uses"| comhost
comhost -->|"requires"| enable_com_hosting
comhost -->|"configured by"| enable_regfreecom
enable_regfreecom -->|"implements"| reg_free_com
vb6 -.->|"uses"| type_library
component_manifest -->|"uses"| clsid
component_manifest -.->|"uses"| progid
reg_free_com -->|"uses"| com
reg_free_com -->|"uses"| activex
reg_free_com -->|"uses"| ocx
reg_free_com -->|"recommended for"| vb6
reg_free_com -->|"recommended for"| mfc
reg_free_com -->|"recommended for"| windows_forms
reg_free_com -->|"not recommended for"| machine_wide_com_sharing
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (26 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
2. What This Article Means by Reg-Free COM
Reg-Free COM is short for Registration-Free COM. In Japanese it is also written as toroku fuyo COM, literally COM that needs no registration.
“Registration-free” here means not depending entirely on global registry registration such as HKCR / CLSID / InprocServer32 in order to use COM.
It does not mean that COM itself goes away, nor that GUIDs are no longer needed.
The main subjects of this article are the following.
- Native COM DLLs
- ATL-based COM servers
- ActiveX / OCX
- COM interop based on .NET Framework
- Exposure through the .NET 5+ / .NET 8 COM host
Conversely, there are two points this article wants to stress.
- Reg-Free COM is a story about activation
- Distributing type information and configuring design-time references can remain a separate issue
Mixing the two muddies the discussion considerably.
flowchart TB
accTitle: Two issues that must not be mixed
accDescr: A diagram showing that Reg-Free COM is about activation while distributing type information and configuring design-time references remain a separate issue, so mixing the two muddies the discussion.
pt1["Reg-Free COM"] --> pt2["A story about activation"]
pt3["Type information and design-time references"] --> pt4["Remain a separate issue"]
pt2 -.-> pt5["Mixing them muddies the discussion"]
pt4 -.-> pt5
Figure 3: Keep the runtime story and the design-time story apart from the start.
3. The Whole Picture on One Page
Before the diagram, here are definitions for the four terms that keep coming up in this article.
| Term | Meaning |
|---|---|
| activation context | A runtime data structure that holds which version of which assembly this thread uses right now. CoCreateInstance consults it before the registry |
| side-by-side assembly | The Windows mechanism for letting components with the same name coexist on one machine in different versions. They are identified by manifests, and assemblyIdentity is the name tag |
| application manifest | XML attached to the EXE that states which side-by-side assemblies the app depends on |
| component manifest (assembly manifest) | XML attached to the component that states which files this assembly contains and which COM classes it exposes. The information that used to live in the registry moves here |
An activation context is held per thread. COM hands the creating thread’s activation context to the hosting thread before it calls LoadLibrary or DllGetClassObject, so no special setup is needed on the calling side.
With that in place, it is faster to see the whole picture in a single diagram.
flowchart LR
APP["MyApp.exe"] --> AM["Application Manifest"]
AM --> DEP["dependentAssembly"]
DEP --> CM["Component / Assembly Manifest"]
CM --> META["file / comClass / typelib"]
META --> DLL["VendorControl.dll / .ocx"]
APP --> ACTX["Activation Context"]
ACTX --> COM["CLSIDFromProgID / CoCreateInstance"]
COM --> DLL
Figure 4: Following the app manifest to the component manifest reaches the DLL without using the registry.
In ordinary COM, CoCreateInstance walks the registry to decide which DLL to load.
In Reg-Free COM, it first looks at the activation context currently in effect and resolves the class from the manifest information written there.
That makes it much easier for app A and app B to run on the same machine while each carries its own version of the same family of COM component. It nudges COM’s culture of sharing a little way back toward being application-local.
4. Why Ordinary COM Deployment Tends to Get Heavy
Ordinary COM deployment is heavy less because COM itself is bad than because of the assumption of global registration.
Using a COM class requires roughly this set of information.
| Information | Role |
|---|---|
| CLSID | GUID that uniquely identifies the class |
| ProgID | A name that is easy for people to work with |
| InprocServer32 | Which DLL to load |
| ThreadingModel | Assumptions such as Apartment or Both |
| TypeLib | Type information |
Once these go into the registry, they are convenient machine-wide, because several apps can share them easily.
In practice, though, that sharing backfires.
- One product’s setup overwrites another product’s COM registration
- An uninstaller breaks shared COM while believing it removed only its own entries
- A registration that happens to be present on the development machine is missing on the production machine
- The 32-bit and 64-bit registrations fail to line up, and only the symptoms drift around in unsettling ways
In other words, the deployment model troubles people far more often than COM itself does. Reg-Free COM is a mechanism for reducing the pain of that deployment model.
flowchart TB
accTitle: How machine-wide sharing backfires
accDescr: A diagram showing that putting COM registration information in the registry makes it easy to share machine-wide, but that in practice the sharing backfires as overwrites by other products, collateral damage during uninstall, and differences between development and production machines, so the deployment model troubles people more than COM itself.
gs1["Share registration information machine-wide"] --> gs2["Convenient because many apps can use it"]
gs1 --> gs3["In practice the sharing backfires"]
gs3 -.-> gs4["Overwrites / collateral damage / environment drift"]
gs3 --> gs5["The deployment model troubles people"]
Figure 5: The pain does not come from COM itself but from the assumption of global registration.
5. How Reg-Free COM Works
5.1 Declaring Dependencies in the Application Manifest
First, the app side writes which side-by-side assemblies it depends on into its application manifest.
This manifest can be handled either way:
- placed next to the EXE, as in
MyApp.exe.manifest - embedded in the EXE as a resource
In practice the split is usually an external file when you want deployment and replacement to stay visible, and embedding when you value robustness and a simple deployment more.
Note that when both an external file and an embedded copy exist, the manifest on the file system wins.
5.2 Describing COM Information in the Component Manifest
Next, the COM side carries the information that would normally live in the registry in a component manifest.
The information that goes in here looks like this.
comClassclsidprogidthreadingModeltypelib- proxy / stub entries, window classes, and so on when they are needed
In other words, the idea is to describe what the COM component looks like in XML instead of in the registry.
This manifest can be set up either way:
- placed as a separate file next to the DLL
- embedded in the DLL as a resource
In practice, embedding it in the DLL as a private assembly is usually harder to get wrong. Running with a separate file is easier to follow, but it is also easy to trip over the mapping between the file name and assemblyIdentity, over where the file has to sit, and over copies that never got made.
flowchart TB
accTitle: Ways to hold the component manifest
accDescr: A diagram showing that the component manifest holds information such as comClass, clsid, and typelib that used to live in the registry as XML, that it can be placed as a separate file next to the DLL or embedded into the DLL as a resource, and that embedding is harder to get wrong in practice.
cm1["Hold the registry information as XML"] --> cm2["Place it as a separate file"]
cm1 --> cm3["Embed it into the DLL"]
cm2 -.-> cm4["Easy to trip over missed copies"]
cm3 -.-> cm5["Usually harder to get wrong in practice"]
Figure 6: The content is the same either way, but how you place it decides how much can go wrong.
5.3 At Runtime, the Activation Context Is Consulted First
This is the heart of Reg-Free COM.
When the app calls CLSIDFromProgID or CoCreateInstance, the COM runtime looks at the active activation context.
If the ProgID to CLSID and CLSID to DLL information it needs is there, it can resolve the class without touching the registry.
If the manifest is missing something it needs, resolution falls back to the usual registration-based path. That behavior sets up the trap where it happens to work on the development machine: you think you have gone Reg-Free, when in fact a local registration is bailing you out.
This is the nastiest pitfall in Reg-Free COM.
flowchart TB
accTitle: The trap of falling back to registration-based resolution
accDescr: A diagram showing that the activation context is consulted first when CoCreateInstance resolves a class, but that resolution falls back to the usual registration-based path when the manifest lacks the information it needs, which creates the trap of the app happening to work on the development machine thanks to a local registration.
ac1["Resolution starts with the activation context"] --> ac2{"Does the manifest have enough information"}
ac2 -->|"Enough"| ac3["Resolved without the registry"]
ac2 -->|"Not enough"| ac4["Falls back to registration-based resolution"]
ac4 -.-> ac5["The trap of happening to work on the dev machine"]
Figure 7: A fallback that happens silently is the biggest pitfall in this mechanism.
6. What You Gain
The benefits of Reg-Free COM are quite clear in practice.
6.1 Easy XCOPY Deployment
You can put every file you need into the app folder, which lightens the installer and the registration steps.
Permissions are a separate matter if you write under Program Files, of course, but at minimum the administrator work needed for COM registration is easy to cut down.
6.2 Easier to Reduce Version Conflicts
Even when several versions of a COM component exist on the same machine, it becomes easy to keep each app on the version it wants.
That makes it far easier to avoid the incident where behavior suddenly changed after another product's setup ran.
6.3 Existing Code Often Needs Few Changes
Reg-Free COM changes how resolution happens rather than fundamentally changing how existing code makes its calls.
So when it fits, you can adopt it with almost no changes to the CoCreateInstance side of the code.
6.4 Removal and Rollback Get Easier
Because everything is contained per app, updates and rollbacks become much more straightforward. At the extreme, it becomes reasonable to think in terms of swapping the whole folder.
flowchart TB
accTitle: What you gain by containing things per application
accDescr: A diagram showing that containing COM components per application yields easy XCOPY deployment, easier avoidance of version conflicts, adoption with almost no changes to existing code, and simple removal and rollback.
cl1["Contain it per application"] --> cl2["Easy XCOPY deployment"]
cl1 --> cl3["Fewer version conflicts"]
cl2 -.-> cl5["Swap the whole folder"]
cl3 -.-> cl4["Calling code barely changes"]
Figure 8: Every one of the benefits grows out of the single property of being contained.
7. Where It Fits and Where It Does Not
7.1 Where It Fits
In cases like these, Reg-Free COM is a strong option.
| Situation | Fit |
|---|---|
| You want to bundle an app-specific COM DLL / OCX | Very good |
| You want several versions coexisting on one PC | Very good |
| You want to avoid registration problems with vendor components | Good |
| You want to use an ActiveX / OCX privately inside an existing desktop app | Good |
| You want lighter deployment without changing existing calls much | Good |
Typically it fits well with line-of-business desktop apps, equipment-integration tools, and existing VB6 / MFC / WinForms assets.
7.2 Where It Does Not Fit, or Deserves a Careful Look
On the other hand, there are cases worth looking at carefully.
| Situation | Comment |
|---|---|
| You want to share COM machine-wide | Reg-Free has little to offer |
| Bitness does not line up | Reg-Free does not solve this |
| Heavy dependence on non-standard registration data or a custom setup | Hard to express as a manifest |
| Distribution of dependent DLLs or the VC++ runtime is not sorted out | You will trip somewhere else instead |
| Design-time tools or IDE reference settings assume the registry | A separate operational design is needed |
The last point in particular matters. Reg-Free COM helps with runtime activation, but it does not single-handedly change what the design-time reference UI assumes.
flowchart TB
accTitle: Runtime is covered but design time is not
accDescr: A diagram showing that Reg-Free COM helps with runtime activation but does not by itself change design-time tools and IDE reference settings that assume the registry, so a separate operational design is needed.
rt1["Runtime activation"] --> rt2["Reg-Free helps here"]
dt1["Design-time reference settings UI"] --> dt2["May assume the registry"]
dt2 -.-> dt3["A separate operational design is needed"]
Figure 9: Getting the software to run is one job; getting it to be developed against is another.
8. Common Misconceptions
8.1 With Reg-Free COM, the Bitness Problem Goes Away
It does not. A 32-bit process can load only 32-bit in-proc COM DLLs, and a 64-bit process takes only 64-bit DLLs. This is the same under Reg-Free as it always was.
8.2 With Reg-Free COM, the Registry Is Never Consulted
Also wrong. If the manifest lacks the information it needs, resolution falls back to the usual registration-based path. So success on the development machine does not mean the Reg-Free configuration is correct.
8.3 With Reg-Free COM, the Type Library Story Sorts Itself Out
This one is only half right.
A manifest can carry typelib information too, but handling type information - VBA reference settings, #import in C++, generating design-time references on the .NET side - routinely needs a design of its own.
Reg-Free COM is, first of all, about getting things to start. How to develop against types is the next issue after that.
flowchart TB
accTitle: The order of getting it to start and dealing with types
accDescr: A diagram showing that a manifest can carry typelib information but that handling type information for VBA reference settings, C++ import, and design-time interop generation on the .NET side needs its own design, so Reg-Free COM is first about getting things to start and typed development is the next issue.
st1["Set up Reg-Free COM"] --> st2["First get it to start"]
st2 --> st3["Then decide how to develop against types"]
st3 -.-> st4["VBA references / import / interop generation"]
Figure 10: Being able to write typelib is not the same as having type information sorted out.
8.4 With Reg-Free COM, Any ActiveX / OCX Just Works As-Is
This one is dangerous too. If the component rides on standard COM registration data, you can move ahead easily, but once it leans heavily on custom registry settings, extra setup steps, licensing logic, or a cluster of other modules, going Reg-Free gets rough fast.
8.5 Reg-Free COM Is Roughly the Same on .NET Framework and .NET 8
They have things in common, but the toolchains differ considerably.
The .NET Framework + RegAsm world and the .NET 5+ / .NET 8 + comhost world stand on different footing, even though both are COM.
9. Differences Between Native, .NET Framework, .NET 5+, and .NET 8
These get mixed up easily, so it is worth separating them once.
| Family | Rough summary |
|---|---|
| Native COM DLL / OCX | Basically a matter of an application manifest plus a component manifest |
| COM interop based on .NET Framework | On top of the Win32-style application manifest, the managed component side needs a manifest as well |
| Exposing COM on .NET 5+ / .NET 8 | EnableComHosting builds a COM host, and EnableRegFreeCom can generate the Reg-Free manifest |
9.1 .NET Framework-Based COM
With .NET Framework-based COM you end up with two tiers: a Win32-style application manifest on the COM app side and a component manifest on the managed component side.
In other words, one more manifest than with native COM. The naming and resource ID constraints in 10.4 apply to this component manifest in exactly the same way.
9.2 Exposing COM on .NET 5+ / .NET 8
On .NET 5+ / .NET 8, the entry point for COM exposure is *.comhost.dll.
Add EnableRegFreeCom=true and the build also emits a side-by-side manifest for Reg-Free COM.
Type information remains a separate issue, as 8.3 says, and .NET Core / .NET 5+ changes that further. This is no longer the world of the .NET Framework days where a TLB falls out of the assembly on its own, so if you need typed usage you have to assemble TLB generation, embedding, and registration yourself. Using a .NET 8 DLL from VBA with Full Typing - COM Exposure and dscom TLB covers the concrete steps.
flowchart TB
accTitle: Reg-Free COM on .NET 5 and later
accDescr: A diagram showing that on .NET 5 and later EnableComHosting builds the comhost.dll that serves as the entry point for COM exposure, that enabling EnableRegFreeCom emits a side-by-side manifest for Reg-Free COM, and that TLB generation and registration still have to be assembled separately.
dn1["Build with EnableComHosting"] --> dn2["comhost.dll becomes the entry point"]
dn2 --> dn3["Enable EnableRegFreeCom"]
dn3 --> dn4["A Reg-Free manifest is emitted"]
dn4 -.-> dn5["Handle the TLB separately"]
Figure 11: On .NET 8 two properties get the plumbing in place, but type information is separate work.
10. A Minimal Configuration
This section sketches the minimal setup in which MyApp.exe uses Vendor.CameraControl.dll through Reg-Free COM.
10.1 File Layout Sketch
MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.Asm.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll
The example above assumes the component manifest sits in a separate file. You can embed it in the DLL instead, but then fixed constraints apply to the assembly name and the resource ID. Section 10.4 covers that along with the steps.
10.2 Application Manifest Sketch
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="KomuraSoft.MyApp"
version="1.0.0.0"
processorArchitecture="amd64" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Vendor.CameraControl.Asm"
version="1.0.0.0"
processorArchitecture="amd64" />
</dependentAssembly>
</dependency>
</assembly>
10.3 Component Manifest Sketch
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="Vendor.CameraControl.Asm"
version="1.0.0.0"
processorArchitecture="amd64" />
<file name="Vendor.CameraControl.dll">
<comClass
clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
progid="Vendor.CameraControl.1"
threadingModel="Apartment"
tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}" />
<typelib
tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}"
version="1.0"
helpdir="" />
</file>
</assembly>
What really matters in this example is not the XML details but that the app-side dependentAssembly and the component-side assemblyIdentity agree.
When they drift apart, you get a startup failure whose cause is invisible from the look of the error alone.
The GUIDs and names above are examples used for explanation. In real work you have to write them to match the CLSID / TLBID / ProgID / threading model that the component actually exposes.
flowchart TB
accTitle: The matching requirement between the two manifests
accDescr: A diagram showing that the app-side dependentAssembly and the component-side assemblyIdentity have to agree on name and version, and that a mismatch produces a startup failure whose cause is invisible from the look of the error alone.
mm1["App-side dependentAssembly"] --> mm3{"Do the name and version match"}
mm2["Component-side assemblyIdentity"] --> mm3
mm3 -->|"Match"| mm4["Resolution succeeds"]
mm3 -->|"Mismatch"| mm5["Startup failure with no visible cause"]
Figure 12: What decides life or death is not the XML details but whether the name tags on both sides agree.
10.4 Where to Put the Manifest and How to Embed It
This is where the procedure trips people up the most. The names you are allowed to use change depending on whether you place the manifest as a separate file or embed it in the binary.
For a private assembly, side-by-side searches in this order relative to the app folder.
- The WinSxS folder
<appdir>\<assemblyname>.DLL<appdir>\<assemblyname>.manifest<appdir>\<assemblyname>\<assemblyname>.DLL<appdir>\<assemblyname>\<assemblyname>.manifest
If a DLL whose name matches the assembly name is found first, the search stops there. That leaves only the following two workable arrangements.
| Placement | Assembly name | Files | Embedded resource ID |
|---|---|---|---|
| Separate file | Must differ from the DLL name. Example: Vendor.CameraControl.Asm |
Place Vendor.CameraControl.Asm.manifest next to the DLL |
Not embedded |
| Embedded in the DLL | May be the same as the DLL name. Example: Vendor.CameraControl |
Vendor.CameraControl.dll only |
1 |
In other words, if you use the name Vendor.CameraControl.Asm as in the 10.2 and 10.3 examples, that is the separate file convention. To switch to embedding, change the name in assemblyIdentity to Vendor.CameraControl and align the dependentAssembly side to the same name.
flowchart TB
accTitle: How the search stops
accDescr: A diagram showing that side-by-side searches for a private assembly from WinSxS through the app folder, that the search stops as soon as a DLL matching the assembly name is found, and that a separate-file setup therefore needs an assembly name different from the DLL name.
se1["Start the private assembly search"] --> se2["Look for a DLL matching the assembly name"]
se2 -->|"Found"| se3["The search stops there"]
se2 -->|"Not found"| se4["Look for a manifest file of the same name"]
se3 -.-> se5["With separate files, use a different name"]
Figure 13: The naming constraint comes straight from the fact that the search stops partway.
There is one more constraint that is easy to get wrong. A component manifest cannot go into the resources of an EXE. What can go into an EXE is the application manifest.
Use mt.exe (the manifest tool) from the Windows SDK to embed a manifest. Run it from the Visual Studio developer command prompt.
rem 1. Get the syntax check to pass before embedding anything
mt.exe -manifest MyApp.exe.manifest -validate_manifest
mt.exe -manifest Vendor.CameraControl.manifest -validate_manifest
rem 2. Embed the application manifest into the EXE
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;#1
rem 3. Embed the component manifest into the DLL (resource ID is 1)
mt.exe -manifest Vendor.CameraControl.manifest -outputresource:Vendor.CameraControl.dll;#1
rem 4. Extract it again to confirm the embedding worked
mt.exe -inputresource:Vendor.CameraControl.dll;#1 -out:extracted.manifest
Comparing the extracted.manifest produced by the fourth command against the original XML rules out the case where you thought you embedded the manifest but nothing actually went in.
flowchart TB
accTitle: Embedding steps with mt.exe
accDescr: A diagram showing the mt.exe flow of first passing the syntax check with validate_manifest, then embedding the application manifest into the EXE and the component manifest into the DLL at resource ID 1, and finally extracting it again to compare against the original XML.
mt1["Pass the syntax check"] --> mt2["Embed the app side into the EXE"]
mt2 --> mt3["Embed the component side into the DLL (ID 1)"]
mt3 --> mt4["Extract it and compare with the original XML"]
Figure 14: Treat embedding as one procedure that runs all the way through verification.
There are two things to watch out for with mt.exe.
- The files a manifest references have to sit in the same directory as the manifest. If you wrote
<file name="Vendor.CameraControl.dll">, put that DLL next to the manifest before running the command. When the build output and the manifest are managed in different places, this is where you stop - If you omit the resource ID from
-outputresource,CREATEPROCESS_MANIFEST_RESOURCE(= 1) is used. Spelling out;#1reads better and keeps an unintended 1 from causing trouble
To replace something that is already embedded, -updateresource:<file>;#1 works. It means the same thing as passing the same argument to both -inputresource and -outputresource.
10.5 A Verification Procedure That Includes a Clean Environment
With Reg-Free COM, “it worked on the development machine” means almost nothing, because the possibility that a local registry registration is bailing you out never goes away. Verify in this order.
- Build, and gather the full set of deliverables into one folder. The EXE, the manifests, the COM DLL, the dependent DLLs, the VC++ runtime, and the proxy / stub DLLs
- Prepare a verification environment. Ideally one where the COM in question has never been registered. Windows Sandbox lets you start from a blank slate every time
- In that environment, confirm first that the COM is not registered. If the commands below fail with a message saying the key was not found, it is unregistered
- Copy the folder over and launch it as-is. No installer, no
regsvr32 - Confirm that COM object creation actually goes through. Simply launching the app does not verify components that are created lazily. Exercise the screens and features where
CoCreateInstancereally runs - If it fails, collect logs with the procedure in 11.2
These are the commands for step 3.
reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:64
reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:32
reg query "HKCR\Vendor.CameraControl.1"
The 32-bit and 64-bit registry views are separate things, so always look at the side that matches the app’s bitness. Checking both /reg:64 and /reg:32 makes it certain.
To try this on the development machine, unregister first with regsvr32 /u Vendor.CameraControl.dll and then check. That has side effects on machines where another product uses the same COM, though, so preparing a clean environment is safer.
flowchart TB
accTitle: The verification flow in a clean environment
accDescr: A diagram showing the flow of gathering the full set of deliverables into one folder, preparing a verification environment where the target COM has never been registered, confirming first that it is unregistered, copying the folder over and launching it as-is, and exercising the features where CoCreateInstance runs.
cv1["Gather the full set of deliverables"] --> cv2["Prepare a clean verification environment"]
cv2 --> cv3["Confirm first that it is unregistered"]
cv3 --> cv4["Copy it over and launch as-is"]
cv4 --> cv5["Exercise the features that create COM objects"]
cv5 -.->|"If it fails"| cv6["Collect logs and investigate"]
Figure 15: Checking that nothing is registered keeps happens-to-work results out of the verification.
11. Pitfalls
11.1 It Works on the Development Machine but Not on the Target
The first suspect is the pattern where a registry registration was actually bailing you out. It is safer to verify Reg-Free COM in a clean environment wherever possible.
11.2 It Fails to Start with “side-by-side configuration is incorrect”
This family of failures comes from manifest inconsistencies, missing dependent DLLs, a missing VC++ runtime, an architecture mismatch, and the like.
The surface error text is quite unhelpful on its own, so the standard move is to chase it through the event log and sxstrace.
For the event log, open Event Viewer > Windows Logs > Application and look for errors whose source is SideBySide. That tells you which assembly failed to resolve.
Capture sxstrace while reproducing the failure. Opening the command prompt as administrator makes this reliable.
rem 1. Start the trace. Leave this window open
sxstrace trace -logfile:sxstrace.etl
rem 2. In another window, launch the app and reproduce the failure
rem 3. Stop the trace. Press Enter in window 1, or run the following from another window
sxstrace stoptrace
rem 4. Convert the raw .etl into a human-readable form
sxstrace parse -logfile:sxstrace.etl -outfile:sxstrace.txt
If you do not want the stop prompt, add -nostop to step 1. If the output is too long, add -filter:MyApp.exe to step 4 to narrow it down to the app in question.
The converted sxstrace.txt lists, in order, which manifests were looked for and where the match failed. If you got the naming in 10.4 wrong, the file names it went looking for will show that here too.
flowchart TB
accTitle: How to investigate a side-by-side error
accDescr: A diagram showing the flow for a startup failure reported as side-by-side configuration is incorrect: check Event Viewer for errors from the SideBySide source, start a trace with sxstrace, reproduce the failure, stop the trace and convert it with parse, and read where the mismatch occurred.
sx1["Check the event log for SideBySide"] --> sx2["Start a trace with sxstrace"]
sx2 --> sx3["Launch the app and reproduce the failure"]
sx3 --> sx4["Stop it and convert with parse"]
sx4 --> sx5["Read the search and the mismatch"]
Figure 16: Do not agonize over the surface error text; follow the resolution path through logs and traces.
11.3 The Component Manifest and the Application Manifest Drift Apart
- The name differs
- The version differs
- The processorArchitecture differs
- The manifest you thought you copied is stale
These look like tiny differences on the surface, but they hit quite hard at startup.
11.4 Forgetting to Ship a Dependent DLL
If you look at Vendor.CameraControl.dll alone and call it done, you leave out the Vendor.Helper.dll that gets loaded downstream, the VC++ runtime, and the proxy / stub DLLs.
Reg-Free COM reduces COM registration problems, but it does not also erase native dependency-resolution problems.
11.5 Putting Off Type Library and Reference-Setting Work
Even once runtime activation goes through, the moment you want to
- early-bind from VBA
- use
#importfrom C++ - generate interop at design time on the .NET side
you need a way to distribute type information. Reg-Free COM does not arrange all of that for you, so it matters to think about runtime and design-time separately.
12. Summary
In one line, Reg-Free COM is a mechanism that shifts COM registration information from the whole machine down to the individual application.
That gives you the following benefits.
- COM DLLs / OCXs are easy to keep application-local
- Version conflicts are easier to reduce
- Deployment and rollback are easier to simplify
At the same time,
- 32-bit / 64-bit
- dependent DLLs
- TLBs and reference settings
- dependencies on non-standard registration data
- verification in a clean environment
all still matter.
So the basic stance when adopting Reg-Free COM is this.
- Accept that this is a story about activation
- Separate the runtime and design-time issues
- Verify in a clean environment
- Line up bitness and dependent DLLs first
Take them in that order and far less goes wrong.
flowchart TB
accTitle: The basic stance when adopting it
accDescr: A diagram showing that adopting Reg-Free COM goes more smoothly when you accept it as a story about activation, separate runtime from design-time issues, verify in a clean environment, and line up bitness and dependent DLLs first.
bs1["Accept it as a story about activation"] --> bs2["Separate runtime from design-time"]
bs2 --> bs3["Verify in a clean environment"]
bs3 --> bs4["Line up bitness and dependent DLLs first"]
Figure 17: Follow the four stances in order and most of the trouble in adoption disappears.
13. Related Articles
- What Are COM / ActiveX / OCX? - The Differences and Relationships Explained
- How to Handle ActiveX / OCX Today - A Keep / Wrap / Replace Decision Table
- Using a .NET 8 DLL from VBA with Full Typing - COM Exposure and dscom TLB
14. References
- Microsoft Learn - Creating Registration-Free COM Objects
- Microsoft Learn - Application Manifests
- Microsoft Learn - Assembly Manifests (resource ID and naming constraints when embedding)
- Microsoft Learn - Assembly Searching Sequence (search order for private assemblies)
- Microsoft Learn - Manifest File Schema
- Microsoft Learn - Mt.exe
- Microsoft Learn - Registration-Free COM Interop (.NET Framework)
- Microsoft Learn - Exposing .NET Core Components to COM
- Microsoft Learn - sxstrace
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
What Are COM / ActiveX / OCX? - The Differences and Relationships Explained
A practical guide to what COM is, what ActiveX is, and what OCX is - covering their differences and relationships, the connection to OLE,...
How the Clipboard and Drag & Drop Work — Handling OLE Data Transfer Correctly in Business Apps
Paste an Excel table and the formatting falls apart; close the source app and you can no longer paste — both come from the clipboard plac...
Windows Shell Integration Today — Context Menus, File Associations, and What Changed in Windows 11
Why a Windows 11 context menu hides items behind "Show more options", explained from the extension → ProgID → verb association basics thr...
DLL and COM Interface Backward Compatibility — A Decision Table for Which Changes Break Callers
Which changes to a DLL or COM component actually break their callers? We lay out the three layers of compatibility — binary, source, and ...
Do Business Apps Run on Windows on Arm? — The Reality of x64 Emulation (Prism) and Native DLLs/COM
An answer, aimed at developers and IT staff, to 'will our business app run on Windows on Arm?' Covers how x64 emulation (Prism) works, th...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
ActiveX Migration
Topic page for staged decisions around keeping, wrapping, or replacing COM / ActiveX / OCX assets.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
This topic ties directly into Windows desktop app implementation, covering COM DLL / OCX deployment, manifest configuration, bitness, and dependent DLLs.
Technical Consulting & Design Review
It is also well suited to sorting out decisions such as whether to adopt Reg-Free COM or keep registration-based operation, and how to separate type libraries from design-time references.
Frequently Asked Questions
Common questions about the topic of this article.
- What is Reg-Free COM?
- It is a mechanism that holds COM registration information in a manifest instead of the registry, and the name is short for Registration-Free COM. At runtime, resolution through CoCreateInstance or CLSIDFromProgID consults the activation context first and resolves the DLL from the manifest information found there. That is what lets you keep a COM DLL or OCX private to each application, which makes XCOPY deployment easy, makes version conflicts easier to avoid, and makes uninstalls harder to break.
- Does moving to Reg-Free COM also solve the 32-bit / 64-bit problem?
- No. A 32-bit process can load only 32-bit in-proc COM DLLs, and a 64-bit process takes only 64-bit DLLs. That is the same under Reg-Free as it always was. You also have to think separately about shipping dependent DLLs and the VC++ runtime, about type libraries, about design-time reference settings, and about dependencies on non-standard registration data. What Reg-Free COM removes is mainly the overhead that comes with global registration.
- Why does a Reg-Free COM setup work on the development machine but fail on the target?
- The first suspect is the pattern where a registry registration was actually bailing you out. When the manifest lacks the information it needs, the COM runtime falls back to the usual registration-based resolution, so a local registration on the development machine can make things happen to work. That is why it is safer to verify Reg-Free COM in a clean environment. When startup fails with side-by-side configuration is incorrect, the cause is a manifest inconsistency, a missing dependent DLL, or something similar, and the standard move is to chase it through the event log and sxstrace.
- Can a COM component built on .NET 8 be made Reg-Free as well?
- Yes. On .NET 5+ and .NET 8, EnableComHosting builds the *.comhost.dll that serves as the entry point for COM exposure, and adding EnableRegFreeCom=true emits a side-by-side manifest for Reg-Free COM. Reg-Free COM and TLB strategy are separate issues, though. On .NET Core and .NET 5+, a TLB does not fall out of the assembly the way it did in the .NET Framework days, so if you need typed usage such as early binding from VBA, it is safer to sort out TLB generation, embedding, and registration on their own.