繁体   English   中英

COM Interop,客户端未在进程外COM中找到接口

[英]COM Interop, client not finding interface in Out-of-process 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'。此操作失败,因为对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中的异常,并显示消息“不支持接口”。 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客户端上出现了另一个错误

此操作失败,因为具有以下ID的IID为“ {6990FF5F-22E2-4032-8B98-36115DBCEFFF}”的接口在COM组件上对QueryInterface的调用由于以下错误而失败:加载类型库/ DLL出错。 (来自HRESULT的异常:0x80029C4A(TYPE_E_CANTLOADLIBRARY))

这个问题可能也可以解决(有相同的问题,但是从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);

这是配准的问题,并且只有在装配体具有与再充气相同的目标时才执行再充气。 对于regasm,应该有一个“ / com_oop之类的”参数,以使其注册LocalServer32而不是InprocServer32,并在64位系统上同时为32位和64位注册它。

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

CSExeComServer具有注册和注销方法,在该方法中,它手动删除InprocServer32键并添加LocalServer32。 为了确保它正常工作,我将对其进行更改,检测它是否在64位系统上注册,然后使其在此处正确注册。 完成后,我将发布对register方法所做的更改。

根据您连接IXXCryptService的需要,尝试添加[ClassInterface(ClassInterfaceType.AutoDispatch)]或[ClassInterface(ClassInterfaceType.AutoDual)]

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

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

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

AFAIK COM将不会越过32/64位边界。

为了在64位和32位之间进行通信,您将需要另一种技巧,例如《 是否可以从32位应用程序访问64位dll?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM