我有一个访问专有数据库的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;
}

我收到以下异常

类型'System.AccessViolationException'的第一次机会异常发生在Conversion.dll中。类型'System.AccessViolationException'的未处理异常发生在Conversion.dll中。

附加信息:尝试读取或写入受保护的内存。 这通常表明其他内存已损坏。

即使我在项目中选择了“调试非托管代码”选项,也无法调试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
}

#1楼 票数:1

抱歉,我没有足够的代表发表评论。

但:

您是否在C中初始化此结构? 由于您的字符串只是指针,请检查您的C代码是否正在为其要填充的字符串分配内存。也许您只是在C中检查它们是否不是NULL并尝试查找字符串的结尾...如果是,在将结构传递给C代码之前对其进行初始化。

解决此类互操作问题的有效方法是编写一个非常简单的C程序或dll,该程序将打印您正在传递的结构的每个字段。 当弄清楚结构如何以C语言到达时,可以用实际的DLL替换DLL。

要尝试的另一件事是在C中获取字符串的sizeof,并将其与C#中报告的sizeof进行比较。 即使是一个字节的偏移量也会引起很多问题。 编写健全性函数并将其导出到DLL上:

int sanity()
{
    return sizeof(IIDX);
}

然后,您可以在C#中进行完整性检查,并使用在C#上计算出的结构大小来测试由完整性返回的值。 对齐问题可能很难看清,如果将来结构尺寸发生变化,您可能会收到一条警告消息。

另外,如果字符串在C中分配,请稍后考虑如何释放这些字符串。

参考: http : //msdn.microsoft.com/zh-cn/library/s9ts558h(v=vs.100).aspx#cpcondefaultmarshalingforstringsanchor2

#2楼 票数:0

您错误地声明了成员iidx.seg和ifil.ix 1 您已经将它们声明为byval或静态数组。 因为您尚未初始化SizeConst,所以我认为运行时会将它们编组为单元素数组。

这意味着C#运行时认为iidx.seg(一个iseg的大小)的字段为6字节宽,而ifil.ix的字段为18或22字节宽(取决于平台)。 但是C结构中两个字段的大小都是指针的大小(4或8个字节,取决于平台)。

顺便说一句,您不需要使用unsafe关键字。 使用指针, fixedsizeof时只需要它。 通常,封送处理使您不必使用不安全的代码。

1您是否考虑过使用与实际单词更相似的名称?

  ask by Phil Salomon translate from so

未解决问题?本站智能推荐:

2回复

将C char [] []数组元素编组为C#

我看了看,尝试了一切我能想到或已经找到的建议。 我仍然没有运气获得我需要的数据。 我正在使用第三方DLL,我认为它是用C语言编写的。我需要在C#中访问此DLL中的函数。 在大多数情况下,我有这个工作,除了一个功能。 我遇到问题的函数有以下标题: 我在C#应用程序中声明了以下内
1回复

从C#到C-DLL调用/封送该结构时,为什么此字符串为空?

我在C-DLL中定义了这样的功能: DLL中将struct密码定义为: 我正在做的是尝试使用以下方法在C#中包装此函数: 和: 我通过以下方式调用此函数: 现在的问题是,返回的代码将发出INVALID PASSWORD信号,表示(根据文档)密码长度为0。是
2回复

如何从本机C .dll导出结构定义以在C#中使用

我知道如何在.dll中使用extern方法,我如何使用extern结构? 我想创建一个C方法,如 myStructure就像是 如何在不首先在C#中定义相同的结构的情况下从一段C#代码调用getStruct()? 我想保留myStructure的集中声明,这样我只需要在一
1回复

C Struct的编组作为C#委托的返回值

我试图通过绑定到本机函数的委托的值返回一个小的(8字节)结构,但是在针对.NET Framework 2.0时遇到以下错误(代码似乎在定位4.0+时正常工作) : testclient.exe中发生了未处理的“System.AccessViolationException”类型异常
1回复

如何封送 C# 和 C 之间的任意结构和联合?

我有一个 C 程序编译成一个 DLL,我将它加载到 C#(使用 kernel32.dll LoadLibrary 和 FreeLibrary)。 使用 GetProcAddress 我可以获得指向内存中某些数据的指针,并且我想将此数据转换为 C# 中的等效结构。 我的第一个想法是在 C# 中创建直
1回复

dllimport:C代码影响通过引用传递的结构(C#)

我有一个包含公开函数的ac dll,它带有三个参数: 我想从C#调用它,它实际上有效。 问题是结果结构不受影响。 这是用c代码定义的结构: 和我的C#代码: 我已经尝试了很多事情,例如:1-使用类而不是没有ref关键字的结构2-使用指针而不是传递结构 每次我遇到
1回复

如何在 C# 中映射双 C 结构指针?

我对 libACL 有以下 C 调用: 我已经跟踪了 typedefs 在 /usr/include/acl/libacl.h 和 /usr/include/sys/acl.h 所以除非我犯了一个错误,这意味着上面的原生调用等价于: 现在我对如何将这些映射到 C# 有点不知所措...
2回复

将C结构编组为C#

假设我有一个结构: 和一个C ++函数: 首先 - 我的IDE。 我正在使用Visual Studio 2010,构建一个C#(4.0)应用程序; C ++部分也是在VS2010中构建的。 我知道如何构建一个C / C ++代码的DLL并在C#应用程序中使用它,但直到今