1 / 32

.NET Interoperability

.NET Interoperability. Liran Ben Haim liran@bna.co.il http://www.bna.co.il. Agenda. Overview P/invoke COM interop Performance What’s new in .NET framework 2.0 Questions . Overview. Platform Invoke Finding and invoking unmanaged functions

caroline
Download Presentation

.NET Interoperability

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. .NET Interoperability Liran Ben Haim liran@bna.co.il http://www.bna.co.il

  2. Agenda • Overview • P/invoke • COM interop • Performance • What’s new in .NET framework 2.0 • Questions

  3. Overview • Platform Invoke • Finding and invoking unmanaged functions • Marshaling managed arguments to and from unmanaged code • COM Interoperability • Runtime Callable Wrapper (RCW) • Used by managed clients to call a method on a COM object • COM Callable Wrapper (CCW) • Used by COM clients to call a method on a managed object

  4. Win32 API / C DLL using System; using System.Runtime.InteropServices; class PlatformInvokeTest { [DllImport("msvcrt.dll")] public static extern int puts(string c); [DllImport("msvcrt.dll")] internal static extern int _flushall(); public static void Main() { puts("Test"); _flushall(); } }

  5. C++ DLL (not COM) • Create a MC++ class library Or • Add 2 global functions: • Create object • Destroy object • Use dumpbin.exe to extract the required member functions • Use CallingConvention.ThisCall

  6. Example class SAMP_API Csamp { int x; public: int getnum(void){return x;} void setnum(int x1){x=x1;} }; extern "C" Csamp SAMP_API *createobject() {return new Csamp;} extern "C" void SAMP_API deleteobject(Csamp *p) {delete p;}

  7. [ DllImport( "samp.dll", EntryPoint="?getnum@Csamp@@QAEHXZ", CallingConvention=CallingConvention.ThisCall )] public static extern int getnum( IntPtr ths); [ DllImport( "samp.dll", EntryPoint="?setnum@Csamp@@QAEXH@Z", CallingConvention=CallingConvention.ThisCall )] public static extern void setnum( IntPtr ths,int n); [ DllImport( "samp.dll" )] public static extern IntPtr createobject(); [ DllImport( "samp.dll" )] public static extern void deleteobject(IntPtr p);

  8. Using the object IntPtr p=Class1.createobject(); Class1.setnum(p,77); MessageBox.Show(Class1.getnum(p). ToString()); Class1.deleteobject(p);

  9. Creating RCW • Adding reference to a COM component in VS.NET IDE • Tlbimp.exe • Tlbimp mycom.dll • Custom wrapper • Using reflection

  10. Custom wrapper example Type excel; object[] parameter= new object[1]; object excelObject; excel = Type.GetTypeFromProgID("Excel.Application"); excelObject = Activator.CreateInstance(excel); parameter[0] = true; excel.InvokeMember("Visible", BindingFlags.SetProperty, null, excelObject, parameter);

  11. Creating CCW • Tlbexp.exe • Regasm.exe • Register for com interop in VS.NET IDE

  12. Marshaling • Governs how data is passed between managed and unmanaged memory during calls • Most data types require no conversion • byte • short • int • long • …

  13. Custom marshaling [DllImport("msvcrt.dll")] public static extern int puts( [MarshalAs(UnmanagedType.LPStr)] string m); • Or use Marshal class

  14. Marshal class • C++ typedef struct _MYSTRSTRUCT2 { char* buffer; UINT size; } MYSTRSTRUCT2; void TestOutArrayOfStructs(int* pSize, MYSTRSTRUCT2** ppStruct);

  15. [ StructLayout( LayoutKind.Sequential)] public class MyStruct { public String buffer; public int size; } [ DllImport( "..\\LIB\\PinvokeLib.dll" )] public static extern void TestOutArrayOfStructs( out int size, out IntPtr outArray );

  16. int size; IntPtr outArray; LibWrap.TestOutArrayOfStructs( out size, out outArray ); MyStruct[] manArray = new MyStruct[ size ]; IntPtr current = outArray; for( int i = 0; i < size; i++ ) { manArray[ i ] = new MyStruct(); Marshal.PtrToStructure( current, manArray[ i ]); Marshal.DestroyStructure( current, typeof(MyStruct) ); current = (IntPtr)((int)current + Marshal.SizeOf( manArray[ i ] )); } Marshal.FreeCoTaskMem( outArray );

  17. Using unsafe code [ StructLayout( LayoutKind.Sequential )] public struct MyUnsafeStruct { public IntPtr buffer; public int size; } [ DllImport( "..\\LIB\\PinvokeLib.dll" )] public static extern void TestOutArrayOfStructs( out int size, MyUnsafeStruct** outArray );

  18. public static unsafe void UsingUnsafe() { int size; MyUnsafeStruct* pResult; LibWrap.TestOutArrayOfStructs( out size, &pResult ); MyUnsafeStruct* pCurrent = pResult; for( int i = 0; i < size; i++, pCurrent++ ) { Console.WriteLine( "Element {0}: {1} {2}", i, Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size ); Marshal.FreeCoTaskMem( pCurrent->buffer ); } Marshal.FreeCoTaskMem( (IntPtr)pResult ); }

  19. Transition performance • With every transition from managed to unmanaged code (and vice versa) there is some performance overhead • Platform invoke call: • 10 machine instructions (approx) + data marshaling time • COM interop call: • 50 machine instructions + data marshaling • Make Chunky Calls

  20. String vs. individual chars typedef struct _OSVERSIONINFOA { DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; CHAR szCSDVersion[ 10 ]; } OSVERSIONINFOA, *POSVERSIONINFOA, *LPOSVERSIONINFOA;

  21. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] class OSVersionInfo { public UInt32 OSVersionInfoSize = (UInt32) Marshal.SizeOf(typeof(OSVersionInfo)); public UInt32 MajorVersion = 0; public UInt32 MinorVersion = 0; public UInt32 BuildNumber = 0; public UInt32 PlatformId = 0; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] public String CSDVersion = null; }

  22. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct OSVersionInfoBlittable { public UInt32 OSVersionInfoSize; public UInt32 MajorVersion; public UInt32 MinorVersion; public UInt32 BuildNumber; public UInt32 PlatformId; unsafe public String CSDVersion { get { fixed (Char* str = &CSDVersion0) { return new String(str); } } } Char CSDVersion0; Char CSDVersion1; Char CSDVersion2; Char CSDVersion3; Char CSDVersion4; Char CSDVersion5; Char CSDVersion6; Char CSDVersion7; Char CSDVersion8; Char CSDVersion9; }

  23. Performance tips • If you can find a .NET type that satisfies your needs, make use of it • Primitive types require almost no marshaling at all • Translations from ASCII to Unicode are expensive

  24. Example - MessageBox • 2 functions: • MessageBoxA - ansi • MessageBoxW – unicode [ DllImport( "User32.dll", EntryPoint="MessageBoxW", CharSet=CharSet.Unicode, ExactSpelling=true )] public static extern int MsgBox( int hWnd, String text, String caption, uint type );

  25. Marshaling value types vs. reference types • Marshaling Value types is preferable • Managed structures are somewhat more similar to C structures than are managed classes • The runtime never reorganize the field layout of managed structures • The GC never moves unboxed values around in memory

  26. SetLastError field [ DllImport( "User32.dll", SetLastError=true )] public static extern int MessageBox( IntPtr hWnd, String text, String caption, int type ); • False in c# • True in VB.NET • Use Marshal.GetLastWin32Error(); • Use FormatMessage() API

  27. Design Considerations • Design chunky interfaces to avoid round trips. • Reduce round trips with a facade. • Implement IDisposable if you hold unmanaged resources across client calls. • Reduce or avoid the use of late binding and reflection. • In ASP.NET – Server.CreateObject or Server.CreateObjectFromClsid

  28. More guidelines • Use IntPtr for manual marshaling. • Use [in] and [out] to avoid unnecessary marshaling. [DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern int CreateFontIndirect( [In, MarshalAs(UnmanagedType.LPStruct)] LOGFONT lplf );

  29. Code Access Security • Use SuppressUnmanagedCode for performance-critical trusted scenarios [DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity] public static extern bool Beep(int frequency, int duration); Allows managed code to call into unmanaged code without a stack walk • TLBIMP /unsafe • disable the full CAS stack walk for the unmanaged code

  30. More info • Improving .NET Application Performance and Scalability http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt07.asp

  31. New In .NET Framework 2.0 • C++/CLI will include some useful templates for simplifying C++ interop • The new SafeHandle class, provide safe and reliable means of manipulating operating system handles use with: [MethodImpl(MethodImplOptions.MustRun)]

  32. Marshaling improvements • The ability to wrap native function pointers into delegates • Marshal.GetDelegateForFunctionPointer • Marshal.GetFunctionPointerForDelegate • The ability to marshal fixed-size arrays of structures inside structures • [module: DefaultCharSet(CharSet.Auto)]

More Related