Groups | Blog | Home
all groups > dotnet interop > may 2005 >

dotnet interop : Does inheritance work in recreating an interface definition from C


Frederik Mangelsdorf
5/31/2005 11:23:01 PM
Dear group,

I'm implementing an Asynchronous Pluggable Protocol. For this I needed the
COM definitions of the interface IInternetProtocol, which in the shipped
headerfile is derived from IInternetProtocolRoot. Because I wasn't able to
find a typelib with the interface, I recreated the interface in C#. As a
side note: I've started out this part of my solution by making an ATL
solution. But now that I'm confident that this is a viable way I'm porting
the ATL code to C# since the remainder of my project is already a .NET
solution.

This was my first go at the interface definitions:

[ InterfaceType( ComInterfaceType.InterfaceIsIUnknown)]
[ Guid( "79EAC9E3-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocolRoot {
void Start( [ MarshalAs( UnmanagedType.LPWStr)]
string szURL,
IInternetProtocolSink Sink,
IInternetBindInfo pOIBindInfo,
uint grfPI,
uint dwReserved);
void Continue( ref PROTOCOLDATA pProtocolData);
void Abort( int hrReason,
uint dwOptions);
void Terminate( uint dwOptions);
void Suspend( );
void Resume( );
} // IInternetProtocolRoot

[ InterfaceType( ComInterfaceType.InterfaceIsIUnknown)]
[ Guid( "79EAC9E4-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocol : IInternetProtocolRoot {
[ PreserveSig( )]
uint Read( IntPtr pv,
uint cb,
out uint pcbRead);
void Seek( long dlibMove,
uint dwOrigin,
out ulong plibNewPosition);
void LockRequest( uint dwOptions);
void UnlockRequest( );
} // IInternetProtocol

I then ported my test ATL code C# and all compiled fine. However as I
started to test/debug this code, the read method of IInterProtocol was called
first, whereas in the ATL project the Start method of IInterprotocolRoot was
called first. Also I noticed that the arguments of the call to Read where
indeed very odd (buffer sizes of 100's of Megabytes). And of course my
program didn't work.

I started experimenting and changed the interface definitions to not use
inheritance anymore because I reasoned that perhaps the layout of the vtable
could be the cause of this strange behavior and bingo now my program works as
expected.

This is the working version of the interfaces:

[ InterfaceType( ComInterfaceType.InterfaceIsIUnknown)]
[ Guid( "79EAC9E3-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocolRoot {
// Caution: because inheritance of the interface doesn't work, this source
// has been copied into IInternetProtocol also.
void Start( [ MarshalAs( UnmanagedType.LPWStr)]
string szURL,
IInternetProtocolSink Sink,
IInternetBindInfo pOIBindInfo,
uint grfPI,
uint dwReserved);
void Continue( ref PROTOCOLDATA pProtocolData);
void Abort( int hrReason,
uint dwOptions);
void Terminate( uint dwOptions);
void Suspend( );
void Resume( );
} // IInternetProtocolRoot

[ InterfaceType( ComInterfaceType.InterfaceIsIUnknown)]
[ Guid( "79EAC9E4-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocol /* : IInternetProtocolRoot */ {
// Manually copy the methods of the root interface, inheritance doesn't
// work for some unkown reason (a .NET interoperation issue perhaps?).
void Start( [ MarshalAs( UnmanagedType.LPWStr)]
string szURL,
IInternetProtocolSink Sink,
IInternetBindInfo pOIBindInfo,
uint grfPI,
uint dwReserved);
void Continue( ref PROTOCOLDATA pProtocolData);
void Abort( int hrReason,
uint dwOptions);
void Terminate( uint dwOptions);
void Suspend( );
void Resume( );
// End of IInternetProtocolRoot copy.
[ PreserveSig( )]
uint Read( IntPtr pv,
uint cb,
out uint pcbRead);
void Seek( long dlibMove,
uint dwOrigin,
out ulong plibNewPosition);
void LockRequest( uint dwOptions);
void UnlockRequest( );
} // IInternetProtocol

I don't really like this because now I've duplicated the
IInternetProtocolRoot interface inside the IInternetProtocol interface.
Since this is working, I'm really just left puzzling why I couldn't get the
proper vtable layout using the inheritance/deriving solution?

Can anyone shed some light on this? Surely I cannot be the first one
running into this, although I've googled and dived into MSDN first of course.
Any comments are greatly appreciated.

Mattias Sjögren
6/2/2005 12:00:00 AM
Frederik,

[quoted text, click to view]

The short answer is "because it doesn't work that way". Repeating the
base members in the derived interface is the right solution.



Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
AddThis Social Bookmark Button