Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active December 24, 2025 21:46
Show Gist options
  • Select an option

  • Save sunmeat/a1c7857aa28955bae307e199dac059a6 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/a1c7857aa28955bae307e199dac059a6 to your computer and use it in GitHub Desktop.
ExactSpelling, SetLastError, CallingConvention, MarshalAs
using System.Runtime.InteropServices;
using System.Text;
// CallingConvention — це перелік, який визначає угоду про виклик функції,
// тобто правила, що визначають, як параметри передаються у функцію, хто очищає стек
// і як передаються повернені значення. Важливість вибору правильної угоди полягає
// у коректній організації обміну даними між керованим і нативним кодом.
// CallingConvention.Cdecl — зазвичай використовується у програмах на C і C++.
// Параметри передаються справа наліво, і сторона, що викликає, очищає стек після виклику функції.
// Часто використовується в компіляторах, які не підтримують стандарт Windows API.
// CallingConvention.StdCall / Winapi — використовується для функцій Windows API, таких як GetUserNameW, MessageBox та багатьох інших.
// Параметри передаються зліва направо, і функція сама очищає стек після виконання.
// Ця угода про виклик є типовою для більшості функцій Windows API.
// CallingConvention.ThisCall — використовується для методів екземплярів класів у C++.
// Параметри передаються зліва направо, а перший параметр (неявно переданий) — це вказівник на поточний об’єкт (this).
// Ця угода про виклик використовується для виклику методів об’єктів у C++.
// CallingConvention.FastCall — використовується для оптимізації передачі параметрів через регістри процесора, що прискорює виконання функцій.
// Параметри передаються через регістри (наскільки це можливо), а решта — через стек.
// Ця угода про виклик може бути використана для прискорення роботи в специфічних випадках, наприклад, у бібліотеках, що вимагають високої продуктивності.
class PInvoke
{
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetUserNameW",
ExactSpelling = true, // ім’я функції в імпорті має точно відповідати імені функції в нативній бібліотеці, включно з регістром символів
SetLastError = true, // повідомляє систему, що ця функція може встановити код останньої помилки, який буде доступний через Marshal.GetLastWin32Error()
CallingConvention = CallingConvention.StdCall)]
public static extern bool GetUserNameW(
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, // вказує, що lpBuffer є рядком Unicode (у форматі UTF-16) і буде переданий у функцію як LPWSTR (вказівник на рядок)
ref uint nSize // розмір буфера, який може бути змінений функцією, якщо буфер занадто малий
);
public static void Main()
{
Console.OutputEncoding = Encoding.UTF8;
uint size = 1024;
var buffer = new StringBuilder((int)size);
bool success = GetUserNameW(buffer, ref size);
if (success)
{
Console.WriteLine($"Ім’я користувача: {buffer.ToString()}");
}
else
{
// якщо функція погано відпрацювала, отримаємо код помилки через Marshal.GetLastWin32Error()
int errorCode = Marshal.GetLastWin32Error();
Console.WriteLine($"Помилка отримання імені користувача. Код помилки: {errorCode}");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment