Win32 API: C++ to .NET






3.77/5 (40 votes)
Mar 1, 2005
12 min read

406130
This is a conversion sheet to go from C++ API calls to .NET P/Invoke. It includes data type conversions and tips.
Introduction
I am writing an article to give a reference to developers who need to use API imports in their .NET programs to call C++ functions. I haven't found a single site that looks good or is totally complete with all the data types or has them converted correctly. So, I decided to write one. I also recommend using any new .NET function that does the same thing as an API if it is available. At least 75% of the API has already been converted to .NET and is available in various classes. This is because they usually work better and look nicer. If you have any questions send me an email or post them to the message board.
.NET API declaration form
VB.NET
Declare Function <Name> Lib <dll name> <Optional fields> (<params>) _
As <return type>
C# definition
[DllImport("<dll name>", <optional fields>)]
static extern <return type> <Method name> (<Params>)
Managed C++ .NET
[DllImport("<Dll name>",<optional fields>)]
static <return type> <Function name>( <Params>);
Examples
Windows API reference for C#, VB.NET & VB6 - This site has every major API declaration for VB.NET, C#.NET and some VB6.
Here is a program I have made that uses these sites:
VB.NET
Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA"(_
ByVal dwFlags As Integer, ByRef lpSource As Object, _
ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, _
ByVal lpBuffer As String, ByVal nSize As Integer, _
ByRef Arguments As Integer) As Integer
C# definition
[DllImport("kernel32.dll", SetLastError=true)]
static extern int FormatMessageA ( int dwFlags, ref object lpSource,
int dwMessageId, int dwLanguageId, string lpBuffer,
int nSize, ref int Arguments)
Managed C++. NET
[DllImport("KERNEL32.DLL",EntryPoint="MoveFileW",
SetLastError=true,CharSet=CharSet::Unicode,ExactSpelling=true,
CallingConvention=CallingConvention::StdCall)]
static bool MoveFile( String^ src, String^ dst );
Tips
- In this list, a pointer to a data type is represented like P, for example
DWORD* = PDWORD
. - Some types like
UIntPtr
are not CLS compliant so I useIntPtr
instead, but you can use any of these. - The first choice that comes up after the "=" in the IDE’s Intellisense is the best choice usually.
- When using strings in COM Interop, for inputs you always use
string
forWCHAR*
,TCHAR*
, etc. For outputs you can usestring
orStringBuilder
, but sometimes you need to use anIntPtr
and marshal the characters out of it usingMarshal.PtrToStructure()
and increment the pointer till you getnull
characters. To increment a pointer turn it into anint
and increase the size each time by the size of the type you get fromMarshal.PtrToStructure()
each time. E.g. :pointer += Marshal.SizeOf(<last object you got back>);
- Sometimes certain data types that aren't correct will work. E.g.: An
int
could be used for auint
. - If you need to convert an
IntPtr
back to anint
or some other class, useMarshal.PtrToStructure()
or some otherIntPtr
method. - If the API your using is dependent on ANSI or Unicode, make sure you select the correct one so that your strings will be formatted correctly. Look at the CharSet enumeration.
- Most of the API calls can be written in a managed declaration, but some need pointers, in C# you can use pointers if you surround the code with the
unsafe
keyword and use the/unsafe
compiler option. - If you want to make sure that the garbage collector doesn't eat your
IntPtr
in an API call you can use aHandleRef
type. - When you need to declare
struct
s for API, make sure they have theStructLayout.Sequential
attribute. Also sometimes you may need to change the packing on astruct
to make it work right, but usually you don't. - When passing or retrieving arrays to/from API methods, look if it's a pointer to an array or a direct input array, if it's a pointer you need to marshal it to an
IntPtr
possibly. - Sometimes choosing the type to use can be hard but you'll get the hang of it after a few times.
- When I show the types to use for pointers to data types I say
IntPtr
or the data type it points to, sometimes you can just sayref <datatype>
orout <datatype>
, but unless it's an inputchar *
you need to useIntPr
for inputs andref IntPtr
for outputs. - If your function declaration fails to work don't always blame it on the way you wrote declaration, it may be a call to the previous methods that messed it up, or just a bad data getting passed in.
- Use the
Marshal
andMarshalAs
classes only when you have to, as they take up more processing power in certain situations.
Data type conversion sheet : C++ to .NET
Term |
Description |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
|
|
.NET =
|
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ =
|
|
.NET = C++ =
|
|
.NET = C++ = |
|
.NET =
C++ =
C++ = |
|
.NET =
C++ =
C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET = C++ = |
|
.NET =
|
|
.NET = C++ = |
|
.NET = standard is default, look at the
|
|
.NET = C++ = |
|
.NET = C++ = |