我在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;
答案 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测试代码的作用。
作为一个粗略的概述,我想这将涉及:
但是,如果可以的话,更好地将COM组件更改为正确执行操作。