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)

DOCX
Srgoc dotnet_new
DOCX
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
DOCX
C# Unit 2 notes
DOCX
PDF
DLL Design with Building Blocks
DOCX
Srgoc dotnet
PDF
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
PPTX
CSharp Presentation
PPT
data Structure Lecture 1
PDF
Embedded C - Lecture 1
PPT
Csharp dot net
PDF
C Programming Tutorial - www.infomtec.com
PPTX
embeddedc-lecture1-160404055102.pptx
PDF
CP Handout#2
PDF
.NET for hackers
DOCX
C# tutorial
DOC
Csharp
PPT
01 Introduction to programming
PPTX
Object Oriented Programming with Object Orinted Concepts
PPTX
ppl unit 3.pptx ppl unit 3 usefull can understood
Srgoc dotnet_new
20145-5SumII_CSC407_assign1.htmlCSC 407 Computer Systems II.docx
C# Unit 2 notes
DLL Design with Building Blocks
Srgoc dotnet
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
CSharp Presentation
data Structure Lecture 1
Embedded C - Lecture 1
Csharp dot net
C Programming Tutorial - www.infomtec.com
embeddedc-lecture1-160404055102.pptx
CP Handout#2
.NET for hackers
C# tutorial
Csharp
01 Introduction to programming
Object Oriented Programming with Object Orinted Concepts
ppl unit 3.pptx ppl unit 3 usefull can understood

Recently uploaded (20)

PPTX
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
PPT
Geologic Time for studying geology for geologist
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
PDF
Enhancing plagiarism detection using data pre-processing and machine learning...
PPT
Galois Field Theory of Risk: A Perspective, Protocol, and Mathematical Backgr...
PDF
Flame analysis and combustion estimation using large language and vision assi...
PPTX
Custom Battery Pack Design Considerations for Performance and Safety
PDF
NewMind AI Weekly Chronicles – August ’25 Week III
PDF
UiPath Agentic Automation session 1: RPA to Agents
PPTX
Microsoft Excel 365/2024 Beginner's training
PDF
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
PDF
STKI Israel Market Study 2025 version august
PDF
Architecture types and enterprise applications.pdf
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PPTX
Chapter 5: Probability Theory and Statistics
PPTX
Modernising the Digital Integration Hub
PDF
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
PPTX
Final SEM Unit 1 for mit wpu at pune .pptx
PDF
The influence of sentiment analysis in enhancing early warning system model f...
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
Geologic Time for studying geology for geologist
1 - Historical Antecedents, Social Consideration.pdf
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
Enhancing plagiarism detection using data pre-processing and machine learning...
Galois Field Theory of Risk: A Perspective, Protocol, and Mathematical Backgr...
Flame analysis and combustion estimation using large language and vision assi...
Custom Battery Pack Design Considerations for Performance and Safety
NewMind AI Weekly Chronicles – August ’25 Week III
UiPath Agentic Automation session 1: RPA to Agents
Microsoft Excel 365/2024 Beginner's training
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
STKI Israel Market Study 2025 version august
Architecture types and enterprise applications.pdf
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
Chapter 5: Probability Theory and Statistics
Modernising the Digital Integration Hub
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
Final SEM Unit 1 for mit wpu at pune .pptx
The influence of sentiment analysis in enhancing early warning system model f...

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

  • 1. Training Material Rainer Stropek software architects gmbh P/Invoke Web http://www.timecockpit.com Mail [email protected] 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 [email protected] 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.