Last active
December 24, 2025 21:46
-
-
Save sunmeat/a1c7857aa28955bae307e199dac059a6 to your computer and use it in GitHub Desktop.
ExactSpelling, SetLastError, CallingConvention, MarshalAs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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