2012-09-17 119 views
2

我有一个访问专有数据库的C DLL。我想从一个C#应用程序访问它,它将用于将数据转换为SQL数据库。从C#到C++ DLL的编组结构

我困在此刻编组从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'的第一次机会异常 'Sy'类型的未处理异常“Conversion.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 
} 
+0

也许你有一个针脚问题?你的字符串是隐式指针,请看这里:http://stackoverflow.com/questions/5589945/net-c-sharp-unsafe-fixed-doesnt-pin-passthrough-array-element – Michel

+0

你确定事物的C方有一包的大小是1? –

+0

是的我在C项目编译是/ Zp1 –

回答

1

对不起,我没有足够的代表处发表评论。

但是:

您是否在C中初始化这个结构?由于你的字符串只是指针,请检查你的C代码是否为它想要填充的字符串分配内存。也许你只是在C中检查它们不是NULL并试图找到字符串的结尾......如果是这样,在将它传递给C代码之前初始化该结构。

这种互操作问题的一个有效方法是编写一个非常简单的C程序或dll,它打印您传递的结构的每个字段。当你弄清楚结构是如何到达C的时候,你可以用真正的DLL代替DLL。

另一个尝试的方法是在C中获取字符串的大小,并与C#中报告的sizeof进行比较。即使是一个字节的偏移也会导致很多问题。撰写理智功能,导出的DLL:

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

然后,你可以在C#中的完整性检查,测试通过理智与C#计算结构的大小返回的值。对齐问题难以查看,如果将来结构大小发生变化,您可以收到警告消息。

另外,如果字符串是用C分配的,那么请考虑一下如何释放这些字符串。

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

0

您误声明的成员iidx.seg和ifil.ix 。你已经将它们都声明为byval或静态数组。因为你还没有初始化SizeConst,所以我认为运行时将它们编组为单元素数组。

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

顺便说一句,您不需要使用unsafe关键字。您只需要使用指针时,fixedsizeof。总的来说,封送不会让你不必使用不安全的代码。

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

+0

我想这个问题是在自动编组。我最终创建了一个新的非托管结构,其中指针变为IntPtr类型,然后手动编组值。数组不是固定的大小,这就是为什么我不能使用SizeConst。无论如何,这工作如果不理想 –