Call unmanaged code in c# and print images - c#

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.

Related

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);

PInvoke Nikon c++ DLL Function from c#

I'm trying to access the Nikon image SDK(for those interested see: 1) to implement access to *.nef file in a programm. I'm stuck at a return code from the dll which should be interpreted as "invalid parameter" and I'm running out of ideas.
Yes I know the chance, that somebody is exactly using this dll is sparse, but I'm rather looking for "writing"/"thinking" errors... I'm still learning (so excuse to any wrong used terms, etc...) and also for this reason this is a little "longer" post (some "aloud thinking" on my side ;-) )
1.) the dll has an entry function where you pass a identifier and a struct as parameter. The identifier stands for a specific command (like open,close,etc....). The struct is used for data exchange with the camera.
2.) I do have everything together and working (since, I'm getting a "return code") but I can't figure out the reason for the return code (maybe some datatype is incompatible?)
So first the "C++"-part:
c++ function definition:
extern "C" unsigned long __declspec(dllexport) WINAPI Nkfl_Entry(unsigned long ulCommand, void* pParam );
this is stdcall, so I do need to worry about any further options to dllimport, since usigned long(c++) corresponds to uint(c#) i get two uints one "out" and one "in"...
c++ struct defintion:
typedef struct tagNkflLibraryParam
{
unsigned long ulSize; // Size of structure
unsigned long ulVersion; // Version
unsigned long ulVMMemorySize; // Size of vertual memory
NkflPtr* pNkflPtr; // Pointer of StratoObject
unsigned char VMFileInfo[ MAX_PATH ]; // Swap file info
} NkflLibraryParam, *NkflLibraryPtr;
so I do need to pass 3 times uints, one pointer to an "StratoObject" ((1.) the doc says "typedef void* NkflPtr" so this is "just" a void* pointer 2.) the doc says if this is zero it will be filled up by the sdk) and finally one byte (since unsigned char(c++) corresponds to byte(c#)).
So first question: Is this correct?
Then going to the "coding-part":
c# struct defintion:
namespace NikonStruct
{
[StructLayout(LayoutKind.Sequential)]
public struct NkflLibraryParam
{
public uint ulSize; // size of the NkflLibraryParam structure
public uint ulVersion; // version number of the interface specification
public uint ulVMMMemorySize; // upper limit of the physical memory that can be used
public IntPtr pNkflPtr; // pointer to the StratoManager object
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
public byte[] VMFileInfo; // swap file information
}
}
now this should correspond to my defintions above...
c# Program class:
class Program
{
public enum eNkflCommand : int
{
kNkfl_Cmd_OpenLibrary = 1,
kNkfl_Cmd_CloseLibrary = 2,
};
[DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
public static extern uint kNkfl_Cmd_OpenLibrary(eNkflCommand ulCommand, ref NikonStruct.NkflLibraryParam data);
[DllImport("NkImgSDK.dll", EntryPoint = "Nkfl_Entry")]
public static extern uint kNkfl_Cmd_CloseLibrary(eNkflCommand ulCommand, IntPtr close);
static void Main(string[] args)
{
try
{
// specify return value of entry function
uint result1, result2;
/// call the kNkfl_Cmd_OpenLibrary Function
// generate data structure, which is used to communicate with kNkfl_Cmd_OpenLibrary function
NikonStruct.NkflLibraryParam _NkflLibraryParam = new NikonStruct.NkflLibraryParam();
// fill the fields of _NkflLibraryParam structure for kNkfl_Cmd_OpenLibrary function
_NkflLibraryParam.ulVersion = 16777216;
_NkflLibraryParam.ulSize = ((uint)Marshal.SizeOf(_NkflLibraryParam)); ;
// call the entry function with parameters for kNkfl_Cmd_OpenLibrary
result1 = kNkfl_Cmd_OpenLibrary(eNkflCommand.kNkfl_Cmd_OpenLibrary, ref _NkflLibraryParam);
Console.WriteLine(result1);
/// call the kNkfl_Cmd_CloseLibrary Function
result2 = kNkfl_Cmd_CloseLibrary(eNkflCommand.kNkfl_Cmd_CloseLibrary, IntPtr.Zero);
Console.WriteLine(result2);
}
catch
{
string errorMsg = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message;
throw new ArgumentException(errorMsg);
}
}
}
So nothing specific here:
eNkflCommand is from the doc
the structure is passed by reference so ref...
the "close" function expects "null pointer" (according to doc)
ulVersion is 0x01000000 (according to doc)
all other struct values are not set (and are zero by default if I understood the clr doc correctly)
Compiles and runs as already mentioned but result1 returns wrong "status-code" which translates to "invalid param" as already mentioned.
Any help appreciated....
FOUND IT:
never trust a documentation of a software developer: there was actually a missing parameter (not declared in the documentation BUT in an additional header definition file which was in another sub-directory of the sdk-package...)
so actually the struct defintion in the c# should be:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct struktur
{
public uint ulSize; // size of the NkflLibraryParam structure
public uint ulVersion; // version number of the interface specification
public uint ulVMMMemorySize; // upper limit of the physical memory that can be used
public IntPtr pNkflPtr; // pointer to the StratoManager object
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
public byte[] VMFileInfo; // swap file information
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
public byte[] DefProfPath; // <- this one is not included in the doc of NIKON (I still don't now what this should hold but it works if it's empty...)
}
Thanks to jszigeti and DavidHeffernan for trying...

Call a C++ DLL from a C# application

I'm currently trying to integrate a C++ DLL into our C# application, but I'm not able to identify what's the correct way to call one of their methods. In two different places of the documentation the method definition are not equal:
ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength)
ImageAndScanError WINAPI GetMicrInfo(char* cMicrInfo,int* iInfoLength);
/*
ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength)
Parameters:
ptrCodeline: a pointer to the output buffer that will receive the code line read by the MICR algorithm. The ptrCodeline should allocate room for 96 characters.
iLength: the number of characters contained in the code line
Function: Read MICR line on the check. This function must be called after StartScan .
Returns: ErrorNone is returned upon success. Otherwise, an enum ImageAndScanError value that indicates the reason for failure is returned.
*/
This is how I'm including the dll method
[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi)]
And this are all the combinations that I've made so far
public static extern ImageAndScanError GetMicrInfo(out IntPtr cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out byte[] cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out string cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out StringBuilder cMicrInfo, out int iInfoLength);
IntPtr cMicrInfoTMP;
byte[] cMicrInfoTMP= new byte[96];
string cMicrInfoTMP;
StringBuilder cMicrInfoTMP;
GetMicrInfo(out cMicrInfoTMP, out iInfoLengthTMP);
When I use IntPtr, the value that the debug gives me in VS2010 is 859256727 with a size of 4, and when I do
string myString = Marshal.PtrToStringAnsi(cMicrInfoTMP);
I always get an empty string.
When I try any of the others (byte[], string, StringBuilder) I get
The runtime has encountered a fatal error. The address of the error was at
0x53e6716a, on thread 0x1084. The error code is 0xc0000005. This error may
be a bug in the CLR or in the unsafe or non-verifiable portions of user
code. Common sources of this bug include user marshaling errors for COM-interop
or PInvoke, which may corrupt the stack.
What am I missing here?
Thanks
You can allocate a buffer, then pass to the native function.
//error handling omitted
[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(IntPtr ptrCodeline,ref int bytesCopied);
IntPtr ip = Marshal.AllocCoTaskMem(bufferLen);
Win32API.ZeroMemory(ip, (uint)(bufferLen));
int bytesCopied=0;
GetMicrInfo(ip, ref bytesCopied);
string info= Marshal.PtrToStringAnsi(bytesCopied);
Marshal.FreeCoTaskMem(ip);
If you do not need to reuse the buffer during multiple calls of GetMicrInfo, you can use the default marshaler for StringBuilder:
[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(StringBuilder ptrCodeline,ref int bytesCopied);
StringBuilder ptrCodeline(bufferLen);
int bytesCopied=0;
GetMicrInfo(ptrCodeline, ref bytesCopied);
It comes with a performance hit if you call GetMicrInfo multiple times, because on each call the default CLR marshaller creates a marshalling buffer for pinning and for unicode-ANSI conversion. This hit may be negligible if the function isn't being called frequently or does not return a lot of data.
Reference:
Default Marshaling for Strings
Marshaling between Managed and Unmanaged Code
In .NET, out parameters are used when the callee creates the object. You need to provide an existing buffer to the function so you should initialize the StringBuilder first. The marshaller then passes a pointer to object's the internal character buffer to the function.
You do have to figure out which character set and encoding is being used for the MICR string. It could be UTF-16, in which case, change the declaration to CharSet.Unicode.
Try this:
[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi)]
private static extern ImageAndScanError GetMicrInfo(StringBuilder cMicrInfo, out int iInfoLength);
public String GetMicrInfo()
{
StringBuilder info = new StringBuilder(96);
int length;
ImageAndScanError error = GetMicrInfo(info, out length);
if (error != ImageAndScanError.ErrorNone) throw new Exception(String.Format("GetMicrInfo error: {0}", error));
return info.ToString();
}

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)

Help Marshaling a C function in 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);

Categories

Resources