C#封送、不平衡堆栈和正确获取PInvoke签名
我试图在我的C#项目中使用封送处理调用一个C DLL,并使一些函数正常工作,但我遇到了其他函数的问题。就像下面这个 我的第一个问题是获得正确的结构,下一个问题是返回PROFILE_INFO作为程序文件列表的数组,或者它不会返回列表,proNum是一个索引 C语言中的函数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
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中显而易见的内容(结构就是结构,…)
- 如果您不确定,请不要添加
,默认情况下.NET在这方面的行为应该与C/C++类似pack
- 如果定义中没有字符串,则不要添加Ansi信息(仅当有字符串或TStr等时)。它不会引起问题,但毫无用处
- 通常,如果不知道属性的用途,请不要添加属性
- C/C++中的
和int
通常是32位的<代码>长在C/C中不是64位++long
[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]