Reputation: 103
I am making a DLL wrapper for some C++ code and have run into an issue. It will be easier for me to illustrate my problem after providing some sample code.
In my C++ application's .h file:
#pragma once
namespace Wrapper {
extern __declspec(dllexport)
void SANDBOX(int arrayLength, int* intArray);
}
In my C++ application's .cpp file:
#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;
}
}
}
}
My C# application imports the method like so:
const string dllFileLocation = "Wrapper.dll";
[DllImport(dllFileLocation, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void SANDBOX(ref int arrayLength, ref int[] intArray);
And finally, my C# application calls the code in a form like this:
//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);
So, what I would expect to happen is I make a null array to get the number of values to initialize. So I get 5 out, make a new array, and print it. It get what I would expect: a message box with 0 five times. However, after the method is called again the second message box is simply the number 1, with no other values. It would appear that the other 4 values are "cut" off of the array, and the C# application cannot see them anymore.
I have successfully imported many other functions from the C++ .DLL. Its this array notation which is causing issues. When debugging the .DLL, the values are properly passed to the C++ code, and they are assigned.
Does anyone know why the C# application "loses" the other 4 values? It does not matter the length of the array, only the first value is ever kept after the call to the method.
Thanks in advance. Any help is greatly appreciated.
EDIT-- The solution to my problem was provided in a comment to this question. I am posting my changes below:
C++ .h file:
#pragma once
namespace Wrapper {
extern __declspec(dllexport)
void SANDBOX(int arrayLength, int* intArray);
}
C++ .cpp file:
#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# calls:
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);
Upvotes: 1
Views: 2726
Reputation: 7959
Passing an array by ref in P/Invoke is a bit of an odd operation, since presumably it allows the called function to replace the reference from the native side. I'm not entirely sure why the code you posted doesn't work, since it seems reasonable (apart from the previously mentioned oddness with ref and the declaration in your header not matching parameter types).
However, I think you can easily change the code to fix the issue by not passing by ref and just taking a pointer to the array. You're not trying to reassign the array reference itself; you just care about changing its contents.
Upvotes: 2