繁体   English   中英

.NET互操作层和COM之间会发生什么?

[英]What happens between the .NET interop layer and COM?

我在我的C#.NET项目中使用COM。
但是我调用的方法之一并没有按预期运行。
所以我很想知道我的.NET代码,Interop层和COM之间发生了什么。
我知道tlbimp.exe为COM组件生成元数据包装器,我可以在Object浏览器中看到这些生成的方法。
我是否能够看到/调试在调用其中一个包装器方法时会发生什么?

我将一个数组传递给下面的方法,并期望将填充此数组,但不会填充数组。 我调用以下tlbimp.exe生成的方法,结果意外:

int GetTags(System.Array buffer)
    Member of CServer.IUser

方法IDL:

[id(0x000000d5)]
HRESULT GetTags(
                [in] SAFEARRAY(long) buffer, 
                [out, retval] long* retval);  

调用此方法的.NET代码:

Array tagsArray = Array.CreateInstance(typeof(int), tagsLength);
userWrapper.GetTags(tagsArray);

其他COM方法我称之为正常工作。 但是,当我调用任何期望将Array作为参数的方法时,它不能按预期工作。
我假设COM互操作编组有一些有趣的东西。
所以我想知道在调用GetTags()方法后是否可以看到发生了什么。

我也在这里阅读了以下内容。

"if you are not satisified with the COM Interop marshaller, you can "override" just about every aspect of it through the very large and useful System::Runtime::InteropServices namespace"

我怎样才能实现上述目标?

编辑:添加一个有效的Delphi测试脚本

procedure TComTestForm.TestUserBtnClick(Sender: TObject);
var
  nCnt :integer;
  User :IUser;
  Persona :IUserPersona;
  ArrayBounds :TSafeArrayBound;
  ArrayData :Pointer;
  TagList :PSafeArray;
  nSize :integer;
begin
  User := Session.GetUser;

  ArrayBounds.lLbound   := 0;
  ArrayBounds.cElements := 0;

  TagList := SafeArrayCreate( varInteger, 1, ArrayBounds );
  User.GetTags( TagList );
  if SafeArrayAccessData( TagList, ArrayData ) = S_OK then
    begin
      nSize := TagList.rgsabound[0].cElements;
      OutLine( '----Available Tags, ' + IntToStr(nSize) + ' tags' );
  for nCnt := 0 to nSize - 1 do
    begin
      OutLine( IntToStr( IntegerArray(ArrayData)[nCnt] ) );
    end;
  OutLine( '----');

  SafeArrayUnAccessData( TagList );
  SafeArrayDestroy( TagList );
    end;

end;

另一个更新 :我只是意识到你可能意味着GetTags本身应该填充该数组(来自COM代码)。 但这可能永远不会起作用,因为该参数是[in]参数。

要使COM组件能够填充该数组,它应该作为[in,out]参数和引用(SAFEARRAY *)传递。


更新 :好的,显然我是在.NET中混合创建COM组件并从.NET调用COM组件。

CCW(com可调用包装器)确实为COM SafeArray采用.NET数组。 我看到你在问题的代码中创建了你的数组,但你没有显示你实际填充它的方式。 也许那段代码出了问题? 你能分享一下吗?


不确定这是否是您问题的解决方案,但我在过去遇到过COM-interop和SAFEARRAY的问题。

有一件事我从中学到的是,.NET相当于一个COM SAFEARRAY的应该永远是object ,所以尽量通过你的数组作为object以代替作为Array

我毫不犹豫地建议这个答案,但......

如果Delphi测试代码确实有效,如其他地方所述,这意味着GetFags方法不能通过SAFEARRAY规则正常播放。 如果COM方法总是在进程中调用,那么您可以通过“手动”执行一些自定义编组来实现.NET代码,完全遵循非托管Delphi测试代码的功能。

作为一个粗略的轮廓,我想这将涉及:

  • 分配非托管缓冲区来保存数组值
  • 通过P / Invoke调用Ole Automation SAFEARRAY初始化API以分配SAFEARRAY结构并将数组缓冲区作为其pData成员附加到它
  • 使用此SAFEARRAY调用GetTags方法
  • 在将...之前的非托管缓冲区编组到托管数组中之前......
  • 调用Win32 API来销毁SAFEARRAY

但是,如果可以的话,更好地将COM组件更改为正确执行操作。

暂无
暂无

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

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