How to call this Delphi function from a DLL in C#? - c#

I am given a Delphi DLL that contains functions that I need to call in C#. One of the functions takes two char arrays, where one is an encrypted password and the other is the key.
TCString = array[0..254] of Char;
...
function Decrypt(const S, Key: TCString): TCString; stdcall;
I tried to figure out how to call this function on my own but I keep getting "Cannot marshal 'return value': Invalid managed/unmanaged type combination." I am using byte since the Char type in Delphi is AnsiChar which is 8 bits.
[DllImport("path", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern byte[] Decrypt(byte[] S, byte[] Key);
What is the correct way to call this in C#?

I think I would be inclined to wrap the fixed length array in a C# struct.
public struct CString
{
[UnmanagedType.ByValArray(SizeConst=255)]
byte[] value;
}
This allows the size to be specified in one place only.
The next hurdle is the return value. The Delphi ABI treats a return value that cannot fit into a register as an additional hidden var parameter. I'll translate that as a C# out parameter.
Finally the two input parameters are declared as const. That means that they are passed by reference.
So the function would be:
[DllImport(dllname, CallingConvention = CallingConvention.StdCall)]
public static extern void Decrypt(
[In] ref CString S,
[In] ref CString Key,
out CString Result
);
I've intentionally avoided any use of text in this because this would appear to be a function that operates on binary data. Many Delphi programmers treat AnsiChar arrays interchangeably with byte arrays in such situations which is often confusing.

Related

Calling a unmanaged C method with a SAFEARRAY **ppsa argument from managed C# code

I've been struggling on how to migrate this VB6 code into C#. It involves calling a function inside a DLL passing an array of structure, among other things.
So in VB6, the "struct" declaration is like this:
'Define structure for RGETDAT_STR procedure call
Type rgetdat_str_data_str
type As Integer 'data type (set internally)
file As Integer 'file in database
rec As Integer 'record in file
word As Integer 'word offset in record
start_bit As Integer 'UNUSED
length As Integer 'length of string
flags As Integer 'flags
padding1 As Integer 'UNUSED
value As String 'database value
status As Integer 'return status
padding2 As Integer 'UNUSED
End Type
and one function that uses this "struct" has a method declared as this:
Public Declare Function rgetdat_str Lib "hscnetapi.dll" _
Alias "rgetdat_str_vb" _
(ByVal Server As String, ByVal num_points As Integer, _
getdat_str_data() As rgetdat_str_data_str) As Integer
So, I attempted to convert these 2 pieces of code into C#. I had tried so many variations, but I will post here the latest one that I have. The idea is to call the function via P/Invoke.
The C# struct (so far):
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct rgetdat_str_data_str
{
public short type;
public short file;
public short rec;
public short word;
public short start_bit;
public short length;
public short flags;
public short padding1;
[MarshalAs(UnmanagedType.LPStr)]
public string value;
public short status;
public short padding2;
}
and the function import (so far):
[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")]
public static extern short rgetdat_str(
[MarshalAs(UnmanagedType.LPTStr)]
string Server,
short num_points,
[In,Out, MarshalAs(UnmanagedType.LPArray)]
ref rgetdat_str_data_str[] getdat_str_data);
Nothing worked so far in my various experiments on marshalling attributes with the parameters.
I managed to find the C header file for this DLL, and the declaration looks like this:
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
_DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa));
and the "struct" in the C world is declared like this:
/* define union used in rgetdat_value in RGETDAT procedure call */
typedef union rgetdat_value_str
{
n_short int2;
n_long int4;
n_float real4;
n_double real8;
n_char *str;
n_ushort bits;
} rgetdat_value;
/* define structure for RGETDAT procedure call */
typedef struct rgetdat_data_str
{
n_ushort type;
n_ushort file;
n_ushort rec;
n_ushort word;
n_ushort start_bit;
n_ushort length;
n_short flags;
rgetdat_value value;
n_short status;
} rgetdat_data;
In my frustration, I tried to open this DLL with the ITypeLib Viewer tool. I was surprised that the DLL file can be opened, even though I cannot add this DLL as a Reference in my project. Anyway, a couple of things that I observed within the viewer.
The function has this signature:
[entry("rgetdat_str_vb"), helpstring("...")]
short _stdcall rGetdat_Str(
[in] LPSTR Server,
[in] short num_points,
[in, out] SAFEARRAY(rGetdat_Str_Data_Str)* getdat_str_data);
and the "struct" looked like this:
typedef struct tagrGetdat_Str_Data_Str {
short type;
short file;
short rec;
short word;
short start_bit;
short length;
short flags;
short padding1;
BSTR value;
short status;
short padding2;
} rGetdat_Str_Data_Str;
Based on these observations, I played around with the marshalling attributes of the C# struct, for example,
1.) Changing the struct's value attribute to [MarshalAs(UnmanagedType.BStr)]
2.) Changing the function's getdat_str_data parameter attribute to MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD)
and still nothing works.
There's an blog/article talking about a similar topic here: http://limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke-part-1/ but I can't just wrap my head around it.
It seems that VB6 can do it very simply compared to C# (.Net) with this DLL function call. Any hints or ideas out there on how to DLLImport declare this function in C# (.Net)?
You need to use MarshalAs with UnmanagedType.SafeArray to tell the marshaller that you want the array marshalled as a SAFEARRAY.
[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")]
public static extern short rgetdat_str(
[MarshalAs(UnmanagedType.LPStr)]
string Server,
short num_points,
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_USERDEFINED)]
ref rgetdat_str_data_str[] getdat_str_data
);
In your C# struct, you handle the BSTR member incorrectly. It should be
[MarshalAs(UnmanagedType.BStr)]
public string value;

SWIG unsigned char to byte array c# [duplicate]

I am calling a C++ dll from my C# program. The DLL consists of several functions and I am able to call most of them except this one.
The C++ function is like as below:
__declspec(dllexport) uint8_t* myHash(const char *filename)
{
uint8_t *hash = (unsigned char*)malloc(72*sizeof(uint8_t));
//some processing on hash
return hash;
}
As can be seen in the above code, the hash function stores a character array. I want to receive the values in my C# program but I am not able to do it.
My C# code is like as below:
[DllImport("myHash.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr myHash(string filename);
IntPtr ptr = myHash(fileA);
char[] result = new char[72];
Marshal.Copy(ptr, result, 0, 72);
The problem is that char in C# is a 16 bit character element. Your C++ code returns an array of 8 bit uint8_t values. You should switch to using a byte array instead.
[DllImport("myHash.dll", CallingConvention=CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
public static extern IntPtr myHash(string filename);
....
IntPtr ptr = myHash(fileA);
byte[] result = new byte[72];
Marshal.Copy(ptr, result, 0, 72);
I specified a calling convention because, as written, your function is __cdecl. Perhaps you omitted something in the transcribing of the question, but the declaration above matches the unmanaged code in the question.
This function would be much better designed to allow the caller to allocate the buffer. That avoids you having to export a deallocator from the C++ code. I'd write the C++ like this:
__declspec(dllexport) int myHash(const char *filename, uint8_t* hash)
{
// calculate hash and copy to the provided buffer
return 0; // return value is an error code
}
And the corresponding C# code:
[DllImport("myHash.dll", CallingConvention=CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
public static extern int myHash(string filename, byte[] hash);
....
byte[] hash = new byte[72];
int retval = myHash(fileA, hash);
This function hard-codes in its interface that the buffer is of length 72. That might be reasonable, but it might make sense to pass the length of the buffer too so that the unmanaged code can defend against buffer overruns.
Note that although you refer to the output of this function as a character array, the use of uint8_t* makes it seem more likely to be a byte array. If it really is a character array, then you can use Encoding.GetString() to convert into a string.

C# P-Invoke:how to convert INT fun( BYTE *bStream, UINT16 *nCount, const UINT8 nblk ) to C#?

With C/C++ DLL SDK fun,like this:
INT CmdGetAllLog( BYTE *bStream, UINT16 *nCount, const UINT8 nblk )
but in project use c#,I do it with:
[DllImport("C:\\PrBioApi.dll", EntryPoint = "CmdGetAllLog")]
private static extern bool CmdGetAllLog(IntPtr bStream, ref UInt16 nCount, byte nblk);
and I use it with:
int nMallocSize = Marshal.SizeOf(new LOG_RECORD()) * stuSystem.wLogCnt + 4096;
byte[] pRecord = new byte[nMallocSize];
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(nMallocSize));
Marshal.Copy(pRecord, 0, p, pRecord.Length);
bGetSucc = CmdGetAllLog(p, ref nGet, nBlk++);
Marshal.FreeHGlobal(p);
but it did not work.
would anyone can help me ?thanks.
Your code which copies between the managed array, and the unmanaged pointer, is in the wrong place. It would need to be after the call to the unmanaged function.
But you may as well let the p/invoke marshaller do the work for you:
[DllImport(#"C:\PrBioApi.dll")]
private static extern bool CmdGetAllLog(
byte[] bStream,
ref ushort nCount,
byte nblk
);
int nMallocSize = ...;
byte[] pRecord = new byte[nMallocSize];
bool bGetSucc = CmdGetAllLog(pRecord, ref nGet, nBlk++);
Because a byte array is blittable then the marshaller will just pin your array during the call and hand it off to the native code.
I'm assuming that the other two parameters are passed correctly. Since you did not specify any more details of the interface, they could well be wrong. I'd guess that nGet is used to tell the function how big the buffer is, and to return how much was copied to it by the function. I cannot see where you specify nGet in the question. I'm trusting that you got that bit right.
Some other comments:
You may need to specify a calling convention in the DllImport attribute. Is the native code cdecl perhaps?
The return value is INT in the native code but you've mapped it to bool. That probably is fine if the protocol is that non-zero return means success. But if the return value indicates more than that then you'd clearly need to use int. Personally I'd be inclined to use int and stay true to the native.

Cannot marshal a struct containing a StringBuilder field

I need to make interop calls to a DLL written in C++. In the C++ code, there are various functions that receive and return strings. These all use a commonly defined type (struct) in C++, which comprises a pointer to a string along with an integer for its size as follows:
struct StringParam
{
int size; // 4 byte integer for the size of the string buffer
LPWSTR buff; // Pointer to a wide char buffer
}
When a string is returned from the DLL and when the string buffer is too small to store the string result, an error code is returned along with the correct size buffer that is required in the integer size field, so that the caller can provide the right size buffer.
Ignoring the struct for the moment, this could be easily accomplished through interop using the combination of a StringBuilder parameter, along with a ref int parameter for the size. However, we are using a struct and StringBuilder fields are not permitted in structs that are marshalled.
Given a C++ function that receives a string as follows:
int __stdcall DoSomethingWithString(StringParam *stringParam)
One can declare the following struct in C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct StringParam
{
public int Size;
[MarshalAs(UnmanagedType.LPWStr)]
public string Text;
public StringParam(string text)
{
this.Text = text;
this.Size = text.Length;
}
}
and can successfully initialize a struct and call a C++ function with the following signature:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int DoSomethignWithString(ref StringParam stringParam);
However, given a function that needs to return a string as follows, presents a problem:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int GetSomeString(ref StringParam stringParam);
When receiving a string from the interop call, we do not know the size of the string and must allocate a buffer sufficient in size for storing the string result. StringBuilder would be ideal, but cannot be used within a struct that is marshalled. We could pre-allocate the string with 2048 dummy characters, which could then be used to store the results. This is in fact recommended in the error message one gets when attempting to use the StringBuilder type:
Cannot marshal field 'Text' of type 'StringParam': Struct or class fields cannot be of type StringBuilder. The same effect can usually be achieved by using a String field and preinitializing it to a string with length matching the length of the appropriate buffer.
This seems kind of messy to pre-initialize a string with dummy values. Is there another/better way to go about this?

Pinvoke struct marshalling help needed - System.AccessViolationException

Hey!
I've just begun fiddling with pinvoke and have encountered a problem. I'm getting the AccessViolationException. First of all, is there some way to debug or trace out which field is causing this error? The only thing being written to is the result struct.
The c++ call looks like:
MyFunc(int var1, _tuchar *var2, _tuchar *var3, _tuchar *var4, MyStruct *Result,
_tuchar *var5, _tuchar *var6);
The c++ struct:
typedef struct MyStruct
{
_tuchar *id;
_tuchar *ErrorMessages;
int int1;
_tuchar language[3];
_tuchar *result;
int type;
int number;
int *type2;
_tuchar **blocks;
}
The C# struct:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.LPStr)]
public string Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=500)]
public char[] ErrorMessages;
public int int1;
[MarshalAs(UnmanagedType.LPStr)]
public string language;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public char[] result;
public int type;
public int number;
public int type2;
[MarshalAs(UnmanagedType.ByValArray)]
public string[] blocks;
The C# method declaration:
[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true,
CharSet = CharSet.Unicode)]
internal static extern int MyFunc(int var1, string var2, string var3,
string var4, ref MyStruct Result, string var5, string var6);
The C# Call:
var result = new MyStruct();
MyFunc(0, "var2", "var3", "var4", ref result, "var5", "var6");
Hope I haven't left anything out.
Thanks for any help!
Ooooh, man! You've picked quite a complex case for your first fiddling experience. I recommend doing something simpler first, and then moving on to the real stuff.
Firstly, CharSet=CharSet.Ansi looks suspicious. All your strings and chars are _tuchar, and I gather the u in there means "Unicode", doesn't it? If that's the case, you need CharSet=CharSet.Unicode.
Secondly, (and this is the most likely culprit) why is the ErrorMessages field marshaled as ByValArray? You know that ByVal here means "by value", don't you? As in, not by reference. And you know that little asterisk thing in C++ means "reference", don't you? So why does your reference field ErrorMessages marshaled as a by-value array? In case you don't know, an array is generally said to be passed "by value" when all of it's content is being passed, instead of just passing a reference (pointer) to a memory location where all that content is stored. In C++ struct definition, you specify _tuchar*, which means "a reference (pointer) to some memory containing one or more of _tuchars", whereas in C# you specify [MarshalAs(UnmanagedType.ByValArray, SizeConst=500)], which means "500 _tuchars are supposed to be here, no more and no less". Seeing how a reference (pointer) usually takes 4 bytes (or 8 bytes on 64bit machines), and 500 unicode characters take 1000 bytes, you have an obvious mismatch right here.
Thirdly and fourthly, same point goes for result and blocks fields.
Fifthly, the language field is exactly reverse situation: the C++ code says "there are 3 _tuchars here", while C# code says "there is a reference (pointer) to a string here" (in case you don't know, LPStr means "Long Pointer to STRing")
And finally, after you have fixed all those problems, I recommend you execute your program and print out the result of call to Marshal.SizeOf( typeof( MyStruct ) ). That will give you exactly how big your struct is, in .NET's opinion. The go on the C++ side and print out sizeof( MyStruct ). That will give you what C++ thinks about the size.
If they turn out different, see what's wrong. Try to remove fields one by one, until they become same. This will give you the culprit field(s). Work with them.
Overall, I suggest you need a better understanding of how things work first. This case is waaaay too complex for a beginner.
Good luck!
This is a bit of a shot in the dark, but have you tried decorating the string parameters with MarshalAs(UnmanagedType.LPWStr):
[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true,
CharSet = CharSet.Unicode)]
internal static extern int MyFunc(
int var1,
[MarshalAs(UnmanagedType.LPWStr)]
string var2,
[MarshalAs(UnmanagedType.LPWStr)]
string var3,
[MarshalAs(UnmanagedType.LPWStr)]
string var4,
ref MyStruct Result,
[MarshalAs(UnmanagedType.LPWStr)]
string var5,
[MarshalAs(UnmanagedType.LPWStr)]
string var6);
I believe that the default marshaling chosen for strings is BStr and _tuchar should expand to wchar_t so I'd guess that LPWStr is the correct marshalling method (pointer to a wide character string).
Update: Various things on MyStruct don't look quite right:
ErrorMessages is marked as ByValArray, and so the .Net interop is probably expecting MyStruct to look a bit like this:
typedef struct MyStruct
{
_tuchar *id;
_tuchar ErrorMessages[500];
// Rest of MyStruct
Which is probably going to cause problems - same thing for result.
Also I think that language should be using ByValArray with a size of 3.
Finally blocks should probably be passed using LPArray - ByValArray doesn't seem right.
(This is all mostly guesswork btw - I hope this is pointing you in the right direction but I don't have that much experience with P/Invoke interop)
Another update: On MyStruct you declare the charset to be Ansi, but on MyFunc its Unicode... is the unmanaged dll compiled with Unicode or Ansi? If it uses Unicode then I believe that you should use LPWStr when marshalling strings, and with Ansi it should be LPStr.

Categories