Sunteți pe pagina 1din 22

C# 30

Unsafe Code and Interoperability 1

C# 3.0
Chapter 22 Unsafe Code and
Interoperability

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 2

Interoperability Introduction
Interoperabilit
Interoperability is the ability
abilit to have
ha e
g code and unmanaged
g code work
managed
together in one application
Managed code is code that requires the execution
environment of the Common Language Runtime
Unmanaged
U
d code
d iis code
d th
thatt d
does nott need
d th
the CLR
Unmanaged code is outside the reach of the CLRs
management services

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 3

.NET
NET Interoperability Options
The .NET
NET pro
provides
ides uss with
ith three main
p
y options:
p
interoperability
Calling C DLL functions from a .NET component
This service is termed Platform
Platform Invoke
Invoke

Interoperability with COM objects


A .NET
NET program invokes methods on a COM object
A non-.NET program invokes methods on a .NET
object as if it were a COM object

Mixing managed and unmanaged code using the C++


.NET
NET version: C++/CLI

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 4

.NET
NET Interoperability Services
The core interoperability services are
performed by the CLR
The .NET framework provides us with several
Interoperability APIs (attributes and helper classes)
System.Runtime.InteropServices
i
i

In this course we will see how to use the


Platform Invoke (P/Invoke) mechanism
COM Interop and C++/CLI
C /CLI are out of the
scope of this course
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 5

Using Pointers Within C# Code


Before getting into the interoperabilit
interoperability
j
subjects:
We will examine pointers within C# code
Pointers may be useful through interoperability
operations, and may improve performance

C# provides
id references
f
References lead to safe code
They are guaranteed to refer to valid objects

Pointers are not safe

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 6

Using Pointers Within C# Code


Pointers are defined with the familiar C
syntax
Pointers may refer to any address in memory
C# allows pointers to be defined only in an unsafe
context
Such a context is declared by using the unsafe
kkeyword
d
publicunsafe voidfunc(int x)
{
int* px =&x;
}

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 7

Using Pointers Within C# Code


Almost anything can be marked as unsafe:
An entire type (class, struct, interface or delegate)
A specific member (field, method, property, event,
indexer, operator, constructor, static constructor, or
finalizer)
A code block can be declared as unsafe

Th
The code
d will
ill only
l compile
il if th
the /unsafe
/
f
compiler
option
is specified
p
p
p

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 8

What Can Pointers Point To?


Pointers can only point to blittable types

Primitive types
Value types with no references (recursively)
Pointer Types (i.e., pointer to a pointer)
void *

You can take the address of a field within


an object or an array element
publicstaticunsafevoidfunc(int[]a)
{
i t* //Thi d
NOT
il !
int*pa=a;//ThisdoesNOTcompile!
}

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 9

The fixed Statement


To take the address of a moveable object,
object
you must use fixed
The fixedstatement does two things:
Enables the assignment of the address of a moveable
variable to a pointer
Declares a block of code in which the CLR
guarantees not to move the moveable variable
The variable is considered to be pinned in memory
publicstaticunsafevoidfunc(int[]a){
fixed (int*pa=a)
(
p
)
{
*pa=17;//ThisDOEScompile!
}
}
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 10

fixed Additional Notes


You can initialize more than one pointer in
a single fixed statement
If they are of the same type
Otherwise, fixed statements must be nested
int[]b=newint[3];strings="Hello";
fixed(int*
ed ( t pa
pa=a,pb
a, pb =b)
b) {
*pa=17;
*pb =18;
//Lik C dC
//LikeCandC++,assigningaString,noneedfor'&'

i i St i

df '&'
fixed(char*ps =s)
{
*ps ='Y';//Donttrythisathome!
}
}
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 11

Platform Invoke

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 12

Platform Invoke
Consider the following C function which
tests whether a number is prime:
int IsPrime(int num);

This function returns a non-zero value to indicate true,


and zero (0) to indicate false

Can this function be called from C#?


Yes! See the code on the next slide

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 13

Calling IsPrime from C#


usingSystem.Runtime.InteropServices;
usingSystem
Runtime InteropServices;
publicclassTest{
[
p
(
)]
[DllImport("GoodOldCFunctions.dll")]
publicstaticexternbool IsPrime(int num);
}
classProgram{
staticvoidMain(string[]args){
Console.WriteLine("Primenumbers:");
(
);
for(int i =0;i <100;++i){
if(Test.IsPrime(i))
Console Write("{0} " i);
Console.Write("{0},",i);
}
}
}
}

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 14

The [DllImport] Attribute


The [DllImport] attribute comes from
System.Runtime.InteropServices
This attribute tells the runtime where to
find the external method
Specifically, it is used to dynamically link to a function
implemented in a Dynamic Link Library (DLL)

It has a single constructor


Which takes a single string parameter indicating the
name of the DLL

It has several optional (named)


parameters
p
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 15

Behind the Scenes


At runtime,
r ntime the DLL is loaded into memory
memor
If it is not found, an exception will be thrown

An entry point with the name of the


function is located within the DLL
If this is not found, a different exception will be thrown

C# parameters are converted to match


standard C conventions
The function is called and its return value
is converted back
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 16

Marshaling Data Types


The .NET
NET pro
provided
ided arg
arguments
ments should
sho ld be
p
marshaled to the C function parameters
The C function return value should be marshaled to
the .NET calling function

Understanding the marshaling principles is


essential for
f using interoperability
Based on the C function signature
g
and the
interoperability marshaling rules we can correctly
create the appropriate
pp p
C# function declaration
Use pinvoke.net or the P/Invoke Interop Assistant

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 17

P/Invoke Interop Assistant


Open
Open-source
so rce Microsoft tool for generating
g
P/Invoke signatures
Has a database of Windows API functions
Can parse a C/C++ header file
Download from: http://www.codeplex.com/clrinterop

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 18

Isomorphic and Non-isomorphic


Some C# ttypes
pes are implemented in the
y that C implements
p
them
same way
For example, int in C# (System.Int32) is
implemented
p e e ted in the
t e same
sa e way
ay as a native
at e C int
t
Such a type is known as Isomorphic or Blittable
No conversion is necessary when passed into a C function

Other types are not implemented in the


same way as in C
bool (System.Boolean) or string (System.String)
These are known as Non-isomorphic or Non-blittable
types
yp
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 19

Type Mappings
C#
Type

Framework Name Isomorphic Matching C Type

float

System.Single

Yes

float

double System.Double

Yes

double

sbyte

System.SByte

Yes

signedchar

byte

System.Byte

Yes

unsignedchar

short

System.Int16

Yes

short

ushort System.UInt16

Yes

unsignedshort

int

System.Int32

Yes

int

uint

y
System.UInt32

Yes

unsignedint
g

long

System.Int64

Yes

__int64

ulong

System.UInt64

Yes

unsigned
int64
unsigned__int64

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 20

Type Mappings
C# T
Type

Framework
F
k
Name

I
Isomorphic
hi Matching
M t hi C Type
T

bool

System Boolean
System.Boolean

No

int

char

System.Char

No

char or wchar_t

string

System Boolean
System.Boolean

No

char* or
wchar_t* (or BSTR
for COM))

object

System.Object

No

VARIANT (COM
interoperability
only)

1D-array of
i
isomorphic
hi

Yes

Array of equivalent
i
isomorphic
hi

Other arrays

No

Interface or
SAFEARRAY (COM)

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 21

String Conversions
Converting simple non
non-isomorphic
isomorphic types
like bool is an easy task for the runtime
There is a one-to-one mapping between these types

Converting a string is more complicated


.NET strings are implemented as a set of Unicode
characters
Strings in C are usually implemented as
char* ((ANSI strings)
g ) or wchar_t* ((Unicode)) strings
g

The default is to assume that C expects ANSI strings


Thus
Thus, by default C# strings undergo a conversion
conversion, before
being passed

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 22

String Example
Consider the following
follo ing C ffunction
nction which
hich
counts the number of digits
g in a string:
g
int CountDigits(char*text);

The
Th corresponding
di C# d
declaration
l ti iis:
[
[DllImport("GoodOldCFunctions.dll")]
p
(
)]
publicstaticexternint CountDigits(stringtext);

What
Wh t should
h ld we do
d if the
th C function
f
ti
p
Unicode characters?
expected

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 23

DllImportAttribute Fields
The DllImportAttribute
DllImportAttrib te class has
properties
p
which can be used to
some p
override the default behavior
The property CharSet can be used to indicate how
strings should be passed
The
Th legal
l
l values
l
ffor thi
this property
t come from
f
the
th
CharSet enumeration which contains:
Ansi
A i (default)
(d f lt)
Unicode
Auto

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 24

Using CharSet
ti expects
t aU
i d string:
ti
Thi
This C ffunction
Unicode
int IsTextAllInGreek(wchar_t*text);

The corresponding C# declaration is:


[DllImport(OldCFunctions.dll",CharSet=CharSet.Unicode)]
publicstaticexternbool IsTextAllInGreek(stringtext);

This causes the runtime to pass the C# string


as a Unicode string to the C function

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 25

The MarshalAs Attribute


Usually the CharSet field of the
p
attribute is enough
g to cause
DllImport
strings to be converted correctly
Sometimes when you need more specific control
control, the
MarshalAs attribute can be handy
For example
example, what would you do if one parameter needs to
be an ANSI string and another a Unicode string?
[DllImport("GoodOldCFunctions.dll")]
[
ll
("
d ld
i
dll")]
publicstaticexternbool IsTextAllInGreek(
[MarshalAs(UnmanagedType LPWStr)] stringtext);
[MarshalAs(UnmanagedType.LPWStr)]

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 26

Calling API Functions


To call the ffunction
nction Beep exported
e ported b
by
Kernel32.dll, you
y would simply
p y declare:

[DllImport(kernel32.dll")]
publicstaticexternint Beep(uint
p
p(
freq,uint
q,
duration);
);

For API functions that accept string


parameters, the considerations outlined
earlier are relevant
However, an additional consideration must be taken
into account

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 27

The API A
A and W
W Suffix
All Win32 API functions
f nctions that contain string
parameters are exported
p
p
as two versions
MessageBox is a macro that becomes:
MessageBoxA for ANSI applications
MessageBoxW for Unicode applications

In C/C++, a call to MessageBox is


converted to one of the above by the pre
preprocessor based on the presence of a
UNICODE pre-processor definition
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 28

Choosing Between A
A and W
W
When declaring such a function in C#
C#,
name
we are allowed to use the generic
g

publicstaticexternint MessageBox(
uint hwnd,stringtext,stringcaption,uint type);

P/Invoke will call either MessageBoxA or


MessageBoxW based on this logic:
DllImport CharSet value Function called
MessageBoxA
CharSet.Ansi (default)
CharSet.Unicode

MessageBoxW

CharSet.Auto

Platform Dependent
p

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 29

Attention
On a Unicode based platform:
platform
The Unicode string gets converted to an ANSI string
This is passed to MessageBoxA which in turn calls
g
MessageBoxExA
MessageBoxExA converts the ANSI string into a
Unicode string
g and p
passed to MessageBoxExW
g

A bit wasteful, dont you think?

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 30

Solution
A better approach would
o ld be to use
se the
CharSet.Auto setting:
g
[DllImport("User32.Dll",CharSet=CharSet.Auto)]
publicstaticexternint MessageBox(
uint hwnd,stringtext,stringcaption,uint type);

On a Unicode based platform:


The C# Unicode string gets passed directly to
MessageBoxW which
hi h iin tturn calls
ll MessageBoxExW

That
Thats
s it. The string is never converted
CharSet.Auto is a good choice for Win32 API

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 31

Other [DllImport] Properties


E
ExactSpelling
tS lli

If sett tto t
true, no attempt
tt
t will
ill be
b
made to add A or W when
looking for the name
name.
The default is false.

EntryPoint

Specifies the name of the exported


function in the DLL. This allows the
C# class to declare the function
with a different name.
The default is to use the given
name.

CallingConvention Specifies the calling convention.


The default is StdCall
StdCall.
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 32

Marshaling Structures
In C/C++
Structure and classes physical field layout is
determined by field order

In C#
Structure field layout is the same as in C/C++
Class
C
layout is determined by the compiler to gain
better performance and memory usage

To control C# physical fields layout


Use the StructLayout attribute
LayoutKind.Sequential is the C/C++ layout

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 33

Marshaling Structures
An API Example
BOOLPtInRect(
CONSTRECT*lprc,//ApointertoaRECTstruct
POINTpt//APOINTstruct
//
);

The structures RECT and POINT are defined by the


API as follows:
typedef struct {
longleft;longtop;longright;longbottom;
}RECT;
typedef
yp
struct {
longx;longy;
}POINT;
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 34

Marshaling Structures
[StructLayout(LayoutKind.Sequential)]//Notreallyneeded
publicstruct Point {
publicint x;
publicint y;
}
[StructLayout(LayoutKind.Sequential)]//Notreallyneeded
publicstruct Rect {
publicint left;
publicint top;
publicint right;
publicint bottom;
}
[DllImport("User32
dll")]
[DllImport(
User32.dll
)]
publicstaticexternbool PtInRect(
refRect rect,Pointpoint);
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 35

Marshaling Classes
[StructLayout(LayoutKind.Sequential)]//Notreallyneeded
publicstruct Point {
publicint x;
publicint y;
}
[StructLayout(LayoutKind.Sequential)]//Amust
publicclassRect {
publicint left;
publicint top;
publicint right;
publicint bottom;
}
[DllImport("User32
dll")]//Rect
[DllImport(
User32.dll
)]//Rect isareferencetype
publicstaticexternbool PtInRect(Rect rect,Pointpoint);

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 36

Using ref
ref and out
out
//extern"C"voidStatistics(doublenums[],int count,
//double*pmean,double*pstddev);
publicclassTest{
[DllImport("GoodOldCFunctions.dll")]
publicstaticexternvoidStatistics(double[]nums,
i t count,outdoublemean,outdoublestddev);
int
t td bl
td bl tdd )
}

double[]nums ={34.5,2.0,78.111,5,0.001};
doublemean;//Themean(average)
doublestddev;//Thestandarddeviation
Test.Statistics(nums,5,outmean,outstddev);
Console.WriteLine("Mean:{0}StandardDeviation:{1}",
mean,stddev);
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 37

Using C# Pointers
//extern"C"voidStatistics(doublenums[],int count,
//
double*pmean,double*pstddev);
publicclassTest{
[DllImport("GoodOldCFunctions.dll")]
publicstaticexternunsafevoidStatistics(double*nums,
i t count,outdoublemean,outdoublestddev);
int
t td bl
td bl tdd )
}
unsafe{
fixed(double*pnums =nums)
{
Test.Statistics(pnums,5,outmean,outstddev);
Console.WriteLine("Mean:{0}Deviation:{1},
(
{ }
{ } ,
mean,stddev);
}
}
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 38

Retrieving Strings
Many C functions return strings as output
They normally do this by having the caller pass in an
uninitialized buffer of characters to be filled by the
function itself
As a safety measure
measure, the caller is usually required to
pass in the length of the buffer

Consider this Win32 API:


DWORDGetModuleFileName(
(
HMODULEhModule,//handletomodule
LPTSTRlpFilename,//filenameofmodule
DWORDnSize
//sizeofbuffer
);

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 39

Retrieving Strings
Ho
How would
o ld ssuch
ch a ffunction
nction be called from
C#?
This turns out to be a special case since marshaling
is required between string types and the string is
being returned
Using a simple string variable wont
won t work,
work because it
is an immutable object

The way
a to handle ssuch
ch sit
situations
ations is b
by
g an object
j
of type
yp StringBuilder
g
using
P/Invoke handles StringBuilder objects in a
special way specifically for this purpose
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 40

Retrieving Strings
publicclassTest{
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
publicstaticexternuint GetModuleFileName(
uint hModule,StringBuilder filename,int nSize);
}
//
g
g
(
);
StringBuilder
filename=newStringBuilder(500);
Test.GetModuleFileName(0,filename,filename.Capacity);
Console.WriteLine(
"Thefilenameofthecurrentmoduleis:{0}",
filename);

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 41

Chapter 22 Exercise 1

CALLING A DLL FUNCTION

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 42

Chapter 22 Exercise 2

CALLING WIN32 API

Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

C# 30

Unsafe Code and Interoperability 43

Chapter Summary
C# can use pointers if the assembly is
marked as unsafe
Use the fixed keyword to get a pointer
P/Invoke lets us call unmanaged functions
from any .NET managed language
P/Invoke knows to marshal parameters
There are times that we will give P/Invoke some hints
To help it understand the correct prototype
To gain
g
performance
p

These hints are passed using the [DllImport]


attribute options or the [MarshalAs] attribute
Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel

S-ar putea să vă placă și