calling function from regular dll from c# - memory allocation issue? - c#

Hi chaps(and chappettes)
Have a regular C dll with an exported function
int GetGroovyName(int grooovyId,char * pGroovyName, int bufSize,)
Basically you pass it an ID (int), a char * buffer with memory pre-allocated and the size of the buffer passed in.
pGroovyName gets filled with some text. (i.e. its a lookup basied on the groovyID)
The question is how do I best call that from c# ?
cheers
Buzz

On the C# side, you would have:
[DllImport("MyLibrary")]
extern static int GetGroovyName(int grooovyId, StringBuilder pGroovyName, int bufSize);
And you call it like:
StringBuilder sb = new StringBuilder (256);
int result = GetGroovyName (id, sb, sb.Capacity); // sb.Capacity == 256

You may use DLLImport in C#.
Check this http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx
Code from MSDN
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}

Have a look at this snippet demonstrating (theoretically) how it should look:
using System;
using System.Runtime.InteropServices;
using System.Text; // For StringBuilder
class Example
{
[DllImport("mylib.dll", CharSet = CharSet.Unicode)]
public static extern int GetGroovyName(int grooovyId, ref StringBuilder sbGroovyName, int bufSize,)
static void Main()
{
StringBuilder sbGroovyNm = new StringBuilder(256);
int nStatus = GetGroovyName(1, ref sbGroovyNm, 256);
if (nStatus == 0) Console.WriteLine("Got the name for id of 1. {0}", sbGroovyNm.ToString().Trim());
else Console.WriteLine("Fail!");
}
}
I set the stringbuilder to be max capacity of 256, you can define something smaller, assuming it returns 0 is success, it prints out the string value for groovy id of 1, otherwise prints fail.
Hope this helps.
Tom

Related

C#, Powershell, undocumeted WinApi function GetFontResourceInfoW

I have a AutoIt script which uses a undocumented gdi32 function (GetFontResourceInfoW) (Autoit: _WinAPI_GetFontResourceInfo).
It returns the name of a font file (.fon, .ttf, .ttc, etc. installed or not)
The script works perfect. I want to recode it now in Powershell.
The function prototype (from GetFontResourceInfo) is:
BOOL GetFontResourceInfo(LPCTSTR lpszFilename, // font file name
LPDWORD cbBuffer, // size of buffer for resouce information
LPVOID lpBuffer, // buffer for returned resouce information
DWORD dwQueryType, // resouce information query type
);
I tried the following, but it does not return the fontname.
$code=#'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
public static class FontUtil{
[DllImport("gdi32.dll")]
public static extern bool GetFontResourceInfoW(string lpszFilename, ref UInt32 cbBuffer, out IntPtr lpBuffer, UInt32 dwQueryType);
}
'#
Add-Type $code
[string]$fn = 'c:\windows\fonts\arial.ttf'
[Uint32]$b = 260
[IntPtr]$LocalStructPtr = Runtime.InteropServices.Marshal]::AllocHGlobal(260)
$ret=[fontutil]::GetFontResourceInfoW($fn, [ref] $b, [ref] $LocalStructPtr,[UInt32]1)
[Runtime.InteropServices.Marshal]::PtrToStringAuto($LocalStructPtr,$b)
[Runtime.InteropServices.Marshal]::FreeHGlobal($LocalStructPtr)
I think there is a problem with the paramaters or interop marshaling.
Any ideas what could be wrong?
out IntPtr lpBuffer
This is declared incorrectly. It should be:
IntPtr lpBuffer
Then the function call becomes:
$ret=[fontutil]::GetFontResourceInfoW($fn, [ref] $b, $LocalStructPtr,[UInt32]1)
You were passing the address of the pointer variable, but instead you pass that pointer variable's value. That's the address of the memory you allocated when you called AllocHGlobal.
Note also that your buffer has room for 130 characters rather than 260, because a UTF-16 code unit is two bytes wide. That's probably fine, but it might not be what you are expecting.
For marshaling strings, StringBuilder is a lot more convenient than mucking around with manually allocated buffers:
$code=#'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
public static class FontUtils {
const int QFR_DESCRIPTION = 1;
[DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool GetFontResourceInfoW(
string lpszFilename,
[In, Out] ref int cbBuffer,
[Out] StringBuilder lpBuffer,
int dwQueryType
);
public static string GetFontDescription(string fileName) {
int bufferSize = 0;
StringBuilder sb = new StringBuilder();
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
sb.Capacity = bufferSize / sizeof(char);
if (!GetFontResourceInfoW(fileName, ref bufferSize, sb, QFR_DESCRIPTION)) {
throw new Win32Exception();
}
return sb.ToString();
}
}
'#
Add-Type $code
[FontUtils]::GetFontDescription('c:\windows\fonts\arial.ttf')
Of course, it's perfectly possible to write the C# code in PowerShell as well (the marshaler isn't language dependent), I just think this is a cleaner separation of concerns.

Type conversion issue in C#

I'm trying something (originally comes from here) about Heap and Pointer on C# Console project. And my program looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
public class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr malloc(int size);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int free(IntPtr region); //Change IntPtr befroe free method to int ---update---
}
public class Program
{
public unsafe void Heap()
{
int* num1, num2, answer;
num1 = Win32.malloc(sizeof(int));
*num1 = 999; // 999 should be the value stored at where pointer num1 refers to
num2 = Win32.malloc(sizeof(int));
*num2 = 1; // 1 should be the value stored at where pointer num2 refers to
answer = Win32.malloc(sizeof(int));
*answer = *num1 + *num2; // 1000 should be the value of pointer answer's reference
Console.WriteLine(*answer); // 1000?
Win32.free(num1);
Win32.free(num2);
Win32.free(answer);
}
}
After debugging, got error message says:
Error 1 Cannot implicitly convert type 'System.IntPtr' to 'int*'. An
explicit conversion exists (are you missing a cast?)
error CS1502: The best overloaded method match for 'Win32.free(System.IntPtr)' has some invalid arguments
error CS1503: Argument 1: cannot convert from 'int*' to 'System.IntPtr'
My questions here are why can't i use IntPtr before malloc and free, since both method return void? What changes should i make on my codes?
Thank you for help.
---Update---
change: public static extern IntPtr free(int hWnd); to public static extern int free(IntPtr region); , free(*num) to free(num)
gives extra 'CS1502' and 'CS1503' two errors.
---second Update---
C# deal heap thing automatically. There is no equivalent of malloc in C#. It's a dead end. T_T
A few mistakes:
in C/C++
void * malloc(int sizeToAllocate);
int free(void * region);
you pass into free the value returned by malloc. Thus your imports should be:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr malloc(int size);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int free(IntPtr region);
and consequently your freeing code should then become:
var num1Ptr = Win32.malloc(sizeof(int));
int * num1 = (int*) num1Ptr.ToPointer();
...
var num2Ptr = Win32.malloc(sizeof(int));
int * num2 = (int*) num2Ptr.ToPointer();
...
var answerPtr = Win32.malloc(sizeof(int));
int * answer = (int*) answerPtr.ToPointer();
...
Win32.free(num1Ptr);
Win32.free(num2Ptr);
Win32.free(answerPtr);

Passing a StringBuilder and getting back a result from a c++ dll to c#

I have the following code in C#:
[DllImport("ClassLibrary2.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void GetString(StringBuilder buffer, ref int bufferSize);
void get()
{
openFileDialog1.ShowDialog();
int bufferSize = 32;
StringBuilder buffer = new StringBuilder(bufferSize);
GetString(buffer, ref bufferSize);
string currentString = buffer.ToString();
MessageBox.Show(currentString);
}
and the following in c++:
extern "C" __declspec(dllexport) void GetString(char* buffer, int* bufferSize){
MD5 md5;
char *returnChar = md5.digestFile(buffer);
cout << returnChar << endl;
strcpy(buffer, returnChar);
}
I'm trying to figure out why it doesn't work.. I've tried many many many things and neither seem to work. This is probably the only thing that doesn't crash my C# program directly so I am left to using it. I need to get a string but I can do with a StringBuilder too.
Yes, my program does work as the cout<<returnChar<<endl; works and displays what I need to see.
Yes, I have tried marshaling it using the calling convention stdcall and many others... what is the simplest way to pass and get a string back?
CharSet = CharSet.Auto is not compatible with void GetString(char* buffer, int* bufferSize). Use CharSet = CharSet.Ansi to make it work. CharSet.Auto is only for importing system library functions that exist in both Ansi and Unicode variants and having .net pick the right one to call.
Why not just do this?
public string CalculateMD5Hash(byte[] input)
{
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] hash = md5.ComputeHash(input);
// Convert to hex string
return string.Join("", hash.Select(h => h.ToString("X2")));
}
And call it with var hash = CalculateMD5Hash(File.ReadAllBytes("path-goes-here"))?

How to pass strings from C# to C++ (and from C++ to C#) using DLLImport?

I've been trying to send a string to/from C# to/from C++ for a long time but didn't manage to get it working yet ...
So my question is simple :
Does anyone know some way to send a string from C# to C++ and from C++ to C# ?
(Some sample code would be helpful)
in your c code:
extern "C" __declspec(dllexport)
int GetString(char* str)
{
}
extern "C" __declspec(dllexport)
int SetString(const char* str)
{
}
at .net side:
using System.Runtime.InteropServices;
[DllImport("YourLib.dll")]
static extern int SetString(string someStr);
[DllImport("YourLib.dll")]
static extern int GetString(StringBuilder rntStr);
usage:
SetString("hello");
StringBuilder rntStr = new StringBuilder();
GetString(rntStr);
Passing string from C# to C++ should be straight forward. PInvoke will manage the conversion for you.
Geting string from C++ to C# can be done using a StringBuilder. You need to get the length of the string in order to create a buffer of the correct size.
Here are two examples of a well known Win32 API:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public static string GetText(IntPtr hWnd)
{
// Allocate correct string length first
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool SetWindowText(IntPtr hwnd, String lpString);
SetWindowText(Process.GetCurrentProcess().MainWindowHandle, "Amazing!");
A lot of functions that are encountered in the Windows API take string or string-type parameters. The problem with using the string data type for these parameters is that the string datatype in .NET is immutable once created so the StringBuilder datatype is the right choice here. For an example examine the API function GetTempPath()
Windows API definition
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
.NET prototype
[DllImport("kernel32.dll")]
public static extern uint GetTempPath
(
uint nBufferLength,
StringBuilder lpBuffer
);
Usage
const int maxPathLength = 255;
StringBuilder tempPath = new StringBuilder(maxPathLength);
GetTempPath(maxPathLength, tempPath);

Calling DLL function with char* param from C#?

I have a C++ dll that I need to call from C#. One of the functions in the dll requires a char* for an input parameter, and another function uses a char* as an output parameter.
What is the proper way to call these from C#?
string should work if the parameter is read-only, if the method modifies the string you should use StringBuilder instead.
Example from reference below:
[DllImport ("libc.so")]
private static extern void strncpy (StringBuilder dest,
string src, uint n);
private static void UseStrncpy ()
{
StringBuilder sb = new StringBuilder (256);
strncpy (sb, "this is the source string", sb.Capacity);
Console.WriteLine (sb.ToString());
}
If you don't know how p/invoke marshaling works you could read http://www.mono-project.com/Interop_with_Native_Libraries
If you are only conserning with strings, read only the section: http://www.mono-project.com/Interop_with_Native_Libraries#Strings
Just using strings will work fine for input parameters, though you can control details about the string with the MarshalAs attribute. E.g.
[DllImport("somedll.dll", CharSet = CharSet.Unicode)]
static extern void Func([MarshalAs(UnmanagedType.LPWStr)] string wideString);
As for returning char* parameters, that's a little more complex since object ownership is involved. If you can change the C++ DLL you can use CoTaskMemAllocate, with something like:
void OutputString(char*& output)
{
char* toCopy = "hello...";
size_t bufferSize = strlen(toCopy);
LPVOID mem = CoTaskMemAlloc(bufferSize);
memcpy(mem, toCopy, bufferSize);
output = static_cast<char*>(mem);
}
The C# side then just uses an 'out string' parameter, and the garbage collector can pick up the ownership of the string.
Another way of doing it would be to use a StringBuilder, but then you need to know how big the string will be before you actually call the function.
Not sure this works, but have you tried with
StringObject.ToCharArray();
Not sure about initialising the String from char * tho. Mybe just assign to a string object, its worth a try.
Have you tried StringBuilder? I found this in a Google search:
[DllImport("advapi32.dll")]
public static extern bool GetUserName(StringBuilder lpBuffer, ref int nSize);
If you post the call you're making we can help you assemble it.
If the DLL function is expecting an allocated buffer of char* (not a wide/multibyte buffer) then the following will work:
[DllImport("somedll.dll", CharSet = CharSet.Ansi)]
static extern void TheFunc(byte[] someBuffer, int someSize);
Here a buffer allocated in c# is passed to TheFunc which fills it with a string of characters (of type char). Bytes aren't "interpreted" by C# they are treated like 8 bit integers, so are perfect for holding 8 bit characters.
An example code snipped would therefore be:
byte[] mybuffer;
int bufSize;
bufSize = 2048;
mybuffer = new byte[bufSize];
TheFunc(mybuffer, bufSize);
string value;
for(value = "", int ix = 0; (mybuffer[ix] != 0) && (ix < bufSize); ix++)
value += (char) mybuffer[ix];
DoSomethingWithTheReturnedString(value);

Categories