Help Marshaling a C function in C# - c#

I'm trying to call a C function from C#.
Here is the function from the C header file :
int __stdcall GetImageKN (unsigned short *ndat );
And from the documentation about this function :
ndat : Pointer of the grayscale image
data acquiring buffer. Always secure
the range image storage area using the
application program. The size of the
range image data storage area should be:
160’ 120 ‘2 = 38400 bytes The
grayscales are returned as 8 bit that
is doubled from 7-bit.
How do I invoke this function and read the image data ?
Thanks,
SW

30Kb is a small buffer. If your function runs quickly, you can rely on default marshaling behaviour and do this:
[DllImport ("your.dll")]
extern int GetImageKN (short[] ndat) ;
var buffer = new short[160 * 120] ;
var result = GetImageKN (buffer) ;
Even if it can block for a long time, you can get away with this if you don't call this function on many threads at once.

[DllImport ("your.dll")]
extern int GetImageKN (IntPtr ndat);
will probably do...
EDIT
generally pointers are represented as IntPtr.
you can create a managed array and Marshal it to IntPtr,

I would try the following:
[DllImportAttribute("your.dll", CallingConvention=CallingConvention.StdCall)]
extern int GetImageKN(
[Out, MarshalAs(UnmanagedType.LPArray, SizeConst=38400)] ushort[] ndat);
Not really sure however.

ushort ndat= 123;
GetImageKN(ref ndat);

Related

How pass a pointer to a pointer of byte array in C#

I have to call from a C# application a C function (from a DLL) declared as:
void fillBuffer( uint8_t ** pData, uint32_t * size );
This function checks if pData is not null and in case it fills the buffer with some fancy data. The variable size it is used as input parameter to limit the number of bytes that will be written in pData, and as output parameter to inform how many bytes have been actually written.
In case pData is null, it will allocate the buffer itself and will return in size the number of bytes allocated.
How I can declare and call this function from a C# application (avoiding unsafe if possibile) in both scenarios (passing an already allocated buffer or letting it allocates for me)?
I think I solved using this solution:
...
UInt32 len;
IntPtr ppData = IntPtr.Zero;
fillBuffer( ref ppData, out len );
...
And declaring the function as following:
[DllImport( "mylib.dll", CallingConvention = CallingConvention.Cdecl )]
static extern void fillBuffer( ref IntPtr ppData,out UInt32 size );
Thank you
You cant call C functions without unsafe context. This is simply not possible. You cant use unsafe pointers in managed context unless you declared so.

P/Invoke C++ DLL for filling a managed buffer

Basically I have a DLL and a header file (C++) for a data acquisition device that I use for my research. The device has 8 sensors and each sensor has x,y,z,etc data points. I'd like to create a UI program in WPF for this device. So far I've successfully been able to communicate with the device in .NET via an unsafe code implementation and read data into an array of structs (where each struct corresponds to one of the sensors). However I'd like to see if I can get it working with a strictly safe code implementation, but I've just been hitting brick walls for a while now. This is my first time working with unmanaged vs. managed code so please bear with me. I've searched countless threads online and the rabbit hole just keeps getting deeper so I'd like some advice from someone with experience. Basically the API header file has a function with the following definition:
int GetSynchronousRecord(USHORT sensorID, void *pRecord, int recordSize);
Essentially we pass the function a buffer by reference, and it fills it up. I have the option of getting either a single sensor's data, or all sensors at once depending on the sensorID argument I pass. What HAS worked for me so far (in the managed world) is if I do the following:
[StructLayout(LayoutKind.Sequential)]
public struct DOUBLE_POSITION_ANGLES_TIME_Q_RECORD
{
public double x;
public double y;
public double z;
public double a;
public double e;
public double r;
public double time;
public ushort quality;
};
...
[DllImport("ATC3DG64.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSynchronousRecord(ushort sensorID, ref DOUBLE_POSITION_ANGLES_TIME_Q_RECORD record, int recordSize);
...
DOUBLE_POSITION_ANGLES_TIME_Q_RECORD record = new DOUBLE_POSITION_ANGLES_TIME_Q_RECORD();
// Get the data from SENSOR_1 only
errorCode = GetSynchronousRecord(1, ref record, Marshal.SizeOf(record));
So this implementation works fine, I can get all the coordinate data and at a really good speed. However, I'd like to get ALL the sensors at once. In the C++ API code samples, they pass the GetSynchronousRecord function an ARRAY of STRUCTS, one struct for each sensor. I tried to do the same in C# as follows:
[DllImport("ATC3DG64.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSynchronousRecord(ushort sensorID, ref DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[] record, int recordSize);
// Define Array of Struct for each sensor
DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[] record = new DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[8];
while(recording) {
...
// Get data from ALL sensors (0xffff)
errorCode = GetSynchronousRecord(0xffff, ref record, Marshal.SizeOf(record)*8);
...
}
But this straight up crashes my program with an System.ExecutionEngineException error. I've read that since my function is expecting a void* pointer, that I should use an IntPtr argument, but this approach seemed quite confusing to be honest. Another thing I tried is to actually loop over each sensor and call the function for the sensor, but this dropped the speed INSANELY almost to 1 record/second (instead of 100 records/second). Many other similar threads on stackexchange say to use out parameter, or to use [In, Out] attribute on the function definition, but none of these suggestions worked.
TL;DR: If I understand my situation correctly, I have a MANAGED array of structs that I need to correctly pass to a C++ function as an argument (pass by reference), and then the function will fill my structs with data from a data acquisition device.
I apologize for the wall of text/code, any information for me from someone with experience would be much appreciated.
EDIT: Just to clarify, the GetSynchronousRecord function is INSIDE a while loop where on each iteration I'm getting new data points for each struct.
Your second p/invoke declaration is wrong. You had
[DllImport("ATC3DG64.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSynchronousRecord(
ushort sensorID,
ref DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[] record,
int recordSize
);
The problem is the array parameter. Because you pass that array by ref that actually makes it a double pointer. Instead you want to simply remove the ref and declare the import like so:
[DllImport("ATC3DG64.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSynchronousRecord(
ushort sensorID,
[Out] DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[] record,
int recordSize
);
The [Out] attribute tells the marshaler that the data is flowing out of the function. Without it the default assumption is that the data flows in.
When you call the function do so like this:
errorCode = GetSynchronousRecord(0xffff, record, Marshal.SizeOf(record)*record.Length);
The best way is probably using IntPtr rather than ref DOUBLE_POSITION_ANGLES_TIME_Q_RECORD.
I'd change the P/Invoke signature to:
[DllImport("ATC3DG64.DLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetSynchronousRecord(ushort sensorID, IntPtr record, int recordSize);
Create an IntPtr that points to the needed memory space:
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf<DOUBLE_POSITION_ANGLES_TIME_Q_RECORD>() * 8);
Call the P/Invoke function (which should fill the memory with the structs):
errorCode = GetSynchronousRecord(0xffff, ptr, Marshal.SizeOf<DOUBLE_POSITION_ANGLES_TIME_Q_RECORD>() * 8);
Get the structures from the memory block:
DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[] records = new DOUBLE_POSITION_ANGLES_TIME_Q_RECORD[8];
for (i = 0; i < 8; i++) {
records[i] = Marshal.PtrToStructure<DOUBLE_POSITION_ANGLES_TIME_Q_RECORD>(IntPtr.Add(ptr, i * Marshal.SizeOf<DOUBLE_POSITION_ANGLES_TIME_Q_RECORD>()));
}
Marshal.FreeHGlobal(ptr);

What's the correct way to marshal a const float**?

I'm trying to read an array that's created by pinvoking a dll function from C#. When I print out the array's contents it's actually full of junk.
I suspect this is happening because I am incorrectly marshalling a const float** to an out IntPtr. How do you properly marshal a const float**?
DLL C++ Interface
int Foo(void *objPtr, uint64_t *resultLen, const float **result);
DLL Import Statement
[DllImport("foo.dll", CharSet = CharSet.Auto)]
public static extern int Foo(IntPtr objPtr, out ulong resultLen, out IntPtr result);
Calling Code
IntPtr objPtr = getObj();
IntPtr result;
ulong resultLen;
int output = Foo(objPtr, out resultLen, out result);
Because there is no way to tell the marshaler the size of the array ahead of time you will have to copy the array manually. So out IntPtr is correct.
Note you will have a problem with very large arrays. See https://msdn.microsoft.com/en-us/library/hh285054(v=vs.110).aspx and How to get around Marshal.Copy (32bit) length limit? . This snippet will use int as the resulting array length. You will need to figure out what to do in your particular case.
Also note your DLL must be responsible for releasing the memory it allocates. See Release unmanaged memory from managed C# with pointer of it .
IntPtr objPtr = getObj();
IntPtr result;
int resultLen;
// call your external function
int output = Foo(objPtr, out resultLen, out result);
// create an array to hold the output data
float[] array = new float[resultLen];
// copy the data
Marshal.Copy(result, array, 0, resultLen);
// since the memory was allocated by the DLL only it knows how to free it
// so call the free function exported by the DLL
FreeBufferAfterFoo(result);

Call unmanaged code in c# and print images

I need to print image in device with windows mobile 6.5 (with printer) through CF 2.0 and i have c++ header file and i also wrapped class that call unmanaged code:
Problem: I cant figure out how can i print images even if I read this document
In documentation
PRNAPI UINT WINAPI PrinterLoadImageFile (LPCTSTR pszFile);
Description: Read the Image files. Return: PRINTER_OK: Success
PRINTER_ERROR: Errors Argument: LPCTSTR pszFile: [in] file to read
PRNAPI UINT WINAPI PrinterImage (int nMode); Description: Print
image. Return: PRINTER_OK: Success PRINTER_ERROR: Errors Argument:
int nMode: [in] set the image printing mode. PRINTER_IMAGE_NORMAL:
200 * 200 dpi Default PRINTER_IMAGE_DOUBLEWIDTH: 100 * 200 dpi
PRINTER_IMAGE_DOUBLEHEIGHT: 200 * 100 dpi PRINTER_IMAGE_QUADRUPLE:
100 * 100 dpi
PRNAPI UINT WINAPI PrinterCloseImageFile (); Description: Remove
reading image. Return: PRINTER_OK: Success PRINTER_ERROR: Errors
PRNAPI LPCTSTR WINAPI PrinterGetImageName (); Description: Get
the name of image that is read. Return: LPCTSTR: [out] the name of
the file
and i did come with this wrapper .net code
[DllImport(#"PRN_DLL.dll")]
public static extern uint PrinterCloseImageFile();
[DllImport(#"PRN_DLL.dll")]
public static extern uint PrinterLoadImageFile(string pszFile);
[DllImport(#"PRN_DLL.dll")]
public static extern uint PrinterImage(int nMode);
[DllImport(#"PRN_DLL.dll")]
public static extern char[] PrinterGetImageName();
part of h file:
//Close Image File
_DLL_EXPORT_ UINT WINAPI PrinterCloseImageFile();
//Load Image File
_DLL_EXPORT_ UINT WINAPI PrinterLoadImageFile(TCHAR* pszFile);
_DLL_EXPORT_ void WINAPI PrinterSetImageLeft(UINT nImageLeft);//ÇöÀç ´Ü»öºñÆ®¸Ê¸¸ Áö¿ø °¡´ÉÇÔ(2008³â11¿ù)
//Print Image
_DLL_EXPORT_ UINT WINAPI PrinterImage(int nMode);
//Get Image Name
_DLL_EXPORT_ TCHAR* PrinterGetImageName();
When I call this code
String path = PathInfo.GetStartupPath() + "\\logo.png";//Path to image
NativPrinter.PrinterGetImageName();
MessageBox.Show(NativPrinter.PrinterLoadImageFile(path).ToString());
NativPrinter.PrinterImage(NativPrinter.PRINTER_IMAGE_NORMAL);
NativPrinter.PrinterCloseImageFile();
I'm getting error in PrinterLoadImageFile (error code 1000 that mean print error).
So can any one have any clue where is my mistake.
sorry for my English .
The obvious way in which your call to PrinterLoadImageFile could be wrong is that your C# code will pass UTF-16 Unicode text, but perhaps the native library expects 8 bit ANSI. We can't tell because we don't know what TCHAR expands to. If that's it then you'll need to pass an IntPtr to PrinterLoadImageFile and convert to ANSI manually. Use
byte[] ansiBytes = Encoding.Default.GetBytes(path);
byte[] pszPath = new byte[ansiBytes.Length + 1];//+1 for null terminator
ansiBytes.CopyTo(pszPath, 0);
to convert to a null terminated ANSI string, stored in a byte array.
And then copy that to a null-terminated string allocated on the unmanaged heap.
IntPtr ptr = Marshal.AllocHGlobal(pszPath.Length);
Marshal.Copy(pszPath, 0, ptr, pszPath.Length);
You can then pass that on to PrinterLoadImageFile. When you are done with the memory, deallocate it with Marshal.FreeHGlobal.
The other problem is PrinterGetImageName. Almost certainly that returns a pointer to a string that is allocated in the library. So you'd need to declare the return value as IntPtr, and use the Marshal class to convert into a C# string. Your code is going to result in an attempt by the p/invoke marshaller to deallocate the block of memory returned by PrinterGetImageName and I'm sure that's not what you want.

Correct way to marshall uchar[] from native dll to byte[] in c#

I'm trying to marshall some data that my native dll allocated via CoTaskMemAlloc into my c# application and wondering if the way I'm doing it is just plain wrong or I'm missing some sublte decorating of the method c# side.
Currently I have c++ side.
extern "C" __declspec(dllexport) bool __stdcall CompressData( unsigned char* pInputData, unsigned int inSize, unsigned char*& pOutputBuffer, unsigned int& uOutputSize)
{ ...
pOutputBuffer = static_cast<unsigned char*>(CoTaskMemAlloc(60000));
uOutputSize = 60000;
And on the C# side.
private const string dllName = "TestDll.dll";
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport(dllName)]
public static extern bool CompressData(byte[] inputData, uint inputSize, out byte[] outputData, out uint outputSize );
...
byte[] outputData;
uint outputSize;
bool ret = CompressData(packEntry.uncompressedData, (uint)packEntry.uncompressedData.Length, out outputData, out outputSize);
here outputSize is 60000 as expected, but outputData has a size of 1, and when I memset the buffer c++ side, it seems to only copy across 1 byte, so is this just wrong and I need to marshall the data outside the call using an IntPtr + outputSize, or is there something sublte I'm missing to get working what I have already?
Thanks.
There are two things.
First, the P/Invoke layer does not handle reference parameters in C++, it can only work with pointers. The last two parameters (pOutputBuffer and uOutputSize) in particular are not guaranteed to marshal correctly.
I suggest you change your C++ method declaration to (or create a wrapper of the form):
extern "C" __declspec(dllexport) bool __stdcall CompressData(
unsigned char* pInputData, unsigned int inSize,
unsigned char** pOutputBuffer, unsigned int* uOutputSize)
That said, the second problem comes from the fact that the P/Invoke layer also doesn't know how to marshal back "raw" arrays (as opposed to say, a SAFEARRAY in COM that knows about it's size) that are allocated in unmanaged code.
This means that on the .NET side, you have to marshal the pointer that is created back, and then marshal the elements in the array manually (as well as dispose of it, if that's your responsibility, which it looks like it is).
Your .NET declaration would look like this:
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport(dllName)]
public static extern bool CompressData(byte[] inputData, uint inputSize,
ref IntPtr outputData, ref uint outputSize);
Once you have the outputData as an IntPtr (this will point to the unmanaged memory), you can convert into a byte array by calling the Copy method on the Marshal class like so:
var bytes = new byte[(int) outputSize];
// Copy.
Marshal.Copy(outputData, bytes, 0, (int) outputSize);
Note that if the responsibility is yours to free the memory, you can call the FreeCoTaskMem method, like so:
Marshal.FreeCoTaskMem(outputData);
Of course, you can wrap this up into something nicer, like so:
static byte[] CompressData(byte[] input, int size)
{
// The output buffer.
IntPtr output = IntPtr.Zero;
// Wrap in a try/finally, to make sure unmanaged array
// is cleaned up.
try
{
// Length.
uint length = 0;
// Make the call.
CompressData(input, size, ref output, ref length);
// Allocate the bytes.
var bytes = new byte[(int) length)];
// Copy.
Marshal.Copy(output, bytes, 0, bytes.Length);
// Return the byte array.
return bytes;
}
finally
{
// If the pointer is not zero, free.
if (output != IntPtr.Zero) Marshal.FreeCoTaskMem(output);
}
}
The pinvoke marshaller cannot guess how large the returned byte[] might be. Raw pointers to memory in C++ do not have a discoverable size of the pointed-to memory block. Which is why you added the uOutputSize argument. Good for the client program but not quite good enough for the pinvoke marshaller. You have to help and apply the [MarshalAs] attribute to pOutputBuffer, specifying the SizeParamIndex property.
Do note that the array is getting copied by the marshaller. That's not so desirable, you can avoid it by allowing the client code to pass an array. The marshaller will pin it and pass the pointer to the managed array. The only trouble is that the client code will have no decent way to guess how large to make the array. The typical solution is to allow the client to call it twice, first with uOutputSize = 0, the function returns the required array size. Which would make the C++ function look like this:
extern "C" __declspec(dllexport)
int __stdcall CompressData(
const unsigned char* pInputData, unsigned int inSize,
[Out]unsigned char* pOutputBuffer, unsigned int uOutputSize)

Categories

Resources