Platform Invocation Services
P/Invoke
Juan Ramírez (@ichramm)@NETUYMeetup
● Intro con dibujito
● Qué es? Qué hace? Para qué sirve?
● Analizando el problema
○ P/Invoke vs C++/CLI
● DllImport y sus ...
Quées?Quehace?Paraquésirve?
● Es una funcionalidad del CLR ...
… que permite invocar código nativo
(unmanaged) desde .Net ...
DLL
Common Language
Runtime
Managed
source
code
DLL Function
Unmanaged Managed
Assembly
Metadata
MSIL code
DLL Function
DL...
PARA QUÉ
SIRVE?
y...
Problema
● Se desea utilizar cierta API nativa, que no
tiene bindings para .Net.
● Debe ser Portable.
● No se dispone del ...
Ejemplos(pococoncretos)
● API de Windows
● Librería que implementa determinado
protocolo.
● Interoperabilidad con distinto...
YquépasaconC++/CLI?
● Crear un wrapper sería más sencillo. ✓
● Buena performance, mejor que P/Invoke en
algunos casos. ✓
●...
YquépasaconC++/CLI?
● No es portable (solo Windows). ✘
● Se necesita el código fuente de la librería. ✘
● Hay que tocar ot...
YconP/Invoke?
● Solo necesito la DLL. ✓
● Es portable (mono project). ✓
● Solo tengo que tocar C#. ✓
Peeeero...
● No es type-safe. ✘
● Más lento en ciertos casos. ✘
● Se puede volver muy complicado. ✘
Enresumen
● Es la solución a un problema
● Permite utilizar funcionalidades que de otra
manera no se podrían utilizar.
GETTING
BUSINESSTO
DOWN
Basta de cháchara...
Ejemplo
// Usage:
bool copied = CopyFile(textBox1.Text, textBox2.Text, true);
using System.Runtime.InteropServices;
[DllIm...
● Indica que el método es expuesto por una DLL
nativa (class DllImportAttribute).
/- DllImport
● El keyword extern indica ...
Ejemplo
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode)]
private static extern bool CopyFile (
[MarshalAs(UnmanagedT...
/-CharSet
● Marshalling de strings
○ Charset.Ansi -> char*
○ Charset.Unicode -> wchar_t*
● Name matching
○ Charset.Ansi ->...
Ejemplo
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
ExactSpelling = true)]
private static extern bool CopyFile (...
/-CharSet vs ExactSpelling
● ExactSpelling deshabilita name matching.
● La función CopyFile no existe en
kernel32.dll.
● S...
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
ExactSpelling = true)]
private static extern bool CopyFileW (
[Marsh...
Ejemplo
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
SetLastError = true, // This function sets last error
Callin...
Ejemplo
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
SetLastError = true, // This function sets last error
Callin...
/-CallingConvention
● Esquema que establece como una función recibe
parámetros y devuelve un resultado.
● El código necesa...
/-CallingConvention
StdCall
● El callee limpia el
stack.
● Default en el
Windows API.
Cdecl
● El caller limpia el
stack.
●...
Ejemplo
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
SetLastError = true,
CallingConvention = CallingConvention.S...
/-EntryPoint
● Especifica el nombre con el que se va a buscar
la función.
● O el índice de la función dentro de la DLL .
○...
Ejemplo
void CopyFile(string from, string to)
{
bool copied = NativeCopyFile(from, to, true);
if (copied == false)
{
throw...
LOCOS
EJEMPLITOS
DOS
> git checkout example1
> git checkout example2
● Se trata de una especie de transformación
de datos.
● Desde el mundo managed al mundo
nativo.
● Desde el mundo nativo al...
Para cada data type de .net existe un data type
unmanaged por defecto.
● int -> int
● bool -> BOOL /ojo! son 4 bytes
● str...
DataMarshaling/DataTypes/System.IntPtr
● Se utiliza para representar punteros (o
handles).
● IntPtr es ideal para tipos op...
Ejemplo
[DllImport("kernel32.dll")]
public static extern IntPtr OpenMutex(
uint dwDesiredAccess, bool bInheritHandle, stri...
DataMarshaling/DataTypes/ System.String
● Ya vimos como pasar strings desde el
mundo managed al mundo unmanaged.
● Vamos a...
DWORD WINAPI GetModuleFileName(
HMODULE hModule, LPTSTR lpFilename, DWORD nSize
);
[DllImport("kernel32.dll")]
public stat...
Ejemplo
public string StartupPath {
get {
StringBuilder sb = new StringBuilder(260);
GetModuleFileName(IntPtr.Zero, sb, sb...
EJEMPLITO
OTRO
> git checkout example3
● Se debe especificar el layout
● Members pueden llevar atributos
DataMarshaling/Structs
[StructLayout(LayoutKind.Sequenti...
● El layout se puede configurar explícitamente
[StructLayout(LayoutKind.Explicit)]
public class LOGFONT {
[FieldOffset(0)]...
● Cual es el tamaño de este struct?
public struct Test {
public byte a;
public int b;
public short c;
public byte d;
}
Dat...
JUMP!
> git checkout example4
● Mapean directo con delegates
DataMarshaling/Callbacks
● Mismas reglas que con las demas
funciones.
● Una forma de llamar...
Ejemplo
ESME_HANDLE SMPP_API libSMPP_ClientCreate (
OnIncomingMessageCallback onNewMessage
);
Ejemplo
typedef void (*OnIncomingMessageCallback)(
ESME_HANDLE hClient,
const char* from,
const char* to,
const char* cont...
Ejemplo
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void IncomingMessageHandler(
IntPtr hClient,
string f...
Ejemplo
[DllImport("inconcertsmpp.dll"
, CharSet = CharSet.Ansi
, CallingConvention = CallingConvention.Cdecl)]
static ext...
hClient = libSMPP_ClientCreate(
new IncomingMessageHandler( delegate(
IntPtr hClient, string from, string to,
byte[] conte...
Pero...
● Ese código vuela por los aires
● El garbage collector se lleva el delegate
● Hay que mantener vivas las referenc...
m_handler = new IncomingMessageHandler( delegate(
IntPtr hClient, string from, string to,
byte[] content, int bufferSize)
...
Gracias!
Didn’t make it:
● Keywords: unsafe, fixed
● Custom Marshallers
● Punteros
Upcoming SlideShare
Loading in...5
×

.NET UY Meetup 6 - Integrando con C/C++ por medio de P/Invoke by Juan Ramirez

527

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
527
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

.NET UY Meetup 6 - Integrando con C/C++ por medio de P/Invoke by Juan Ramirez

  1. 1. Platform Invocation Services P/Invoke Juan Ramírez (@ichramm)@NETUYMeetup
  2. 2. ● Intro con dibujito ● Qué es? Qué hace? Para qué sirve? ● Analizando el problema ○ P/Invoke vs C++/CLI ● DllImport y sus allegados ● Data Marshalling ○ Data Types ○ Estructuras ○ Callbacks Agenda
  3. 3. Quées?Quehace?Paraquésirve? ● Es una funcionalidad del CLR ... … que permite invocar código nativo (unmanaged) desde .Net (managed). ● Es muy flexible, y con defaults razonables.
  4. 4. DLL Common Language Runtime Managed source code DLL Function Unmanaged Managed Assembly Metadata MSIL code DLL Function DLL Function P/Invoke Compiler “Permite ejecutar native code desde managed code”
  5. 5. PARA QUÉ SIRVE? y...
  6. 6. Problema ● Se desea utilizar cierta API nativa, que no tiene bindings para .Net. ● Debe ser Portable. ● No se dispone del código fuente de la librería.
  7. 7. Ejemplos(pococoncretos) ● API de Windows ● Librería que implementa determinado protocolo. ● Interoperabilidad con distintos frameworks
  8. 8. YquépasaconC++/CLI? ● Crear un wrapper sería más sencillo. ✓ ● Buena performance, mejor que P/Invoke en algunos casos. ✓ ● Estáticamente type-safe. ✓ ● Transiciones entre managed y unmanaged son sencillas y seguras. ✓
  9. 9. YquépasaconC++/CLI? ● No es portable (solo Windows). ✘ ● Se necesita el código fuente de la librería. ✘ ● Hay que tocar otro lenguaje, una especie de C++ maquillado. ✘
  10. 10. YconP/Invoke? ● Solo necesito la DLL. ✓ ● Es portable (mono project). ✓ ● Solo tengo que tocar C#. ✓
  11. 11. Peeeero... ● No es type-safe. ✘ ● Más lento en ciertos casos. ✘ ● Se puede volver muy complicado. ✘
  12. 12. Enresumen ● Es la solución a un problema ● Permite utilizar funcionalidades que de otra manera no se podrían utilizar.
  13. 13. GETTING BUSINESSTO DOWN Basta de cháchara...
  14. 14. Ejemplo // Usage: bool copied = CopyFile(textBox1.Text, textBox2.Text, true); using System.Runtime.InteropServices; [DllImport("kernel32.dll")] private static extern bool CopyFile ( string lpExistingFileName, string lpNewFileName, bool bFailIfExists );
  15. 15. ● Indica que el método es expuesto por una DLL nativa (class DllImportAttribute). /- DllImport ● El keyword extern indica que el método está implementado en otro lado. ● En nuestro ejemplo: ○ Dll Nativa: kernel32.dll ○ Función : CopyFile
  16. 16. Ejemplo [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] private static extern bool CopyFile ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, bool bFailIfExists ); // Usage: bool copied = CopyFile(textBox1.Text, textBox2.Text, true);
  17. 17. /-CharSet ● Marshalling de strings ○ Charset.Ansi -> char* ○ Charset.Unicode -> wchar_t* ● Name matching ○ Charset.Ansi -> CopyFileA ○ Charset.Unicode -> CopyFileW
  18. 18. Ejemplo [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern bool CopyFile ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, bool bFailIfExists );
  19. 19. /-CharSet vs ExactSpelling ● ExactSpelling deshabilita name matching. ● La función CopyFile no existe en kernel32.dll. ● Sí existen CopyFileA y CopyFileW
  20. 20. [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern bool CopyFileW ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, bool bFailIfExists ); /-CharSet vs ExactSpelling Posible solución
  21. 21. Ejemplo [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, // This function sets last error CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CopyFile ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, [MarshalAs(UnmanagedType.Bool)] bool bFailIfExists );
  22. 22. Ejemplo [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, // This function sets last error CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CopyFile ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, [MarshalAs(UnmanagedType.Bool)] bool bFailIfExists );
  23. 23. /-CallingConvention ● Esquema que establece como una función recibe parámetros y devuelve un resultado. ● El código necesario lo genera el propio compilador (C/C++). ● El default en .Net es Winapi (StdCall). ● “... quien limpia el stack”.
  24. 24. /-CallingConvention StdCall ● El callee limpia el stack. ● Default en el Windows API. Cdecl ● El caller limpia el stack. ● Default en Visual C++.
  25. 25. Ejemplo [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall, EntryPoint = "CopyFile")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool NativeCopyFile ( [MarshalAs(UnmanagedType.LPWStr)] string lpExistingFileName, [MarshalAs(UnmanagedType.LPWStr)] string lpNewFileName, [MarshalAs(UnmanagedType.Bool)] bool bFailIfExists );
  26. 26. /-EntryPoint ● Especifica el nombre con el que se va a buscar la función. ● O el índice de la función dentro de la DLL . ○ Ej: EntryPoint = "#167" ● El default es el nombre del método marcado con el DllImport.
  27. 27. Ejemplo void CopyFile(string from, string to) { bool copied = NativeCopyFile(from, to, true); if (copied == false) { throw new Win32Exception(Marshal.GetLastWin32Error()); } }
  28. 28. LOCOS EJEMPLITOS DOS > git checkout example1 > git checkout example2
  29. 29. ● Se trata de una especie de transformación de datos. ● Desde el mundo managed al mundo nativo. ● Desde el mundo nativo al mundo managed. DataMarshaling
  30. 30. Para cada data type de .net existe un data type unmanaged por defecto. ● int -> int ● bool -> BOOL /ojo! son 4 bytes ● string -> char * (o TCHAR) ● etc DataMarshaling/DataTypes
  31. 31. DataMarshaling/DataTypes/System.IntPtr ● Se utiliza para representar punteros (o handles). ● IntPtr es ideal para tipos opacos. ● Es platform-specific (x86, x64).
  32. 32. Ejemplo [DllImport("kernel32.dll")] public static extern IntPtr OpenMutex( uint dwDesiredAccess, bool bInheritHandle, string lpName ); // typedef void * HANDLE; -> winnt.h HANDLE WINAPI OpenMutex( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );
  33. 33. DataMarshaling/DataTypes/ System.String ● Ya vimos como pasar strings desde el mundo managed al mundo unmanaged. ● Vamos a ver como se hace al revés.
  34. 34. DWORD WINAPI GetModuleFileName( HMODULE hModule, LPTSTR lpFilename, DWORD nSize ); [DllImport("kernel32.dll")] public static extern uint GetModuleFileName( IntPtr hModule, // System.String is not mutable StringBuilder lpFilename, [MarshalAs(UnmanagedType.U4)] int nSize ); DataMarshaling/DataTypes/ System.String
  35. 35. Ejemplo public string StartupPath { get { StringBuilder sb = new StringBuilder(260); GetModuleFileName(IntPtr.Zero, sb, sb.Capacity); // TODO: Handle error return sb.ToString(); } }
  36. 36. EJEMPLITO OTRO > git checkout example3
  37. 37. ● Se debe especificar el layout ● Members pueden llevar atributos DataMarshaling/Structs [StructLayout(LayoutKind.Sequential)] public class LOGFONT { // members... [MarshalAs(UnmanagedType.ByValTStr, SizeConst = LF_FACESIZE)] public string lfFaceName;
  38. 38. ● El layout se puede configurar explícitamente [StructLayout(LayoutKind.Explicit)] public class LOGFONT { [FieldOffset(0)] public int lfHeight; // more members… } DataMarshaling/Structs
  39. 39. ● Cual es el tamaño de este struct? public struct Test { public byte a; public int b; public short c; public byte d; } DataMarshaling/Structs ● Ojo con el padding!! 12
  40. 40. JUMP! > git checkout example4
  41. 41. ● Mapean directo con delegates DataMarshaling/Callbacks ● Mismas reglas que con las demas funciones. ● Una forma de llamar funciones de .Net desde el mundo unmanaged.
  42. 42. Ejemplo ESME_HANDLE SMPP_API libSMPP_ClientCreate ( OnIncomingMessageCallback onNewMessage );
  43. 43. Ejemplo typedef void (*OnIncomingMessageCallback)( ESME_HANDLE hClient, const char* from, const char* to, const char* content, // UTF-8 unsigned int size );
  44. 44. Ejemplo [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void IncomingMessageHandler( IntPtr hClient, string from, string to, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] byte[] content, [MarshalAs(UnmanagedType.U4)] int bufferSize );
  45. 45. Ejemplo [DllImport("inconcertsmpp.dll" , CharSet = CharSet.Ansi , CallingConvention = CallingConvention.Cdecl)] static extern IntPtr libSMPP_ClientCreate( [MarshalAs(UnmanagedType.FunctionPtr)] IncomingMessageHandler onNewMessage );
  46. 46. hClient = libSMPP_ClientCreate( new IncomingMessageHandler( delegate( IntPtr hClient, string from, string to, byte[] content, int bufferSize) { string text = Encoding.UTF8.GetString(content); // ... } ); Ejemplo
  47. 47. Pero... ● Ese código vuela por los aires ● El garbage collector se lleva el delegate ● Hay que mantener vivas las referencias a esos elementos
  48. 48. m_handler = new IncomingMessageHandler( delegate( IntPtr hClient, string from, string to, byte[] content, int bufferSize) { string text = Encoding.UTF8.GetString(content); // ... }; hClient = libSMPP_ClientCreate(m_handler); Ejemplo
  49. 49. Gracias! Didn’t make it: ● Keywords: unsafe, fixed ● Custom Marshallers ● Punteros
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×