将Bool数组从c#传递给c++代码
本文关键字:c++ 代码 Bool 数组 | 更新日期: 2023-09-27 18:02:43
我目前正在与其他几个人一起做一个项目,遗憾的是他们不再可以作为参考材料。这个项目使用c#作为GUI,使用c++来更新我们的旧数据库。目前,我在c#中有这个函数:
[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值翻转为真或假。
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;
在上面的例子中,我传入true,如果没有对文件进行更改,则将其设置为false,以避免处理不需要它的文件。
现在,我的问题是,当c++代码完成后,当它们应该设置为false时,仍然有True标记。如果我通过ref发送它,就会导致堆栈溢出。如果没有ref,数组似乎不会改变。
编辑:这是被要求的。
SYNC_API Int32 Synch(void * voidPtr, const TCHAR * databaseDir, const TCHAR * truckDir, bool wholeFiles[])
Edit2:在c++代码中,我有一个日志语句,循环数组并在整个efiles数组中每行每个位置输出一次true/false,并且我最终得到适当的日志输出,但是当我在c#代码中查看数组后完成,它是不变的。
如果DllImport
下面的注释是c++侧的确切函数声明,那么您的wholeFiles
数组将永远不会在c++侧看到,因为它不期望第5个参数。请确保先解决这个问题。
在c#中,bool
只有一种大小,那就是1字节。在c++中有两种类型,C风格的1字节bool
和Win32的4字节BOOL
。默认情况下,P/Invoke将封送工具作为BOOL
。
所以如果第一个比特不是你的全部问题,它不起作用,那么你正在使用C风格的bool
,需要用[MarshalAs]像这样告诉c#:
[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#中声明一个缓冲区,将整个efiles数组复制到该缓冲区,然后将缓冲区的地址传递给c#(这是我过去所做的)。然后c++代码修改缓冲区,然后你可以在调用完dll后将其复制回wholeFiles。
选项3
(在我看来)最好的选择是使用SWIG。SWIG使包装c++函数以供c#使用(实际上还有许多其他语言)变得非常容易。这将为您提供一个名为sync的c#函数,该函数在后台调用dll,为您处理任何内存问题。
示例(简单)synch.i
文件假设c++头名为synch.h
:
%module SynchSWIG
%{
#include "synch.h"
%}
%include "synch.h
使用命令(未测试)生成包装器:
swig -c++ -csharp -dllimport Synch.DLL synch.i
这将给你一个c#文件编译到你的c#项目中,以及一个c++文件编译到c++ dll项目中。