I am using COM in my C# .NET project.
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.
I know the tlbimp.exe
generates the metadata wrapper for the COM component and I can see these generated methods in the Object browser.
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:
int GetTags(System.Array buffer)
Member of CServer.IUser
Method IDL:
[id(0x000000d5)]
HRESULT GetTags(
[in] SAFEARRAY(long) buffer,
[out, retval] long* retval);
.NET code calling this method:
Array tagsArray = Array.CreateInstance(typeof(int), tagsLength);
userWrapper.GetTags(tagsArray);
Other COM methods I call work fine. However when I call any method which expects an Array as a parameter it does not work as expected.
I am presuming that there is something funny going in with the COM interop marshaller.
So I would like to know if I can see what is happening after I call the GetTags()
method.
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
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). But this can never work as that parameter is an [in]
parameter.
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*).
Update: Ok, apparently I was mixing the creation of a COM component in .NET with calling a COM component from .NET.
The CCW (com callable wrapper) indeed takes a .NET Array for COM SafeArray's. 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.
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
.
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. 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.
As a rough outline, I would imagine that this would involve:
But much better to get the COM component changed to do things properly, if you can.
User contributions licensed under CC BY-SA 3.0