Compiling a COM-visible DLL

Looking for some advice about compiling rust into a so-called COM visible DLL.

I have zero experience with this and after reading some docs and code examples I am now just totally confused.

I found some minimal rust code example that I can compile to 32 bit.
The resulting DLL registers without errrors.

regsvr32 comtest.dll

Unfortunately, the VBScript is not able to create the object

Set obj = CreateObject("Example.Hello")

returns

Error: ActiveX component can't create object

I think it is using the correct dispatch method (but I don't know what that means)

Code shared from the Rust Playground

I'm not a Windows user any more, my windows api knowlege is mostly outdated and rotten. but a quick look at the DllRegisterServer() function, this line feels very suspicious to me:

        let len = GetModuleFileNameW(None, &mut buf) as usize;

if I remember correctly, when you pass a NULL as first argument to GetModuleFileNameW(), it returns the name of the executable file, regsvr32.exe in this case, not the name of your dll comtest.dll.

to confirm if this is the case, register the dll and then check the InprocServer32 registry key you just created. is it regsvr32.exe or comtest.dll?

btw, I'm not really into COM, but I remember the windows crate provides macros to generate the vtable boilerplate code so you can use "normal" rust code to authorize COM classes, although they are not well documented.

see the #[interface] and #[implement] macros, which are defined in windows-interface and windows-implement crates, respectively, and re-exported in the windows-core crate, or the windows::core submodule.

If you put #[unsafe(no_mangle)] on all the exported functions, does it help?

The problem is you registered regsvr32.exe as an inproc32 server instead of your .dll, because you provided None to GetModuleFileNameW as a first argument. Check MSDN to see how it works.

Then, use powershell to see what you have in the registry

cd HKCU:\Software\Classes\CLSID\
Get-ChildItem '.\{D61F6C41-9E19-4B8D-9C6B-4B72B5D1A123}\'

You should see your .dll name, but you probably do not.

How to fix it?

Here is cargo.toml I used to compile your file:

name = "myserver"
//..

[lib]
crate-type = ["cdylib"]
//...

so the name is myserver.dll. Lets load it (again, use MSDN to see how GetModuleHandleW works), you might also use crate_name crate to get a crate name probably not to hardcode it.

let h = GetModuleHandleW(&HSTRING::from("myserver")).unwrap();
let len = GetModuleFileNameW(Some(h), &mut buf) as usize;

All together:

PS C:\temp\snapshot> cargo build --release
PS C:\temp\snapshot> regsvr32 .\target\release\myserver.dll
PS C:\temp\snapshot> cd HKCU:\Software\Classes\CLSID\
PS HKCU:\Software\Classes\CLSID\> Get-ChildItem '.\{D61F6C41-9E19-4B8D-9C6B-4B72B5D1A123}\'


    Hive: HKEY_CURRENT_USER\Software\Classes\CLSID\{D61F6C41-9E19-4B8D-9C6B-4B72B5D1A123}


Name                           Property
----                           --------
InprocServer32                 (default) : C:\temp\snapshot\target\release\myserver.dll

(if you wonder about GUID, check HKCU:\Software\Classes\Example.Hello)

And now:

PS C:\temp\snapshot> Get-Content .\1.vbs

Set obj = CreateObject("Example.Hello")
PS C:\temp\snapshot> wscript 1.vbs
PS C:\temp\snapshot> cscript 1.vbs

Works in my hands.

Thank you all. I wasn't expecting this much support :slight_smile:

It works now when calling a VBS script via cscript or wscript,
but unfortunately not when called from the VBS runtime.

I have done this:

  • compiled it as 32-bit dll (release build with target i686-pc-windows-msvc)
  • registered it with C:\Windows\SysWOW64\regsvr32.exe myserver.dll

The error is still

Error: ActiveX component can't create object

It might be a limitation in the VBS runtime.

I found this repo on github: mfumagalli95/WinCCLibrary which generates a similar DLL (but not in rust).

It might help to figure out what is still missing.

Now looking into what RegAsm /CODEBASE should do (vs regsvr32) ...

Edit: it is working on the server, but not when calling it from the web client.

Microsoft has deprecated ActiveX in web browsers and it will be removed at some point.

I am not sure what do you mean by "web client", but if it is 32-bit (quite strange in 2026) then you did everything correctly.

If you meant Internet Explorer, it is long time deprecated, and while it might work, I wouldn't recommend using such an old technology deprecated by the vendor.

RegAsm

This is a tool to registry .NET .dlls as COM objects, so you if you wrote your COM server in .NET, you would need it, but I do not think you need it for Rust.