pinvoke

Upload: oren-cohen-shwartz

Post on 31-May-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/15/2019 pinvoke

    1/3

    Essential P/InvokeBy Cohen Shwartz Oren

    The article aims to shed some light on an irksome topic, in managed code, namedP/Invoke.Introduction

    The article aims to shed some light on an irksome topic, in managed code, namedP/Invoke. The article contains a useful table of how to translate managed to

    unmanaged types, short code examples (in C#), tips and a list of resources.

    You will not find here confound theoretical information about what P/Invoke is,but an essential knowledge. The article is by no means a complete guide and Iam not pretending to be an expert in this filed, only one with some experience.

    Lazy development

    Working in a managed environment like the .NET Framework is fun. With coolwrapper classes like Thread and Environment, our life becomes easy. But as soon

    as we start to feel lazy, the need for P/Invoke pops up (d-a-m-n!).

    In a nutshell, P/Invoke (Platform Invoke) is Microsoft's way to get lazy, by not

    having to wrap all the Win32 APIs. This leaves, us, developers with some work todo. For example if you feel the need to share an Event between two processes

    (event is a named kernel object) you will be surprised (or not) to know that C#does not include this feature. For that reason, and many more, you needP/Invoke.

    CreateEvent, Win API, as implemented in kernel32.dll:HANDLE CreateEvent(

    LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,

    BOOL bInitialState,LPCTSTR lpName

    );

    C# P/Invoke code:[DllImport("kernel32.dll, SetLastError=true ")]static extern IntPtr CreateEvent(IntPtr lpEventAttributes,

    bool bManualReset, bool bInitialState,

    [MarshalAs(UnmanagedType.LPStr) string lpName);

    As you can see you need to declare the exact prototype with the static keyword

    (the only way to simulate a global method in C#), the extern keyword (confess

    to the CLR that the method is not implemented in the assembly) and the

    DllImport attribute.

    Hmmm At this point you might think that this is not too bad, but, as you will

    soon witness, using P/Invoke can be a real pain.

    Everything might go just well till you face the need to call a complex API thatdazzles and puzzles you. "With what kinds oftypes should I declare theprototype? How to call the imported method? What to do when allocation isrequired? What to do with structures?"

    http://www.codeproject.com/script/profile/whos_who.asp?id=627547http://www.codeproject.com/script/profile/whos_who.asp?id=627547
  • 8/15/2019 pinvoke

    2/3

    For example, the CreateFileMapping method (implemented in the kernel32.dll):

    HANDLE CreateFileMapping(

    HANDLE hFile,LPSECURITY_ATTRIBUTES lpAttributes,DWORD flProtect,

    DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPCTSTR lpName

    );

    [DllImport("kernel32.dll", SetLastError=true)]

    static extern IntPtr CreateFileMapping(IntPtr hFile,IntPtr lpFileMappingAttributes, PageProtection flProtect,uint dwMaximumSizeHigh,

    uint dwMaximumSizeLow, string lpName);

    Tips

    Use MarshalAs whenever the P/Invoke type is different from the one that

    the API requires (see the CreateEvent example).

    The default marshaling type for strings in P/Invoke is LPTSTR. If the actual

    parameter type differs from the P/Invoke default then you will need to usethe MarshalAs attribute in the function prototype declaration. For

    example, if a function receives the LPCTSTR parameter then we should use

    [MarshalAs(UnmanagedType.LPTStr)] strings.

    Use CharSet.Auto in DllImport. This is important for strings. If the API

    works with Unicode and you don't use the auto attribute then the CLR willmarshal the data as ANSI. For some reason Microsoft has decided not touse the auto attribute as default. The auto tells the CLR to figure out

    automatically what the preferred charset is. Performance considerations: " P/Invoke has an overhead of between 10

    and 30 x86 instructions per call. In addition to this fixed cost, marshalingcreates additional overhead. There is no marshaling cost between blittabletypes that have the same representation in managed and unmanagedcode. For example, there is no cost to translate between int andInt32.

    For higher performance, it may be necessary to have fewer P/Invoke callsthat marshal as much data as possible, rather than have more calls that

    marshal less data per call. Or somewhat more memorably: prefer achunky over a chatty API."( MSDN).

    Make sure you use the fixed keyword when passing managed allocation

    buffers to unmanaged code. When marshaling pointer to data, the garbage

    collector needs to be alerted not to mess with the allocated data,otherwise the unmanaged code might crash while trying to retrieve acorrupted memory addresses. The fixed keyword tells the GC to leave

    your allocated data (PIN), and hence not to compact it during generatingcollections.

    Unmanaged to Managed type translation table

    C/C++ C#

    HANDLE, LPDWORD, LPVOID, void* IntPtr

    LPCTSTR, LPCTSTR, LPSTR, char*, const

    char*, Wchar_t*, LPWSTR String [in], StringBuilder [in, out]

  • 8/15/2019 pinvoke

    3/3

    DWORD, unsigned long, UlongUInt32,[MarshalAs(UnmanagedType.U4)]

    bool bool

    LP [In] ref

    SIZE_T uint

    LPDWORD out uint

    LPTSTR [Out] StringBuilder

    PULARGE_INTEGER out ulong

    WORD uInt16

    Byte, unsigned char byte

    Short Int16

    Long, int Int32

    float single

    double double

    NULL pointer IntPtr.Zero

    Uint Uint32

    Resources

    http://www.pinvoke.net/ - This a wonderful site with tons of examples

    (sorted by Win DLL) and a search engine. This site is my main reason for

    not having examples in this article).

    PINVOKE.NET add-in for Visual Studio. This is a great add-in contributed

    by GotDotnet. It uses the pinvoke.net web site database.

    P/Invoke MSDN tutorial. Loop holes around P/Invoke.

    Epilogue

    Given the fact that in the current .NET framework (2.0 Beta) we still don't have

    wrappers for every Win32 API, using Platform Invoke (P/Invoke) is almostunavoidable.

    You might not find all or exactly what you need from the above resources or fromthe entire article, but I am sure you will be able to learn from it and use what you

    have learned to find a solution to your needs. I encourage you to add yourcomments and promise to update the article periodically.

    http://www.pinvoke.net/http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=75122f62-5459-4364-b9ba-7b5e6a4754fe%3C/Ahttp://www.codeproject.com/script/Submit/P/Invoke%20MSDN%20tutorial%20%20-%20http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkPlatformInvokeTutorial.asphttp://www.codeproject.com/script/Submit/moemeka6.asphttp://www.pinvoke.net/http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=75122f62-5459-4364-b9ba-7b5e6a4754fe%3C/Ahttp://www.codeproject.com/script/Submit/P/Invoke%20MSDN%20tutorial%20%20-%20http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkPlatformInvokeTutorial.asphttp://www.codeproject.com/script/Submit/moemeka6.asp