Reputation: 205
I am attempting to create a C# program that can pass data into a C/C++ DLL, store the data, and complete calculations on it. The result would then be returned to the C# program. The reason for not using C# for the calculations is that I am planning to accelerate it with CUDA.
I currently declaring a byte array in C#, and passing that as an argument to the DLL to send data.
I then declare a byte array of the same size in C# and pass it as an argument to receive the data. The DLL should then write the results into that memory.
When I run the program, the correct numbers get printed to the screen. (As I am writing 1,2,3... to the array twice, the addition of these is 2,4,6...) "The cat chased the mouse" is then printed. When I press a key, "The mouse chased the cat" is displayed, and the program crashes before it exits displaying a vshost32.exe stopped working error. I was able to solve this error from this question.
Now when I attempt to run the EXE directly from windows explorer, I get the number 36 printed as the first step, but then I get the following error on the compute function call:
"Unhanded exception: System.AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt"
I know the DLL loaded correctly because the init function returned the correct number. I am not sure why it would only be crashing when I am running it as an EXE and not in the debugger. What could be causing this?
Is there a different way I should be handling the memory exchange between the DLL and the C# program? My goal is to avoid copying it using a Marshal Copy as I need this to be high performance. The end goal would be the DLL copying the memory to or from the GPU and the GPU doing the calculations, so I see no reason to have it copied a 2nd time in the DLL before going to the GPU.
C++ DLL Code (written as C code)
#include "stdafx.h"
#include "stdlib.h"
const int CONSTANT = 3;
char** items;
int itemCount = 0;
int xcnt = -1;
int ycnt = -1;
extern "C" int __declspec(dllexport) __stdcall init(int itemcount_local, int xcnt_local, int ycnt_local){
itemCount = itemcount_local;
xcnt = xcnt_local;
ycnt = ycnt_local;
items = (char**)malloc(itemCount);
if (items == NULL){
return -1;
}
for (int i = 0; i < itemCount; i++){
items[i] = (char*)malloc(CONSTANT*xcnt*ycnt);
if (items[i] == NULL){
return -1;
}
for (int d = 0; d < CONSTANT*xcnt*ycnt; d++){
items[i][d] = 0;
}
}
return CONSTANT*xcnt*ycnt;
}
//frees the memory created in init
extern "C" void __declspec(dllexport) __stdcall cleanup(){
for (int i = 0; i < itemCount; i++){
free(items[i]);
}
free(items);
return;
}
extern "C" void __declspec(dllexport) __stdcall loadItem(int index, char* data){
memcpy(items[index], data, CONSTANT*xcnt*ycnt);
return;
}
//fills the buffer with the computed result. Buffer needs to be the size of CONSTANT*xcnt*ycnt
extern "C" void __declspec(dllexport) __stdcall compute(char* buffer){
for (int x = 0; x < CONSTANT*xcnt*ycnt; x++){
int sum = 0;
for (int i = 0; i < itemCount; i++){
sum += items[i][x];
}
if (sum > 255){ //saturate at 255
buffer[x] = 255;
}
else {
buffer[x] = sum;
}
}
return;
}
C# code
class Program
{
[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern int init(int imagecount_local, int xres_local, int yres_local);
[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void cleanup();
[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void loadItem(int index, byte[] data);
[DllImport("DllTest1.dll", CallingConvention=CallingConvention.StdCall, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern void compute(byte[] buffer);
static void Main(string[] args)
{
int x = 4, y = 3;
int total = x * y * 3;
Console.WriteLine(init(5, x, y));
byte[] a = new byte[total];
compute(a);
for (int i = 0; i < total; i++)
{
Console.WriteLine(a[i]);
}
byte[] b = new byte[total];
for (int i = 0; i < total; i++)
{
b[i] = (byte)i;
}
loadItem(0, b);
loadItem(1, b);
compute(a);
for (int i = 0; i < total; i++)
{
Console.WriteLine(a[i]);
}
//cleanup();
Console.WriteLine("The cat chased the mouse");
Console.ReadKey();
Console.WriteLine("The mouse chased the cat");
return;
}
}
Upvotes: 1
Views: 1445
Reputation: 205
I was able to solve the problem. The line
items = (char**)malloc(itemCount);
should have been
items = (char**)malloc(itemCount*sizeof(char*));
Upvotes: 1