Upload
philomena-jacobs
View
225
Download
0
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