C#封送、不平衡堆栈和正确获取PInvoke签名

C#封送、不平衡堆栈和正确获取PInvoke签名,c#,arrays,struct,pinvoke,marshalling,C#,Arrays,Struct,Pinvoke,Marshalling,我试图在我的C#项目中使用封送处理调用一个C DLL,并使一些函数正常工作,但我遇到了其他函数的问题。就像下面这个 我的第一个问题是获得正确的结构,下一个问题是返回PROFILE_INFO作为程序文件列表的数组,或者它不会返回列表,proNum是一个索引 C语言中的函数 extern "C" __declspec(dllexport) int WINAPI GetProgramFileList (unsigned long proNum, PROFILE_INFO *proFile); typ

我试图在我的C#项目中使用封送处理调用一个C DLL,并使一些函数正常工作,但我遇到了其他函数的问题。就像下面这个

我的第一个问题是获得正确的结构,下一个问题是返回PROFILE_INFO作为程序文件列表的数组,或者它不会返回列表,proNum是一个索引

C语言中的函数

extern "C" __declspec(dllexport) int WINAPI GetProgramFileList (unsigned long proNum, PROFILE_INFO *proFile);

typedef struct{
    PROINFO         proInfo;
    __int64             proSize;
    PROGRAM_DATE    createDate;
    PROGRAM_DATE    writeDate;
}PROFILE_INFO;

typedef struct{
    char wno[33];
    char dummy[7];
    char comment[49];
    char dummy2[7];
    char type;
    char dummy3[7];
}PROINFO;

typedef struct{
    short   year;
    char    month;
    char    day;
    char    hour;
    char    min;
    char    dummy[2];
}PROGRAM_DATE;
我的职能

[DllImport(@".\IFDLL.dll", EntryPoint = "GetProgramFileList", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern int GetProgramFileListTest(ulong proNum, ref PROFILE_INFO pro);

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct PROFILE_INFO
{
    [MarshalAs(UnmanagedType.Struct)]
    public PROINFO proInfo;            // WNo/name/type
    public long proSize;               // Program size
    [MarshalAs(UnmanagedType.Struct)]
    public PROGRAM_DATE createDate;    // Program creating date
    [MarshalAs(UnmanagedType.Struct)]
    public PROGRAM_DATE writeDate;     // Program updating date
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct PROINFO
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string wno;         // WNo.
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy;       // dummy
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)] public string comment;     // program name
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy2;      // dummy
    public char type;                                                               // program type
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy3;      // dummy
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct PROGRAM_DATE
{
    public short year;                 // Date (Year) 4-digit
    public char month;                 // Date (Month)
    public char day;                   // Date (Day)
    public char hour;                  // Date (Time)
    public char min;                   // Date (Minutes)
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)] private char dummy; // Dummy
}
C#结构概要文件#信息中的程序_datecreatedate将抛出:

无法封送类型为“CClient.Models.PROFILE_INFO”的字段“createDate”:此字段的类型定义包含布局信息,但具有无效的托管/非托管类型组合或不可封送

将PROGRAM_DATE fields更改为string会使函数接受它,但函数会返回一个参数(-60)错误。虽然不确定我是否离成功更近了

其他尝试,包括尝试获取作为数组返回的配置文件信息(ref PROFILE_INFO[]),到达:

调用PInvoke函数使堆栈不平衡。这可能是因为托管PInvoke签名与非托管目标签名不匹配

我在C dll中得到了以下描述:

解释 获取标准区域中的程序列表

论点 旋前体[内]

指定要获取的数据的数量

资料[输出]

将程序信息存储在标准区域中的PROFILE_信息类型中

在执行此功能之前,请确保要获取的数据数量的数据区域

返回值 如果成功,则返回“0”。如果有错误,则返回“0”以外的值

我使用的其他函数有GetProgramDirInfo、SendProgram、ReceiveProgram、SearchProgram等,但它们不返回任何数组,所以我假设封送数组是我的问题。此外,我还试图避免使用不安全的指针,我不确定是否需要自己进行复制


非常感谢您的帮助。

使用p/invoke时,请注意以下几点:

  • 不要添加.NET中显而易见的内容(结构就是结构,…)
  • 如果您不确定,请不要添加
    pack
    ,默认情况下.NET在这方面的行为应该与C/C++类似
  • 如果定义中没有字符串,则不要添加Ansi信息(仅当有字符串或TStr等时)。它不会引起问题,但毫无用处
  • 通常,如果不知道属性的用途,请不要添加属性
  • C/C++中的
    int
    long
    通常是32位的<代码>长在C/C中不是64位++
下面是一个应该更好的代码:

  [DllImport(@".\IFDLL.dll", EntryPoint = "GetProgramFileList")]
  public static extern int GetProgramFileListTest(uint proNum, ref PROFILE_INFO pro);

  [StructLayout(LayoutKind.Sequential)]
  public struct PROFILE_INFO
  {
      public PROINFO proInfo;            // WNo/name/type
      public long proSize;               // Program size
      public PROGRAM_DATE createDate;    // Program creating date
      public PROGRAM_DATE writeDate;     // Program updating date
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct PROINFO
  {
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string wno;         // WNo.
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy;       // dummy
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)] public string comment;     // program name
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy2;      // dummy
      public char type;                                                               // program type
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)] private string dummy3;      // dummy
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct PROGRAM_DATE
  {
      public short year;                 // Date (Year) 4-digit
      public char month;                 // Date (Month)
      public char day;                   // Date (Day)
      public char hour;                  // Date (Time)
      public char min;                   // Date (Minutes)
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)] private string dummy; // Dummy
  }

非常感谢,这帮了大忙。。如果我将proNum设置为1,我成功地获取了数据,但如果我将proNum设置为>=2,则无法获取数据。它不应该返回数组吗?@KimJensen-这取决于您在C/C++代码中执行的操作名称和描述提示了一个“列表”,假设它将返回proNum大小的数组是否正确?如果proNum是一个索引,那么proNum=2应该会给我一些数据,因为GetProgramDirInfo告诉我totalProNum=56,但它会崩溃。如果它是一个数组,请尝试将函数定义为
GetProgramFileListTest(uint proNum,[In,Out]PROFILE_INFO[]pro)
并传递
pi
其中
var pi=new PROFILE_INFO[2]