未注册C# COM组件时Delphi调用报错“CLASS未注册”,求免注册方案
问题
未注册C# COM组件时,Delphi无法调用该组件并报错“CLASS is not registered”。
我用C#写了一个COM DLL,在Delphi 10里作为COM对象调用,注册DLL后能正常运行,但我想实现无需注册就能使用该组件,请问该怎么做?
我的C#代码
Assembly.cs中已设置ComVisible属性为true:
[assembly: ComVisible(true)]
组件代码:
using System; using System.Runtime.InteropServices; namespace ComCalculator { [ComVisible(true)] [Guid("c0a3a815-fade-4fb3-9c75-f6eff1851e23")] public interface ICalculator { int Add(int a, int b); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [Guid("427754c1-c975-4099-9ff7-df788281d3a8")] public class Calculator : ICalculator { public int Add(int a, int b) { return a + b; } } }
我的Delphi代码
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, ComObj, ComCalculator_TLB; type TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } comObject: ICalculator; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var A, B, Result: Integer; begin A := 10; B := 5; Result := comObject.Add(A, B); ShowMessage('The result is: ' + IntToStr(Result)); end; procedure TForm1.FormCreate(Sender: TObject); begin comObject := CoCalculator.Create; end; end.
解决方案
要实现无需注册就能让Delphi调用C# COM组件,有以下几种可行方案:
方案1:使用RegFree COM(免注册COM)
这是Windows官方支持的免注册方式,通过应用程序清单文件描述COM组件信息,替代注册表的作用。
步骤1:生成C#组件的清单文件
- 编译C#项目时,临时勾选“为COM互操作注册”(生成必要类型信息后可取消)。
- 使用Windows SDK工具
mt.exe生成组件清单:
生成的文件会包含组件的CLSID、接口ID等关键信息。mt.exe -tlb:ComCalculator.tlb -dll:ComCalculator.dll -out:ComCalculator.manifest
步骤2:创建Delphi应用的清单文件
在Delphi项目根目录创建YourDelphiApp.exe.manifest文件,内容示例如下(替换对应信息):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity type="win32" name="YourDelphiApp" version="1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="ComCalculator" version="1.0.0.0" publicKeyToken="你的组件公钥令牌" /> </dependentAssembly> </dependency> <file name="ComCalculator.dll"> <comClass clsid="{427754c1-c975-4099-9ff7-df788281d3a8}" description="ComCalculator.Calculator" /> <comInterfaceExternalProxyStub iid="{c0a3a815-fade-4fb3-9c75-f6eff1851e23}" name="ICalculator" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}" /> </file> </assembly>
- 公钥令牌可通过
sn.exe -T ComCalculator.dll命令获取。 - 确保
ComCalculator.dll与Delphi exe在同一目录。
步骤3:配置Delphi项目
将清单文件与exe放在同一目录,或在Delphi项目设置中嵌入该清单。
方案2:通过Unmanaged Exports直接导出非托管函数
绕开COM规范,用第三方工具直接从C# DLL导出函数,让Delphi直接调用。
步骤1:C#项目配置
- 安装
UnmanagedExportsNuGet包。 - 修改C#代码,移除COM相关属性,导出函数:
编译生成普通.NET DLL。using RGiesecke.DllExport; using System.Runtime.InteropServices; namespace ComCalculator { public class Calculator { [DllExport("Add", CallingConvention = CallingConvention.StdCall)] public static int Add(int a, int b) { return a + b; } } }
步骤2:修改Delphi代码
直接调用导出的函数,无需COM对象:
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } function Add(a, b: Integer): Integer; stdcall; external 'ComCalculator.dll'; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var A, B, Result: Integer; begin A := 10; B := 5; Result := Add(A, B); ShowMessage('The result is: ' + IntToStr(Result)); end; end.
确保ComCalculator.dll与Delphi exe在同一目录。
方案3:COM+应用程序隔离(不推荐)
通过COM+创建应用程序包部署组件,无需系统注册表注册,但配置复杂度高,仅适合大型组件场景。
内容的提问来源于stack exchange,提问作者Santosh Vishwakarma
相关产品推荐
相关产品推荐

