Read/Write C# array from C++ application - c#

Previously I had a c++ console application and I rewrote everything to C# WPF application so I have now UI, but I cant figure out how to get a correct offset (pointer) to change or read a value via C++ application.
In c++ it was so easy to get address
uint32_t check = 0xABCD;
uint64_t add[1];
add[0] = (uintptr_t)✓
printf("address: 0x%I64x\n", (uint64_t)&add[0] - (uint64_t)GetModuleHandle(NULL));
and then from another program I was able to read/write add.
Tried with garbage collector, but everytime address changes + wrong address. Also NativeMemory was not working because I can not use unsafe code.
public static IntPtr[] add = new IntPtr[1];
protected static int check = 0xABCD;
public static void SomeFunction()
{
GCHandle check_handle = GCHandle.Alloc(check, GCHandleType.Pinned);
IntPtr check_ptr = check_handle.AddrOfPinnedObject();
add[0] = check_ptr;
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
{
if (long.TryParse(add[0].ToString(), out long add0))
{
long offset_addr = (long)add[0] - (long)GetModuleHandle(null);
a.add_offset_textbox.Text = "0x" + offset_addr.ToString("X");
}
}));
}

Related

Marshal char* from double pointer Struct from C++ to C#

Goal: Retrieve the array of structs from c++, from the c++ side it's finalized to return pointer to struct pointer (Double pointer)(Not in my control).
Sample c++ code :
struct Output
{
char* Name;
};
extern "C"
{
__declspec(dllexport) Output** getoutput()
{
Output* items = (Output*)malloc(sizeof(Output) * 4);
items->Name = "Hello World";
return &items;
}
}
c# Side code :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Output
{
[MarshalAsAttribute(UnmanagedType.LPStr)]
public string Name;
};
[DllImport(#"CPPInvokeExposed.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr getoutput();
static void Main(string[] args)
{
var output = Program.getoutput();
Output[] outputs = new Output[1];
MarshalUnmananagedArray2Struct<Output>(output, 1, out outputs);
**outputs[0]// this has junk chars**
}
public static void MarshalUnmananagedArray2Struct<T>(IntPtr unmanagedArray, int length, out T[] mangagedArray)
{
var size = Marshal.SizeOf(typeof(T));
mangagedArray = new T[length];
for (int i = 0; i < length; i++)
{
IntPtr ins = new IntPtr(unmanagedArray.ToInt64() + i * size);
mangagedArray[i] = Marshal.PtrToStructure<T>(ins);
}
}
Is not clear whether the problem is in c++ or c# code. What should be the correct way get the Char* from c++ which exists in struct.
One strange thing is, for the same code if c++ code return single pointer(Output*) instead double pointer(Output**), there is no junk character, getting the correct assigned value. looks like something wrong while returning double pointer from c++.
You C++ code causes undefined behaviour:
return &items;
This returns the address of an automatic variable.
That variable will not exist anymore when the function returns. Accessing that memory location is illegal and causes undefined behaviour.
A clean solution would be to return the pointer itself, not the address. But in your question you state that the return type is not under your control.
In that case you must create the second level of indirection by yourself:
__declspec(dllexport) Output** getoutput()
{
Output* items = (Output*)malloc(sizeof(Output) * 4);
items->Name = "Hello World";
Output **retval = (Output**)malloc(sizeof(Output*))
*retval = items;
return retval;
}
Of course you also need to take care about freeing both levels of memory allocation afterwards.
BTW:
You allocate memory for 4 structs but only assign a value to member of the first element.

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

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 yet\n";
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.

Passing list of struct to C++ DLL from C# Application

I am trying to pass struct as a parameter from C# application to the C++ MFC DLL. DLL fills records in the struct object and return back to the C# application. So here I used "out" keyword in C# application to call C++ method. When I execute it, it fails with error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." I am allocating memory at C++ DLL to store the records and assign it to out parameter. I could send data in struct object and print it in C++ DLL but not able to do modification in struct object at DLL side and return back to C# application.
Could anybody please help on this.
NativeDLLHelper.cs
class NativeDLLHelper
{
const int FIELD_LENGTH = 255;
[StructLayout(LayoutKind.Sequential)]
public struct APPDATA
{
public int ID;
public int Version;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = FIELD_LENGTH)]
public string AppName;
};
[DllImport("Parser.dll", EntryPoint = "?FillLstStructData#DLLWrapper##QAEXAAPAU_APPDATA#1##Z")]
public static extern void FillLstStructData(out APPDATA[] AppDataStruct);
}
Main.cs
NativeDLLHelper.APPDATA[] lstFillAppDataStruct;
NativeDLLHelper.FillLstStructData(out lstFillAppDataStruct);
for (int i = 0; i < lstFillAppDataStruct.Length; i++)
{
Console.WriteLine(" ID[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].ID);
Console.WriteLine(" Version[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].Version);
Console.WriteLine(" AppName[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].AppName);
}
C++ DLL:
static const int FIELD_LENGTH = 128;
typedef struct _APPDATA
{
int ID;
double Version;
TCHAR AppName[FIELD_LENGTH];
}APPDATA;
extern "C" __declspec(dllexport) FillLstStructData(APPDATA* &pAppData)
{
APPDATA *localAppDataStruct = new APPDATA[2];
localAppDataStruct[0].ID = 1;
localAppDataStruct[0].Version = 1.1;
_tcscpy(localAppDataStruct[0].AppName, L"MS Visual Studio 2010");
localAppDataStruct[1].ID = 2;
localAppDataStruct[1].Version = 2.1;
_tcscpy(localAppDataStruct[1].AppName, L"MS Office 2010");
pAppData = localAppDataStruct;
}
Your exported function unmangles to:
void __thiscall DLLWrapper::FillLstStructData(struct DLLWrapper::_APPDATA * &)
That makes it an instance method of a C++ class. You cannot pinvoke such methods, they require the C++ object to be created first and you cannot do this reliably with pinvoke. Only static C++ member functions can be pinvoked. Do note that this function doesn't need to be an instance method at all, it doesn't actually use instance members of the class.
That isn't the only problem, there's also a nasty memory management issue. The function allocates memory with ::operator new and memory needs to be released by the caller. But a C# program cannot do this, it doesn't have access to the ::operator delete that the C++ code uses. This kind of function is very hard to use reliably from a C++ program for that reason, it doesn't get better when you do it from C#. The proper way to do it is to allow the caller to pass the array. In other words, APPDATA[] and an extra argument that says how long the passed array is.
If you can't rewrite this function then you must write a wrapper for this class using the C++/CLI language. Very important that this wrapper uses the exact same compiler and CRT version as the C++ DLL.

Passing an array of unknown size of structs from c# to c++ dll and back

I asked a similar question yesterday, but this is slightly different. I am having problems passing arrays of struct from c# to c++, and getting this back again.
Here is the c++ code. Firstly, the struct:
struct Tri
{
public:
int v1, v2, v3;
}
and now the c++ dll part:
extern "C" __declspec(dllexport) void Dll_TriArray(Tri *tri)
{
int num = 10;
tri = new Tri[num];
for (int i = 0; i < num; i++)
{
tri[i].v1 = i + 5;
tri[i].v2 = i + 10;
tri[i].v3 = i + 25;
}
}
and here's the c# code, again starting with the struct:
[StructLayout(LayoutKind.Sequential)]
public struct Tri
{
public int v1, v2, v3;
}
public class Testing
{
[DllImport("testing.dll")]
static extern void Dll_TriArray(out Tri[] tryArray);
public GetTriArray()
{
Tri[] triArray;
Dll_TriArray(out triArray);
}
}
So the triArray i get when calling the GetTriArray method will come back as null. I have thought about passing an IntPtr in as the argument, but then how does one marshal an intptr into/from an array of struct?
BTW - at this stage, i'm not interested in memory leaks.
I'm not an expert (by any means) in C# but the C++ part gets passed a pointer to Tri-struct, which in C++ can be used like an dynamic array you allocate and fill that correctly but you don't have a way to get it back, because from C-perspective you'd need to modify the caller's (C#) pointer but you only get a copy and not a reference to the original.
In C++ the closest thing to what you are tying to do, would be to change the prototype to void Dll_TriArray(Tri *&tri) (call by ref, not call by copy) but I'm not sure how to interface that with C# (probably Dll_TriArray(ref triArray); ).

How do I call this c function in c# (unmarshalling return struct)?

I want to use c# interop to call a function from a dll written in c. I have the header files.
Take a look at this:
enum CTMBeginTransactionError {
CTM_BEGIN_TRX_SUCCESS = 0,
CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};
#pragma pack(push)
#pragma pack(1)
struct CTMBeginTransactionResult {
char * szTransactionID;
enum CTMBeginTransactionError error;
};
struct CTMBeginTransactionResult ctm_begin_customer_transaction(const char * szTransactionID);
How do I call ctm_begin_customer_transaction from c#. The const char * mapps well to string, but despite various attempts (looking at stackoverflow and other sites), I fail to marshal the return structure. If I define the function to return IntPtr it works ok...
Edit
I changed the return type to IntPtr and use:
CTMBeginTransactionResult structure = (CTMBeginTransactionResult)Marshal.PtrToStructure(ptr, typeof(CTMBeginTransactionResult));
but it throws AccessViolationException
I also tried:
IntPtr ptr = Transactions.ctm_begin_customer_transaction("");
int size = 50;
byte[] byteArray = new byte[size];
Marshal.Copy(ptr, byteArray, 0, size);
string stringData = Encoding.ASCII.GetString(byteArray);
stringData == "70e3589b-2de0-4d1e-978d-55e22225be95\0\"\0\0\a\0\0\b\b?" at this point. The "70e3589b-2de0-4d1e-978d-55e22225be95" is the szTransactionID from the struct. Where is the Enum? Is it the next byte?
There's a memory management problem hidden in this struct. Who owns the C string pointer? The pinvoke marshaller will always assume that the caller owns it so it will try to release the string. And passes the pointer to CoTaskMemFree(), same function as the one called by Marshal.FreeCoTaskMem(). These functions use the COM memory allocator, the universal interop memory manager in Windows.
This rarely comes to a good end, C code does not typically use that allocator unless the programmer designed his code with interop in mind. In which case he'd never have used a struct as a return value, interop always works much less trouble-free when the caller supplies buffers.
So you cannot afford to let the marshaller do its normal duty. You must declare the return value type as IntPtr so it doesn't try to release the string. And you must marshal it yourself with Marshal.PtrToStructure().
That however still leaves the question unanswered, who owns the string? There is nothing you can do to release the string buffer, you don't have access to the allocator used in the C code. The only hope you have is that the string wasn't actually allocated on the heap. That's possible, the C program might be using string literals. You need to verify that guess. Call the function a billion times in a test program. If that doesn't explode the program then you're good. If not then only C++/CLI can solve your problem. Given the nature of the string, a "transaction ID" ought to change a lot, I'd say you do have a problem.
I hate to answer my own question, but I found the solution to marshal the resulting struct. The struct is 8 bytes long (4 bytes for the char * and 4 bytes for enum). Marshalling the string does not work automatically, but the following works:
// Native (unmanaged)
public enum CTMBeginTransactionError
{
CTM_BEGIN_TRX_SUCCESS = 0,
CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};
// Native (unmanaged)
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
internal struct CTMBeginTransactionResult
{
public IntPtr szTransactionID;
public CTMBeginTransactionError error;
};
// Managed wrapper around native struct
public class BeginTransactionResult
{
public string TransactionID;
public CTMBeginTransactionError Error;
internal BeginTransactionResult(CTMBeginTransactionResult nativeStruct)
{
// Manually marshal the string
if (nativeStruct.szTransactionID == IntPtr.Zero) this.TransactionID = "";
else this.TransactionID = Marshal.PtrToStringAnsi(nativeStruct.szTransactionID);
this.Error = nativeStruct.error;
}
}
[DllImport("libctmclient-0.dll")]
internal static extern CTMBeginTransactionResult ctm_begin_customer_transaction(string ptr);
public static BeginTransactionResult BeginCustomerTransaction(string transactionId)
{
CTMBeginTransactionResult nativeResult = Transactions.ctm_begin_customer_transaction(transactionId);
return new BeginTransactionResult(nativeResult);
}
The code works, but I still need to investigate, if calling the unmanaged code results in memory leaks.

Categories

Resources