【发布时间】:2014-07-03 23:05:30
【问题描述】:
我正在为一些 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);
【问题讨论】:
-
pinvoke marshaller 不知道数组可能有多大。您的 C 代码实际上并没有创建数组(好),因此您的声明不合适。从 C 声明中删除 []。从 C# 声明中删除 ref。
-
您的更改创造了我想要的效果。我仍然试图围绕 PInvoke marshaller 的细微差别。非常感谢!
标签: c# c++ arrays dll dllimport