我有一个访问专有数据库的 C DLL。我想从 C# 应用程序访问它,该应用程序将用于将数据转换为 SQL 数据库。
我目前无法从 C# 编码一个特别复杂的结构。
我的 C 结构定义如下
typedef struct iseg {
short soffset; /* segment offset */
short slength; /* segment length */
short segmode; /* segment mode */
} ISEG, *LPISEG;
typedef struct iidx {
short ikeylen; /* key length */
short ikeytyp; /* key type */
short ikeydup; /* duplicate flag */
short inumseg; /* number of segments */
LPISEG seg; /* segment information */
char *ridxnam; /* r-tree symbolic name */
} IIDX, *LPIIDX;
typedef struct ifil {
char *pfilnam; /* file name (w/o ext) */
char *pfildes; /* file description */
unsigned short dreclen; /* data record length */
unsigned short dxtdsiz; /* data file ext size */
short dfilmod; /* data file mode */
short dnumidx; /* number of indices */
unsigned short ixtdsiz; /* index file ext size */
short ifilmod; /* index file mode */
LPIIDX ix; /* index information */
unsigned short rfstfld; /* r-tree 1st fld name */
unsigned short rlstfld; /* r-tree last fld name */
int tfilno; /* temporary file number*/
char datetime; /* Update Date & Time Fields */
} IFIL, *LPIFIL;
我尝试了很多不同的变体,但这就是我的 C# 结构的样子
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct iseg
{
public short soffset;
public short slength;
public short segmode;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct iidx
{
public short ikeylen;
public short ikeytyp;
public short ikeydup;
public short inumseg;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public iseg[] seg;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string ridxnam;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct ifil
{
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string pfilnam;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string pfildes;
public ushort dreclen;
public ushort dxtdsiz;
public short dfilmod;
public short dnumidx;
public ushort ixtdsiz;
public short ifilmod;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public iidx[] ix;
public ushort rfstfld;
public ushort rlstfld;
public int tfilno;
public byte datetime;
}
我收到以下异常
Conversion.dll 中发生类型为“System.AccessViolationException”的第一次机会异常 Conversion.dll 中出现“System.AccessViolationException”类型的未处理异常
附加信息:试图读取或写入 protected 内存。这通常表明其他内存已损坏。
我无法调试 C DLL,即使我在项目中选择了“调试非托管代码”选项。问题可能出现在编码代码中?
我调用的c代码是
public class NativeMethods
{
/// Return Type: int
///lpIfil: LPIFIL->IFIL*
[System.Runtime.InteropServices.DllImportAttribute(@"c:\db\debug\db.dll", EntryPoint = "OPNIFIL")]
public static extern int OPNIFIL(ref ifil lpIfil);
}
if (NativeMethods.OPNIFIL(ref ifil) == 0)
{
// No error occured
}
最佳答案
抱歉,我没有足够的代表发表评论。
但是:
你在 C 中初始化这个结构吗?由于您的字符串只是指针,请检查您的 C 代码是否正在为其要填充的字符串分配内存。也许您只是在 C 中检查它们不为 NULL 并试图找到字符串的结尾......如果是这样,在将结构传递给 C 代码之前对其进行初始化。
解决此类互操作问题的有效方法是编写一个非常简单的 C 程序或 dll,打印您传递的结构的每个字段。当您弄清楚该结构如何到达 C 时,您可以将 DLL 替换为真实的 DLL。
要尝试的另一件事是在 C 中获取字符串的大小,并与 C# 中报告的大小进行比较。即使是一个字节的偏移量也会导致很多问题。编写一个健全的功能并将其导出到 DLL 上:
int sanity()
{
return sizeof(IIDX);
}
然后,您可以在 C# 中进行健全性检查,用在 C# 上计算的结构的大小来测试健全性返回的值。对齐问题可能很难看出来,如果将来结构大小发生变化,您会收到一条警告消息。
此外,如果字符串是在 C 中分配的,请考虑稍后如何释放这些字符串。
关于c# - 将结构从 C# 编码到 C++ DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12459691/