我正在为某些C++代码制作DLL包装器,但遇到了问题。提供一些示例代码后,我将更容易说明问题。
在我的C++应用程序的.h文件中:
#pragma once
namespace Wrapper {
extern __declspec(dllexport)
void SANDBOX(int arrayLength, int* intArray);
}
在我的C++应用程序的.cpp文件中:
#include "stdafx.h"
#include "Wrapper.h"
#include <windows.h>
using namespace Wrapper;
extern "C"{
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return TRUE;
}
__declspec(dllexport) void SANDBOX(int* arrayLength, int* intArray[])
{
if(*intArray == NULL)
{
*arrayLength = 5;
return;
}
else
{
int i = 0;
for(i = 0; i < (*arrayLength); i++)
{
(*intArray)[i] = 1 + i*i;
}
}
}
}
我的C#应用程序导入方法如下:
const string dllFileLocation = "Wrapper.dll";
[DllImport(dllFileLocation, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void SANDBOX(ref int arrayLength, ref int[] intArray);
最后,我的C#应用程序以如下形式调用代码:
//Initialize some things
string outString;
int numInArray = -1;
int[] iArray = null;
//Fill the numInArray integer
Wrapper_Handle.SANDBOX(ref numInArray, ref iArray);
//Lets initialize the array and print the values
iArray = new int[numInArray];
outString = "";
foreach(int i in iArray)
{
outString += i + "\n";
}
MessageBox.Show(outString);
//Now lets put values into the array and print the new ones out
Wrapper_Handle.SANDBOX(ref numInArray, ref iArray);
outString = "";
foreach(int i in iArray)
{
outString += i + "\n";
}
MessageBox.Show(outString);
因此,我期望发生的事情是创建一个空数组以获取要初始化的值的数量。所以我拿出5个,制作一个新的数组,然后打印。它达到了我的期望:一个带有0的消息框,五次。但是,再次调用该方法后,第二个消息框只是数字1,没有其他值。看来其他4个值是从数组中“切掉”的,C#应用程序无法再看到它们。
我已经从C++ .DLL成功导入了许多其他功能。这是引起问题的数组符号。调试.DLL时,会将值正确传递给C++代码,并对其进行赋值。
有谁知道为什么C#应用程序会“丢失”其他4个值?数组的长度无关紧要,仅在调用该方法之后才保留第一个值。
提前致谢。任何帮助是极大的赞赏。
编辑 -
在对该问题的评论中提供了我的问题的解决方案。我在下面发布我的更改:
C++ .h文件:
#pragma once
namespace Wrapper {
extern __declspec(dllexport)
void SANDBOX(int arrayLength, int* intArray);
}
C++ .cpp文件:
#include "stdafx.h"
#include "Wrapper.h"
#include <windows.h>
using namespace Wrapper;
extern "C"{
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return TRUE;
}
__declspec(dllexport) void SANDBOX(int* arrayLength, int* intArray)
{
if(intArray == NULL)
{
*arrayLength = 5;
return;
}
else
{
int i = 0;
for(i = 0; i < (*arrayLength); i++)
{
(intArray)[i] = 1 + i*i;
}
}
}
}
C#导入:
const string dllFileLocation = "Wrapper.dll";
[DllImport(dllFileLocation, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void SANDBOX(ref int arrayLength, int[] intArray);
C#调用:
string outString;
int numInArray = -1;
int[] iArray = null;
Wrapper_Handle.SANDBOX(ref numInArray, iArray);
iArray = new int[numInArray];
outString = "";
foreach(int i in iArray)
{
outString += i + "\n";
}
MessageBox.Show(outString);
Wrapper_Handle.SANDBOX(ref numInArray, iArray);
outString = "";
foreach(int i in iArray)
{
outString += i + "\n";
}
MessageBox.Show(outString);
最佳答案
通过P / Invoke中的ref传递数组是一个奇怪的操作,因为大概它允许被调用函数从本机端替换引用。我不太确定为什么您发布的代码不起作用,因为它似乎是合理的(除了前面提到的带有ref的奇数和 header 中的声明与参数类型不匹配之外)。
但是,我认为您可以通过不传递ref并仅使用指向数组的指针来轻松更改代码以解决此问题。您不是要尝试重新分配数组引用本身;您只关心更改其内容。