C#封送处理,不平衡的堆栈和正确的PInvoke签名

时间:2018-07-11 09:59:17

标签: 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);

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#结构PROFILE_INFO中的PROGRAM_DATE createDate将抛出:

  

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

将PROGRAM_DATE字段更改为字符串可以使其接受字符串,但是该函数将返回参数(-60)错误。尽管不确定我是否更接近成功。

其他尝试,包括尝试获取PROFILE_INFO以数组形式返回(参考PROFILE_INFO []),

  

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

我在C dll之后有这些描述:

  

说明

     

在标准区域中获取程序列表

     

参数

     
    

proNum [in]

         

指定要获取的数据数。

         

proFile [输出]

         

以PROFILE_INFO类型将程序信息存储在标准区域中。

  
     

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

     

返回值

     

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

我正在使用的其他函数是GetProgramDirInfo,SendProgram,ReceiveProgram,SearchProgram等,但是它们不返回任何数组,因此我认为在这里处理数组是我的问题。另外,我试图避免使用不安全的指针,并且不确定是否需要自己复制。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

使用p /调用时的几点注意事项:

  • 不要添加对.NET显而易见的内容(结构是结构,...)
  • 如果不确定,请不要添加pack,在默认情况下,.NET的行为应类似于C / C ++
  • 如果定义中没有字符串,则不要添加Ansi信息(仅当存在字符串或TStr等时)。它不会引起问题,但是没有用
  • 通常,如果您不知道属性的用途,请不要添加属性
  • C / C ++中的
  • intlong通常是32位。 long在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
  }