آشنایی با P/Invoke در دات نت
در این مطلب با نحوه استفاده از P/Invoke در پروژه های دات نت آشنا خواهیم شد.

P/Invoke چیست؟
Platform Invoke یا به اختصار P/Invoke به شما اجازه میدهد به توابع و سایر اجزای موجود در کتابخانههای غیرمدیریت شده در کدهای مدیریت شده دسترسی پیدا کنید.
مطالب مرتبط با این موضوع:
- ⬅️ آشنایی با P/Invoke در دات نت (همین مطلب)
- ⚡آشنایی با CsWin32 برای تولید کدهای P/Invoke در دات نت
برای شروع، کد زیر که یک پیغام ساده را در ویندوز نمایش میدهد را در نظر بگیرید.
using System;
using System.Runtime.InteropServices;
public partial class Program
{
// Import user32.dll (containing the function we need) and define
// the method corresponding to the native function.
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
private static partial int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType);
public static void Main(string[] args)
{
// Invoke the function as a regular managed method.
MessageBoxW(IntPtr.Zero, "Command-line message box", "Attention!", 0);
}
}
در کدهای فوق، ابتدا با استفاده از LibraryImport به کامپایلر اعلام شده است که کتابخانه غیرمدیریت شده user32.dll باید بارگذاری شود.
[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
سپس در خط بعدی متد MessageBoxW با امضاء یکسان نسبت به متد اصلی تعریف شده است.
private static partial int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType);
با مراجعه به مستندات MessageBoxW میتوان یکسان بودن امضاء (Signature) متد را بررسی کرد.
int MessageBoxW(
[in, optional] HWND hWnd,
[in, optional] LPCWSTR lpText,
[in, optional] LPCWSTR lpCaption,
[in] UINT uType
);
سپس در ادامه متد MessageBoxW همانند یک متد عادی فراخوانی شده است.
MessageBoxW(IntPtr.Zero, "Command-line message box", "Attention!", 0);
با اجرای نمونه کد فوق، پیغام زیر نمایش داده خواهد شد.
---------------------------
Attention!
---------------------------
Command-line message box
---------------------------
OK
---------------------------
ℹ️ توجه داشته باشید: برای اجرای دستورات فوق لازم است AllowUnsafeBlocks را در فایل پروژه خود فعال کنید.
<PropertyGroup>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
P/Invoke در سایر پلتفرمها
همانطور که میدانید، از دات نت میتوان در سایر پلتفرمها نیز استفاده کرد. P/Invoke نیز از این قاعده مستثنی نیست.
در نمونه کد زیر نحوه دریافت Process ID فعلی را در لینوکس میتوانید مشاهده کنید.
public static partial class Program
{
// Import the libSystem shared library and define the method
// corresponding to the native function.
[LibraryImport("libSystem.dylib")]
private static partial int getpid();
public static void Main(string[] args)
{
// Invoke the function and get the Process ID.
int pid = getpid();
Console.WriteLine(pid);
}
}
LibraryImport چه کاری انجام میدهد؟
اگر به متد MessageBoxW مثال قبلی دقت کرده باشید از کلمه کلیدی partial برای تعریف آن استفاده شده است.
[LibraryImport(...)]
private static partial int MessageBoxW(...);
این Attribute که در دات نت 7 معرفی شده است در واقع یک Source Generator است که کدهای لازم برای انجام P/Invoke را در هنگام کامپایل تولید میکند.
با مراجعه به بخش Analyzers در پروژه خود میتوانید کدهای تولید شده را مشاهده کنید.

P/Invoke در نسخههای قبلی دات نت
برای استفاده از P/Invoke در نسخههای قبلی دات نت، کدهای تعریف MessageBoxW به شکل زیر تغییر پیدا خواهد کرد.
public class Program
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int MessageBoxW(int hWnd, string text, string caption, uint type);
public static void Main(string[] args)
{
MessageBoxW(0, "Command-line message box", "Attention!", 0);
}
}
در کدهای فوق:
- ابتدا با استفاده از
DllImportبه کامپایلر اعلام شده است کهuser32.dllباید بارگذاری شود. - سپس متد
MessageBoxWبا استفاده از کلمه کلیدیexternتعریف شده است.
برای کسب اطلاعات بیشتر در مورد تفاوت بین LibraryImport و DllImport میتوانید به این مطلب مراجعه کنید.