[Q] Interop: Pointer to structure in interface method

Y

yadolov

I have COM-object with Iface interface:

typedef struct
{
....
} TStruct;

[
object,
uuid(...)
pointer_default(unique),
local
]
interface Iface : IUnknown
{
TStruct* getDataPtr();
}

Question: how can i use this object in .Net?

For wrappers

[StructLayout(LayoutKind.Sequential)]
public struct TStruct
{
....
}

[Guid("..."), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface Iface
{
TStruct getDataPtr();
}

Tlbexp output is following:

[
odl,
uuid(...),
version(1.0),
oleautomation,
custom(..., ...)

]
interface Iface : IUnknown {
HRESULT _stdcall getDataPtr([out, retval] TStruct * pRetVal);
};

Many Thanks!
 
N

Nicholas Paldino [.NET/C# MVP]

That's a poorly defined COM interface. Aside from the AddRef and
Release methods on the IUnknown interface, COM interfaces are supposed to
return an HRESULT. Return values are supposed to be passed through
parameters with the out and retval attributes applied to them.

The TLBIMP program is expecting this.

You are going to have to define this interface yourself in code, like
so:

[Guid("..."), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[PreserveSig]
public interface Iface
{
IntPtr getDataPtr();
}

Notice the addition of the PreserveSig attribute, as well as the
returning of an IntPtr (since you are returning a pointer in your code).

Once you get the IntPtr, you can call the static PtrToStructure method
on the Marshal class to get the structure returned.

After you do that, you should pass the IntPtr to the static
FreeCoTaskMem method on the Marshal class, to de-allocate the memory
allocated in the implementation of the getDataPtr method. COM dictates that
you have to allocate memory locations that are passed around through the
IMalloc interface (which is wrapped up in the utility function
CoTaskMemAlloc). If you are not allocating the memory that is returned with
this function, then that's another error in the implementation.

Your COM interface should really be defined like this:

[
object,
uuid(...)
pointer_default(unique),
local
]
interface IFace : IUnknown
{
HRESULT GetDataPtr([in, out] TStruct *struct);
}

This requires the structure to be allocated by the caller. All you have
to do is check to make sure that the pointer is not null in your code, and
then set the values on the structure passed in. Then, your .NET code will
work correctly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top