SlideShare a Scribd company logo
Training Material

Rainer Stropek
software architects gmbh

P/Invoke

Web http://www.timecockpit.com
Mail rainer@timecockpit.com
Twitter @rstropek

.NET Interop

Saves the day.
C++ Basics

Interop-related topics for C++
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the PINVOKE_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// PINVOKE_EXPORTS functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef PINVOKE_EXPORTS
#define PINVOKE_API __declspec(dllexport)
#else
#define PINVOKE_API __declspec(dllimport)
#endif

DLL Exports

// Some quite simple functions to begin with
extern "C" PINVOKE_API int AddNumbers(int x, int y);
extern "C" PINVOKE_API int AddArray(int x[], int size);

// A very simple DLL export.
extern "C" PINVOKE_API int AddNumbers(int x, int y)
{
return x + y;
}
// A method taking an array.
extern "C" PINVOKE_API int AddArray(int x[], int size)
{
auto ans = 0;
for (int i = 0; i < size; i++)
{
ans += x[i];
}
return ans;
}
See also MSDN
dumpbin
Get list of exports of an
unmanaged DLL
Parameters
/imports
/exports

See MSDN for details
Memory Handling
 Native

DLL should avoid allocating memory and expect the
caller to free the memory

 Use

CoTaskMemAlloc instead of new

Freed by Interop Marshaller of .NET automatically using CoTaskMemFree
Can be freed manually using Marshal.FreeCoTaskMem

 Native

DLL could offer a function to free the memory

See CMiniVan example (CreateMiniVan and DeleteMiniVan)
Debugging
Enable native code
debugging

Step into unmanaged code
Interop Basics
Interop Basics
 System.Runtime.InteropServices

Namespace

 System.Runtime.InteropServices.Marshal
Important helper methods for working with unmanaged code

class

 System.Runtime.InteropServices.DllImportAttribute
Import a method from an unmanaged DLL
Data Type Mapping
See also MSDN
More detailed list can be
found in Nathan, .NET
and COM, 779ff

Source: Troelsen, COM and .NET Interoperability
Marshal Class

For details see MSDN
DllImportAttribute
DllImportAttribute
 Calling

convention

 Character

set

 Entry

point

 Exact

spelling

 Error

handling

Can be used to rename functions

Controls whether character set is used to look for entry point name

SetLastError behavior
Calling Conventions
 See

also MSDN article about calling conventions

By default, VC++ uses _cdecl

 P/Invoke

behavior has changed in .NET 4

In .NET < 4 you could call a _cdecl function with __stdcall without any problems
In .NET >= 4 you will get an exception in the debugger
See also pInvokeStackImbalance and NetFx40_PInvokeStackResilience

See also http://blogs.msdn.com/b/oldnewthing/archive/2004/01/08/48616.aspx
// This works
extern "C" PINVOKE_API int __stdcall AddNumbers(int x, int y);
[DllImport("PInvokeIntroduction.dll")]
public static extern int AddNumbers(int x, int y);

// This works, too
extern "C" PINVOKE_API int AddNumbers(int x, int y);
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern int AddNumbers(int x, int y);

// Anything else will throw an exception in the debugger

Calling Conventions
Marshal Strings
 Character

sets

Ansi
Unicode
Auto (depends on operating system type)
None (obsolete)

 Specify

character set

In DllImportAttribute
In MarshalAsAttribute
using System.Runtime.InteropServices;
namespace Samples.PInvoke.IntroductionClient
{
[StructLayout(LayoutKind.Sequential)]
public class Car
{
[MarshalAs(UnmanagedType.LPWStr)]
public string Make;

Character Sets

[MarshalAs(UnmanagedType.LPWStr)]
public string Color;

}
…
}

[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Unicode)]
public static extern void DisplayBetterCar(Car2 c);

See also MSDN
// Rename the MessageBoxW() function to 'DisplayMessage'.
[DllImport("user32.dll",
ExactSpelling = true,
CharSet = CharSet.Unicode,
EntryPoint = "MessageBoxW")]
public static extern int DisplayMessage(int hwnd, string text,
string caption, int type);

Renaming Method
// Note that we pass an invalid window handle
// to MessageBox  error
PInvokeWrapper.DisplayMessage(999, "Hello World!", "Greeting",
0);
Console.WriteLine("Last Win32 Error: {0}",
Marshal.GetLastWin32Error());
Console.WriteLine(new Win32Exception(
Marshal.GetLastWin32Error()).Message);

Win32 Errors
LayoutKind




Necessary when marshalling structure

Note that you can marshal structures as C# structs or classes

LayoutKind.Sequential

Recommendation for structure marshalling
Order of the fields is preserved



LayoutKind.Explicit

Manually calculate the physical position of fields
Combined with FieldOffsetAttribute
Use FieldOffsetAttribute for implementing unions, too



LayoutKind.Auto

Not used for P/Invoke as C# compiler could change the order of the fields
using System.Runtime.InteropServices;
namespace Samples.PInvoke.IntroductionClient
{
[StructLayout(LayoutKind.Sequential)]
public class Car
{
public string Make;
public string Color;
}
// A structure containing another structure.
[StructLayout(LayoutKind.Sequential)]
public class Car2
{
public Car Car = new Car();
public string PetName;
}

}

StructLayout
// A Method returning an array of structs.
extern "C" PINVOKE_API void GiveMeThreeBasicCars(CAR** theCars)
{
auto numbOfCars = 3;
// Use CoTaskMemAlloc instead of new as .NET's P/Invoke uses
// CoTaskMemFree. See also http://blogs.msdn.com/b/dsvc/archive/2009/06/22/troubleshooting-pinvoke-related-issues.aspx
// and http://stackoverflow.com/questions/3614367/c-sharp-free-memory-allocated-by-operator-new-from-p-invoke-dll
// for details.
*theCars = (CAR*)CoTaskMemAlloc(numbOfCars * sizeof(CAR));
LPSTR carMakes[3] = { "BMW", "Ford", "Viper" };
LPSTR carColors[3] = { "Green", "Pink", "Red" };
auto pCurCar = *theCars;
for (int i = 0; i < numbOfCars; i++, pCurCar++)
{
pCurCar->color = carColors[i];
pCurCar->make = carMakes[i];
}
}

[DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void GiveMeThreeBasicCars(out IntPtr theCars);
public static IEnumerable<Car> GiveMeThreeBasicCarsHelper() {
const int size = 3;
var result = new List<Car>(size);
// Pass in an IntPtr as an output parameter.
IntPtr outArray;
PInvokeWrapper.GiveMeThreeBasicCars(out outArray);
try {
// Helper for iterating over array elements
IntPtr current = outArray;
for (int i = 0; i < size; i++) {
// Get next car using Marshal.PtrToStructure()
var car = Marshal.PtrToStructure<Car>(current);
result.Add(car);
// Calculate location of next structure using Marshal.SizeOf().
current = (IntPtr)((int)current + Marshal.SizeOf<Car>());
}
}
finally {
// Free memory for the allocated array.
Marshal.FreeCoTaskMem(outArray);
}
return result;
}

Marshal an Array
#include "stdafx.h"
// A class to be exported.
class PINVOKE_API CMiniVan
{
private:
int m_numbSeats;
public:
CMiniVan()
{
m_numbSeats = 9;
}
int GetNumberOfSeats()
{
return m_numbSeats;
}

};
// Functions for class
extern "C" PINVOKE_API
extern "C" PINVOKE_API
extern "C" PINVOKE_API

marshaling.
CMiniVan* CreateMiniVan();
void DeleteMiniVan(CMiniVan* obj);
int GetNumberOfSeats(CMiniVan* obj);

Marshalling Classes
// extern "C" PINVOKE_API CMiniVan* CreateMiniVan();
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateMiniVan();
// extern "C" PINVOKE_API void DeleteMiniVan(CMiniVan* obj);
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern void DeleteMiniVan(IntPtr miniVan);
// extern "C" PINVOKE_API int GetNumberOfSeats(CMiniVan* obj);
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern int GetNumberOfSeats(IntPtr miniVan);

var miniVan = PInvokeWrapper.CreateMiniVan();
try
{
Console.WriteLine(PInvokeWrapper.GetNumberOfSeats(miniVan));
}
finally
{
PInvokeWrapper.DeleteMiniVan(miniVan);
}

Marshalling Classes
typedef void (CALLBACK *SAYHELLOCALLBACK)();
extern "C" PINVOKE_API void CallMeBackToSayHello(
SAYHELLOCALLBACK callback);
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern void CallMeBackToSayHello(
Action callback);

Marshalling Callbacks
typedef struct
{
double a;
double b;
double c;
} TRIANGLE;
typedef void (CALLBACK *PYTHAGORASCALLBACK)(TRIANGLE result);
extern "C" PINVOKE_API void ReportPythagorasBack(
double a, double b, PYTHAGORASCALLBACK callback);

[StructLayout(LayoutKind.Sequential)]
public struct Triangle
{
public double a;
public double b;
public double c;
}
public delegate void TriangleCallback(Triangle t);
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern void ReportPythagorasBack(
double a, double b, TriangleCallback callback);

Marshalling Callbacks
Unsafe C#
Unsafe C#
 Use

unsafe keyword

Used with type or member
Unsafe code block

 Adds

pointer arithmetic to C#

Similar to C#

 Unsafe

does not mean less safe than normal C#

If you use IntPtr, you are not safer
In both scenarios, C# does not do any checks for buffer overruns

 You

can program P/Invoke without unsafe

Use IntPtr and methods of the Marshal class instead
type *identifier;
void *identifier;// Ptr to unknown type

int* pNumber;
int** ppNumber;
int*[] pArray;

// Ptr to a ptr to int
// Array of int*

int* pNumber
Console.WriteLine(*pNumber);
// Get value that pNumber points to

Pointers in C#
Supported types

sbyte, byte, short, ushort, int, uint,
long, ulong, char, float, double,
decimal, or bool.
Enums
Pointers
User-defined structs with
unmanaged types
namespace FixedSizeBuffers
{
internal unsafe struct MyBuffer
{
public fixed char fixedBuffer[128];
}
internal unsafe class MyClass
{
public MyBuffer myBuffer = default(MyBuffer);
}
internal class Program
{
static void Main()
{
MyClass myC = new MyClass();
unsafe
{
// Pin the buffer to a fixed location in memory.
fixed (char* charPtr = myC.myBuffer.fixedBuffer)
{
*charPtr = 'A';
}
}
}
}
}

Fixed size buffers
Buffer with fixed size

Typically used inside a struct

Supported data types

bool, byte, char, short, int, long,
sbyte, ushort, uint, ulong, float,
or double
Marshalling Details
Tipps & Tricks
 BOOL

can be marshalled to System.Int32 or bool

Marshalling to bool is a little bit slower but convenient
See MSDN for details

 InAttribute

and OutAttribute

By default, direction attribute for non-blittable types is In (performance reasons)
Best practice: Specify [In, Out] for input and output parameters (even for blittable types)
Exception: StringBuilder (In, Out by default)
See also sample in MSDN
Memory Management
 Marshaler

always attempts to free memory allocated by
unmanaged code

Use IntPtr to prevent this

 Memory

is always freed using CoTaskMemFree

Library has to provide a dedicated free method if allocated differently

 See

MSDN for details about copying/pinning

See MSDN for details
String Marshalling
 System.String

for constant strings

LPCSTR, LPCWSTR, etc.

 System.Text.StringBuilder

for string buffers that can change

LPSTR, LPWSTR, etc.
Always initialize size of the StringBuilder (constructor, Capacity property)
StringBuilder are guaranteed to have a terminating null character

 Use

IntPtr and Marshal.PtrToStringXXX if caller should not
free the memory
String Marshalling
 Use

[MarshalAs(UnmanagedType.ByValXXX,
SizeConst=XXX)] for fixed size char buffers

 See

MSDN for details
public
{
//
//
//

static class StringIntPtrHandling
Note that GetPrivateProfileSectionNames returns a string with embedded NULL characters.
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724352(v=vs.85).aspx
for details.

[DllImport("kernel32.dll")]
static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, int nSize, string lpFileName);
public static void ExecuteSample()
{
IntPtr ptr = IntPtr.Zero;
string s = string.Empty;
try
{
// Allocate a buffer in unmanaged memory
ptr = Marshal.AllocHGlobal(1024);
// Call Kernel API
var numChars = GetPrivateProfileSectionNames(
ptr,
1024,
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Sample.ini"));
// Copy the buffer into a managed string
s = Marshal.PtrToStringAnsi(ptr, numChars - 1);
}
finally
{
// Free the unmanaged buffer
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
}
}
// Display the sections by splitting the string based on NULL characters
foreach (var section in s.Split('0'))
{
Console.WriteLine(section);
}

}
}

Strings and IntPtr
typedef struct
{
// Note that this structure contains an array of characters
char make[256];
char color[256];
} CARFIXED;
extern "C" PINVOKE_API void FillThreeBasicCars(CARFIXED* theCars);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CarStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Make;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Color;
}
[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void FillThreeBasicCars(
[In, Out, MarshalAs(UnmanagedType.LPArray)] CarStruct[] theCars);

Marshalling Arrays
extern "C" PINVOKE_API void GiveMeMakes(BSTR** makes, int *length);

[DllImport("PInvokeIntroduction.dll",
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void GiveMeMakes(
[Out, MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.BStr,
SizeParamIndex = 1)] out string[] makes,
[Out] out int length);

Marshalling Arrays
Training Material

Rainer Stropek
software architects gmbh

Q&A

Mail rainer@timecockpit.com
Web http://www.timecockpit.com
Twitter @rstropek

Thank your for coming!
Saves the day.
is the leading time tracking solution for knowledge workers.
Graphical time tracking calendar, automatic tracking of your work using
signal trackers, high level of extensibility and customizability, full support to
work offline, and SaaS deployment model make it the optimal choice
especially in the IT consulting business.
Try
for free and without any risk. You can get your trial account
at http://www.timecockpit.com. After the trial period you can use
for only 0,20€ per user and day without a minimal subscription time and
without a minimal number of users.
ist die führende Projektzeiterfassung für Knowledge Worker.
Grafischer Zeitbuchungskalender, automatische Tätigkeitsaufzeichnung über
Signal Tracker, umfassende Erweiterbarkeit und Anpassbarkeit, volle
Offlinefähigkeit und einfachste Verwendung durch SaaS machen es zur
Optimalen Lösung auch speziell im IT-Umfeld.
Probieren Sie
kostenlos und ohne Risiko einfach aus. Einen
Testzugang erhalten Sie unter http://www.timecockpit.com. Danach nutzen
Sie
um nur 0,20€ pro Benutzer und Tag ohne Mindestdauer
und ohne Mindestbenutzeranzahl.

More Related Content

PPT
01 dll basics
PDF
[C++ Korea] Effective Modern C++ Study, Item 11 - 13
PDF
Insecure coding in C (and C++)
PDF
Part II: LLVM Intermediate Representation
PDF
Debugging and Profiling C++ Template Metaprograms
PPTX
Lesson 7 io statements
PPTX
Programming Fundamentals lecture 5
PPT
Constructor,destructors cpp
01 dll basics
[C++ Korea] Effective Modern C++ Study, Item 11 - 13
Insecure coding in C (and C++)
Part II: LLVM Intermediate Representation
Debugging and Profiling C++ Template Metaprograms
Lesson 7 io statements
Programming Fundamentals lecture 5
Constructor,destructors cpp

What's hot (20)

PPT
Managed Compiler
PDF
Cling the llvm based interpreter
PPT
C Language Unit-1
PDF
Plsql pdf
PDF
Oop Presentation
PPS
Aae oop xp_07
PPTX
Project Roslyn: Exposing the C# and VB compiler’s code analysis
PPT
Handling Exceptions In C &amp; C++ [Part B] Ver 2
PDF
(7) cpp abstractions inheritance_part_ii
PPTX
Adding Love to an API (or How to Expose C++ in Unity)
PPTX
SoCal Code Camp 2015: An introduction to Java 8
PPT
C tutorial
PDF
Aptitute question papers in c
PPTX
Review: Apitrace and Vogl
PDF
Checking the Source Code of FlashDevelop with PVS-Studio
PDF
Handling inline assembly in Clang and LLVM
PDF
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
PDF
HKG15-207: Advanced Toolchain Usage Part 3
PDF
How to capture a variable in C# and not to shoot yourself in the foot
PDF
Top 10 bugs in C++ open source projects, checked in 2016
Managed Compiler
Cling the llvm based interpreter
C Language Unit-1
Plsql pdf
Oop Presentation
Aae oop xp_07
Project Roslyn: Exposing the C# and VB compiler’s code analysis
Handling Exceptions In C &amp; C++ [Part B] Ver 2
(7) cpp abstractions inheritance_part_ii
Adding Love to an API (or How to Expose C++ in Unity)
SoCal Code Camp 2015: An introduction to Java 8
C tutorial
Aptitute question papers in c
Review: Apitrace and Vogl
Checking the Source Code of FlashDevelop with PVS-Studio
Handling inline assembly in Clang and LLVM
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
HKG15-207: Advanced Toolchain Usage Part 3
How to capture a variable in C# and not to shoot yourself in the foot
Top 10 bugs in C++ open source projects, checked in 2016
Ad

Viewers also liked (14)

PPTX
WPF and Prism 4.1 Workshop at BASTA Austria
PPTX
Parallel and Async Programming With C#
PPTX
Agile and Scrum Workshop
PPTX
Whats New in Visual Studio 2012 for C++ Developers
PPTX
Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...
PPTX
SaaS, Multi-Tenancy and Cloud Computing
PPTX
The CoFX Data Model
PPTX
Business Model Evolution - Why The Journey To SaaS Makes Sense
PPTX
Programming With WinRT And Windows8
PPT
Michael Kiener Associates Ltd
PPT
Vertaalbureau Perfect
PPTX
Telerik Kendo UI vs. AngularJS
PPS
Sculptura in coaja de ou
PPTX
Cloud computing was bringt's
WPF and Prism 4.1 Workshop at BASTA Austria
Parallel and Async Programming With C#
Agile and Scrum Workshop
Whats New in Visual Studio 2012 for C++ Developers
Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...
SaaS, Multi-Tenancy and Cloud Computing
The CoFX Data Model
Business Model Evolution - Why The Journey To SaaS Makes Sense
Programming With WinRT And Windows8
Michael Kiener Associates Ltd
Vertaalbureau Perfect
Telerik Kendo UI vs. AngularJS
Sculptura in coaja de ou
Cloud computing was bringt's
Ad

Similar to P/Invoke - Interoperability of C++ and C# (20)

PPT
CFInterop
PPTX
Unmanged code InterOperability
PPT
MSMDC_CLI363
PDF
【Unite 2017 Tokyo】パフォーマンス向上のためのスクリプトのベストプラクティス
PDF
Binary art - Byte-ing the PE that fails you (extended offline version)
PDF
Unmanaged Parallelization via P/Invoke
DOCX
C# tutorial
PDF
Marshaling with C# Pocket Reference
PPTX
C++ idioms.pptx
PPTX
Keep Your Arms and Legs Inside the Platform
DOC
Csharp Hands On Lab Paul Yao
PPTX
Memory models in c#
PPT
Dot Net Framework
PPTX
Interoperation
PPTX
Visual programming
PDF
Redesigning FFI calls in Pharo: Exploiting the baseline JIT for more performa...
PPTX
Back-2-Basics: .NET Coding Standards For The Real World
PPTX
Back-2-Basics: .NET Coding Standards For The Real World
PDF
【Unite 2017 Tokyo】パフォーマンス向上のためのスクリプトのベストプラクティス(note付き)
PDF
Strategies to improve embedded Linux application performance beyond ordinary ...
CFInterop
Unmanged code InterOperability
MSMDC_CLI363
【Unite 2017 Tokyo】パフォーマンス向上のためのスクリプトのベストプラクティス
Binary art - Byte-ing the PE that fails you (extended offline version)
Unmanaged Parallelization via P/Invoke
C# tutorial
Marshaling with C# Pocket Reference
C++ idioms.pptx
Keep Your Arms and Legs Inside the Platform
Csharp Hands On Lab Paul Yao
Memory models in c#
Dot Net Framework
Interoperation
Visual programming
Redesigning FFI calls in Pharo: Exploiting the baseline JIT for more performa...
Back-2-Basics: .NET Coding Standards For The Real World
Back-2-Basics: .NET Coding Standards For The Real World
【Unite 2017 Tokyo】パフォーマンス向上のためのスクリプトのベストプラクティス(note付き)
Strategies to improve embedded Linux application performance beyond ordinary ...

Recently uploaded (20)

PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Empathic Computing: Creating Shared Understanding
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
KodekX | Application Modernization Development
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Encapsulation theory and applications.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Machine learning based COVID-19 study performance prediction
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
NewMind AI Weekly Chronicles - August'25 Week I
Reach Out and Touch Someone: Haptics and Empathic Computing
Empathic Computing: Creating Shared Understanding
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
KodekX | Application Modernization Development
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Encapsulation theory and applications.pdf
Electronic commerce courselecture one. Pdf
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Unlocking AI with Model Context Protocol (MCP)
Understanding_Digital_Forensics_Presentation.pptx
MYSQL Presentation for SQL database connectivity
Per capita expenditure prediction using model stacking based on satellite ima...
Network Security Unit 5.pdf for BCA BBA.
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Machine learning based COVID-19 study performance prediction

P/Invoke - Interoperability of C++ and C#

  • 1. Training Material Rainer Stropek software architects gmbh P/Invoke Web http://www.timecockpit.com Mail rainer@timecockpit.com Twitter @rstropek .NET Interop Saves the day.
  • 3. // The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the PINVOKE_EXPORTS // symbol defined on the command line. This symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // PINVOKE_EXPORTS functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef PINVOKE_EXPORTS #define PINVOKE_API __declspec(dllexport) #else #define PINVOKE_API __declspec(dllimport) #endif DLL Exports // Some quite simple functions to begin with extern "C" PINVOKE_API int AddNumbers(int x, int y); extern "C" PINVOKE_API int AddArray(int x[], int size); // A very simple DLL export. extern "C" PINVOKE_API int AddNumbers(int x, int y) { return x + y; } // A method taking an array. extern "C" PINVOKE_API int AddArray(int x[], int size) { auto ans = 0; for (int i = 0; i < size; i++) { ans += x[i]; } return ans; } See also MSDN
  • 4. dumpbin Get list of exports of an unmanaged DLL Parameters /imports /exports See MSDN for details
  • 5. Memory Handling  Native DLL should avoid allocating memory and expect the caller to free the memory  Use CoTaskMemAlloc instead of new Freed by Interop Marshaller of .NET automatically using CoTaskMemFree Can be freed manually using Marshal.FreeCoTaskMem  Native DLL could offer a function to free the memory See CMiniVan example (CreateMiniVan and DeleteMiniVan)
  • 8. Interop Basics  System.Runtime.InteropServices Namespace  System.Runtime.InteropServices.Marshal Important helper methods for working with unmanaged code class  System.Runtime.InteropServices.DllImportAttribute Import a method from an unmanaged DLL
  • 9. Data Type Mapping See also MSDN More detailed list can be found in Nathan, .NET and COM, 779ff Source: Troelsen, COM and .NET Interoperability
  • 12. DllImportAttribute  Calling convention  Character set  Entry point  Exact spelling  Error handling Can be used to rename functions Controls whether character set is used to look for entry point name SetLastError behavior
  • 13. Calling Conventions  See also MSDN article about calling conventions By default, VC++ uses _cdecl  P/Invoke behavior has changed in .NET 4 In .NET < 4 you could call a _cdecl function with __stdcall without any problems In .NET >= 4 you will get an exception in the debugger See also pInvokeStackImbalance and NetFx40_PInvokeStackResilience See also http://blogs.msdn.com/b/oldnewthing/archive/2004/01/08/48616.aspx
  • 14. // This works extern "C" PINVOKE_API int __stdcall AddNumbers(int x, int y); [DllImport("PInvokeIntroduction.dll")] public static extern int AddNumbers(int x, int y); // This works, too extern "C" PINVOKE_API int AddNumbers(int x, int y); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int AddNumbers(int x, int y); // Anything else will throw an exception in the debugger Calling Conventions
  • 15. Marshal Strings  Character sets Ansi Unicode Auto (depends on operating system type) None (obsolete)  Specify character set In DllImportAttribute In MarshalAsAttribute
  • 16. using System.Runtime.InteropServices; namespace Samples.PInvoke.IntroductionClient { [StructLayout(LayoutKind.Sequential)] public class Car { [MarshalAs(UnmanagedType.LPWStr)] public string Make; Character Sets [MarshalAs(UnmanagedType.LPWStr)] public string Color; } … } [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern void DisplayBetterCar(Car2 c); See also MSDN
  • 17. // Rename the MessageBoxW() function to 'DisplayMessage'. [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, EntryPoint = "MessageBoxW")] public static extern int DisplayMessage(int hwnd, string text, string caption, int type); Renaming Method
  • 18. // Note that we pass an invalid window handle // to MessageBox  error PInvokeWrapper.DisplayMessage(999, "Hello World!", "Greeting", 0); Console.WriteLine("Last Win32 Error: {0}", Marshal.GetLastWin32Error()); Console.WriteLine(new Win32Exception( Marshal.GetLastWin32Error()).Message); Win32 Errors
  • 19. LayoutKind   Necessary when marshalling structure Note that you can marshal structures as C# structs or classes LayoutKind.Sequential Recommendation for structure marshalling Order of the fields is preserved  LayoutKind.Explicit Manually calculate the physical position of fields Combined with FieldOffsetAttribute Use FieldOffsetAttribute for implementing unions, too  LayoutKind.Auto Not used for P/Invoke as C# compiler could change the order of the fields
  • 20. using System.Runtime.InteropServices; namespace Samples.PInvoke.IntroductionClient { [StructLayout(LayoutKind.Sequential)] public class Car { public string Make; public string Color; } // A structure containing another structure. [StructLayout(LayoutKind.Sequential)] public class Car2 { public Car Car = new Car(); public string PetName; } } StructLayout
  • 21. // A Method returning an array of structs. extern "C" PINVOKE_API void GiveMeThreeBasicCars(CAR** theCars) { auto numbOfCars = 3; // Use CoTaskMemAlloc instead of new as .NET's P/Invoke uses // CoTaskMemFree. See also http://blogs.msdn.com/b/dsvc/archive/2009/06/22/troubleshooting-pinvoke-related-issues.aspx // and http://stackoverflow.com/questions/3614367/c-sharp-free-memory-allocated-by-operator-new-from-p-invoke-dll // for details. *theCars = (CAR*)CoTaskMemAlloc(numbOfCars * sizeof(CAR)); LPSTR carMakes[3] = { "BMW", "Ford", "Viper" }; LPSTR carColors[3] = { "Green", "Pink", "Red" }; auto pCurCar = *theCars; for (int i = 0; i < numbOfCars; i++, pCurCar++) { pCurCar->color = carColors[i]; pCurCar->make = carMakes[i]; } } [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern void GiveMeThreeBasicCars(out IntPtr theCars); public static IEnumerable<Car> GiveMeThreeBasicCarsHelper() { const int size = 3; var result = new List<Car>(size); // Pass in an IntPtr as an output parameter. IntPtr outArray; PInvokeWrapper.GiveMeThreeBasicCars(out outArray); try { // Helper for iterating over array elements IntPtr current = outArray; for (int i = 0; i < size; i++) { // Get next car using Marshal.PtrToStructure() var car = Marshal.PtrToStructure<Car>(current); result.Add(car); // Calculate location of next structure using Marshal.SizeOf(). current = (IntPtr)((int)current + Marshal.SizeOf<Car>()); } } finally { // Free memory for the allocated array. Marshal.FreeCoTaskMem(outArray); } return result; } Marshal an Array
  • 22. #include "stdafx.h" // A class to be exported. class PINVOKE_API CMiniVan { private: int m_numbSeats; public: CMiniVan() { m_numbSeats = 9; } int GetNumberOfSeats() { return m_numbSeats; } }; // Functions for class extern "C" PINVOKE_API extern "C" PINVOKE_API extern "C" PINVOKE_API marshaling. CMiniVan* CreateMiniVan(); void DeleteMiniVan(CMiniVan* obj); int GetNumberOfSeats(CMiniVan* obj); Marshalling Classes
  • 23. // extern "C" PINVOKE_API CMiniVan* CreateMiniVan(); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr CreateMiniVan(); // extern "C" PINVOKE_API void DeleteMiniVan(CMiniVan* obj); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void DeleteMiniVan(IntPtr miniVan); // extern "C" PINVOKE_API int GetNumberOfSeats(CMiniVan* obj); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int GetNumberOfSeats(IntPtr miniVan); var miniVan = PInvokeWrapper.CreateMiniVan(); try { Console.WriteLine(PInvokeWrapper.GetNumberOfSeats(miniVan)); } finally { PInvokeWrapper.DeleteMiniVan(miniVan); } Marshalling Classes
  • 24. typedef void (CALLBACK *SAYHELLOCALLBACK)(); extern "C" PINVOKE_API void CallMeBackToSayHello( SAYHELLOCALLBACK callback); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void CallMeBackToSayHello( Action callback); Marshalling Callbacks
  • 25. typedef struct { double a; double b; double c; } TRIANGLE; typedef void (CALLBACK *PYTHAGORASCALLBACK)(TRIANGLE result); extern "C" PINVOKE_API void ReportPythagorasBack( double a, double b, PYTHAGORASCALLBACK callback); [StructLayout(LayoutKind.Sequential)] public struct Triangle { public double a; public double b; public double c; } public delegate void TriangleCallback(Triangle t); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void ReportPythagorasBack( double a, double b, TriangleCallback callback); Marshalling Callbacks
  • 27. Unsafe C#  Use unsafe keyword Used with type or member Unsafe code block  Adds pointer arithmetic to C# Similar to C#  Unsafe does not mean less safe than normal C# If you use IntPtr, you are not safer In both scenarios, C# does not do any checks for buffer overruns  You can program P/Invoke without unsafe Use IntPtr and methods of the Marshal class instead
  • 28. type *identifier; void *identifier;// Ptr to unknown type int* pNumber; int** ppNumber; int*[] pArray; // Ptr to a ptr to int // Array of int* int* pNumber Console.WriteLine(*pNumber); // Get value that pNumber points to Pointers in C# Supported types sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool. Enums Pointers User-defined structs with unmanaged types
  • 29. namespace FixedSizeBuffers { internal unsafe struct MyBuffer { public fixed char fixedBuffer[128]; } internal unsafe class MyClass { public MyBuffer myBuffer = default(MyBuffer); } internal class Program { static void Main() { MyClass myC = new MyClass(); unsafe { // Pin the buffer to a fixed location in memory. fixed (char* charPtr = myC.myBuffer.fixedBuffer) { *charPtr = 'A'; } } } } } Fixed size buffers Buffer with fixed size Typically used inside a struct Supported data types bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float, or double
  • 31. Tipps & Tricks  BOOL can be marshalled to System.Int32 or bool Marshalling to bool is a little bit slower but convenient See MSDN for details  InAttribute and OutAttribute By default, direction attribute for non-blittable types is In (performance reasons) Best practice: Specify [In, Out] for input and output parameters (even for blittable types) Exception: StringBuilder (In, Out by default) See also sample in MSDN
  • 32. Memory Management  Marshaler always attempts to free memory allocated by unmanaged code Use IntPtr to prevent this  Memory is always freed using CoTaskMemFree Library has to provide a dedicated free method if allocated differently  See MSDN for details about copying/pinning See MSDN for details
  • 33. String Marshalling  System.String for constant strings LPCSTR, LPCWSTR, etc.  System.Text.StringBuilder for string buffers that can change LPSTR, LPWSTR, etc. Always initialize size of the StringBuilder (constructor, Capacity property) StringBuilder are guaranteed to have a terminating null character  Use IntPtr and Marshal.PtrToStringXXX if caller should not free the memory
  • 34. String Marshalling  Use [MarshalAs(UnmanagedType.ByValXXX, SizeConst=XXX)] for fixed size char buffers  See MSDN for details
  • 35. public { // // // static class StringIntPtrHandling Note that GetPrivateProfileSectionNames returns a string with embedded NULL characters. See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724352(v=vs.85).aspx for details. [DllImport("kernel32.dll")] static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, int nSize, string lpFileName); public static void ExecuteSample() { IntPtr ptr = IntPtr.Zero; string s = string.Empty; try { // Allocate a buffer in unmanaged memory ptr = Marshal.AllocHGlobal(1024); // Call Kernel API var numChars = GetPrivateProfileSectionNames( ptr, 1024, Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Sample.ini")); // Copy the buffer into a managed string s = Marshal.PtrToStringAnsi(ptr, numChars - 1); } finally { // Free the unmanaged buffer if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } } // Display the sections by splitting the string based on NULL characters foreach (var section in s.Split('0')) { Console.WriteLine(section); } } } Strings and IntPtr
  • 36. typedef struct { // Note that this structure contains an array of characters char make[256]; char color[256]; } CARFIXED; extern "C" PINVOKE_API void FillThreeBasicCars(CARFIXED* theCars); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct CarStruct { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string Make; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string Color; } [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern void FillThreeBasicCars( [In, Out, MarshalAs(UnmanagedType.LPArray)] CarStruct[] theCars); Marshalling Arrays
  • 37. extern "C" PINVOKE_API void GiveMeMakes(BSTR** makes, int *length); [DllImport("PInvokeIntroduction.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern void GiveMeMakes( [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.BStr, SizeParamIndex = 1)] out string[] makes, [Out] out int length); Marshalling Arrays
  • 38. Training Material Rainer Stropek software architects gmbh Q&A Mail rainer@timecockpit.com Web http://www.timecockpit.com Twitter @rstropek Thank your for coming! Saves the day.
  • 39. is the leading time tracking solution for knowledge workers. Graphical time tracking calendar, automatic tracking of your work using signal trackers, high level of extensibility and customizability, full support to work offline, and SaaS deployment model make it the optimal choice especially in the IT consulting business. Try for free and without any risk. You can get your trial account at http://www.timecockpit.com. After the trial period you can use for only 0,20€ per user and day without a minimal subscription time and without a minimal number of users.
  • 40. ist die führende Projektzeiterfassung für Knowledge Worker. Grafischer Zeitbuchungskalender, automatische Tätigkeitsaufzeichnung über Signal Tracker, umfassende Erweiterbarkeit und Anpassbarkeit, volle Offlinefähigkeit und einfachste Verwendung durch SaaS machen es zur Optimalen Lösung auch speziell im IT-Umfeld. Probieren Sie kostenlos und ohne Risiko einfach aus. Einen Testzugang erhalten Sie unter http://www.timecockpit.com. Danach nutzen Sie um nur 0,20€ pro Benutzer und Tag ohne Mindestdauer und ohne Mindestbenutzeranzahl.