You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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++函数参数是HDINFO*(结构体指针),C#无需手动分配IntPtr,直接用ref HDINFO即可,CLR会自动处理指针封送。
    • 返回值ULONGTYPE对应C#的uint,而非int。
  • 调用约定不匹配: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:35:17