C#
DLL
COM interop
programming
software development

Turn a simple C DLL into a COM interop component

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

If you want an old COM client such as VBA, VB6, or a classic unmanaged application to call code from a managed DLL, you do not "convert" the DLL into native COM. Instead, you expose a .NET class library to COM by giving it COM-visible types, stable GUIDs, and a registration step.

The most practical path for classic COM interop is a C# class library targeting .NET Framework. That gives you access to the standard registration workflow through regasm, which older COM consumers understand well.

What COM Needs from Your Assembly

A COM client does not understand ordinary .NET metadata by itself. It needs a COM-visible interface and class identity. In practice, that means:

  • mark the assembly or types as COM-visible,
  • assign explicit GUIDs,
  • expose an interface that COM clients can bind to,
  • register the assembly so COM can locate it.

The safest pattern is to expose an interface and then implement it in a class. Avoid auto-generated class interfaces because they are fragile for versioning.

A Minimal COM-Visible C# Library

Here is a small example:

csharp
1using System;
2using System.Runtime.InteropServices;
3
4[assembly: ComVisible(true)]
5
6namespace SampleComInterop
7{
8    [Guid("4E93C95B-8D5A-4E03-9873-5EB6F53D10A1")]
9    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
10    public interface IMessageService
11    {
12        string Echo(string input);
13    }
14
15    [Guid("8D5A1F60-2E77-4A7A-BA2D-4A40667AF357")]
16    [ClassInterface(ClassInterfaceType.None)]
17    [ProgId("SampleComInterop.MessageService")]
18    public class MessageService : IMessageService
19    {
20        public string Echo(string input)
21        {
22            return $"Managed echo: {input}";
23        }
24    }
25}

The key details are the Guid attributes, the explicit interface, and ClassInterfaceType.None. Those choices make the COM contract stable and predictable.

Build and Register the Assembly

After building the DLL, register it with regasm from a Developer Command Prompt:

bat
regasm SampleComInterop.dll /codebase /tlb:SampleComInterop.tlb

This does two important things:

  • registers the assembly for COM activation,
  • generates a type library file that many COM clients can reference.

The /codebase switch tells COM where the assembly lives when it is not installed in the Global Assembly Cache. For development and internal tools, that is often sufficient.

Calling It from a COM Client

Once registered, a COM client can create the object through the ProgId. For example, in VBA:

vb
1Sub TestComInterop()
2    Dim service As Object
3    Set service = CreateObject("SampleComInterop.MessageService")
4    MsgBox service.Echo("Hello from VBA")
5End Sub

That round-trip is the core interop story: the unmanaged client activates the COM class, and the CLR hosts the managed implementation behind it.

Versioning and Deployment

The biggest mistake in COM interop work is treating the public interface as disposable. COM clients often bind to exact interface contracts, so changing GUIDs or method signatures casually can break consumers.

A practical rule is:

  • keep interface GUIDs stable for compatible versions,
  • add new interfaces rather than mutating old ones aggressively,
  • redeploy and re-register the assembly intentionally.

If you need a cleaner deployment story, consider installer-based registration or registration-free COM patterns, but the basic mechanics remain the same.

Common Pitfalls

  • Exposing only a class and relying on an auto-generated class interface.
  • Forgetting explicit GUIDs, which makes versioning brittle.
  • Building for the wrong architecture when the COM client is 32-bit only.
  • Trying to use regasm with a library that is not built for the classic .NET Framework interop path.
  • Changing an existing COM-visible interface in a breaking way without understanding downstream clients.

Summary

  • A managed DLL becomes COM-consumable by exposing COM-visible interfaces and classes, not by becoming native COM code.
  • Use explicit interfaces, Guid attributes, and ClassInterfaceType.None.
  • Register the assembly with regasm and generate a type library when needed.
  • Use stable COM contracts because old clients often depend on them tightly.
  • For classic COM consumers, a .NET Framework class library is usually the smoothest path.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.