【发布时间】:2015-03-19 00:04:26
【问题描述】:
我用 C# 编写了一个简单的 COM 对象,只有一个方法,称为 GetMac。我无法让它工作。我正在尝试从旧版 Borland C++ Builder 4 (BCB4) 应用程序访问它,我知道它很旧,并且不再使用太多,但我可以从中访问其他 COM 对象。
Borland 开发机器运行的是 Windows XP,所以我将 C# COM 对象以 .NET 4.0 框架为目标。我将 DLL 和 PDB 文件从 C# Visual Studio 机器复制到 XP 机器。我通过以下命令注册了它:
"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\regasm.exe" TRSDotNetCOM.dll /tlb /nologo /codebase
我可以通过以下代码行很好地实例化 COM 对象(类):
Variant TDN = CreateOleObject("TRSDotNetCOM.TRSCOM_Class");
如果我更改名称字符串,它不起作用,所以我知道这部分是正确的。
但是,当我尝试按如下方式调用该方法时:
MacV = TDN.OleFunction(funcNameV,counterV,macKeyV);
...我得到一个运行时异常(不幸的是,BCB4 对 OLE 调用的异常处理存在问题,因此调试器给我的唯一信息是“发生异常”)。
由于我能够以相同的方式从同一个 BCB4 应用程序调用其他 COM 对象,我认为问题不在于我的 C++ 代码。我认为这是 C# 创建的 COM DLL 或其注册的问题。
为了探索这一点,我使用 Microsoft OLE/COM 对象查看器来浏览我的系统以查找 OLE 对象。正如预期的那样,我能够找到我的对象为“TRSDotNetCOM.TRSCOM_Class”。
我是使用 OLE/COM 对象查看器的新手,所以我希望我看到的是正确的东西:
当我展开课程时,我看到以下内容:
我右键单击 _Object 并选择“查看”,然后选择“查看类型信息”。然后,右侧窗格显示:
[ uuid(65074F7F-63C0-304E-AF0A-D51741CB4A8D), hidden, dual, nonextensible,
custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "System.Object")
] dispinterface _Object {
properties:
methods:
[id(00000000), propget,
custom({54FC8F55-38DE-4703-9C4E-250351302B1C}, "1")]
BSTR ToString();
[id(0x60020001)]
VARIANT_BOOL Equals([in] VARIANT obj);
[id(0x60020002)]
long GetHashCode();
[id(0x60020003)]
_Type* GetType(); };
当我展开左侧的树时,我看到的是:
我没有在其中的任何地方看到我的方法“GetMac”。所以,我认为该方法对 COM 不可见,或者它没有通过 regasm 注册。
这是 COM 对象的来源:
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace TRSDotNetCOM
{
[Guid("80ef9acd-3a75-4fcd-b841-11199d827e8f")]
public interface TRSCOM_Interface
{
[DispId(1)]
string GetMac(string counter, string macKey);
}
// Events interface Database_COMObjectEvents
[Guid("67bd8422-9641-4675-acda-3dfc3c911a07"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface TRSCOM_Events
{
}
[Guid("854dee72-83a7-4902-ab50-5c7a73a7e17d"),
ClassInterface(ClassInterfaceType.None),
ComVisible(true),
ComSourceInterfaces(typeof(TRSCOM_Events))]
public class TRSCOM_Class : TRSCOM_Interface
{
public TRSCOM_Class()
{
}
[ComVisible(true)]
public string GetMac(string counter, string macKey)
{
// convert counter to bytes
var counterBytes = Encoding.UTF8.GetBytes(counter);
// import AES 128 MAC_KEY
byte[] macKeyBytes = Convert.FromBase64String(macKey);
var hmac = new HMACSHA256(macKeyBytes);
var macBytes = hmac.ComputeHash(counterBytes);
var retval = Convert.ToBase64String(macBytes);
return retval;
}
}
}
我确实确定并进入项目属性并选中“注册 COM 互操作”复选框。我还使用“sn”实用程序生成了一个安全名称文件,并将该文件加载到设置的“签名”部分。
所以...
1) 我是否在 OLE/COM 对象查看器中为我的方法寻找正确的位置?
2) 如果是这样,为什么我的方法不可见或未注册?
3) 有什么想法可能是错误的吗?
更新:这是 Joe W 和 Paulo 建议的更新代码。 (但它仍然不起作用)
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace TRSDotNetCOM
{
[Guid("80ef9acd-3a75-4fcd-b841-11199d827e8f"),
ComVisible(true)]
public interface TRSCOM_Interface
{
[DispId(1)]
string GetMac(string counter, string macKey);
}
// Events interface Database_COMObjectEvents
[Guid("67bd8422-9641-4675-acda-3dfc3c911a07"),
ComImport,
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface TRSCOM_Events
{
}
[Guid("854dee72-83a7-4902-ab50-5c7a73a7e17d"),
ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(typeof(TRSCOM_Interface)),
ComVisible(true),
ComSourceInterfaces(typeof(TRSCOM_Events))]
public class TRSCOM_Class : TRSCOM_Interface
{
public TRSCOM_Class()
{
}
public string GetMac(string counter, string macKey)
{
// convert counter to bytes
var counterBytes = Encoding.UTF8.GetBytes(counter);
// import AES 128 MAC_KEY
byte[] macKeyBytes = Convert.FromBase64String(macKey);
var hmac = new HMACSHA256(macKeyBytes);
var macBytes = hmac.ComputeHash(counterBytes);
var retval = Convert.ToBase64String(macBytes);
return retval;
}
}
}
【问题讨论】: