C#调用C++ DLL的PInvoke栈不平衡异常排查求助
PInvoke调用C++硬件信息DLL的栈不平衡问题修复
问题根源分析
导致栈不平衡异常的核心原因是C# PInvoke签名与C++函数定义不匹配,具体问题点如下:
- 结构体内存布局破坏:VERSION和HDINFO结构体错误设置了
Size=1,强制结构体大小为1字节,完全违背C++结构体的内存结构,直接移除该属性。 - 数据类型不匹配:
- C++的
ULONGTYPE是unsigned long int,对应C#的uint(无符号32位整数),而非有符号的int。 - C++的
CHARTYPE是unsigned char(ASCII字符),C#字符串默认用Unicode封送,需显式指定字符集为Ansi。
- C++的
- 函数签名错误:
- C++函数参数是
HDINFO*(结构体指针),C#无需手动分配IntPtr,直接用ref HDINFO即可,CLR会自动处理指针封送。 - 返回值
ULONGTYPE对应C#的uint,而非int。
- C++函数参数是
- 调用约定不匹配:C++的
extern "C"默认使用cdecl调用约定,DllImport默认是StdCall,这是栈不平衡的主要诱因,必须显式指定调用约定。
修正后的C#代码
using System; using System.Runtime.InteropServices; namespace ConsoleHardwareApp { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] struct VERSION { public byte major; public byte minor; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] struct HDINFO { public VERSION hardwareVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string hardwareManufactureID; public uint hardwareflags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string hardwareDesc; public VERSION apiVersion; } class Program { [DllImport("sampleHardwareOp.dll", CallingConvention = CallingConvention.Cdecl)] public static extern uint GetHardwareInfo(ref HDINFO hdInfo); static void Main(string[] args) { HDINFO hdInfo = new HDINFO(); uint rv = GetHardwareInfo(ref hdInfo); Console.WriteLine($"返回值: {rv}"); Console.WriteLine($"硬件版本: {hdInfo.hardwareVersion.major}.{hdInfo.hardwareVersion.minor}"); Console.WriteLine($"厂商ID: {hdInfo.hardwareManufactureID.Trim()}"); Console.WriteLine($"硬件描述: {hdInfo.hardwareDesc.Trim()}"); Console.WriteLine($"API版本: {hdInfo.apiVersion.major}.{hdInfo.apiVersion.minor}"); Console.ReadKey(); } } }
关键修正说明
- 移除手动内存分配代码,通过
ref传递结构体,CLR自动完成托管与非托管内存的封送,避免内存泄漏。 - 字符串通过
CharSet.Ansi配合ByValTStr,确保与C的unsigned char数组正确映射,SizeConst=32对应C数组长度。 - 统一数据类型与C++定义匹配,修正返回值和成员变量的类型错误。
- 指定
CallingConvention.Cdecl,解决栈不平衡的核心问题。
内容的提问来源于stack exchange,提问作者prao
相关产品推荐
相关产品推荐

