Returning an array of structs from an unmanaged C++ function to C#












1















I am currently working on a group project where aside from the GUI which is done in C# all of the code is done in C++.



In C++ we are using a funtion that reads formatted text from a file and seperates it into an array of structs, an example of a struct is:



typedef struct example{
string id;
string name;
string email;
char status;
string phone_number;
}example;


And of an array:



example* example_arr=new example[10];


We then want to return that array from the C++ function and use it in C# (DLLImport) to display that info in a Form.



When I started thinking about the implementation of the C# part I realized that I'm pretty much clueless about how to approach it since I've never seen unmanaged memory being used in C#, so I started looking for possible solutions but most of the cases I found are about sending info the opposite direction(from C# to C++) or were rather unclear in their explanation. The only thing I got from them really is that the concept of marshalling might be of use, however, I couldn't really wrap my head around it.



I would honestly appreciate any help on the topic, I really want to make it happen even though I'm not experienced with handling unmanaged memory in C#.



EDIT:



I've tried implementing what Hans suggested but I've faced a problem.
The C# code runs, executes the C++ function which runs as well up until it gets to the return statement and just stops(doesn't break/throw just freezes like it's waiting for something to happen) which in return stops the C# code from continuing it's run.



This is the code(I simplified the struct for the sake of testing):



C++



///header file
typedef struct example
{
int num;
char str[5];
}example;

extern "C" __declspec(dllexport) int __stdcall test(a arr,int len);

///Cpp file
int __stdcall test(example* arr,int len)
{
for (int i = 0; i < len; i++)
{
arr[i].num = i;
std::cout <<"arr["<<i<<"].num = "<< arr[i].num<<"n";//for debugging purposes
strcpy(arr[i][0].str, "test");
}
std::cout << "not yetn";
return -1;//*does not get executed*
}


C#



public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct example
{
public int num;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string str;
};

[DllImport("unmanaged.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int test(out example arr,int len);

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)//Form Loaded Event function
{
example arr = new example[10];
int res = test(out arr,10);//*Code freezes here*

Debug.WriteLine(res);
_text.Text =arr[0].str;
}
}


The output in the debug window is(should end with -1 if everything works):



arr[0].num = 0
arr[1].num = 1
arr[2].num = 2
arr[3].num = 3
arr[4].num = 4
arr[5].num = 5
arr[6].num = 6
arr[7].num = 7
arr[8].num = 8
arr[9].num = 9
not yet


I find it to be really weird, it might be some mechanic related to the [out] modifier but I've got not clue.










share|improve this question

























  • unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

    – Marc Gravell
    Nov 21 '18 at 13:16








  • 1





    You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

    – Hans Passant
    Nov 21 '18 at 13:24











  • So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

    – Onlugassy
    Nov 21 '18 at 13:24








  • 1





    Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

    – Hans Passant
    Nov 21 '18 at 13:26








  • 1





    No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

    – Hans Passant
    Nov 21 '18 at 13:30


















1















I am currently working on a group project where aside from the GUI which is done in C# all of the code is done in C++.



In C++ we are using a funtion that reads formatted text from a file and seperates it into an array of structs, an example of a struct is:



typedef struct example{
string id;
string name;
string email;
char status;
string phone_number;
}example;


And of an array:



example* example_arr=new example[10];


We then want to return that array from the C++ function and use it in C# (DLLImport) to display that info in a Form.



When I started thinking about the implementation of the C# part I realized that I'm pretty much clueless about how to approach it since I've never seen unmanaged memory being used in C#, so I started looking for possible solutions but most of the cases I found are about sending info the opposite direction(from C# to C++) or were rather unclear in their explanation. The only thing I got from them really is that the concept of marshalling might be of use, however, I couldn't really wrap my head around it.



I would honestly appreciate any help on the topic, I really want to make it happen even though I'm not experienced with handling unmanaged memory in C#.



EDIT:



I've tried implementing what Hans suggested but I've faced a problem.
The C# code runs, executes the C++ function which runs as well up until it gets to the return statement and just stops(doesn't break/throw just freezes like it's waiting for something to happen) which in return stops the C# code from continuing it's run.



This is the code(I simplified the struct for the sake of testing):



C++



///header file
typedef struct example
{
int num;
char str[5];
}example;

extern "C" __declspec(dllexport) int __stdcall test(a arr,int len);

///Cpp file
int __stdcall test(example* arr,int len)
{
for (int i = 0; i < len; i++)
{
arr[i].num = i;
std::cout <<"arr["<<i<<"].num = "<< arr[i].num<<"n";//for debugging purposes
strcpy(arr[i][0].str, "test");
}
std::cout << "not yetn";
return -1;//*does not get executed*
}


C#



public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct example
{
public int num;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string str;
};

[DllImport("unmanaged.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int test(out example arr,int len);

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)//Form Loaded Event function
{
example arr = new example[10];
int res = test(out arr,10);//*Code freezes here*

Debug.WriteLine(res);
_text.Text =arr[0].str;
}
}


The output in the debug window is(should end with -1 if everything works):



arr[0].num = 0
arr[1].num = 1
arr[2].num = 2
arr[3].num = 3
arr[4].num = 4
arr[5].num = 5
arr[6].num = 6
arr[7].num = 7
arr[8].num = 8
arr[9].num = 9
not yet


I find it to be really weird, it might be some mechanic related to the [out] modifier but I've got not clue.










share|improve this question

























  • unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

    – Marc Gravell
    Nov 21 '18 at 13:16








  • 1





    You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

    – Hans Passant
    Nov 21 '18 at 13:24











  • So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

    – Onlugassy
    Nov 21 '18 at 13:24








  • 1





    Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

    – Hans Passant
    Nov 21 '18 at 13:26








  • 1





    No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

    – Hans Passant
    Nov 21 '18 at 13:30
















1












1








1








I am currently working on a group project where aside from the GUI which is done in C# all of the code is done in C++.



In C++ we are using a funtion that reads formatted text from a file and seperates it into an array of structs, an example of a struct is:



typedef struct example{
string id;
string name;
string email;
char status;
string phone_number;
}example;


And of an array:



example* example_arr=new example[10];


We then want to return that array from the C++ function and use it in C# (DLLImport) to display that info in a Form.



When I started thinking about the implementation of the C# part I realized that I'm pretty much clueless about how to approach it since I've never seen unmanaged memory being used in C#, so I started looking for possible solutions but most of the cases I found are about sending info the opposite direction(from C# to C++) or were rather unclear in their explanation. The only thing I got from them really is that the concept of marshalling might be of use, however, I couldn't really wrap my head around it.



I would honestly appreciate any help on the topic, I really want to make it happen even though I'm not experienced with handling unmanaged memory in C#.



EDIT:



I've tried implementing what Hans suggested but I've faced a problem.
The C# code runs, executes the C++ function which runs as well up until it gets to the return statement and just stops(doesn't break/throw just freezes like it's waiting for something to happen) which in return stops the C# code from continuing it's run.



This is the code(I simplified the struct for the sake of testing):



C++



///header file
typedef struct example
{
int num;
char str[5];
}example;

extern "C" __declspec(dllexport) int __stdcall test(a arr,int len);

///Cpp file
int __stdcall test(example* arr,int len)
{
for (int i = 0; i < len; i++)
{
arr[i].num = i;
std::cout <<"arr["<<i<<"].num = "<< arr[i].num<<"n";//for debugging purposes
strcpy(arr[i][0].str, "test");
}
std::cout << "not yetn";
return -1;//*does not get executed*
}


C#



public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct example
{
public int num;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string str;
};

[DllImport("unmanaged.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int test(out example arr,int len);

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)//Form Loaded Event function
{
example arr = new example[10];
int res = test(out arr,10);//*Code freezes here*

Debug.WriteLine(res);
_text.Text =arr[0].str;
}
}


The output in the debug window is(should end with -1 if everything works):



arr[0].num = 0
arr[1].num = 1
arr[2].num = 2
arr[3].num = 3
arr[4].num = 4
arr[5].num = 5
arr[6].num = 6
arr[7].num = 7
arr[8].num = 8
arr[9].num = 9
not yet


I find it to be really weird, it might be some mechanic related to the [out] modifier but I've got not clue.










share|improve this question
















I am currently working on a group project where aside from the GUI which is done in C# all of the code is done in C++.



In C++ we are using a funtion that reads formatted text from a file and seperates it into an array of structs, an example of a struct is:



typedef struct example{
string id;
string name;
string email;
char status;
string phone_number;
}example;


And of an array:



example* example_arr=new example[10];


We then want to return that array from the C++ function and use it in C# (DLLImport) to display that info in a Form.



When I started thinking about the implementation of the C# part I realized that I'm pretty much clueless about how to approach it since I've never seen unmanaged memory being used in C#, so I started looking for possible solutions but most of the cases I found are about sending info the opposite direction(from C# to C++) or were rather unclear in their explanation. The only thing I got from them really is that the concept of marshalling might be of use, however, I couldn't really wrap my head around it.



I would honestly appreciate any help on the topic, I really want to make it happen even though I'm not experienced with handling unmanaged memory in C#.



EDIT:



I've tried implementing what Hans suggested but I've faced a problem.
The C# code runs, executes the C++ function which runs as well up until it gets to the return statement and just stops(doesn't break/throw just freezes like it's waiting for something to happen) which in return stops the C# code from continuing it's run.



This is the code(I simplified the struct for the sake of testing):



C++



///header file
typedef struct example
{
int num;
char str[5];
}example;

extern "C" __declspec(dllexport) int __stdcall test(a arr,int len);

///Cpp file
int __stdcall test(example* arr,int len)
{
for (int i = 0; i < len; i++)
{
arr[i].num = i;
std::cout <<"arr["<<i<<"].num = "<< arr[i].num<<"n";//for debugging purposes
strcpy(arr[i][0].str, "test");
}
std::cout << "not yetn";
return -1;//*does not get executed*
}


C#



public partial class Form1 : Form
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct example
{
public int num;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string str;
};

[DllImport("unmanaged.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int test(out example arr,int len);

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)//Form Loaded Event function
{
example arr = new example[10];
int res = test(out arr,10);//*Code freezes here*

Debug.WriteLine(res);
_text.Text =arr[0].str;
}
}


The output in the debug window is(should end with -1 if everything works):



arr[0].num = 0
arr[1].num = 1
arr[2].num = 2
arr[3].num = 3
arr[4].num = 4
arr[5].num = 5
arr[6].num = 6
arr[7].num = 7
arr[8].num = 8
arr[9].num = 9
not yet


I find it to be really weird, it might be some mechanic related to the [out] modifier but I've got not clue.







c# c++ .net unmanaged managed






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 13:05







Onlugassy

















asked Nov 21 '18 at 13:12









OnlugassyOnlugassy

133




133













  • unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

    – Marc Gravell
    Nov 21 '18 at 13:16








  • 1





    You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

    – Hans Passant
    Nov 21 '18 at 13:24











  • So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

    – Onlugassy
    Nov 21 '18 at 13:24








  • 1





    Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

    – Hans Passant
    Nov 21 '18 at 13:26








  • 1





    No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

    – Hans Passant
    Nov 21 '18 at 13:30





















  • unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

    – Marc Gravell
    Nov 21 '18 at 13:16








  • 1





    You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

    – Hans Passant
    Nov 21 '18 at 13:24











  • So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

    – Onlugassy
    Nov 21 '18 at 13:24








  • 1





    Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

    – Hans Passant
    Nov 21 '18 at 13:26








  • 1





    No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

    – Hans Passant
    Nov 21 '18 at 13:30



















unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

– Marc Gravell
Nov 21 '18 at 13:16







unmanaged memory actually has pretty good support in C#, however: it is usually much easier if you can handle the allocations (and thus the lifetime) from the C# side, essentially passing a pointer in to the C/C++ (the pointer could be from managed heap, unmanaged heap, or stack memory - it doesn't really matter). Is it possible to consider an API that allows the consumer to handle the allocation site?

– Marc Gravell
Nov 21 '18 at 13:16






1




1





You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

– Hans Passant
Nov 21 '18 at 13:24





You are heading for a crash into a memory management wall at a hundred miles an hour. C# is not going to use the delete operator to release the allocation again. It can't, guaranteed memory leak. Always favor writing this code so you pass the C# array to the C++ code, along with its length, so the C++ code can simply fill the array elements. A handle-based approach can work too, typically requires create(), getdata() and destroy() functions. Where destroy() would use the delete operator.

– Hans Passant
Nov 21 '18 at 13:24













So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

– Onlugassy
Nov 21 '18 at 13:24







So if I understand you correctly(I'm not a native speaker so I'm just making sure) you are suggesting to send the pointer created in C# to C++ and do all the assignments there so that I don't need to return anything and just access the the data when the function is done?

– Onlugassy
Nov 21 '18 at 13:24






1




1





Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

– Hans Passant
Nov 21 '18 at 13:26







Yes. [Out] required on the array argument so it knows it needs to copy the array back. Don't skimp on the length argument since it is easy to corrupt the GC heap when you overflow the array bounds.

– Hans Passant
Nov 21 '18 at 13:26






1




1





No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

– Hans Passant
Nov 21 '18 at 13:30







No, that is the job of the pinvoke marshaler to take care of. You need a declaration for the struct both in the C++ and the C# code. It needs to be an exact match, sizeof(example) in C++ must be equal to Marshal.SizeOf(typeof(Example)) in C#. Usually not a problem, won't hurt to check.

– Hans Passant
Nov 21 '18 at 13:30














0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53412842%2freturning-an-array-of-structs-from-an-unmanaged-c-function-to-c-sharp%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53412842%2freturning-an-array-of-structs-from-an-unmanaged-c-function-to-c-sharp%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

How to fix TextFormField cause rebuild widget in Flutter