Registration and Bitness Pitfalls in COM/OCX/ActiveX Development

· · COM, ActiveX, OCX, Visual Studio, Windows Development, 32bit, 64bit, Interop

In COM component and OCX / ActiveX projects, the things that trip you up tend to live at the boundaries of runtime environment, registration, host, and privileges — not in the code itself.

The typical symptoms look like this.

  • The build succeeds, but at startup you get 0x80040154.
  • It works on your own development machine but not on other PCs.
  • It runs fine at runtime, but only the Visual Studio Designer dies.
  • It works when launched as administrator but breaks under normal privileges.
  • You keep running regsvr32, yet somehow nothing gets fixed.

These are less individual bugs and more a state where some assumption of COM is misaligned somewhere.

If you first want to sort out the terminology itself — COM / ActiveX / OCX — start with What Are COM / ActiveX / OCX? The Differences and Relationships Explained to get the big picture. This article covers the next stage: where you actually get stuck in practice, including Visual Studio bitness and administrator-rights issues.

1. The Conclusion First

Put in terms that matter in real work, it comes down to this.

  1. COM / OCX / ActiveX trouble is more often caused by mismatches in bitness (32bit / 64bit), registration location, host, and privileges than by code logic.
  2. Visual Studio 2022 is a 64bit process, so design-time integration that assumed 32bit and used to just work will break as is.12
  3. regsvr32 is not a magic command that registers everything. It is for native in-proc COM servers (DLL / OCX). To expose .NET Framework assemblies to COM you use Regasm.exe, and for .NET 5+ / .NET 6+ / .NET 8+ you register the generated .comhost.dll.3456
  4. “It works as administrator, so it’s fine” is dangerous. It is not unusual that the component is only visible by accident through a per-user registration, or that registration that should be done by the installer was done by hand only on the development machine.378

So when you deal with COM / OCX / ActiveX, the safe approach is to look at these four axes first.

  • Which process hosts the component
  • Whether that process is 32bit or 64bit
  • Where it is registered (HKCU / HKLM, 32bit view / 64bit view)
  • Whether the operation or execution requires administrator rights

2. Working Backwards from Symptoms

Symptom First suspect Common real cause
0x80040154 Class not registered Not registered Often it is actually “registered only on the other bitness side” or “registered only for that one user”
DllRegisterServer failed: 0x80070005 Insufficient privileges Trying to register as a standard user, or registering in a post-build step without elevation
Only the Designer breaks in VS2022 Designer constraints The 64bit Visual Studio cannot directly load a 32bit COM / ActiveX component
Works only when launched as administrator Privilege issue The real problem is usually less about privileges and more about misaligned registration scope or installation design
A 64bit app cannot call a 32bit OCX A constraint of how COM works An in-proc server can only be loaded into a host of the same bitness
Works on the UI thread but hangs on a background thread Threading model Violated assumptions about STA / MTA, CoInitializeEx, and the message loop

Officially, 0x80040154 is REGDB_E_CLASSNOTREG — literally Class not registered.9 And 0x80070005 from regsvr32 is officially documented as the case where you lack administrator rights and cannot write to the registry or System32.10

The important thing here is not to take the error name at face value. For example, Class not registered does not necessarily mean “not registered at all” — it also occurs when the component is registered in a different registry view or registered somewhere visible only to that particular user.117

3. Getting Stuck on Visual Studio Bitness

3.1. Visual Studio 2022 Became 64bit

This is the single most common stumbling point in COM / ActiveX development today.

In Visual Studio 2022, devenv.exe is 64bit only.1 As a result, in the WinForms design-time experience, Visual Studio itself cannot directly load 32bit components. Microsoft explicitly states that because Visual Studio 2022 is a 64bit process, it cannot load 32bit .NET / COM / ActiveX components.2

In other words, what used to hold together loosely under these assumptions —

  • the project is x86
  • the referenced ActiveX is also x86
  • Visual Studio itself is 32bit

— twists in VS2022 into:

  • the app can still run as x86 at runtime
  • but the Designer runs inside the 64bit Visual Studio

That produces the rather nasty state where the app is alive at runtime, but only the Designer crashes.2

3.2. Switching to AnyCPU Does Not Necessarily Fix It

This is another common misconception.

AnyCPU is not magic that makes your dependencies neutral too. As Microsoft’s own explanation notes, even a component that looks like AnyCPU will still be a problem at Visual Studio 2022 design time if, further down the chain, it references a COM / ActiveX component pinned to 32bit.2

So when switching to AnyCPU does not make the error go away, it is faster to suspect:

  • whether there is a 32bit native dependency further down from that assembly
  • whether the ActiveX / OCX is pinned to x86
  • whether there is code that is only loaded at design time

3.3. The System32 and SysWOW64 Trap

On Windows x64, the names and the reality do not line up, which causes endless confusion.

Microsoft Learn explains that on x64 Windows, %windir%\System32 is for 64bit applications. The 32bit side is redirected elsewhere by the WOW64 file system redirector.12 The registry behaves the same way: the WOW64 registry redirector presents separate logical views to 32bit and 64bit code.11

For that reason, when you troubleshoot locally, it is safer to be explicit about which bitness of regsvr32 you are using.

# To register a 64bit DLL / OCX
C:\Windows\System32\regsvr32.exe vendor.ocx

# To register a 32bit DLL / OCX on x64 Windows
C:\Windows\SysWOW64\regsvr32.exe vendor.ocx

The nasty part of this trap is that if you register on the wrong side, the component is invisible to the target process even though you “registered” it. The result is:

  • regsvr32 succeeded
  • but the app still reports 0x80040154
  • the registry looks like the entry is there
  • but you are looking at the other view

1113

3.4. regsvr32 Cannot Register Everything

This is another area full of misconceptions.

Native in-proc COM servers normally support self-registration by exporting DllRegisterServer / DllUnregisterServer.3 regsvr32 is the tool for exactly those DLLs / OCXs.4

On the other hand, if you want to use a .NET Framework assembly from COM, the standard tool is Regasm.exe. Microsoft Learn likewise states that Regasm.exe is used to register assemblies for use with COM.514

Furthermore, COM exposure in .NET 5+ / .NET 6+ / .NET 8+ works a little differently: when you build with <EnableComHosting>true</EnableComHosting>, a *.comhost.dll is generated, and that is what you register with regsvr32.6

Roughly categorized, it looks like this.

What you want to expose Typical registration mechanism
Native C++ DLL / OCX regsvr32
.NET Framework assembly exposed to COM Regasm.exe
.NET 5+ / 6+ / 8+ COM exposure Register the generated .comhost.dll with regsvr32

Mixing these up produces a common pattern:

  • run regsvr32 against a managed DLL
  • naturally, DllRegisterServer is not found
  • conclude — wrongly — that “the DLL is corrupted”

In the world that needs type libraries (VBA / VB6 / some early-binding clients), generating and registering the TLB is yet another separate problem. With .NET Framework you can generate and register a type library via Regasm.exe /tlb, and Microsoft explains that “registering types” and “registering the type library” are separate activities.15

4. Getting Stuck on Administrator Rights

4.1. Registering in a Post-Build Step That Only Succeeds as Administrator

In Visual Studio C++ builds, calling regsvr32.exe from a build event or custom build step is perfectly possible. Microsoft Learn even shows registration with regsvr32.exe as an example post-build event.16

However, what is possible and what is safe are two different things.

Running regsvr32 as a standard user can fail with 0x80070005 because you cannot write to the registry or System32. Microsoft’s KB likewise attributes the cause to lacking administrator rights.10

What tends to happen here is:

  • launch Visual Studio with normal privileges and the build passes
  • but only the post-build registration fails
  • the failure in the log goes unnoticed
  • a previous, stale registration is still in place, so locally it happens to work
  • on a clean environment, of course, it does not

The basic remedy for this kind of project is to separate build from registration.

  • The build only produces binaries
  • Registration is done by an explicit install step / script / installer
  • In CI, put “steps that require registration” in a separate job from the build

That separation alone prevents a lot of accidents.

4.2. Mixing Per-User and Per-Machine Registration Breaks Things

If your only mental model is “COM looks at HKCR”, this is where you get stuck.

In reality, as Microsoft Learn explains, COM looks at HKEY_CURRENT_USER\Software\Classes first, and then processes machine-wide information.3 Also, HKEY_CLASSES_ROOT is a merged view of HKLM\Software\Classes and HKCU\Software\Classes.717

Which means situations like this happen routinely:

  • developer A registered the component manually under their own user
  • it works under A’s account
  • it does not work for developer B
  • it does not work for the service account either
  • running it as administrator changes the behavior

Furthermore, Microsoft states that applications that require administrator rights should register their dependent COM objects into the per-machine COM configuration store at install time.87

So in a development team, you should make this distinction explicit.

  • Is this a development-only registration used by just your own user?
  • Is this a production registration used by every user on the machine?
  • Is this a registration that services or elevated applications will look up?

Leave this vague, and you end up with stories like “for some reason it only works as administrator” or “it works in the Explorer extension but not in the service”.

4.3. Always Running Visual Studio “as Administrator” Is Not a Solution

There are genuinely cases where it is necessary. But if you keep Visual Studio permanently elevated, you can end up hiding, behind IDE elevation, problems that should be solved by an installer or registration script.

On top of that, Visual Studio itself treats per-user extensions differently when elevated. Microsoft Learn describes a setting whereby running Visual Studio elevated disables per-user extensions.18

So as an operating practice:

  • do day-to-day development with normal privileges
  • run only the steps that need registration in an explicitly elevated Developer Command Prompt / PowerShell / installer
  • if something “only reproduces as administrator”, treat that premise itself as something to specify and sort out

That will save you trouble later.

5. Pitfalls Specific to ActiveX / OCX

5.1. Design-Time and Run-Time Licenses Are Separate

A quietly troublesome aspect of OCX / ActiveX is licensing.

Especially with older ActiveX controls, the design-time license and run-time license can be separate. The MFC ActiveX documentation describes the mechanism of separating design-time and run-time via license files and license keys.1920

In this world, things like the following happen:

  • it can be used at runtime
  • but when you try to drop it on a form, you get “no license”
  • it can be placed on development machine A
  • but not on development machine B

Errors like “License information for this component not found” or “you don’t have an appropriate license” are not rare with old ActiveX.21

5.2. The Moment It Sits on a WinForms Form, a Wrapper Is Already Involved

When you use ActiveX from WinForms, Windows Forms is not hosting the ActiveX control directly. As the Microsoft Learn documentation for Aximp.exe explains, the ActiveX Control Importer generates a WinForms wrapper from the COM type library and treats it as an AxHost-based control.2223

So the problem is not one layer but several:

  1. the original OCX / ActiveX itself
  2. the type library
  3. the generated interop / wrapper
  4. the WinForms Designer / runtime

That is why things like these happen:

  • swapping the vendor OCX changed the event signatures
  • re-adding the reference regenerated the wrapper and produced a huge diff
  • the generated interop differs subtly from one development machine to another

Seeing the control appear in Choose Toolbox Items is no guarantee. Whether the Designer can place it, whether events arrive at runtime, and whether the wrapper holds together on the deployment target are safer to verify separately.

5.3. Underestimate STA / MTA and the Message Loop, and Things Freeze

COM must be initialized with CoInitializeEx on every thread that uses it. Microsoft Learn explicitly states that each thread that uses COM must call CoInitializeEx individually.24

Also, an STA (single-threaded apartment) requires a message loop.2425

UI-oriented OCX / ActiveX components in particular usually assume STA, so you get:

  • it works on the UI thread
  • it freezes when offloaded to Task.Run or the ThreadPool
  • events never come back
  • it reproduces only occasionally

— a thoroughly unpleasant class of bug.

On top of that, in STA there is the rule that you must not simply copy interface pointers to another thread — they must be marshaled if needed.2425

These bugs are far less friendly than 0x80040154: all you see is hangs, no response, occasional crashes, so they eat just as much time as the registry-related trouble.

6. A Field-Proven Order of Elimination

In practice, rather than diving deep right away, slicing the problem in this order is faster.

6.1. First Pin Down “Which Process, and What Bitness”

This is the first thing to look at.

  • What is the host (Visual Studio Designer / your own app / Office / Access / Explorer / a browser-compatibility environment)
  • Is that host 32bit or 64bit
  • Is the target DLL / OCX 32bit or 64bit
  • Is it in-proc or out-of-proc

If you start digging in the registry with this still vague, you will almost always get lost.

6.2. Next, Confirm “the Kind of Registration”

The next thing to look at is what is supposed to be registered with what.

  • Native DLL / OCX → regsvr32
  • .NET Framework COM exposure → Regasm.exe
  • .NET 5+ / 6+ / 8+ COM exposure → .comhost.dll
  • A DLL that simply has no self-registration → not a job for regsvr32

This classification alone stops a great deal of friendly fire.

6.3. Only Then Look at “Where It Got Registered”

Looking at HKCR alone is not enough. You need to check:

  • HKCU\Software\Classes
  • HKLM\Software\Classes
  • the 32bit / 64bit registry views, if relevant
  • the target ProgID / CLSID / TypeLib
  • InprocServer32 / LocalServer32
  • ThreadingModel
  • the actual path of the referenced DLL

“It exists in HKCR” is insufficient — it only means something once you also know who is looking, at what bitness, and through which view.711

6.4. Finally, Check Whether Privileges Are Masking the Problem

Lastly, verify whether the problem is genuinely about privileges, or whether privileges merely make a different registration visible.

  • Does the behavior change between standard user and administrator
  • What changes when you elevate Visual Studio
  • Does it reproduce under a service account or a different user
  • Does it hold up in a clean environment provisioned via the installer

If you have only ever looked at a single development machine, this is where you truly misjudge things.

7. Operating Decisions That Prevent Accidents If Made Up Front

In COM / ActiveX / OCX development and maintenance, how you decide to operate often matters more than implementation technique.

7.1. Decide the Bitness Policy First

Decide this at the start.

  • Are you committing to x86
  • Is x64 the source of truth
  • Are you supporting both
  • Does that particular component have to be in-proc

Especially if a vendor OCX is pinned to x86, ignoring that and porting only your app to x64 will get you stuck later. As a larger architectural topic, How to Call a 64bit DLL from a 32bit App — A Case Study Where a COM Bridge Helps is also relevant here.

7.2. Decide the Registration Strategy

Registration is also something you should not do ad hoc.

  • Used machine-wide → per-machine registration via the installer
  • Used only by that user → use per-user deliberately
  • Closed within your own app → consider registration-free COM
  • Needed only for development → confine it to an explicit dev setup script

Registration-free COM can carry activation information in a manifest instead of the registry, making it an effective way to reduce registration hell. Both the Win32 side of registration-free COM and the .NET side of RegFree COM are officially documented.26627

7.3. Don’t Leave Too Many Artifacts Outside Source Control

A classic failure mode in OCX / ActiveX work is the scattering of dependencies.

  • the OCX itself
  • dependent DLLs
  • the TLB
  • .lic files
  • interop DLLs
  • AxHost wrappers
  • registration scripts
  • a sample host

If these exist only on somebody’s local machine, an accident a few months later is guaranteed.

At a minimum, keep the following next to the code:

  • which version is assumed
  • what gets installed in what order
  • which command performs the registration
  • whether it targets x86 or x64

8. Consultations That Fit This Topic Well

For this topic, triage and policy clarification alone tend to deliver value, before any full-scale rework.

For example, it pairs especially well with consultations like:

  • You want the causes of 0x80040154 or 0x80070005 sorted into bitness / registration / privileges
  • The Designer broke after upgrading to Visual Studio 2022 and you want to see how much can be salvaged
  • You want to keep a vendor OCX while moving the surrounding code toward .NET and C#
  • You want to decide how long to extend x86-pinned assets, and where to bridge / wrap / replace
  • You want to stop depending on hand-run regsvr32 and redesign install / deploy

For the keep / wrap / replace decision itself, How to Handle ActiveX / OCX Today — A Keep / Wrap / Replace Decision Table should also be helpful.

9. Summary

When you get stuck in COM component or OCX / ActiveX development, the cause almost always comes down to one of these four:

  1. The bitness does not match
  2. The registration method is wrong
  3. The registration scope (HKCU / HKLM, 32bit / 64bit view) is misaligned
  4. Something that is only visible thanks to privileges is being mistaken for a healthy state

With Visual Studio 2022 going 64bit, designs that used to “somehow just work” now surface their problems much more readily.12 That is exactly why, when touching COM / OCX / ActiveX, the shortcut is to align the environmental assumptions before writing code.

Rather than counting how many times you run regsvr32, sort out:

  • which process is hosting
  • what bitness that process is
  • where the registration should go
  • whether that registration genuinely requires administrator rights
  • whether you are looking at the Designer and the runtime separately

— and you will solve it far faster.


References

  1. Microsoft Learn, Visual Studio 2022 version 17.0 Release Notesdevenv.exe is now 64-bit only 2 3

  2. Microsoft Learn, Troubleshoot 32-bit problems - Windows Forms — Visual Studio 2022 is a 64bit process and cannot directly load 32bit .NET / COM / ActiveX components; constraints of the out-of-process designer.  2 3 4 5

  3. Microsoft Learn, Classes and Servers — COM registration, HKCU / HKCR, self-registration and DllRegisterServer 2 3 4

  4. Microsoft Learn, regsvr32 — syntax and role of regsvr32 2

  5. Microsoft Learn, Registering Assemblies with COM — COM registration for .NET Framework uses Regasm.exe 2

  6. Microsoft Learn, Exposing .NET Core components to COMEnableComHosting, the generated .comhost.dll, regsvr32, EnableRegFreeCom 2 3

  7. Microsoft Learn, Merged View of HKEY_CLASSES_ROOT — HKCR is a merged view of HKLM and HKCU.  2 3 4 5

  8. Microsoft Learn, HKEY_CLASSES_ROOT Key — applications that require administrator rights are advised to register into the per-machine COM configuration.  2

  9. Microsoft Learn, COM Error Codes (Generic) (Winerror.h)REGDB_E_CLASSNOTREG (0x80040154) and others. 

  10. Microsoft Learn, You receive 0x80070005 error when you try to register a DLL by using Regsvr32.exe — the typical case of DLL registration failing due to insufficient privileges.  2

  11. Microsoft Learn, Registry Redirector — the 32bit / 64bit registry views under WOW64.  2 3 4

  12. Microsoft Learn, File System Redirector%windir%\System32 on x64 Windows and WOW64 file system redirection. 

  13. Microsoft Learn, Overview of compatibility considerations for 32-bit programs on 64-bit versions of Windows — file / registry redirection under WOW64. 

  14. Microsoft Learn, Regasm.exe (Assembly Registration Tool) — the role of Regasm.exe and options such as /tlb

  15. Microsoft Learn, Packaging a .NET Framework Assembly for COM — type libraries and Regasm.exe /tlb

  16. Microsoft Learn, Understanding Custom Build Steps and Build Events — example of using regsvr32.exe in a post-build event. 

  17. Microsoft Learn, Windows registry for advanced usersHKCU\Software\Classes and HKLM\Software\Classes, HKCR behavior. 

  18. Microsoft Learn, Find, install, and manage extensions for Visual Studio — handling of per-user extensions when running elevated. 

  19. Microsoft Learn, MFC ActiveX Controls: Licensing an ActiveX Control — design-time / run-time licenses, .LIC

  20. Microsoft Learn, Application Settings, MFC ActiveX Control Wizard — run-time license generation and the .lic file. 

  21. Microsoft Learn, License information for this component not found. You don’t have an appropriate license to use this functionality in the design environment. 

  22. Microsoft Learn, Aximp.exe (Windows Forms ActiveX Control Importer) — converting ActiveX into a WinForms wrapper. 

  23. Microsoft Learn, AxHost Class — the AxHost-based wrapper generated by the ActiveX Control Importer. 

  24. Microsoft Learn, Initializing the COM LibraryCoInitializeEx, per-thread initialization, the STA message loop.  2 3

  25. Microsoft Learn, Single-Threaded Apartments — the STA message loop, marshaling, ThreadingModel 2

  26. Microsoft Learn, Creating Registration-Free COM Objects — registration-free COM via activation contexts. 

  27. Microsoft Learn, Registration-Free COM Interop — registration-free COM interop in .NET Framework. 

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog