CRITICAL_SECTION in c# - c#

All. I need to use winapi critical section in c# code.
First of all, I import functions:
[StructLayout(LayoutKind.Sequential)]
public struct CRITICAL_SECTION { public int dummy; }
// INIT CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern bool InitializeCriticalSectionAndSpinCount(ref CRITICAL_SECTION
lpCriticalSection, uint dwSpinCount);
// DELETE CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void DeleteCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
// ENTER CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
// LEAVE CRITICAL SECTION
[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref CRITICAL_SECTION
lpCriticalSection);
In this way I try to use critical section:
static void Main(string[] args)
{
GenerateArray();
InvokeThread invokeThread = () =>
{
WaitForSingleObject(ghSemaphore, 0);
EnterCriticalSection(ref CriticalSection); // critical section
int[] array = new int[ARRAY_SIZE_PER_THREAD];
int baseI = thread * ARRAY_SIZE_PER_THREAD;
for (int i = 0; i < ARRAY_SIZE_PER_THREAD; ++i)
{
array[i] = gList[baseI + i];
}
LeaveCriticalSection(ref CriticalSection); // critical section
ReleaseSemaphore(ghSemaphore, 1, IntPtr.Zero);
return 0;
};
ghSemaphore = CreateSemaphore(ref seqAttr, THREADS_NUMBER, THREADS_NUMBER, "");
InitializeCriticalSectionAndSpinCount(ref CriticalSection, 0);
IntPtr threadPtr = Marshal.GetFunctionPointerForDelegate(invokeThread);
IntPtr[] handlers = new IntPtr[THREADS_NUMBER];
for (int i = 0; i < THREADS_NUMBER; ++i)
{
int handle = CreateThread(IntPtr.Zero, 0, threadPtr, IntPtr.Zero, 0, 0);
handlers[i] = new IntPtr(handle);
}
WaitForMultipleObjects(THREADS_NUMBER, handlers, true, Infinite);
DeleteCriticalSection(ref CriticalSection); // delete critical section
}
}
But at next line gList containes wrong values. And every thing is good, if I don't use critical section.
for (int i = 0; i < ARRAY_SIZE_PER_THREAD; ++i)
{
array[i] = gList[baseI + i];
}
Where could be a problem?

Your definition of the CRITICAL_SECTION struct is wrong. In the Windows headers is has 24 bytes or so, but yours has only 4.
Also, you don't do new CRITICAL_SECTION anywere. And you need it, InitializeCriticalSection sets the data, but don't allocate it.

I also agree that using the critical section API from .net seems like a bad design choice. If you must then I'd contemplate writing a C++/CLI mixed-mode wrapper. That way you can include the windows header files directly.
However, there is a rather obvious flaw in your p/invoke code. That's the declaration of the CRITICAL_SECTION struct. You've declared it as holding a single integer value. But the native struct is bigger than that. On x86 it is 24 bytes long, and on x64 it is 40 bytes long. You don't need to declare any of the fields since from your perspective it's just an opaque block of memory.
If I were you I would get rid of CRITICAL_SECTION. I would change all the ref CRITICAL_SECTION parameters to IntPtr. And I would use Marshal.AllocHGlobal(40) to create a large enough block of memory to hold the critical section data.
For example:
[DllImport("kernel32.dll")]
static extern bool InitializeCriticalSectionAndSpinCount(
IntPtr lpCriticalSection,
uint dwSpinCount
);
and so on.

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.

Can a pointer be marshalled to an array when passing a struct?

In the below example, the dataArray defined in C++ works if defined as an array, but not as a pointer (Just turns out garbage data). Is there another way to marshal the C# array so that it reads the pointer in as an array?
C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CSharpFoo{
int alpha;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5]
public int[] dataArray;
int beta;
}
C++
struct CPPFoo{
int alpha;
//int* dataArray; //Doesn't work, even though initialized to an array elsewhere
int dataArray[5];
int beta;
}
Being passed through a function like this
C#
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public extern static bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)] ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(CSharpFoo value);
C++
//Callback
typedef void(__stdcall * ResultCallback)(CPPFoo);
__declspec(dllexport) bool InitializeDLL(ResultCallback callback);
Thanks in advance!
Edit::
Because "initialized to an array elsewhere" wasn't clear:
CPPFoo(int dummy){ //Constructor
alpha = 32;
dataArray = new int[5];
for (int i = 0; i < 5; i++){
dataArray[i] = i;
}
beta = 13;
}
//dataArray C++ {0,1,2,3,4}
//alpha C# 32
//dataArray C# {Total random garbage} (dataArray[3] is 13!)
//beta C# 0
PS, the CPPFoo struct is a complex struct that comes from a DLL, so I cannot change it. For now, to get things working, I copy it to a more appropriate array like in NonCreature0714's answer, but this results in all of the data being copied--twice. It's this double copy that I'm trying to avoid.
Another edit:
While it seems that for a struct containing a single array the values get passed properly, for a complex struct, garbage gets thrown in.
I have updated the code to reflect a more complex struct!
I did a couple of tests on my local machine, as far as I understood your code. I had no problems with the following code
c# side
struct Foo
{
public int alpha;
public IntPtr Data;
public int beta;
public void GetData(ref int[] buffer,int length)
{
Marshal.Copy(Data,buffer,0,length);
}
}
class Program
{
[DllImport("MyPtr.dll",EntryPoint = "InitializeDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)]ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(ref Foo value);
static void CallBackMe(ref Foo value)
{
var buffer = new int[5];
value.GetData(ref buffer,buffer.Length);
}
static void Main(string[] args)
{
InitializeDLL(CallBackMe);
}
}
C++ side
struct CPPFoo {
int* dataArrayPtr;
CPPFoo()
{
dataArrayPtr = new int[5];
for (int i = 0; i < 5; i++) {
dataArrayPtr[i] = i;
}
}
};
typedef void(__stdcall * ResultCallback)(CPPFoo);
extern "C" __declspec(dllexport) bool InitializeDLL(ResultCallback callback)
{
CPPFoo f;
callback(f);
return true;
}
Code in action
My experience in C# is very limited but it seems that it works with int dataArray[5]; because the code agrees to the type of CSharpFoo and CPPFoo. The size of both is five ints. When you change the type to a pointer then one is the size of five ints and the other is a single pointer which would be less then five ints.
Most likely passing a dynamically sized array will need a size and to get a pointer you may need to do something with unsafe code but I don't write in C# so that is just a guess.
struct CPPFoo {
int* dataArray = nullptr;
int size = 0;
}
Use a vector.
#include <vector>
struct CPPFoo {
std::vector<int> dataArray;
};
Vector is more readable and more safe. It only slighty increases the size of the code, and is only slightly slower than using a primitive array. You also don’t need to worry about keeping around a variable for size, and updating it every time it’s changes.

Tracing source of access violation in unmanaged C# code

I am currently working on some C# code that talks to a C++ dll. This is not an area in which I - or anyone else at my company - has any experience. It's been an eye-opener to say the least.
After a lot of reading, trial and error, and frustration, I've managed to iron out most of the kinks and get something that's largely functional. However, from time to time, it still throws this at me ...
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
.. and then dies. This error only appears when I run the call on parallel threads - it's fine single threaded. This dll is supposed to be thread safe and we've good reason to believe it ought to be, if handled correctly.
The cause of this error is always a call to the same function:
[DllImport(DLL, SetLastError = true, CharSet = CharSet.Ansi)]
public static extern int QABatchWV_Close(IntPtr vi1);
I have the header file for the library, which defines this function as:
__declspec(dllimport) int __stdcall QABatchWV_Close(int);
From what I understand there are additional tools at my disposal like SafeHandle and MarshalAs. But, frankly, I'm unsure as to how to best deploy them in this situation.
This error tends to take several hours of use time to show up, so tweaking and hoping isn't going to be a productive approach here. Can anyone point me as to what I might be doing wrong in calling down to the C++ function?
Well, first of all you don't need setting Charset here, because there are no strings.
Second of all - function in cpp should be declared as exported not imported, so it should look like:
__declspec(dllimport) int __stdcall QABatchWV_Close(int);
Next, you should set calling convention in your C# code to stdcall:
[DllImport(DLL, SetLastError = true, CallingConvention=CallingConvention.Stdcall)]
Next you should have int instead of IntPtr in C# code. And I'm nearly sure that name of this function (in C++ dll) is mangled and it's not QABatchWV_Close but rather something like QABatchWV_Close#32. You should check it using "dll export viewer".
Have a look at the following code which I use to call a c (not c++) dll. I know it is not really an answer to your question, but perhaps you can use some of this going foreward.
Note the "CallingConvention"-specifier in the dll declaration and also the "FreeGlobal" in the "finally" part of the try catch.
public class csInterface
{
[DllImport(#"myDLL.dll", EntryPoint = "dllFunc", CallingConvention = CallingConvention.StdCall)]
private static extern void dllFunc(IntPtr inp, IntPtr outp);
public static int myDll(ref MyInput myInput, ref MyOutput myOutput)
{
int sizeIn, sizeOut;
IntPtr ptr_i = IntPtr.Zero, ptr_u = IntPtr.Zero;
sizeIn = Marshal.SizeOf(typeof(myInput));
sizeOut = Marshal.SizeOf(typeof(myOutput));
/* Calling C */
try
{
ptr_i = Marshal.AllocHGlobal(sizeIn);
ptr_u = Marshal.AllocHGlobal(sizeOut);
Marshal.StructureToPtr(myInput, ptr_i, true);
Marshal.StructureToPtr(myOutput, ptr_u, true);
dllFunc(ptr_i, ptr_u);
myOutput = (MyOutput)(Marshal.PtrToStructure(ptr_u, typeof(MyOutput)));
}
catch (Exception)
{
//Return something meaningful (or not)
return -999;
}
finally
{
//Free memory
Marshal.FreeHGlobal(ptr_i);
Marshal.FreeHGlobal(ptr_u);
}
//Return something to indicate it all went well
return 0;
}
}
In C# I declare my types
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MySubType
{
public int a;
public double b;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyInput
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)]
public string aString; //A string of length 3
public bool aBoolean;
public int anInt;
public char aChar;
public double aDouble;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 12)]
public MySubType[] aSubType; //Array of struct of length 12
}
And something similar for the output.
Now in C (its probably the same or similar in c++) i declare my dll
__declspec(dllexport) void _stdcall dllFunc(MyCInput *myCInput, MyCOutput *myCOutput)
{
//Code
}
And the corresponding C types which obviously have to mirror the C# types exactly
typedef struct
{
int a;
double b;
} MyCSubType;
typedef struct
{
char aString[4];
int aBoolean; //This needs to be cast over to your C boolean type
int anInt;
char aChar;
double aDouble;
MyCSubType myCSubType[12];
} MyCType;
Now the types I have used in this example do not exactly match what I have used in my code, and i have not tested this code. So there may be typos and such, but the "principle" is ok.

Porting (unmanaged) C++ to C# vs. using the C++ as a DLL in a C# application

I have a code library written in plain old C++ (no .NET/managed code) and I'm porting the application that uses this code to C#. I'm faced with two options:
Rewrite the C++ code in C# to achieve the same functionality;
Compile the C++ as a DLL and use it as a library in the C# application.
I'm relatively new to C# and am pretty unfamiliar with the implications of using an unmanaged code library in a C# app (or if there even are any). The code itself is moderate in size; it will likely take only a few days to rewrite in C#, but my thought is that leaving the code as a it is would allow me to use it in other applications as well (and to compile it on UNIX, etc).
What sort of things should I be aware of when making this decision? Are there any major drawbacks or gotchas to using the DLL in the C# application?
I would make a wrapper library using C++/CLI to expose the library to C#. This can leave your library unchanged, and just wrap it for use from .NET, providing the best of both options.
One thing I've found useful is to delve into C++/CLI when dealing with unmanaged C++ libraries. Create a managed wrapper using C++/CLI and call it from your C# code. The managed wrapper can include the library (I assume it's statically linked) in its DLL, and a project reference is all you need for your C# code.
It's not necessary to write a wrapper in C++/CLI. You can directly use Platform Invoke from C#:
http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx
EDIT: If you do it using C++/CLI, you'll need to be doing LoadLibrary calls and creating function pointers. This is significantly easier in C#. This is from the MSDN tutorial linked above, but with my own added comments:
class PlatformInvokeTest
{
[DllImport("msvcrt.dll")] // Specify the DLL we're importing from
public static extern int puts(string c); // This matches the signature of the DLL function. The CLR automatically marshals C++ types to C# types.
[DllImport("msvcrt.dll")]
internal static extern int _flushall();
public static void Main()
{
puts("Test");
_flushall();
}
}
EDIT: Complex types can also be marshaled, though it's necessary to define the structs. This example taken from my own code that invokes GDI+. I've snipped it a bit.
private static int SRCCOPY = 0x00CC0020;
private static uint BI_RGB = 0;
private static uint DIB_RGB_COLORS = 0;
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
private struct BITMAPINFO
{
public uint biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public uint[] cols;
}
public static Bitmap Downsample(Bitmap input, int bpp)
{
Bitmap retval = null;
// We will call into this GDI functionality from C#. Our plan:
// (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed)
// (2) Create a GDI monochrome hbitmap
// (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above)
// (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed)
IntPtr inputHandle = input.GetHbitmap();
//
// Step (2): create the monochrome bitmap.
//
BITMAPINFO bmi = new BITMAPINFO();
bmi.biSize = 40; // the size of the BITMAPHEADERINFO struct
bmi.biWidth = input.Width;
bmi.biHeight = input.Height;
bmi.biPlanes = 1;
bmi.biBitCount = (short)bpp; // 1bpp or 8bpp
bmi.biCompression = BI_RGB;
bmi.biSizeImage = (uint)(((input.Width + 7) & 0xFFFFFFF8) * input.Height / 8);
bmi.biXPelsPerMeter = 0; // not really important
bmi.biYPelsPerMeter = 0; // not really important
//
// Create the color palette.
//
uint numColors = (uint)1 << bpp; // 2 colors for 1bpp; 256 colors for 8bpp
bmi.biClrUsed = numColors;
bmi.biClrImportant = numColors;
bmi.cols = new uint[256];
if (bpp == 1)
{
bmi.cols[0] = MAKERGB(0, 0, 0);
bmi.cols[1] = MAKERGB(255, 255, 255);
}
else
{
for (int i = 0; i < numColors; i++)
{
bmi.cols[i] = MAKERGB(i, i, i);
}
}
//
// Now create the indexed bitmap
//
IntPtr bits0;
IntPtr indexedBitmapHandle = CreateDIBSection(IntPtr.Zero, ref bmi, DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0);
IntPtr sourceDC = GetDC(IntPtr.Zero);
IntPtr hdc = CreateCompatibleDC(sourceDC);
IntPtr hdc0 = CreateCompatibleDC(sourceDC);
SelectObject(hdc, inputHandle);
SelectObject(hdc0, indexedBitmapHandle);
BitBlt(hdc0, 0, 0, input.Width, input.Height, hdc, 0, 0, SRCCOPY);
retval = Bitmap.FromHbitmap(indexedBitmapHandle);
//
// Dispose of the crud
//
DeleteDC(hdc);
DeleteDC(hdc0);
ReleaseDC(IntPtr.Zero, sourceDC);
DeleteObject(inputHandle);
DeleteObject(indexedBitmapHandle);
return retval;
}

Strange problem calling a .DLL from C#

I'm trying to call the HtmlTidy library dll from C#. There's a few examples floating around on the net but nothing definitive... and I'm having no end of trouble. I'm pretty certain the problem is with the p/invoke declaration... but danged if I know where I'm going wrong.
I got the libtidy.dll from http://www.paehl.com/open_source/?HTML_Tidy_for_Windows which seems to be a current version.
Here's a console app that demonstrates the problem I'm having:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication5
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct TidyBuffer
{
public IntPtr bp; // Pointer to bytes
public uint size; // # bytes currently in use
public uint allocated; // # bytes allocated
public uint next; // Offset of current input position
};
[DllImport("libtidy.dll")]
public static extern int tidyBufAlloc(ref TidyBuffer tidyBuffer, uint allocSize);
static void Main(string[] args)
{
Console.WriteLine(CleanHtml("<html><body><p>Hello World!</p></body></html>"));
}
static string CleanHtml(string inputHtml)
{
byte[] inputArray = Encoding.UTF8.GetBytes(inputHtml);
byte[] inputArray2 = Encoding.UTF8.GetBytes(inputHtml);
TidyBuffer tidyBuffer2;
tidyBuffer2.size = 0;
tidyBuffer2.allocated = 0;
tidyBuffer2.next = 0;
tidyBuffer2.bp = IntPtr.Zero;
//
// tidyBufAlloc overwrites inputArray2... why? how? seems like
// tidyBufAlloc is stomping on the stack a bit too much... but
// how? I've tried changing the calling convention to cdecl and
// stdcall but no change.
//
Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
tidyBufAlloc(ref tidyBuffer2, 65535);
Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
return "did nothing";
}
}
}
All in all I'm a bit stumpped. Any help would be appreciated!
You are working with an old definition of the TidyBuffer structure. The new structure is larger so when you call the allocate method it is overwriting the stack location for inputArray2. The new definition is:
[StructLayout(LayoutKind.Sequential)]
public struct TidyBuffer
{
public IntPtr allocator; // Pointer to custom allocator
public IntPtr bp; // Pointer to bytes
public uint size; // # bytes currently in use
public uint allocated; // # bytes allocated
public uint next; // Offset of current input position
};
For what it's worth, we tried Tidy at work and switched to HtmlAgilityPack.
Try changing your tidyBufAlloc declaration to:
[DllImport("libtidy.dll", CharSet = CharSet.Ansi)]
private static extern int tidyBufAlloc(ref TidyBuffer Buffer, int allocSize);
Note the CharSet.Ansi addition and the "int allocSize" (instead of uint).
Also, see this sample code for an example of using HTML Tidy in C#.
In your example, if inputHTML is large, say 50K, inputArray and inputArray2 will be also be 50K each.
You are then also trying to allocate 65K in the tidyBufAlloc call.
If a pointer is not initialised correctly, it is quite possible a random .NET heap address is being used. Hence overwriting part or all of a seemingly unrelated variable/buffer occurs. It is problaby just luck, or that you have already allocated large buffers, that you are not overwriting a code block which would likely cause a Invalid Memory access error.

Categories

Resources