Execute C++ function from C# application - c#

I have a DLL written in C++ which is a wrapper for C# around an LZO library. But for testing purposes I want to know if I can convert the types, so I created a test function that takes in the file's content and size and writes a copy of it.
extern "C"
{
__declspec(dllexport) void WriteFile(lzo_uint8 * source, int size)
{
FILE * fileToWrite;
fileToWrite = fopen("test.eix", "wb+");
if (fileToWrite)
{
fwrite(source, 1, size, fileToWrite);
}
fclose(fileToWrite);
free(source);
}
}
Here is the image of the code, for better readability: http://i.epvpimg.com/u4mgh.png
I then import it like this:
[DllImport(#"GLZO.dll")]
public static extern void WriteFile(byte[] source, int size);
And call it like this:
byte[] g = ReadFile("raw/roota.eix");
WriteFile(g, g.Length);
The problem is not in the ReadFile function, I checked it. I created a copy from a different file and checked both with checksums.
So, my question is: how should I convert a byte[] to an lzo_uint8* (unsigned char*)?

Got it! I just had to marshal it to an IntPtr, unsigned char * = IntPtr in C#.
Also, to avoid exceptions regarding "not equivalent" types, you need to import the dll as this:
[DllImport(#"GLZO.dll", CallingConvention = CallingConvention.Cdecl)]

Related

Preserve C++ Pointer in C#

I am writing a little Program in C# which includes a C++ Dll.
In C++, there are many classes which needed to be instanced and left for later use.
This looks like the following function:
C++:
__declspec(dllexport) FrameCapture* GetFrameCapturer(HWND windowHandle) {
ProcessWindow* window = ProcessWindowCollection::GetInstance()->FindWindow(windowHandle);
FrameCapture* capture = new FrameCapture(window);
return capture;
}
As you can see I just create a FrameCapture class and return a Pointer to it.
This Pointer is stored in C# as an IntPtr.
C#:
[DllImport("<dllnamehere>")]
public static extern IntPtr GetFrameCapturer(IntPtr windowHandle);
This works really well so far.
But if I use that Pointer to get an Instance of FrameCapture
C++:
__declspec(dllexport) BITMAPFILEHEADER* GetBitmapFileHeader(FrameCapture* frameCapturer) {
return frameCapturer->GetBitmapFileHeader();
}
the class will be completely empty.
How do I get the Instance of the Class I initialized in step one?
EDIT:
I did some testing and replaced the Pointers with integers which are better to look at.
I casted 'capture' to an Int32 and returned this instead.
In my testcase it returned byte(208,113,244,194).
This values are, as expected, in C++ and C# the same.
But, now it becomes odd.
If I pass this Int32 into 'GetBitmapFileHeader' the value becomes suddenly byte(184,231,223,55).
That's not even close! I thought of Little <-> Big Endian or something like this but, this is a whole new Memoryblock?
The same behavior will go on with the IntPtr.
As requested I post also the Import of 'GetBitmapFileHeader'
[DllImport("<dllnamehere>")]
public static extern tagBITMAPFILEHEADER GetBitmapFileHeader(IntPtr capturerHandle);
Okay, I got it.
See this import from C#.
C#:
[DllImport("<dllnamehere>")]
public static extern tagBITMAPFILEHEADER GetBitmapFileHeader(IntPtr capturerHandle);
Its wrong!
The function now returns an IntPtr wich works completely fine.
This is the new Setup:
C++:
__declspec(dllexport) void* __stdcall GetBitmapFileHeader(void* frameCapturer) {
FrameCapture* cap = (FrameCapture*)frameCapturer;
return cap->GetBitmapFileHeader();
}
C#:
[DllImport("libWinCap.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetBitmapFileHeader(IntPtr frameCapturer);
[...]
//calling
IntPtr ptr = GetBitmapFileHeader(m_capturerHandle);
m_bitmap.m_fileHeader = (tagBITMAPFILEHEADER)Marshal.PtrToStructure(ptr, typeof(tagBITMAPFILEHEADER));
Iam only moving Pointers now and use PtrToStructure to read the Memory.
Also, Thanks for every comment.

Issue with native C++ dll in C#

I have native C++ dll with function that finds the number of cameras connected to the computer and returns their serial number. I am trying to use native C++ dll in C# application but I keep getting the Access Violation error(Attempted to read or write protected memory).
The function in question is
uint32_t GetSerialNumList(char** theBufList, int theBufSize, int theListLength);
The way I am using PInvoke is as follows:
[DllImport(CameraDll, EntryPoint = "GetSerialNumList", CallingConvention = CallingConvention.Cdecl)]
private static extern uint GetSerialNumList(out byte[] pBuf, int BufSize, int ListLength);
If I create native C++ application to use the dll and use the function as follows:
char* theSerialNumb;
theSerialNumb = (char *) malloc(sizeof(char)* 8);
status = TRI_GetSerialNumList(&theSerialNumb, 8, 1);
It works fine however, if I use as follows in C# it give me above mentioned error:
byte[] BufList;
BufList = new byte[8];
rv = GetSerialNumList(out BufList, 8, 1);
The parameter you're passing in c# is a pointer to a byte array. What you're passing in c++ is a pointer to a pointer to a byte array. Also, in the C++ example, you're passing data to the function, but in the C# example, you're passing it as an out instead of a ref.
Although I'm not sure this would work, I would try to create a struct containing a byte array and pass the struct to the external function.
To answer some of the above comments, these functions typically modify memory passed to it rather than try to allocate additional memory due to the different ways programs create heaps.
The first thing I'd check is the C# import signature being used. There's the P/Invoke Interop Assistant tool available for free here.
Loading your function signature into the tool, translates it to:
public partial class NativeMethods {
/// Return Type: unsigned int
///theBufList: char**
///theBufSize: int
///theListLength: int
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="GetSerialNumList")]
public static extern uint GetSerialNumList(ref System.IntPtr theBufList, int theBufSize, int theListLength) ;
}
The second thing, is that since you are allocating memory for the buffer in the C++/native version; perhaps you need to pass a pre-allocated buffer as well, when using C#.
Hope this helps.
Okay, I took pointers from Russell and kvr and did some digging around and following is the scheme that I came up with.
Original native function call:
uint32_t GetSerialNumList(char** theBufList, int theBufSize, int theListLength);
The way I am using PInvoke is as follows:
[DllImport(CameraDll, EntryPoint = "GetSerialNumList", CallingConvention = CallingConvention.Cdecl)]
private static extern int GetSerialNumList(ref IntPtr pBuf, int BufSize, int ListLength);
byte[] BufIn;
BufIn = new byte[8 * ListLength];
IntPtr pBuf = IntPtr.Zero;
pBuf = Marshal.AllocHGlobal(8 * ListLength);
Console.WriteLine("Calling GetSerialNumList");
rv = GetSerialNumList(ref pBuf, 8, ListLength);
Marshal.Copy(pBuf, BufIn, 0, 8*ListLength);
I feel this is somewhat long, but it gives me the desired result.

Passing String from Native C++ DLL to C# App

I have written a DLL in C++. One of the functions writes to a character array.
C++ Function
EXPORT int xmain(int argc, char argv[], char argv2[])
{
char pTypeName[4096];
...
//Other pTypeName ends up populated with "Portable Network Graphics"
//This code verifies that pTypeName is populated with what I think it is:
char szBuff[64];
sprintf(szBuff, pTypeName, 0);
MessageBoxA(NULL, szBuff, szBuff, MB_OK);
//The caption and title are "Portable Network Graphics"
...
//Here, I attempt to copy the value in pTypeName to parameter 3.
sprintf(argv2, szBuff, 0);
return ret;
}
C# Import
//I believe I have to use CharSet.Ansi because by the C++ code uses char[],
[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
public static extern int xmain(int argc, string argv, ref string zzz);
C# Function
private void button2_Click(object sender, EventArgs e)
{
string zzz = "";
int xxx = xmain(2, #"C:\hhh.bmp", ref zzz);
MessageBox.Show(zzz);
//The message box displays
//MessageBox.Show displays "IstuÈst¼ÓstÄstlÄstwÄstiÑstõÖstwÍst\
// aÖst[ÖstÃÏst¯ÄstÐstòÄstŽÐstÅstpÅstOleMainThreadWndClass"
}
I have attempted to pass a parameter from C# by reference and have the C++ DLL populate the parameter. Even though I have verified that the value is correct in the DLL, gibberish gets passed to the C# application.
What can I do to write the correct string value to the C# string?
Use a StringBuilder to pass a character array that native code can fill in (see Fixed-Length String Buffers).
Declare the function:
[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
public static extern int xmain(int argc, string argv, StringBuilder argv2);
Use it:
// allocate a StringBuilder with enough space; if it is too small,
// the native code will corrupt memory
StringBuilder sb = new StringBuilder(4096);
xmain(2, #"C:\hhh.bmp", sb);
string argv2 = sb.ToString();
Give some other information to the DLLImport call. Look at the following example of my own:
[DllImport("tcpipNexIbnk.dll", EntryPoint = "SendData", CallingConvention = CallingConvention.Cdecl)]
public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);
Notice two things, the CallingConvention parameter:
CallingConvention = CallingConvention.Cdecl)
Use that as it is.
And then just behind the c# string type, you can play with the different Unmanaged types using the MarshalAS instruction, that will cast your C# string parameter to the native string type you have in your c++ program:
public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);
Hope it helps.

How can I return a StringBuilder or other string buffer from a PInvoke native callback

I would like a clean way to increase the size of a StringBuilder() as required for population by native code, the callback method below seems clean, but somehow we get a copy of the buffer instead of the actual buffer - I'm interested in explanations and solutions (preferably sticking to the callback type allocation as it would be nice and clean if only it could be made work).
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace csharpapp
{
internal class Program
{
private static void Main(string[] args)
{
var buffer = new StringBuilder(12);
// straightforward, we can write to the buffer but unfortunately
// cannot adjust its size to whatever is required
Native.works(buffer, buffer.Capacity);
Console.WriteLine(buffer);
// try to allocate the size of the buffer in a callback - but now
// it seems only a copy of the buffer is passed to native code
Native.foo(size =>
{
buffer.Capacity = size;
buffer.Replace("works", "callback");
return buffer;
});
string s = buffer.ToString();
Console.WriteLine(s);
}
}
internal class Native
{
public delegate StringBuilder AllocateBufferDelegate(int bufsize);
[DllImport("w32.dll", CharSet = CharSet.Ansi)]
public static extern long foo(AllocateBufferDelegate callback);
[DllImport("w32.dll", CharSet = CharSet.Ansi)]
public static extern void works(StringBuilder buf, int bufsize);
}
}
native header
#ifdef W32_EXPORTS
#define W32_API __declspec(dllexport)
#else
#define W32_API __declspec(dllimport)
#endif
typedef char*(__stdcall *FnAllocStringBuilder)(int);
extern "C" W32_API long foo(FnAllocStringBuilder fpAllocate);
extern "C" W32_API void works(char *buf, int bufsize);
native code
#include "stdafx.h"
#include "w32.h"
#include <stdlib.h>
extern "C" W32_API long foo(FnAllocStringBuilder fpAllocate)
{
char *src = "foo X";
int len = strlen(src) + 1;
char *buf = fpAllocate(len);
return strcpy_s(buf,len,src);
}
extern "C" W32_API void works(char *buf, int bufsize)
{
strcpy_s(buf,bufsize,"works");
}
I have a theory for why this happens. I suspect that the marshalling of StringBuilder involves making a copy of the data, passing it to the P/Invoke call, and then copying back into the StringBuilder. I couldn't actually verify this though.
The only alternative to this would require the StringBuilder to be flattened first (it is internally a linked list of char[]'s), and the char[] pinned, and even then this would only work for marshalling to pointer-to-Unicode-chars strings, but not to ANSI or COM strings.
Thus, when you pass a StringBuilder as an argument, there's an obvious place for .NET to copy any changes back: right after the P/Invoke returns.
The same isn't true for when you pass a delegate returning a StringBuilder. In this case .NET needs to create a wrapper which converts an int => StringBuilder function into an int => char* function. This wrapper will create the char* buffer and populate it, but obviously can't copy any changes back yet. It also can't do this after the function that takes the delegate returns: it's still too early!
In fact, there is no obvious place at all where the reverse copy could occur.
So my guess is that this is what happens: when marshalling a StringBuilder-returning delegate, .NET can only perform a one-way conversion, hence any changes you make aren't reflected in the StringBuilder. This is slightly better than being completely unable to marshal such delegates.
As for solutions: I would recommend first asking the native code how large the buffer needs to be, and then passing a buffer of the appropriate size in a second call. Or, if you need better performance, guess a large enough buffer, but allow the native method to communicate that more space is required. This way most calls would involve only one P/Invoke transition.
This can be wrapped into a more convenient function that you can just call from the managed world without worrying about buffers.
In addition to the input provided by romkyns I will share the minimal changes solution I came up with. If anyone uses this be careful of your encodings!
the principal modification is:
private static void Main(string[] args)
{
byte[] bytes = null;
var gcHandle = new GCHandle();
Native.foo(size =>
{
bytes = new byte[size];
gcHandle = GCHandle.Alloc(bytes,GCHandleType.Pinned);
return gcHandle.AddrOfPinnedObject();
});
if(gcHandle.IsAllocated)
gcHandle.Free();
string s = ASCIIEncoding.ASCII.GetString(bytes);
Console.WriteLine(s);
}
with the delegate signature changeing to:
public delegate IntPtr AllocateBufferDelegate(int bufsize);

C# dll call not passing char* to C++ MFC regular dll

I have a C++ MFC regular DLL I am calling with the following:
public static class Access3rdPartyDLL
{
public static string FilePath;
[DllImport("3rdparty.dll")]
// I have also tried LPWStr
public static extern long Download([MarshalAs(UnmanagedType.LPStr)]string sDownloadFile,
int iDeviceNum
...);
public static long DownloadToDevice()
{
long result;
string FilePath = "C:\\myfile.txt"
result = Download(FilePath, 1, ...);
// check if success or error
if(result > 0)
...
}
}
I get an error back from the DLL saying "File: 'C:\myfile.txt' not found. But its there...
I have also tried using StringBuilder but this also fails.
Could this be a problem with the DLL or am I doing something wrong?
I found this current code here: SO: equivalent char* in C#
EDIT: I have done this in C++ before and this code works:
extern "C" __declspec(dllimport) HRESULT __stdcall Download(char* sDownloadFile, int ...
which I call with:
HRESULT result = Download(file_for_download, 1, .. // where file_for_download is a char*
The only thing wrong with the P/invoke is that you are using C# long which is 64 bits, but an HRESULT is only 32 bits.
You have matching calling conventions, default marshalling for managed string is char* on the unmanaged side.
Mismatching return value size would not explain why your C# code receives a string message File: 'C:\myfile.txt' not found so your main problem most likely lies in the code that you haven't shown us.
I don't see any reason why the following wouldn't work in this simple scenario:
[DllImport( "3rdparty.dll", CharSet = CharSet.Ansi )]
static extern long Download(string sDownloadFile, int iDeviceNum, ...)
long result = Download("C:\\myfile.txt", 1, ...);

Categories