COM互操作,客户端在进程外COM中找不到接口

本文关键字:COM 找不到 接口 互操作 客户端 进程 | 更新日期: 2023-09-27 18:04:22

我使用微软的CSExeCOMServer作为设置进程外COM服务器的基础,但它不能正常工作。服务器为64位,客户端为32位。

下面是示例界面

[Guid(XXCryptService.InterfaceId), ComVisible(true)/*, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)*/]
public interface IXXCryptService
{
  [DispId(1)] string Encrypt(string password, string key);
  [DispId(2)] string Decrypt(string password, string key);
}

和类

[ClassInterface(ClassInterfaceType.None)]   
[Guid(XXCryptService.ClassId), ComVisible(true)]
public class XXCryptService : ReferenceCountedObject, IXXCryptService
{
    internal const string ClassId =
        "C5F6938B-5593-4872-B8C7-B47EE33EABCD";
    internal const string InterfaceId =
        "6990FF5F-22E2-4032-8B98-36115DBCEFFF";
    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComRegisterFunction()]
    public static void Register(Type t)
    {
        try
        {
            COMHelper.RegasmRegisterLocalServer(t);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw ex; 
        }
    }
    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComUnregisterFunction()]
    public static void Unregister(Type t)
    {
        try
        {
            COMHelper.RegasmUnregisterLocalServer(t);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw ex;
        }
    }
    public string Encrypt(string password, string key)
    {
      return "Encrypted";
    }
    public string Decrypt(string password, string key)
    {
      return "Decrypted";
    }
}

程序运行,但是当客户端连接时,在服务器触发ObjectClassFactory上的CreateInstance并返回ppvObject上的对象后,它在客户端崩溃。GetComInterfaceForObject(new XXCryptService(), typeof(IXXCryptService))并返回0.

在。net上运行客户端会触发"无法强制转换COMTest类型的COM对象"。到接口类型"COMTest.IXXCryptService"。此操作失败,因为对IID为"{6990FF5F-22E2-4032-8B98-36115DBCEFFF}"的接口的COM组件的QueryInterface调用失败,由于以下错误:(Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND)).".

[Guid("6990FF5F-22E2-4032-8B98-36115DBCEFFF")]
//[InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IXXCryptService
{
  [DispId(1)] string Encrypt(string password, string key);
  [DispId(2)] string Decrypt(string password, string key);
}
[ComImport, Guid("C5F6938B-5593-4872-B8C7-B47EE33EABCD")]
class XXCryptService
{
}
class Program
{
  static void Main(string[] args)
  {
    XXCryptService cs = new XXCryptService();
    IXXCryptService ics = (IXXCryptService) cs;
    Console.WriteLine(ics.Encrypt("Test","Test"));
    Console.ReadKey();
  }
}

在Delphi上运行客户端会触发EIntfCastError异常,消息为'Interface not supported'。COM是通过"Import Type Library"导入的,并像这样使用。

procedure TForm1.FormCreate(Sender: TObject);
begin
  FCrypter := CoXXCryptService.Create;
end;

TLB接口如下图

IXXCryptService = interface(IDispatch)
  ['{6990FF5F-22E2-4032-8B98-36115DBCEFFF}']
  function Encrypt(const password: WideString; const key: WideString): WideString; safecall;
  function Decrypt(const password: WideString; const key: WideString): WideString; safecall;
end;
// *********************************************************************//
// DispIntf:  IXXCryptServiceDisp
// Flags:     (4416) Dual OleAutomation Dispatchable
// GUID:      {6990FF5F-22E2-4032-8B98-36115DBCEFFF}
// *********************************************************************//
IXXCryptServiceDisp = dispinterface
  ['{6990FF5F-22E2-4032-8B98-36115DBCEFFF}']
  function Encrypt(const password: WideString; const key: WideString): WideString; dispid 1;
  function Decrypt(const password: WideString; const key: WideString): WideString; dispid 2;
end;

我已经检查了注册表,一切似乎都注册正确,所以我不明白为什么会出现这个问题。

有人知道是什么问题吗?

编辑:将客户端编译为64位并且工作正常。此外,它引用了错误的路径,在我调整它之后,我在。net x86客户端上得到了不同的错误

此操作失败,因为IID为'{6990FF5F-22E2-4032-8B98-36115DBCEFFF}'的接口的COM组件上的QueryInterface调用失败,原因是以下错误:加载类型库/DLL错误。(Exception from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))

COM互操作,客户端在进程外COM中找不到接口

这是注册的问题,并且只有当程序集与regasm具有相同的目标时才执行regasm。regasm应该有一个"/com_oop或其他东西"参数,使其注册LocalServer32而不是InprocServer32,并在64位系统上注册32位和64位。

为了解决这个问题,我不得不暂时将可执行文件(使用相同的路径)编译为32位,运行32位regasm(使用/tlb:..),然后编译回64位,运行64位regasm(使用/tlb:..)),现在它可以正常工作在32位和64位,而不是64位可执行文件。

CSExeComServer有一个注册和注销方法,它手动删除InprocServer32键并添加LocalServer32。为了确保它能正常工作,我要改变这个,检测它是否在64位系统上注册,然后让它在那里正确注册。当我完成时,我将发布我对register方法所做的更改。

这个问题可能也解决了(有同样的问题,但从64位客户端访问32位服务器的另一种方式,然后你可以使用CLSCTX_ACTIVATE_32_BIT_SERVER代替):

HRESULT hr = CoCreateInstance(CLSID_ZZZ, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_ACTIVATE_64_BIT_SERVER, IID_IZZZ, (void ** )&l_IZZZ);

尝试添加[ClassInterface(ClassInterfaceType.AutoDispatch)]或[ClassInterface(ClassInterfaceType.AutoDual)]取决于您需要接口IXXCryptService

[ClassInterface(ClassInterfaceType.AutoDual)] 
[Guid(XXCryptService.InterfaceId), ComVisible(true)/*, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)*/]
public interface IXXCryptService

我认为通过COM混合32位和64位进程在所有情况下都会失败。

为了从32位Delphi进程访问,DotNet程序集必须被编译为x86(即在32位模式下),而不是x64。

afaikcom不会跨越32/64位边界。

为了在64位和32位之间进行通信,您需要另一个技巧,例如在"是否有可能从32位应用程序访问64位dll"中发布的技巧?