Platform Invocation Services

From Wikipedia, the free encyclopedia

Platform Invocation Services, commonly referred to as just P/Invoke, is a feature of Common Language Infrastructure implementations, like Microsoft's Common Language Runtime, that enables managed code to call native code in dynamic-linked libraries (DLLs). The native code is referenced via metadata that describes functions exported from a native DLL.

Contents

[edit] Usage and common pitfalls

When using P/Invoke, the CLR handles DLL loading and conversion of the unmanaged legacy types to CTS types (also referred to as parameter marshalling)[1]. To perform this, the CLR:

  • Locates the DLL containing the function.
  • Loads the DLL into memory.
  • Locates the address of the function in memory and pushes its arguments onto the stack, marshalling data as required.

P/Invoke is useful for using legacy C or C++ DLLs. It can be used when a programmer needs to have access to the extensive Windows API, as there are no available wrappers for a lot of functions provided by the Windows libraries. When a Win32 API is not exposed by the .NET framework the wrapper to this API must be written manually.

Writing these wrappers can be difficult and error prone. Using native DLLs means that the programmer can no longer benefit from type safety and garbage collection as is usually provided in the .NET environment. When they are used improperly this may cause problems such as segmentation faults or memory leaks. Getting the exact signatures of the legacy functions for use in the .NET environment can be hard, which can result in such problems. For this purpose a tools and websites exist to obtaining such signatures, helping to prevent signature problems. [1]

Other pitfalls include:

  • Incorrect data alignment of user-defined types in the managed language: there are different ways data can be aligned depending on compilers or compiler directives in C and care must be taken to explicitly tell the CLR how to align data for non-blittable types. A common example of this is when trying to define a data type in .NET to represent a union in C. Two different variables overlap in memory, and defining these two variables in a type in .NET would cause them to be in different locations in memory, so special attributes must be used to correct the issue.
  • Interference with the location of data by the managed language's garbage collector: if a reference is local to a method in .NET and is passed to a native function, when the managed method returns, the garbage collector may reclaim that reference. Care should be taken that the object reference is pinned, preventing it from being collected or moved by the garbage collector, which would result in an invalid access by the native module.

[edit] Examples

This first simple example shows how to get the version of a particular DLL:

DllGetVersion function signature in the Windows API:

HRESULT DllGetVersion
(
    DLLVERSIONINFO* pdvi
)

P/Invoke C# code to invoke the DllGetVersion function:

[DllImport("shell32.dll")]
static extern int DllGetVersion(ref DLLVERSIONINFO pdvi);

The second example shows how to extract an Icon in a File:

ExtractIcon function signature in the Windows API:

HICON ExtractIcon
(      
    HINSTANCE hInst,
    LPCTSTR lpszExeFileName,
    UINT nIconIndex
);

P/Invoke C# code to invoke the ExtractIcon function:

[DllImport("shell32.dll")]
static extern IntPtr ExtractIcon(
    IntPtr hInst, 
    [MarshalAs(UnmanagedType.LPStr)] string lpszExeFileName, 
    uint nIconIndex);

This next complex example shows how to share an Event between two processes in the Windows platform:

CreateEvent function signature:

HANDLE CreateEvent(
    LPSECURITY_ATTRIBUTES lpEventAttributes,
    BOOL bManualReset,
    BOOL bInitialState,
    LPCTSTR lpName
);

P/Invoke C# code to invoke the CreateEvent function:

[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr CreateEvent(
    IntPtr lpEventAttributes, 
    bool bManualReset,
    bool bInitialState, 
    [MarshalAs(UnmanagedType.LPStr)] string lpName);

[edit] References

  1. ^ Parameter marshalling is not to be confused with the general term marshalling, meaning Serialization. Marshalled parameters are copied in the CLR stack after their conversion to CTS types, but are not serialized.

[edit] See also

[edit] External links