Marshalling native function - c#

I have a function in a C DLL that performs SCrypt key derivation, but I'm having real trouble marshalling the values into my C# program.
The function declaration is as follows in C:
__declspec(dllexport) int scrypt(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,uint8_t * buf, size_t buflen);
passwd and salt are both passed in a pointers to uint8 arrays, N, r and p are tuning values for the algorithm. Buflen is the size you wish the output buffer to be. buf is the output buffer (and so either needs to be a ref or an out I think);
I've tried various approaches, with the most recent being Marshal.Copy to move data out of the IntPtrs into byte arrays (and vice-versa), however as these are UInt pointers as opposed to IntPtr I don't know if that is right. Currently it crashes when I try and copy the data out of the buf IntPtr and back into the array.
I'd really appreciate any assistance.
class Program
{
[DllImport("SCrypt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern int scrypt(IntPtr passwd, UIntPtr passwdlen, IntPtr salt, UIntPtr saltlen, UInt64 N, UInt32 r, UInt32 p, out IntPtr buf, UIntPtr buflen);
static void Main(string[] args)
{
byte[] encoded = new byte[32];
IntPtr encodedptr;
byte[] password = System.Text.Encoding.Unicode.GetBytes("test");
byte[] salt = System.Text.Encoding.Unicode.GetBytes("ThisistheSaltweareusingforthiskey");
IntPtr passwordptr, saltptr;
passwordptr = Marshal.AllocHGlobal(password.Length);
Marshal.Copy(password, 0, passwordptr, password.Length);
saltptr = Marshal.AllocHGlobal(salt.Length);
Marshal.Copy(salt, 0, saltptr, salt.Length);
int returnVal = scrypt(passwordptr, (UIntPtr)password.Length, saltptr, (UIntPtr)salt.Length, 262144, 8, 1,out encodedptr,(UIntPtr) 32);
Marshal.Copy(encodedptr, encoded, 0, 32);
Console.WriteLine(BitConverter.ToString(encoded));
Console.ReadKey();
}
}

I'd probably use the following function declaration:
public static extern int scrypt(byte[] passwd, uint passwdlen, byte[] salt, uint saltlen, ulong N, uint r, uint p, byte[] buf, uint buflen).
Keep in mind that there are multiple different ways of marshalling certain types, but in this case the above variant is probably the clearest because it maps directly to the respective types.
You can trivially convert a string to a byte[] by asking an Encoding to do so for you. In the case of passwords as long as you convert to Unicode everything should be fine. But make sure to use the same variant in every place that might need to convert a password to a byte[].

Related

Get pointer (IntPtr) from a Span<T> staying in safe mode

I would like to use Span and stackalloc to allocate an array of struct and pass it to an interop call. Is it possible to retrieve a pointer (IntPtr) from the Span without being unsafe ?
Here is how i did it without unsafe:
i just changed lpBuffer to ref byte instead of byte[] (for c++ user COULD represent it as uint8_t*)
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(nint hProcess, nuint lpBaseAddress, ref byte lpBuffer, int dwSize, out int lpNumberOfBytesRead);
Span<byte> bytes = stackalloc byte[8];
// Get reference to first byte in the span (for c++ user we COULD represent it as `uint8_t*`)
ref byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `ref MemoryMarshal.AsRef<byte>(bytes)` to the function directly
bool success = Win32.ReadProcessMemory(_processHandle, address, ref bytesReference, cSize, out int numberOfBytesRead);
lpBuffer could be in byte instead of ref byte as that will allow you to use ReadOnlySpan
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(nint hProcess, nuint lpBaseAddress, in byte lpBuffer, int dwSize, out int lpNumberOfBytesWritten);
ReadOnlySpan<byte> bytes = stackalloc byte[8];
ref readonly byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `in MemoryMarshal.AsRef<byte>(bytes)` to the function directly
Win32.WriteProcessMemory(_processHandle, address, in bytesReference, bytes.Length, out int numberOfBytesWritten);
Notes:
[+] You could use GetPinnableReference instead of MemoryMarshal.AsRef but it is not intended to be called by user code.
[+] ReadProcessMemory Windows API function.
[+] ReadProcessMemory(kernel32) pinvoke Original implementation.

Use C++ DLL in C#

My program need control a hardware. Vendor provide a DLL which is design for C/C++ language.
Most of functions passed my test beside below function:
int32 ni845xSpiWriteRead(NiHandle DeviceHandle,
NiHandle ConfigurationHandle,
uInt32 WriteSize,
uInt8 * pWriteData,
uInt32 * pReadSize,
uInt8 * pReadData);
Document of this function is here:
Inputs NiHandle DeviceHandle
Device handle returned from ni845xOpen.
NiHandle ConfigurationHandle
The configuration handle returned from ni845xSpiConfigurationOpen.
uInt32 WriteSize
The number of bytes to write. This must be nonzero.
uInt8 * pWriteData
The data bytes to be written.
Outputs uInt32 * pReadSize
A pointer to the amount of bytes read.
uInt8 * pReadData
A pointer to an array of bytes where the bytes that have been read
are stored.
My code in C# is here:
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]
public static extern int ni845xSpiWriteRead(
long DeviceHandle, //In
long ConfigurationHandle, //In
int WriteSize, //In
IntPtr pWriteData, //In
IntPtr pReadSize, //Out
IntPtr pReadData //Out
);
I always got AccessViolationException exception. I am guessing that is caused by the pointer input/output parameter.
The code of invoke Swrapper.ni845xSpiWriteRead() i here:
public void WriteData(int length, int[] writeArray)
{
byte[] writeDate = new byte[8];
int writeSize = writeDate.Length;
try
{
//Define pointers
IntPtr writeDataPointer = Marshal.AllocHGlobal(writeDate.Length);
IntPtr readDataSizePointer = Marshal.AllocHGlobal(writeDate.Length);
IntPtr readDataPointer = Marshal.AllocHGlobal(writeDate.Length);
//Copy value to write data pointer
Marshal.Copy(writeDate, 0, writeDataPointer, writeDate.Length);
int state = Ni845xNativeMethods.ni845xSpiWriteRead(_niHandle, _niConfigrationHandle, writeSize, writeDataPointer,readDataSizePointer,readDataPointer);
this.CheckStatus(state);
}
catch (Exception)
{
throw;
}
}
Most likely the p/invoke should be:
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]
public static extern int ni845xSpiWriteRead(
IntPtr DeviceHandle,
IntPtr ConfigurationHandle,
uint WriteSize,
[In] byte[] WriteData,
out uint ReadSize,
[Out] byte[] ReadData
);
You'll need to allocate a byte[] of sufficient length to use as the ReadData parameter. Presumably you know how to do this.
I've taken at face value the statement that ReadSize is an output parameter. However, if it is both in and out, then declare it as ref.
The most likely thing is it's just the Out size parameter. So:
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]
public static extern int ni845xSpiWriteRead(
long DeviceHandle, //In
long ConfigurationHandle, //In
int WriteSize, //In
IntPtr pWriteData, //In
out uint ReadSize, //Out
IntPtr pReadData //Out
);
This is similar to #Marius, but the handles should be fine as integers. The trick is to get the size returned as an integer, so either 'out uint' or 'ref uint' to do that.
Much better if we could see the calling code.
Having seen the code, you could also try something like this.
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]
public static extern int ni845xSpiWriteRead(
long DeviceHandle, //In
long ConfigurationHandle, //In
int WriteSize, //In
[MarshalAs(UnmanagedType.LPArray)] long [] writeData, //In
out uint ReadSize, //Out
[MarshalAs(UnmanagedType.LPArray), Out] readData //Out
);
This avoids all that Marshal.Copy stuff. Make sure the readData buffer is big enough.
I think both of the existing answers are somewhat incorrect, so I will add another (probably also incorrect) answer.
If DeviceHandle and ConfigurationHandle are truly HANDLE types (or other pointer types) then you should use IntPtr as the type for P/Invoke.
Given the C function declaration, the ReadData buffer must be allocated by the caller. Also, it is likely that ReadSize must be initialized to the size of the buffer and will be set to the actual number of bytes read during the function call.
I think this may come close to working:
class Program
{
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]
public static extern int ni845xSpiWriteRead(
IntPtr DeviceHandle,
IntPtr ConfigurationHandle,
UInt32 WriteSize,
[MarshalAs(UnmanagedType.LPArray)][In] Byte[] pWriteData,
ref UInt32 ReadSize,
[MarshalAs(UnmanagedType.LPArray)][Out] Byte[] pReadData);
static void Main(string[] args)
{
IntPtr DeviceHandle = (IntPtr)123;
IntPtr ConfigurationHandle = (IntPtr)456;
Byte[] WriteData = new Byte[2324];
Byte[] ReadData = new Byte[8274];
UInt32 ReadSize = (UInt32)ReadData.Length;
int result = ni845xSpiWriteRead(DeviceHandle,
ConfigurationHandle,
(UInt32) WriteData.Length,
WriteData,
ref ReadSize,
ReadData);
}
}
Change your calling convention from Cdecl to stdCall and it will work now.
[DllImport("Ni845x", CallingConvention = CallingConvention.Cdecl)]

How to initialise an unsafe pointer in C# and convert it to a byte[]?

I put a post up yesterday, How does one create structures for C# originally written in C++.
Thank you for your responses.
I'm trying, without much success, to use DeviceIOControl on an ARM platform running WinCE 6.0 and .NET Compact framework 2.0 All I am trying to achieve is the control of a port pin and it's proving to be a nightmare.
The following is the PInvoke declaration:
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern bool DeviceIoControlCE(int hDevice,
int dwIoControlCode,
byte[] lpInBuffer,
int nInBufferSize,
byte[] lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
The PInvoke declaration suggests a byte[] may be passed to it simply. Surely it's an easy matter to write the values to each member of a structure, convert it to an array of bytes and pass it to the dll.
I have the following:
[StructLayout(LayoutKind.Sequential)]
public struct pio_desc
{
unsafe byte* pin_name; //Length???
public uint pin_number; //4 bytes
public uint default_value; //4 bytes
public byte attribute; //1 byte
public uint pio_type; //4 bytes
}
and
pio_desc PA13 = new pio_desc();
So surely now it's a matter of doing something like:
PA13.pin_number = AT91_PIN_PA13; //Length 4 bytes
PA13.default_value = 0; //Length 4 bytes
PA13.attribtue = PIO_DEFAULT; //Length 1 byte
PA13.pio_type = PIO_OUTPUT; //Length 4 bytes
and to convert (pin_number for example) to a byte[]:
byte[] temp = BitConverter.GetBytes(PA13.pin_number); //uints are 4 bytes wide
byteArray[++NumberOfChars] = temp[0];
byteArray[++NumberOfChars] = temp[1];
byteArray[++NumberOfChars] = temp[2];
byteArray[++NumberOfChars] = temp[3]; //Will need to check on Endianess
Questions:
In the structure PA13, how do I initialise the unsafe pointer pin_name? The author of the driver notes that this is not used, presumably by his driver. Will Windows need this to be some value?
PA13.pin_name = ??????
Then, how do I convert this pointer to a byte to fit into my byte[] array to be passed to DeviceIOControl?
I've become quite disappointed and frustrated at how difficult it is to change the voltage level of a port pin - I've been struggling with this problem for days now. Because I come from a hardware background, I think it's going to be easier (and less eligant) for me to implement IO control on another controller and to pass control data to it via a COM port.
Thanks again for any (simple) assistance.
You will need to do a few different things here. First, replace this member:
unsafe byte* pin_name; //Length???
with:
[MarshalAs(UnmanagedType.LPStr)] public string pin_name;
Then replace the in/out buffers in the P/Invoke declaration from byte[] to IntPtr. Then you can use this code to convert the data:
pio_desc PA13;
// Set the members of PA13...
IntPtr ptr = IntPtr.Zero;
try {
var size = Marshal.SizeOf(PA13);
ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(PA13, ptr, false);
// Your P/Invoke call goes here.
// size will be the "nInBufferSize" argument
// ptr will be the "lpInBuffer" argument
} finally {
if (ptr != IntPtr.Zero) {
Marshal.DestroyStructure(ptr, typeof(pio_desc));
Marshal.FreeHGlobal(ptr);
}
}
You can make this a lot easier by lying about the [DllImport] declaration. Just declare the lpInBuffer argument as the structure type, the pinvoke marshaller will convert it to a pointer anyway. Thus:
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern bool SetOutputPin(IntPtr hDevice,
int dwIoControlCode,
ref pio_desc lpInBuffer,
int nInBufferSize,
IntPtr lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);
Using IntPtr for lpOutBuffer because the driver probably doesn't return anything. Pass IntPtr.Zero. Same idea with the structure. If the field isn't used then simply declare it as an IntPtr:
[StructLayout(LayoutKind.Sequential)]
public struct pio_desc
{
public IntPtr pin_name; // Leave at IntPtr.Zero
public uint pin_number; //4 bytes
public uint default_value; //4 bytes
public byte attribute; //1 byte
public uint pio_type; //4 bytes
}
Be careful about the Packing property, it makes a difference here because of the byte sized field. You may need 1 but that's just a guess without knowing anything about the driver. If you have working C code then test the value of sizeof(pio_desc) and compare with Marshal.SizeOf(). Pass Marshal.SizeOf(typeof(pio_desc)) as the nInBufferSize argument. If you would have posted the C declarations then this would have been easier to answer accurately.
Declare lpInBuffer and lpOutBuffer as IntPtr. Initialize them using Marshal.AllocHGlobal (don't forget to release them with Marshal.FreeHGlobal in the end). Fill these buffer and read it using different Marshal.Copy overloads.

How to write the C# prototype to P/Invoke a function which takes a char* as an argument, and returns its value there

As the title suggests, I'm trying to write some C# code to interop with a C DLL (It's a Windows device driver, basically). The error code function signature in C is:
UINT DLLErrorMsg( DWORD errorCode, char * pBuf, UINT nSize );
nSize is the size of pBuf. If nSize can fit the error message, it is copied into pBuf and 0 returned, otherwise (the buffer was too small and) the return value is the minimum size the buffer needs to be to fit the error message.
I've tried some variants of the following:
internal class DLLWrapper
{
[DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl)]
public static extern UInt32 GetErrorMessage(UInt32 dwError, ref char * pBuf, UInt32 nBufSize);
}
The client code at the moment looks something like this:
GetError( UInt32 errorCode )
{
char[] errorMsg = new char[bufSize];
UInt32 moreChars = DLLWrapper.GetErrorMessage(errorCode, out errorMsg, bufSize);
if (moreChars > 0)
{
errorMsg = new char[moreChars];
TWLDLLInterface.GetErrorMessage(errorCode, out errorMsg, moreChars);
}
}
But I get an exception at the call to GetErrorMessage:
An unhandled exception of type 'System.ArgumentException' occurred in NdevInterface.dll
Additional information: Method's type signature is not Interop compatible.
I've also tried playing around with IntPtr and trying Marshal.IntPtrToStringAuto(), but that wasn't helpful because I need to allocate the buffer, and I obviously can't cast a char[] into an IntPtr.
I've tried searching through the MSDN and general internet for tips on how to do this, but most of it seems to be a little different than what I'm trying.
What am I doing wrong?
You can marshal this using a StringBuilder. For details, see this P/Invoke intro:
[DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl)]
public static extern UInt32 GetErrorMessage(UInt32 dwError, StringBuilder pBuf, UInt32 nBufSize);
Just make sure the StringBuilder has been constructed with enough memory for the pBuf to get filled in.
This example is very similar to what you're trying to achieve.
I think you want this:
internal class DLLWrapper
{
[DllImport(_libName, EntryPoint="DLLErrorMsg", CallingConvention=CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern UInt32 GetErrorMessage(UInt32 dwError, StringBuilder * pBuf, UInt32 nBufSize);
public static UInt32 GetErrorMessage( UInt32 dwError, out string msg)
{
uint buffersize = 1024;
StringBuilder sb = new StringBuilder((int)buffersize);
uint result = GetErrorMessage( dwError, sb, buffersize );
msg = sb.ToString();
return result;
}
}

How can I pass a pointer to an array using p/invoke in C#?

Example C API signature:
void Func(unsigned char* bytes);
In C, when I want to pass a pointer to an array, I can do:
unsigned char* bytes = new unsigned char[1000];
Func(bytes); // call
How do I translate the above API to P/Invoke such that I can pass a pointer to C# byte array?
The easiest way to pass an array of bytes is to declare the parameter in your import statement as a byte array.
[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(byte[]);
byte[] ar = new byte[1000];
Func(ar);
You should also be able to declare the parameter as an IntPtr and Marshal the data manually.
[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(IntPtr p);
byte[] ar = new byte[1000];
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * ar.Length);
Marshal.Copy(ar, 0, p, ar.Length);
Func(p);
Marshal.FreeHGlobal(p);
You can use unsafe code:
unsafe
{
fixed(byte* pByte = byteArray)
IntPtr intPtr = new IntPtr((void *) pByte);
Func(intPtr);
}
If you need to use safe code, you can use a few tricks:
IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(byteArray));
Marshal.Copy(byteArray, 0, intPtr, Marshal.SizeOf(byteArray));
Func(intPtr);
Marshal.FreeHGlobal(intPtr);
However, the safe code is going to be slow IMHO.
Here is the appropriate signature for the native function.
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Func")]
public static extern void Func(System.IntPtr bytes) ;

Categories