编辑
2025-09-20
C#
00

目录

基本数据类型对应关系
处理指针和句柄
示例1:获取当前进程的ID
示例2:使用指针访问数组
示例3:操作窗口句柄
总结

在使用C#进行P/Invoke调用Windows API或其他非托管代码时,理解C#数据类型与Windows API数据类型之间的对应关系至关重要。这不仅有助于正确地声明外部函数,还能确保数据在托管和非托管代码之间正确传递,避免数据损坏和程序崩溃。

基本数据类型对应关系

下面是一些常见的C#数据类型与Windows API数据类型之间的对应关系:

  • int (C#) 对应 INT (Windows API)
  • uint (C#) 对应 UINT (Windows API)
  • short (C#) 对应 SHORT (Windows API)
  • ushort (C#) 对应 USHORT (Windows API)
  • long (C#) 对应 LONG (Windows API)
  • ulong (C#) 对应 ULONG (Windows API)
  • bool (C#) 对应 BOOL (Windows API);注意,C#中的bool是1字节,而Windows API中的BOOL通常是4字节。
  • char (C#) 对应 WCHAR (Windows API);在使用Unicode字符集时。
  • string (C#) 对应 LPCWSTR (Windows API);在使用Unicode字符串时。
  • IntPtr (C#) 对应 HANDLEHWNDHINSTANCEHDCHMODULE等 (Windows API);用于表示指针或句柄。

处理指针和句柄

在C#中,IntPtr类型用于表示指针或句柄的值。由于C#是一种安全的语言,直接操作内存的能力有所限制,但通过IntPtr,我们仍然可以在需要时与非托管代码交互,包括接收来自非托管代码的指针或句柄,或将指针或句柄传递给非托管代码。

示例1:获取当前进程的ID

GetCurrentProcessId是一个Windows API函数,用于获取当前进程的进程ID(PID)。在C#中,可以通过P/Invoke调用这个函数来获取当前进程的进程ID。

C#
[DllImport("kernel32.dll", EntryPoint = "GetCurrentProcessId")] public static extern uint GetCurrentProcessId(); static void Main() { uint processHandle = GetCurrentProcessId(); Console.WriteLine($"当前进程的句柄:0x{processHandle.ToString("X")}"); }

image.png

示例2:使用指针访问数组

C#
// 导入msvcrt.dll中的memcpy函数 [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] public static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count); static void Main() { byte[] source = new byte[] { 1, 2, 3, 4, 5 }; byte[] destination = new byte[source.Length]; // 获取数组的指针 GCHandle srcHandle = GCHandle.Alloc(source, GCHandleType.Pinned); GCHandle destHandle = GCHandle.Alloc(destination, GCHandleType.Pinned); try { IntPtr srcPtr = srcHandle.AddrOfPinnedObject(); // 获取源数组的指针 IntPtr destPtr = destHandle.AddrOfPinnedObject(); // 获取目标数组的指针 // 使用memcpy函数复制数组 memcpy(destPtr, srcPtr, new UIntPtr((uint)source.Length)); } finally { if (srcHandle.IsAllocated) srcHandle.Free(); if (destHandle.IsAllocated) destHandle.Free(); } Console.WriteLine("复制后的数组: " + string.Join(",", destination)); }

image.png

示例3:操作窗口句柄

运行Spy++取得某一个窗体的句柄

image.png

C#
[DllImport("user32.dll", SetLastError = true)] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); static void Main() { // 假设hWnd是一个有效的窗口句柄 IntPtr hWnd = new IntPtr(0x00920574); // 示例句柄值 // 移动窗口 MoveWindow(hWnd, 100, 100, 500, 500, true); }

总结

在C#中通过P/Invoke与Windows API进行交互时,理解和处理数据类型、指针和句柄是基础且重要的。通过上述示例和数据类型对应关系的介绍,我们可以看到,虽然C#是一种高级语言,通过P/Invoke机制,它也能有效地与底层的非托管代码进行通信。正确地使用这些技术可以让我们的.NET应用程序充分利用现有的底层资源和库,提高应用程序的功能性和性能。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!