32
.NET .NET Interoperability Liran Ben Haim Liran Ben Haim [email protected] http://www.bna.co.il

NET.NET Interoperability Liran Ben Haim [email protected]

Embed Size (px)

Citation preview

.NET .NET Interoperability

Liran Ben HaimLiran Ben [email protected]://www.bna.co.il

22

AgendaAgenda

OverviewOverview P/invokeP/invoke COM interopCOM interop

Performance Performance What’s new in .NET framework 2.0What’s new in .NET framework 2.0 Questions Questions

33

OverviewOverview 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

44

Win32 API / C DLLWin32 API / C DLLusing System;using System;using System.Runtime.InteropServices;using System.Runtime.InteropServices;

class PlatformInvokeTestclass PlatformInvokeTest{{ [DllImport("msvcrt.dll")][DllImport("msvcrt.dll")] public static extern int puts(string c);public static extern int puts(string c); [DllImport("msvcrt.dll")][DllImport("msvcrt.dll")] internal static extern int _flushall();internal static extern int _flushall();

public static void Main() public static void Main() {{ puts("Test");puts("Test"); _flushall();_flushall(); }}}}

55

C++ DLL (not COM)C++ DLL (not COM)

Create a MC++ class libraryCreate a MC++ class library

Or Or Add 2 global functions:Add 2 global functions:

Create objectCreate object Destroy objectDestroy object

Use dumpbin.exe to extract the required Use dumpbin.exe to extract the required member functionsmember functions

Use CallingConvention.ThisCallUse CallingConvention.ThisCall

66

ExampleExample

class SAMP_API Csamp {class SAMP_API Csamp {int x;int x;

public:public:int getnum(void){return x;}int getnum(void){return x;}void setnum(int x1){x=x1;}void setnum(int x1){x=x1;}

};};

extern "C" Csamp SAMP_API *createobject() extern "C" Csamp SAMP_API *createobject() {return new Csamp;}{return new Csamp;}

extern "C" void SAMP_API deleteobject(Csamp *p)extern "C" void SAMP_API deleteobject(Csamp *p) {delete p;}{delete p;}

77

[ DllImport( "samp.dll", [ DllImport( "samp.dll", EntryPoint="?getnum@Csamp@@QAEHXZ", EntryPoint="?getnum@Csamp@@QAEHXZ",

CallingConvention=CallingConvention.ThisCall )]CallingConvention=CallingConvention.ThisCall )]

public static extern int getnum( IntPtr ths);public static extern int getnum( IntPtr ths);

[ DllImport( "samp.dll", [ DllImport( "samp.dll", EntryPoint="?setnum@Csamp@@QAEXH@Z", EntryPoint="?setnum@Csamp@@QAEXH@Z",

CallingConvention=CallingConvention.ThisCall )]CallingConvention=CallingConvention.ThisCall )]

public static extern void setnum( IntPtr ths,int public static extern void setnum( IntPtr ths,int n);n);

[ DllImport( "samp.dll" )][ DllImport( "samp.dll" )]public static extern IntPtr createobject();public static extern IntPtr createobject();

[ DllImport( "samp.dll" )][ DllImport( "samp.dll" )]public static extern void deleteobject(IntPtr p);public static extern void deleteobject(IntPtr p);

88

Using the objectUsing the object

IntPtr p=Class1.createobject();IntPtr p=Class1.createobject();

Class1.setnum(p,77);Class1.setnum(p,77);

MessageBox.Show(Class1.getnum(p). MessageBox.Show(Class1.getnum(p). ToString());ToString());

Class1.deleteobject(p);Class1.deleteobject(p);

99

Creating Creating RCW

Adding reference to a COM component Adding reference to a COM component in VS.NET IDEin VS.NET IDE

Tlbimp.exeTlbimp.exe Tlbimp mycom.dllTlbimp mycom.dll

Custom wrapperCustom wrapper Using reflectionUsing reflection

1010

Custom wrapper exampleCustom wrapper example

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

null, excelObject, parameter);null, excelObject, parameter);

1111

Creating CCWCreating CCW

Tlbexp.exeTlbexp.exe Regasm.exeRegasm.exe

Register for com interop in VS.NET IDERegister for com interop in VS.NET IDE

1212

MarshalingMarshaling

Governs how data is passed between Governs how data is passed between managed and unmanaged memory managed and unmanaged memory during callsduring calls

Most data types require no conversionMost data types require no conversion bytebyte short short int int long long ……

1313

Custom marshalingCustom marshaling

[DllImport("msvcrt.dll")][DllImport("msvcrt.dll")]

public static extern int puts(public static extern int puts(

[MarshalAs(UnmanagedType.LPStr)][MarshalAs(UnmanagedType.LPStr)]

string m);string m);

Or use Marshal classOr use Marshal class

1414

Marshal classMarshal class

C++C++

typedef struct _MYSTRSTRUCT2typedef struct _MYSTRSTRUCT2

{{

char* buffer;char* buffer;

UINT size; UINT size;

} MYSTRSTRUCT2;} MYSTRSTRUCT2;

void TestOutArrayOfStructs(int* pSize, void TestOutArrayOfStructs(int* pSize, MYSTRSTRUCT2** ppStruct);MYSTRSTRUCT2** ppStruct);

1515

[ StructLayout( LayoutKind.Sequential)][ StructLayout( LayoutKind.Sequential)]

public class MyStruct public class MyStruct

{{

public String buffer;public String buffer;

public int size;public int size;

}}

[ DllImport( "..\\LIB\\PinvokeLib.dll" )][ DllImport( "..\\LIB\\PinvokeLib.dll" )]

public static extern void public static extern void

TestOutArrayOfStructs( out int size, TestOutArrayOfStructs( out int size,

outout IntPtr outArray );IntPtr outArray );

1616

int size;int size;IntPtr outArray;IntPtr outArray;

LibWrap.TestOutArrayOfStructs( out size, out outArray );LibWrap.TestOutArrayOfStructs( out size, out outArray );

MyStruct[] manArray = new MyStruct[ size ];MyStruct[] manArray = new MyStruct[ size ];

IntPtr current = outArray;IntPtr current = outArray;for( int i = 0; i < size; i++ )for( int i = 0; i < size; i++ ){{

manArray[ i ] = new MyStruct();manArray[ i ] = new MyStruct();Marshal.PtrToStructure( current, manArray[ i ]);Marshal.PtrToStructure( current, manArray[ i ]);

Marshal.DestroyStructure( current, typeof(MyStruct) );Marshal.DestroyStructure( current, typeof(MyStruct) );current = (IntPtr)((int)current +current = (IntPtr)((int)current +

Marshal.SizeOf( manArray[ i ] ));Marshal.SizeOf( manArray[ i ] ));}}Marshal.FreeCoTaskMem( outArray );Marshal.FreeCoTaskMem( outArray );

1717

Using unsafe codeUsing unsafe code

[ StructLayout( LayoutKind.Sequential )][ StructLayout( LayoutKind.Sequential )]

public struct MyUnsafeStruct public struct MyUnsafeStruct

{{

public IntPtr buffer;public IntPtr buffer;

public int size;public int size;

}}

[ DllImport( "..\\LIB\\PinvokeLib.dll" )][ DllImport( "..\\LIB\\PinvokeLib.dll" )]

public static extern void public static extern void TestOutArrayOfStructs( out int size, TestOutArrayOfStructs( out int size, MyUnsafeStruct** outArray );MyUnsafeStruct** outArray );

1818

public static unsafe void UsingUnsafe()public static unsafe void UsingUnsafe(){{

int size;int size;MyUnsafeStruct* pResult;MyUnsafeStruct* pResult;LibWrap.TestOutArrayOfStructs( out size, &pResult );LibWrap.TestOutArrayOfStructs( out size, &pResult );

MyUnsafeStruct* pCurrent = pResult;MyUnsafeStruct* pCurrent = pResult;for( int i = 0; i < size; i++, pCurrent++ )for( int i = 0; i < size; i++, pCurrent++ ){{

Console.WriteLine( "Element {0}: {1} {2}", i, Console.WriteLine( "Element {0}: {1} {2}", i, Marshal.PtrToStringAnsi( pCurrent-Marshal.PtrToStringAnsi( pCurrent-

>buffer ), >buffer ), pCurrent->size );pCurrent->size );

Marshal.FreeCoTaskMem( pCurrent->buffer );Marshal.FreeCoTaskMem( pCurrent->buffer );}}Marshal.FreeCoTaskMem( (IntPtr)pResult );Marshal.FreeCoTaskMem( (IntPtr)pResult );

}}

1919

Transition performance Transition performance

With every transition from managed to With every transition from managed to unmanaged code (and vice versa) there unmanaged code (and vice versa) there is some performance overheadis some performance overhead

Platform invoke call:Platform invoke call: 10 machine instructions (approx) + data 10 machine instructions (approx) + data

marshaling timemarshaling time

COM interop call:COM interop call: 50 machine instructions + data marshaling 50 machine instructions + data marshaling

Make Chunky CallsMake Chunky Calls

2020

String vs. individual charsString vs. individual chars

typedef struct _OSVERSIONINFOA { typedef struct _OSVERSIONINFOA { DWORD dwOSVersionInfoSize; DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwBuildNumber; DWORD dwPlatformId; DWORD dwPlatformId; CHAR szCSDVersion[ 10 ]; CHAR szCSDVersion[ 10 ];

} OSVERSIONINFOA, } OSVERSIONINFOA, *POSVERSIONINFOA, *POSVERSIONINFOA, *LPOSVERSIONINFOA; *LPOSVERSIONINFOA;

2121

[StructLayout(LayoutKind.Sequential, CharSet = [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] CharSet.Auto)]

class OSVersionInfo { class OSVersionInfo { public UInt32 OSVersionInfoSize = (UInt32) public UInt32 OSVersionInfoSize = (UInt32)

Marshal.SizeOf(typeof(OSVersionInfo)); Marshal.SizeOf(typeof(OSVersionInfo)); public UInt32 MajorVersion = 0; public UInt32 MajorVersion = 0; public UInt32 MinorVersion = 0; public UInt32 MinorVersion = 0; public UInt32 BuildNumber = 0; public UInt32 BuildNumber = 0; public UInt32 PlatformId = 0; public UInt32 PlatformId = 0;

[MarshalAs(UnmanagedType.ByValTStr, [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] SizeConst = 10)] public String CSDVersion = null; public String CSDVersion = null;

} }

2222

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)][StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]internal struct OSVersionInfoBlittable internal struct OSVersionInfoBlittable { {

public UInt32 OSVersionInfoSize; public UInt32 OSVersionInfoSize; public UInt32 MajorVersion; public UInt32 MinorVersion;public UInt32 MajorVersion; public UInt32 MinorVersion;public UInt32 BuildNumber; public UInt32 PlatformId;public UInt32 BuildNumber; public UInt32 PlatformId;unsafe public String CSDVersion {unsafe public String CSDVersion {

getget {{

fixed (Char* str = &CSDVersion0) fixed (Char* str = &CSDVersion0) {{

return new String(str); return new String(str); }}

}}}}Char CSDVersion0; Char CSDVersion1; Char Char CSDVersion0; Char CSDVersion1; Char

CSDVersion2; CSDVersion2; Char CSDVersion3; Char CSDVersion4; Char Char CSDVersion3; Char CSDVersion4; Char

CSDVersion5;CSDVersion5;Char CSDVersion6; Char CSDVersion7; Char Char CSDVersion6; Char CSDVersion7; Char

CSDVersion8; CSDVersion8; Char CSDVersion9;Char CSDVersion9;

}}

2323

Performance tipsPerformance tips

If you can find a .NET type that satisfies If you can find a .NET type that satisfies your needs, make use of ityour needs, make use of it

Primitive types require almost no Primitive types require almost no marshaling at allmarshaling at all

Translations from ASCII to Unicode are Translations from ASCII to Unicode are expensive expensive

2424

Example - MessageBoxExample - MessageBox

2 functions:2 functions: MessageBoxA - ansiMessageBoxA - ansi MessageBoxW – unicodeMessageBoxW – unicode

[ DllImport( "User32.dll", [ DllImport( "User32.dll", EntryPoint="MessageBoxW", EntryPoint="MessageBoxW", CharSet=CharSet.Unicode, CharSet=CharSet.Unicode, ExactSpelling=true )]ExactSpelling=true )]

public static extern int MsgBox( int hWnd, public static extern int MsgBox( int hWnd, String text, String caption, uint type );String text, String caption, uint type );

2525

Marshaling value types vs. Marshaling value types vs. reference typesreference types Marshaling Value types is preferable Marshaling Value types is preferable Managed structures are somewhat more Managed structures are somewhat more

similar to C structures than are similar to C structures than are managed classesmanaged classes

The runtime never reorganize the field The runtime never reorganize the field layout of managed structureslayout of managed structures

The GC never moves unboxed values The GC never moves unboxed values around in memory around in memory

2626

SetLastError fieldSetLastError field

[ DllImport( "User32.dll", SetLastError=true )][ DllImport( "User32.dll", SetLastError=true )]

public static extern int MessageBox( IntPtr hWnd, public static extern int MessageBox( IntPtr hWnd, String text, String caption, int type );String text, String caption, int type );

False in c#False in c# True in VB.NETTrue in VB.NET Use Marshal.GetLastWin32Error();Use Marshal.GetLastWin32Error(); Use FormatMessage() APIUse FormatMessage() API

2727

Design 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

2828

More guidelinesMore 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 );

2929

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 Allows managed code to call into

unmanaged code without a stack walk unmanaged code without a stack walk TLBIMP /unsafe

disable the full CAS stack walk for the unmanaged code

Code Access SecurityCode Access Security

3030

More info More info

Improving .NET Application Improving .NET Application Performance and Scalability Performance and Scalability

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpahttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt07.aspg/html/scalenetchapt07.asp

3131

New In .NET Framework 2.0New In .NET Framework 2.0

C++/CLI will include some useful C++/CLI will include some useful templates for simplifying C++ interop templates for simplifying C++ interop

The new SafeHandle class, provide safe The new SafeHandle class, provide safe and reliable means of manipulating and reliable means of manipulating operating system handles operating system handles

use with:use with:

[MethodImpl(MethodImplOptions.MustRun)][MethodImpl(MethodImplOptions.MustRun)]

3232

The ability to wrap native function The ability to wrap native function pointers into delegates pointers into delegates Marshal.GetDelegateForFunctionPointerMarshal.GetDelegateForFunctionPointer Marshal.GetFunctionPointerForDelegate Marshal.GetFunctionPointerForDelegate

The ability to marshal fixed-size arrays The ability to marshal fixed-size arrays of structures inside structures of structures inside structures

[module: DefaultCharSet(CharSet.Auto)] [module: DefaultCharSet(CharSet.Auto)]

Marshaling improvements Marshaling improvements