简体   繁体   English

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

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

I am using COM in my C# .NET project. 我在我的C#.NET项目中使用COM。
However one of the methods I call is not acting as expected. 但是我调用的方法之一并没有按预期运行。
So I am curious to see what is happening between my .NET code, the Interop layer and COM. 所以我很想知道我的.NET代码,Interop层和COM之间发生了什么。
I know the tlbimp.exe generates the metadata wrapper for the COM component and I can see these generated methods in the Object browser. 我知道tlbimp.exe为COM组件生成元数据包装器,我可以在Object浏览器中看到这些生成的方法。
Am I able to see/debug what happens when one of these wrapper methods is called? 我是否能够看到/调试在调用其中一个包装器方法时会发生什么?

I pass an Array to the method below, and expect that this array will be populated, however the Array does not get populated. 我将一个数组传递给下面的方法,并期望将填充此数组,但不会填充数组。 I am calling the following tlbimp.exe generated method with unexpected results: 我调用以下tlbimp.exe生成的方法,结果意外:

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

Method IDL: 方法IDL:

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

.NET code calling this method: 调用此方法的.NET代码:

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

Other COM methods I call work fine. 其他COM方法我称之为正常工作。 However when I call any method which expects an Array as a parameter it does not work as expected. 但是,当我调用任何期望将Array作为参数的方法时,它不能按预期工作。
I am presuming that there is something funny going in with the COM interop marshaller. 我假设COM互操作编组有一些有趣的东西。
So I would like to know if I can see what is happening after I call the GetTags() method. 所以我想知道在调用GetTags()方法后是否可以看到发生了什么。

Also I have read the following 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"

How can I achieve the above? 我怎样才能实现上述目标?

EDIT: Adding a Delphi test script which works 编辑:添加一个有效的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;

Another update : I just realize it might be that you mean that the GetTags itself should populate that Array (from the COM code). 另一个更新 :我只是意识到你可能意味着GetTags本身应该填充该数组(来自COM代码)。 But this can never work as that parameter is an [in] parameter. 但这可能永远不会起作用,因为该参数是[in]参数。

For the COM component to be able to fill up that Array, It should be passed as an [in, out] parameter, and by reference (SAFEARRAY*). 要使COM组件能够填充该数组,它应该作为[in,out]参数和引用(SAFEARRAY *)传递。


Update : Ok, apparently I was mixing the creation of a COM component in .NET with calling a COM component from .NET. 更新 :好的,显然我是在.NET中混合创建COM组件并从.NET调用COM组件。

The CCW (com callable wrapper) indeed takes a .NET Array for COM SafeArray's. CCW(com可调用包装器)确实为COM SafeArray采用.NET数组。 I see you create your array in the code in your question, but you don't show how you actually populate it. 我看到你在问题的代码中创建了你的数组,但你没有显示你实际填充它的方式。 Maybe something's wrong with that code? 也许那段代码出了问题? Could you share it? 你能分享一下吗?


Not sure if this is a solution to your problem, but I've experienced problems with COM-interop and SAFEARRAY's in the past. 不确定这是否是您问题的解决方案,但我在过去遇到过COM-interop和SAFEARRAY的问题。

One thing I learned from it is that the .NET equivalent of a COM SAFEARRAY should always be object , so try passing your array as an object in stead of as an Array . 有一件事我从中学到的是,.NET相当于一个COM SAFEARRAY的应该永远是object ,所以尽量通过你的数组作为object以代替作为Array

I hesitate to suggest this as an answer, but... 我毫不犹豫地建议这个答案,但......

If the Delphi test code really does work, as noted elsewhere, this means the GetTags method must not be playing properly by SAFEARRAY rules. 如果Delphi测试代码确实有效,如其他地方所述,这意味着GetFags方法不能通过SAFEARRAY规则正常播放。 If the COM method is always called in-process, you MAY be able to get the .NET code to work by doing some custom marshalling "by hand", following exactly what the unmanaged Delphi test code does. 如果COM方法总是在进程中调用,那么您可以通过“手动”执行一些自定义编组来实现.NET代码,完全遵循非托管Delphi测试代码的功能。

As a rough outline, I would imagine that this would involve: 作为一个粗略的轮廓,我想这将涉及:

  • allocating an unmanaged buffer to hold the array values 分配非托管缓冲区来保存数组值
  • calling Ole Automation SAFEARRAY initialization APIs via P/Invoke to allocate a SAFEARRAY structure and attach the array buffer to it as its pData member 通过P / Invoke调用Ole Automation SAFEARRAY初始化API以分配SAFEARRAY结构并将数组缓冲区作为其pData成员附加到它
  • invoking the GetTags method with this SAFEARRAY 使用此SAFEARRAY调用GetTags方法
  • marshalling your unamanaged buffer into a managed array, before... 在将...之前的非托管缓冲区编组到托管数组中之前......
  • calling the Win32 API to destroy the SAFEARRAY 调用Win32 API来销毁SAFEARRAY

But much better to get the COM component changed to do things properly, if you can. 但是,如果可以的话,更好地将COM组件更改为正确执行操作。

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

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