【发布时间】:2011-08-21 13:25:58
【问题描述】:
我在我的 C# .NET 项目中使用 COM。
但是,我调用的其中一种方法没有按预期运行。
所以我很想知道我的 .NET 代码、互操作层和 COM 之间发生了什么。
我知道tlbimp.exe 为 COM 组件生成元数据包装器,我可以在对象浏览器中看到这些生成的方法。
当调用这些包装方法之一时,我是否能够查看/调试会发生什么?
我将一个数组传递给下面的方法,并期望这个数组会被填充,但是数组不会被填充。
我正在调用以下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;
【问题讨论】:
-
您遇到了什么错误?什么不是“按预期工作”?
-
@Simon Mourier:感谢您的回复。我没有收到任何错误。该方法执行得很好,但数组没有被填充。 COM 代码已经用 delphi 测试过并且工作正常,所以这让我相信在 com-interop 层中发生了一些事情?
-
我想如果你希望能够在 COM 层填充数组,你的 COM 原型应该是不同的。您需要通过引用来定义 SAFEARRAY 或将 [in, out] 添加到 .IDL 我想。 .NET Marshaler(与任何其他 marshaler BTW 一样)认为这只是一种单向调用。
-
@Simon:再次感谢您的回复。我将如何通过引用定义 SAFEARRAY?另外,如果我需要更改 IDL,这是否意味着重新创建 COM dll?
标签: c# .net com com-interop tlbimp