我正在为一些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个值?数组的长度无关紧要,只有在调用方法后才保留第一个值。
提前致谢。非常感谢任何帮助。
EDIT-- 在对这个问题的评论中提供了我的问题的解决方案。我在下面发布我的更改:
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#import:
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);
答案 0 :(得分:2)
在P / Invoke中通过ref传递数组是一个奇怪的操作,因为可能它允许被调用的函数替换来自本机端的引用。我不完全确定为什么你发布的代码不起作用,因为它似乎是合理的(除了前面提到的ref与你的标题中的声明并不匹配参数类型)。
但是,我认为您可以轻松更改代码以解决问题,方法是不通过ref传递并只是指向数组。你不是要重新分配数组引用本身;你只关心改变它的内容。