从C#传递Bool数组到C ++代码

我目前正在和一些其他人一起开展一个项目,他们很遗憾不再提供参考资料。 该项目使用C#作为GUI,使用C ++更新我们的古老数据库。 目前,我在C#中有这个function:

[DllImport("Synch.DLL", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] //Synch bool Synch(void * voidPtr, const TCHAR * databaseDir, const TCHAR * truckDir) static extern Int32 Synch(IntPtr pSync, string databaseDir, string destDir, ref bool[] wholeFiles); 

wholeFiles是一个布尔数组,用于根据用户输入确定是否应同步某些文件。

C ++应该接受这个数组,并且能够在满足某些条件时将一些bool翻转为true或false。

 if (numSyncRecords > 0){ Log::WriteVerbose(_T(" %d recs, %d differences found"), (int) numRecsUsed, (int) numSynRecords); if(wholeFiles[sourceFileID]){ CString tempPath = _T(""); tempPath += destDir; tempPath += fileName; DeleteFile(tempPath); } else wholeFiles[sourceFileID] = false; } else wholeFiles[sourceFileID] = false; 

在上面的例子中,我传入了Trues,如果没有对文件进行任何更改,请将其设置为false以避免处理不需要它的文件。

现在,我的问题是,当C ++代码完成时,仍然应该将True标记设置为false。 如果我通过ref发送它,那么我得到堆栈溢出。 没有ref,arrays似乎没有改变。

编辑:这是请求。

 SYNC_API Int32 Synch(void * voidPtr, const TCHAR * databaseDir, const TCHAR * truckDir, bool wholeFiles[]) 

编辑2:在C ++代码中,我有一个循环数组的日志语句,并在wholeFiles数组中每个位置每行输出一次真/假,最后我得到了相应的日志输出,但是当我查看数组时完成之后的C#代码,它没有改变。

如果你的DllImport下面的注释是C ++方面的确切函数声明,那么你的wholeFiles数组将永远不会出现在C ++端,因为它不期望第五个参数。 请务必先解决该问题。

在C#中,只有一个bool大小,即1个字节。 在C ++中有两种类型,C风格的1字节bool和Win32 4字节BOOL 。 默认情况下,P / Invoke会将bool编组为BOOL

因此,如果第一位不是你的整个问题并且它不起作用,那么你正在使用C风格的bool并且需要告诉C#,使用[MarshalAs]这样:

 [DllImport("Synch.DLL", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] static extern Int32 Synch( IntPtr pSync, string databaseDir, string destDir, [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.I1)] bool[] wholeFiles); 

您也不需要ref因为数组本身就是一个引用类型。 只有在您调用的函数想要将数组与另一个数组交换时, ref数组才有用。

另请注意,您不必将其设为多行,如果函数全部在一行中,该属性将起作用,我只是为了可读性而这样做。

如果没有完整的C ++函数,很难确切知道#s是怎么回事,但是你可以尝试的一件事就是让C ++函数返回修改后的数组(而不是依赖于就地修改)。

 [DllImport("Synch.DLL", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] // Now return an IntPtr static extern IntPtr Synch(IntPtr pSync, string databaseDir, string destDir, ref bool[] wholeFiles); wholeFiles = Synch(..., wholeFiles); 

选项2

另一个选择是在C#中声明一个缓冲区,将wholeFiles数组复制到该缓冲区,然后将缓冲区的地址传递给C#(这是我过去所做的)。 然后,C ++代码修改缓冲区,然后您可以在调用dll完成后将其复制回wholeFiles。

选项3

最好的选择(在我看来)是使用SWIG 。 SWIG使C#函数包含C ++函数变得非常容易(实际上还有许多其他语言)。 这将为您提供一个名为Synch的C#函数,它在幕后调用dll,为您处理任何内存问题。

假设C ++标头名为synch.h示例(简单) synch.i文件:

 %module SynchSWIG %{ #include "synch.h" %} %include "synch.h 

使用命令生成包装器(未测试):

 swig -c++ -csharp -dllimport Synch.DLL synch.i 

这将为您提供C#文件以编译到您的C#项目中,以及一个C ++文件以编译到C ++ DLL项目中。