c# – COM Interop,客户端未在进程外COM中查找接口

我使用Microsoft的
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后,它在客户端崩溃,并使用Marshal.GetComInterfaceForObject(new XXCryptService(),typeof(IXXCryptService))返回ppvObject上的对象并返回0.

在.NET上运行客户端会触发“无法将类型为’COMTest.XXCryptService’的COM对象’转换为接口类型’COMTest.IXXCryptService’.此操作失败,因为QueryInterface调用COM组件上的IID为{6990FF5F-的接口22E2-4032-8B98-36115DBCEFFF}由于以下错误而失败:找不到元素.(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并像这样使用.

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时出错. (来自HRESULT的异常:0x80029C4A(TYPE_E_CANTLOADLIBRARY))

最佳答案 这是注册的问题,而且只有当程序集与regasm具有相同的目标时,才会执行regasm. regasm应该有一个“/ com_oop或something”参数,使其注册LocalServer32而不是InprocServer32,并在64位系统上为32位和64位注册.

为了解决这个问题,我不得不暂时将可执行文件(使用相同的路径)编译为32位,运行32位regasm(使用/ tlb:..),然后编译回64位,运行64位regasm(使用/ tlb:..再次),现在它适用于32位和64位对64位可执行文件.

CSExeComServer有一个注册和取消注册方法,它手动删除InprocServer32密钥并添加LocalServer32.为了确保这个工作正常,我将改变这个,检测它是否在64位系统上注册,然后让它在那里正确注册.当我完成后,我会将我做的更改发布到注册方法中.

点赞