将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#代码中查看数组后完成,它是不变的。

将Bool数组从c#传递给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项目中。