'System.AccessViolationException' in WPF; DLLImport and unsigned char* - c#

I am trying to import a DLL written in C. The definition of the function is:
__declspec(dllexport) double GetData(unsigned char *Buffer, int l)
{
int i;
for (i= 0; i<l; i++)
{
Buffer[i] = MyVal[i]; //MyVal is a global Variable, updated by differnt process
}
return 3.14;
}
The counter function used in C# to import this DLL is:
[DllImportAttribute(DLLLocation, CallingConvention = CallingConvention.Cdecl)]
public static extern double GetData(StringBuilder buffer, int l);
which is called using,
int l = 8;
StringBuilder buffer = new StringBuilder(8) ;
double t = GetData(buffer, l);
string S = buffer.ToString()
But when I run thiscode, I get an error,
An unhandled exception of type 'System.AccessViolationException' occurred in
TestCode.exe
Additional information: Attempted to read or write protected memory. This is
often an indication that other memory is corrupt.
PS: There are two processes that are using the same DLL. MyVal is getting updated by one process and the other process (WPF) is trying to get that.
Thanks in advance

Related

How can I use ifstream from my c++ Dll in my Unity project?

I have to read a .json file with ifstream from a c++ dll, and I need to use that dll in Unity. I know that there's a problem with Unicode and ASCII, but I can't solve this problem
PS: I made convert_to_string myself, it extract an int from a certain string
In the header of the Dll I have:
int leggiCpp(string nomeFile);
extern "C" {
QUARTALIBRERIA_API int leggiCs(wstring nomeFile);
}
In the cpp of the Dll I have:
int leggiCpp(string nomeFile) {
ifstream _stream(nomeFile.c_str());
string temp;
_stream >> temp >> temp >> temp >> temp >> temp;
return convert_to_int(temp);
}
QUARTALIBRERIA_API int leggiCs(wstring nomeFile){
std::string str = std::string(nomeFile.begin(), nomeFile.end());
int daRit = leggiCpp(str);
return daRit;
}
In the Unity script I have:
[DllImport("QuartaLibreria.dll", CharSet = CharSet.Unicode)]
static extern unsafe int leggiCs(string nomeFile);
// Start is called before the first frame update
unsafe void Start()
{
int temp = leggiCs("Assets/alzBraccioCorretto.json");
}
I have no compiling error, but the Unity program crashes and says: Runtime Error!
Program: This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

How to set or get parameter to DLL library in C#?

I have C++ library (32bit), which I would like to load and use in C#. The DLL is working (open connection, close connection and another methods without parameters). The problem is with unexpected results of all methods of C++ library with have parameters. For example:
C++ library methods specification:
unsigned int WINAPI acqStatus (WORD& stat, WORD& err);
unsigned int WINAPI getStatus (double& time, TCHAR* data);
C# source code (extern methods):
[DllImport("DllName.dll")]
public static extern uint acqStatus(ref ushort stat, ref uint err);
[DllImport("DllName.dll")]
public static extern uint getStatus(ref double time, ref StringBuilder data);
C# first method example (returns bad value, or Im doying mistake to convert IntPtr to integer):
ushort stat = 0;
uint err = 0;
TCPInterface.acqStatus(ref stat, ref err);
// Result of stat is: 0x0003 or 0x0004
// bad value 3 (expected is 0), bad value 4 (expected is 1)
Same situation I have with another method, with returns TCHAR*. Result is string (array of bytes). I dont know, how I get the string from data variable.
double time;
StringBuilder data = new StringBuilder();
getStatus(out time, out data);
// Exception:
An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I'm using 64bit Windows 7 and Visual Studio 2015. I sets my C# project to x86.
I tried to:
Marshal.Copy(...) or Marshal.ReadByte(...) Returns following exception:
An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Tried to run on x86 Windows 7: DLL result was the same (bad result).
Tried to change the IntPtr to byte[] I gets same exception like in Marshal.Copy()
Tried to change out with ref // not helped
Example 1 updated:
[DllImport("DllName.dll")]
public static unsafe extern int acqStatus(ref ushort* stat, ref uint* err);
// Elsewhere in source code in unsafe method
ushort* stat = 0;
uint* err = 0;
TCPInterface.acqStatus(ref stat, ref err);
// I have following exception:
An unhandled exception of type 'System.AccessViolationException' occurred in WindowsFormsApplication1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
That's because ToInt32() and ToString() don't work as you expect. These methods returns the memory address of the pointer, not the retrieved value.
For the first signature, change it to:
[DllImport("DllName.dll")]
// WORD C++ is equivalent to ushort in C#
public static extern uint acqStatus(ref ushort stat, ref ushort err);
For the second it's a little bit more complicated without the exact implementation but a good try will be :
[DllImport("DllName.dll", CharSet = CharSet.Auto)]
public static extern uint getStatus(ref double time, StringBuilder data);

.NET Interop: How to get returned string (not null terminated) from unmanaged DLL in C#

I defined a function in C DLL library.
__declspec(dllexport) void* GetText();
It will return a string which is dynamically allocated from heap memory (And GlobalAlloc is used here for allocating memory). Note that the returned string is not null-terminated.
Then at C# side I tried two methods to declare the function
[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern String GetText();
When calling above method, the application will crash without any exception thrown.
[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr GetText();
ptr = GetText();
string text = Marshal.PtrToStringAuto(ptr, 1000);
And calling this method will return incorrect string. Checked the real bytes by using Marshal.Copy, I found the bytes value is not same as the value in DLL library. (I think it's caused by Virtual Memory, C# process cannot access memory space of the DLL directly)
(Don't mind the string length, I hard coded it to 1000 for ease)
This is the C++ code and the memory value of the string when debugging (It's a Console Application but not the original DLL, because Console Application is easy to debug. But the DLL code is same as this one except the logging part).
Following is the original DLL code
__declspec(dllexport) char* GetText(){
VTHDOC hDoc = NULL;
VTHTEXT hText = VTHDOC_INVALID;
DAERR da_err = NULL;
DAERR ta_err = NULL;
DAERR read_err = NULL;
char *buf = (char*)GlobalAlloc(GMEM_FIXED, 1000);
DWORD real_size;
DAInitEx(SCCOPT_INIT_NOTHREADS, OI_INIT_DEFAULT);
da_err = DAOpenDocument(&hDoc, 2, "D:\\1TB.doc", 0);
ta_err = TAOpenText(hDoc, &hText);
read_err = TAReadFirst(hText, (VTLPBYTE)buf, 1000, &real_size);
return buf;
}
But at C# side the bytes are not same as C++ side
You can see the first byte in C++ is 0, but it's 200 for C# (decimal)
Another thing to note: if I return a const string(e.g. "AASSDD") directly in DLL code, C# side will get the correct string
You can't do it that way. Marshaling of string works only for null-terminated strings (or for BSTR, if you specify some options). You can:
[DllImport("D:\\ca\\TextAccessLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr GetText();
But from there, it isn't clear how the C# program should know the length of the string.
The various Marshal methods of C# handle BSTR (that have internally their length) or NUL terminated strings.
As already stated, it works for null-terminated strings only, in the following way:
C# part, declaration:
[DllImport("myDll.dll", EntryPoint = "myString", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
extern private static string myString(out int size);
C# part, usage:
int size;
string s = myString(out size);
C++ part:
char* myString(int* size)
{
*size = 20;
char* strg = (char*)::GlobalAlloc(GMEM_FIXED, *size);
memset(strg, 0x3f, *size); //preset with a questionmark
for (int i=0; i < 9; i++)
strg[i] = 0x40 + i;
strg[*size -1] = 0; //limit the maximum string length
return strg;
}
And the obtained C# string:
"#ABCDEFGH??????????", value of size: 20
A treatment of the issue may be found here

StackOverflowException while calling native (DllImport) function [duplicate]

This question already has answers here:
Why are Cdecl calls often mismatched in the "standard" P/Invoke Convention?
(2 answers)
Closed 7 years ago.
I'm currenty doing micro-benchmarks for a better understanding of clr to native code performance. In the following example I'm getting a StackOverflowException, when compiled as release and executed without debugger attached. I don't get the exception when compiling as debug-build or when running the program with debugger attached. Furthermore I also get this error only with SuppressUnmanagedCodeSecurityAttribute-Attribute.
I built a dll using c and VS2013 (platformtoolset=v120) with one function in it:
__declspec(dllexport) int __cdecl NativeTestFunction(int a, int b, int c, int d)
{
return a + c + b + d;
}
In my C#-program I use DllImport to call this function and do some timing-measurements:
[DllImport("Native.dll", EntryPoint = "NativeTestFunction")]
static extern int NativeTestFunction(int a, int b, int c, int d);
[DllImport("Native.dll", EntryPoint = "NativeTestFunction"), SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);
static void Main(string[] args)
{
byte[] data = new byte[64];
int c = 0;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
c += NativeTestFunction(2, -1, -2, 1);
Console.WriteLine("Unsuppressed: " + sw.Elapsed.ToString());
sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
c += NativeTestFunctionSuppressed(2, -1, -2, 1);
Console.WriteLine("Suppressed..: " + sw.Elapsed.ToString());
}
If I compile this code as release and start it without debugger attached the output is:
Unsuppressed: 00:00:00.2666255
Process is terminated due to StackOverflowException.
However, executed with debugger attached or compiled as debug and launched with or without debugger attached the program succeeds:
Unsuppressed: 00:00:00.2952272
Suppressed..: 00:00:00.1278980
Is this a known Bug in .NET/CLR? What is my mistake? I think the behavior should be the same between attached and not-attached debugger.
This error happens with .NET 2.0 and .NET 4.0. My software is compiled as x86 (and therefore tested only for x86) for compatibility to the Native.dll. If you don't want to setup this scenario yourself you can download my test-projects: Sourcecode.
__declspec(dllexport) int __cdecl NativeTestFunction(int a, char* b, int c, int d)
Note the type of b. It is char*. Then in the C# code you write:
[DllImport("Native.dll", EntryPoint = "NativeTestFunction"),
SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);
Here you declare b to be int. That does not match. It gets worse when you call the function.
NativeTestFunctionSuppressed(2, -1, -2, 1);
Passing -1 will, in a 32 bit process, equate to passing the address 0xffffffff. Nothing good will come of attempting to de-reference that address.
The other problem is that the calling conventions do not match. The native code uses __cdecl, but the managed code uses the default of __stdcall. Change the managed code to:
[DllImport("Native.dll", EntryPoint = "NativeTestFunction",
CallingConvention = CallingConvention.Cdecl),
SuppressUnmanagedCodeSecurityAttribute]
And likewise for the other import.

How to return a double pointer from a C++ dll to C#?

I am trying to return a pointer from my C++ dll to C#. I tried everything, but my pointer of type double doesn't have a value.
Below is my import of the C++ dll:
[DllImport("/Resources/libfli.dll", EntryPoint = "FLIGetTemperature")]
public static extern unsafe int FLIGetTemperature(long dev, double* temperature);
// Get the temperature of a given camera. This function places the temperature of the CCD camera
// cold finger of device dev in the location pointed to by temperature.
// Return Value: Zero on success. Non-zero on failure.
// Parameters: dev Camera device to get the temperature of.
// temperature Pointer to where the temperature will be placed.
// See Also: FLISetTemperature
the defination of FliGetTemperatre from the FLI_SDK_Documentation
LIBFLIAPI FLIGetTemperature (flidev_t dev, double* temperature)
Get the temperature of a given camera.
Below is how I declare my call to the .Dll in C#:
unsafe public void GetTheTemperatureOfTheCamera()
{
int success=0;
long ldev = 0;
long* dev = &ldev;
double lTemperature = 0;
double* temperature = &lTemperature;
success = FLIGetTemperature(ldev, temperature);
}
When I run my code I get the following error below:
An unhandled exception of type 'System.AccessViolationException' occurred in myApplication.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I also tried marshaling and IntPtr, but that is not working either.
I have tried Fliopen that fucntion works. It success. Below is the code for FliOpen.
[DllImport("/Resources/libfli.dll", EntryPoint = "FLIOpen")]
public static extern unsafe int FLIOpen(long* dev, string name, long domain);
unsafe public int InitDevice()
{
long ldev = 0;
long* dev = &ldev;
int success;
string deviceName = "flipro0";// this is default name for device
long domainName = 258; //this is default domain name
success = FLIOpen(dev, deviceName, domainName);
return success;
}
The FLIOpen method is a success though
Reading the documentation, I would have wrote something like this :
unsafe public void GetTheTemperatureOfTheCamera()
{
int success=0;
long dev = 0;
long* ldev = &dev;
success = FLIOpen(ldev, deviceName, domainName); //Get the device handle.
if (success != 0)
throw new Exception("Cannot open device");
double lTemperature = 0;
double* temperature = &lTemperature;
success = FLIGetTemperature(dev, temperature);
}
There is a mismatch between your C# long parameter and the unmanaged type flidev_t. The key point is that long is a 64 bit type. Assuming your code is running in Windows then flidev_t, which is an alias of C++ long, is 32 bits wide.
You also have no need for unsafe code here. You can declare the function like this:
[DllImport("/Resources/libfli.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLIGetTemperature(int dev, out double temperature);
I'm also assuming that the calling convention is cdecl, but you probably need to check the C++ header file to be sure about that.
You'll need to make other changes in your other p/invoke declarations. Essentially everywhere you have translated flidev_t to C# long you should change it to int. Or perhaps even IntPtr. Then you'd be one step ahead of the unmanaged code which currently is not fit for a 64 bit port I suspect!
Starting with FLIOpen that is going to be:
[DllImport("/Resources/libfli.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLIOpen(out int dev, string name, int domain);
Well, the domain parameter might be better translated as a C# enum with int base type.

Categories

Resources