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

时间:2011-05-09 09:37:34

标签: c# .net com com-interop tlbimp

我在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()方法之后我能看到发生了什么。

此外,我已阅读以下here

"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;

2 个答案:

答案 0 :(得分:2)

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

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


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

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


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

我从中学到的一点是,COM SAFEARRAY的.NET等价物应始终为object,因此请尝试将数组作为object而不是Array传递。

答案 1 :(得分:1)

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

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

作为一个粗略的概述,我想这将涉及:

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

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