[英]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.