Trying to read or write protected memory while trying to transfer a large sequence of characters in C #

I am working on a tag reader and I was able to plug it in and read some data. My problem is when I try to read a tag id, which is a large sequence of characters.

The SDK is in C and I am developing a C # application.

short GetIDBuffer(HANDLE hCom, unsigned char* DataFlag, unsigned char * Count, unsigned char *value, unsigned char* StationNum) 

In my C # application:

 [DllImport("Reader2.dll",CharSet = CharSet.Ansi)] public static extern short GetIDBuffer(IntPtr hCom, ref uint DataFlag, ref uint Count, ref String value, ref uint StationNum); 

The data, number, station number are basically small sequences in which the uint type works well. But when it comes to value , this is a great sequence. I tried the type string , but he threw this exception:

Attempted to read or write protected memory. It is often that other memory is corrupted.

  • [MarshalAs (UnmanagedType.LPWStr)] String value

    didn't solve the problem

  • count correctly returns value

  • My operating system is 64 bit: I used corflags application.exe/32bit+ and I was able to load the DLL correctly.

code snapshot:

  [DllImport("Reader2.dll")] public static extern byte OpenReader(ref IntPtr hCom, byte LinkType, string com_port, uint port); [DllImport("Reader2.dll")] public static extern short GetIDBuffer(IntPtr hCom, ref byte DataFlag, ref byte Count,**(type)** value , ref byte StationNum); static void Main(string[] args) { byte count = 0, station = 1, flag = 0; IntPtr hcom = IntPtr.Zero; OpenReader(ref hcom, 2, "192.168.0.178", 4001); // valid handle returned from openReader // **GetIDBuffer code** // 
+4
source share
3 answers

You do not need to use corflags application.exe / 32bit +. All you have to do is install the target x86 platform in the project / properties / assembly.

This will work (it’s good that it uses its own test method, which I created with the same signature as above). This first method does not require an unsafe keyword or requires that the project be built with "Allow unsafe code" equal to true.

 internal static class NativeMethods { [DllImport("Reader2.dll")] public static extern short GetIDBuffer( IntPtr hCom, ref byte dataFlag, ref byte count, byte [] value, ref byte stationNum); } static int TestGetIDBuffer() { const int arraySize = 255; byte[] bytes = new byte[arraySize + 1]; byte dataFlag = 0; byte count = arraySize; byte status = 0; int retval = NativeMethods.GetIdBuffer(IntPtr.Zero, ref dataFlag, ref count, bytes, ref status); Debug.WriteLine(Encoding.ASCII.GetString(bytes)); Debug.WriteLine(dataFlag); Debug.WriteLine(status); Debug.WriteLine(count); Debug.WriteLine(retval); return retval; } 

Here's an alternative using a fixed byte array. This second method requires an unsafe keyword, and also that the project is built with "Allow unsafe code" set to true.

 internal static class NativeMethods { [DllImport("Reader2.dll")] public static extern unsafe short GetIDBuffer( IntPtr hCom, ref byte dataFlag, ref byte count, byte* value, ref byte stationNum); } static unsafe int TestGetIDBuffer() { const int arraySize = 255; byte[] bytes = new byte[arraySize + 1]; byte dataFlag = 0; byte count = arraySize; byte status = 0; int retval; fixed (byte* buffer = bytes) retval = NativeMethods.GetIdBuffer( IntPtr.Zero, ref dataFlag, ref count, buffer, ref status); Debug.WriteLine(Encoding.ASCII.GetString(bytes)); Debug.WriteLine(dataFlag); Debug.WriteLine(status); Debug.WriteLine(count); Debug.WriteLine(retval); return retval; } 

The data dataFlag, count, and stationNum seem to be byte / output values.

The data buffer is populated with an array of bytes. This buffer needs to be fixed so that the GC does not move it while you call your own method. This is done implicitly in the first example and explicitly in the second.

I assume that the available buffer size should be passed to the method in the count parameter and that this value will be the amount of buffer used when exiting. I allowed an extra byte to provide a null terminating character if the byte array should be converted to a string.

In fact, there are two forms of a fixed operator. One of the MSDN mentioned in this article allows you to create a fixed-size array, as in the open fixed byte Bytes [ArraySize]; Another in this MSDN article allows you to specify the location of a variable for its address.

Here is my C ++ test code:

 extern "C" __declspec(dllexport) unsigned short __stdcall GetIDBuffer( HANDLE hCom, unsigned char * dataFlag, unsigned char * count, unsigned char* buffer, unsigned char * status ) { memset(buffer, 0x1E, *count); *dataFlag = 0xa1; *count = 0x13; *status = 0xfe; return 0x7531; } 

The only difference between the above C # code and my test code is that the entry point should be set differently since I used the C ++ compiler, for example.

 [DllImport("PInvokeTestLib.dll", EntryPoint = " _GetIDBuffer@20 ")] public static extern unsafe short GetIdBuffer(... 

You can safely specify the parameters passed to the method (not including the array of values ​​parameter) as primitive types other than bytes, such as int, long, etc. This is due to the fact that 1) the values ​​are passed by reference and 2) x86 uses the byte order of the low byte. This causes a single byte to be written to the least significant byte of the int byte passed in.

Matching types are recommended, but byte in this case.

+4
source

Your definition for Count is incorrect; it must be ref byte not a ref Uint based on your own prototype. If you change it to the correct type and initialize it with the value that you pass to the StringBuilder constructor, everything should work ... if it is not, I would take a step back and use an array of bytes instead of StringBuilder to help better understand what unmanaged does the code.

edit:

The error you get indicates a buffer overflow

 [DllImport("Reader2.dll")] public static extern short GetIDBuffer(IntPtr hCom, ref byte DataFlag, ref byte Count,**(type)** value , ref byte StationNum); static void Main(string[] args) { byte count = 0, station = 1, flag = 0; //this right here is probably your problem IntPtr hcom = IntPtr.Zero; 

The unmanaged code that you call has no way of knowing how big the buffer you are in is. If your API is normal, you initialize the count variable to report this to the buffer size.

If this is not the case, you will need to look at the documentation to see how much buffer you need to provide.

If none of them is true, we must assume that the return value is the number of bytes written, and since it is short, you need to pass at least 65,535 bytes to the buffer.

If you do not need any of these functions, call the provider and find out how to specify the size of the buffer, since this is actually not a problem as a communication problem.

You also do not need to use fixed at all. The goal of the fixed is to provide you with a pointer that will be used between several unmanaged calls or write managed code that is slightly faster (due to the lack of border checking), since none of them use the use of a byte array.

your finished code should look something like this:

 [DllImport("Reader2.dll")] public static extern short GetIDBuffer(IntPtr hCom, ref byte dataFlag, ref byte count,byte [] value, ref byte stationNum); // ... byte[] value = new byte[65536]; byte count = 255; //does 255 imply some buffer size? short len = GetIDBuffer(hCom, ref dataFlag, ref count,value, ref stationNum); var s1 = Encoding.ASCII.GetString(value,0,count); var s2 = Encoding.ASCII.GetString(value,0,len); Console.WriteLine("using count gives\""+s1+"\""); Console.WriteLine("using return value gives\""+s2+"\""); 
+2
source

Try using SafeHandle rather than IntPtr in P / Invoke. It is possible that the managed wrapper around hCom receives GC'd and is completed in the middle of your own call, while hCom rendering hCom invalid.

0
source

Source: https://habr.com/ru/post/1401459/


All Articles