.DLL C++ function to C# - c#

I'm using mpusbapi.dll in WPF project using C#.
In C++ the function prototype is:
DWORD MPUSBWrite(HANDLE handle,
PVOID pData,
DWORD dwLen,
PDWORD pLength,
DWORD dwMilliseconds);
And my p/invoke in C# is:
[DllImport("mpusbapi.dll")]
private static extern DWORD _MPUSBWrite(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds);
So, because I dont make all my project unsafe, I want to buid this next method to send data:
unsafe private void SendPacket(byte* SendData, UInt32 SendLength)
{
uint SendDelay = 10;
UInt32 SentDataLength;
openPipes();
MPUSBWrite(myOutPipe, &SendData, SendLength, &SentDataLength, SendDelay);
closePipes();
}
But Visual Studios show me an error with the variable type of the parameters. "Cannot convert from 'byte**' to 'system.IntPtr'" and "Cannot convert from 'uint*' to 'system.IntPtr'".
I am new using C # and now the pointers have me stuck. How should I translate the c++ parameter to C#? Thanks!
EDIT:
I didn't notice that I've changed the Pinvoke to:
[DllImport("mpusbapi.dll", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 _MPUSBWrite(IntPtr handle,IntPtr pData, UInt32 dwLen,IntPtr pLength, UInt32 dwMilliseconds);
ADD:
Removing the & in the method call did not fix the last errors and added this one "Use of unassigned local variable 'SendDataLenght'".

I don't see the need for any of this to be unsafe and use pointers. Making some basic assumptions on the parameter semantics, you might use this declaration:
[DllImport("mpusbapi.dll")]
private static extern uint _MPUSBWrite(
IntPtr handle,
byte[] data,
uint dataLength,
out uint sentDataLength,
uint timeoutMS
);
I don't know what the calling convention should be. You use both stdcall and cdecl in the question. Rather than guessing, you need to find out definitively.

Related

PInvoke Array Marshalling Failure

I have the following C++ function exported in a DLL:
extern "C" __declspec(dllexport) bool GetResolutionArray(int32_t adapterIndex, int32_t outputIndex, uint32_t arrayLength, Resolution outResolutionArr[]) {
memcpy_s(
outResolutionArr,
sizeof(Resolution) * arrayLength,
RENDER_COMPONENT.GetResolutionArray(adapterIndex, outputIndex),
RENDER_COMPONENT.GetOutput(adapterIndex, outputIndex).NumResolutions * sizeof(Resolution)
);
return true;
}
And, the matching extern function declaration in C#:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex, int outputIndex, uint resolutionArrayLength, [MarshalAs(UnmanagedType.LPArray), In, Out] ref Resolution[] resolutions);
However, when I attempt to use this function as below, the program crashes with a FatalExecutionEngineError (indicating I corrupted something somewhere I guess) (error code 0xc0000005, i.e. access violation):
Resolution[] resolutions = new Resolution[outOutputDesc.NumResolutions];
if (!_GetResolutionArray(outAdapterDesc.AdapterIndex, outOutputDesc.OutputIndex, (uint) resolutions.Length, ref resolutions)) {
EnginePipeline.TerminateWithError("Internal engine call failed: _GetResolutionArray");
}
I strongly suspect that my call to memcpy_s is causing the access violation, but I can't see how or why, and I therefore reason that perhaps the marshalling is going wrong somewhere.
Thank you.
The array parameter is declared incorrectly. A C# array is already a reference and so you don't need the ref. Declare it like this:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray",
CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex,
int outputIndex, uint resolutionArrayLength, Resolution[] resolutions);

Using SetFilePointer in C# has unblanced the stack

Ok, I am using the SetFilePointer function in C# with .NET 4.0. Below are the dllimports I used to call this function:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod);
Whenever I run the code that uses the SetFilePointer function in the debugger I get this exception:
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'MyDiskStuff!MyDiskStuff.HardDisk::SetFilePointer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Whenever I run the same code outside of the debugger I do not get the above exception.
Below is the code I am using to make the calls to SetFilePointer:
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
uint retvalUint = SetFilePointer(mySafeFileHandle, myLong, out myInt, EMoveMethod.Begin);
Is there something wrong with my dllimport signatures?
Your P/Invoke signature is a little off:
Here's the Win32 definition:
DWORD WINAPI SetFilePointer(
_In_ HANDLE hFile,
_In_ LONG lDistanceToMove,
_Inout_opt_ PLONG lpDistanceToMoveHigh,
_In_ DWORD dwMoveMethod
);
And here's the P/Invoke with your enum specified:
[DllImport("kernel32.dll", EntryPoint="SetFilePointer")]
static extern uint SetFilePointer(
[In] Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
[In] int lDistanceToMove,
[In, Out] ref int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod) ;
EDIT: Oh, and some test code:
var text = "Here is some text to put in the test file";
File.WriteAllText(#"c:\temp\test.txt", text);
var file = File.Open(#"c:\temp\test.txt", FileMode.OpenOrCreate);
int moveDistance = 10;
int moveDistanceHighBits = 0;
uint retvalUint = SetFilePointer(file.SafeFileHandle, moveDistance, ref moveDistanceHighBits, EMoveMethod.Begin);
Debug.Assert(Encoding.ASCII.GetBytes(text)[moveDistance] == file.ReadByte());
Also note from the docs:
lDistanceToMove [in]
The low order 32-bits of a signed value that specifies the number of bytes to move the file pointer.
If lpDistanceToMoveHigh is not NULL, lpDistanceToMoveHigh and lDistanceToMove form a single 64-bit signed value that specifies the distance to move.
If lpDistanceToMoveHigh is NULL, lDistanceToMove is a 32-bit signed value. A positive value for lDistanceToMove moves the file pointer forward in the file, and a negative value moves the file pointer back.
lpDistanceToMoveHigh [in, out, optional]
A pointer to the high order 32-bits of the signed 64-bit distance to move.
If you do not need the high order 32-bits, this pointer must be set to NULL.
When not NULL, this parameter also receives the high order DWORD of the new value of the file pointer. For more information, see the Remarks section in this topic.
Likely.
pinvoke.net lets CallingConvention default to StdCall (instead of your Cdecl setting) and since SetFilePointer is declared as WINAPI (which is __stdcall). Incorrect calling convention will damage your stack.

DLLImport in C# has incorrect call

I am getting a PInvokeStackImbalance: 'PInvokeStackImbalance was detected
Message: A call to PInvoke function 'ConvertedClass::MapViewOfFile' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.'
I am fairly new to DLL use, and just managed to work out a few tutorials today.
Any help would be appreciated.
using System.Runtime.InteropServices;
//dll
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, ulong dwNumberOfBytesToMap;)
string szSharedMemory = "FUNKY_BUSINESS";
//other dll call is successful and returns value
IntPtr hMem = OpenFileMapping(FileMapAccessRights.Write, FALSE, szSharedMemory);
///BOOM.. not this one
IntPtr pvHead = MapViewOfFile(hMem, FileMapAccessRights.Write, 0, 0, 0);
Edit: It was a bad argument.. The 5th arg should be UIntPtr instead of ulong.
this is how i feel right now
The final parameter is SIZE_T. That's unsigned, and 32 bits in a 32 bit process and 64 bits in a 64 bit process. So the best solution is to use UIntPtr for the final parameter.
I would use the following:
[DllImport("kernel32")]
public static extern IntPtr MapViewOfFile(
IntPtr hFileMappingObject,
FileMapAccessRights dwDesiredAccess,
uint dwFileOffsetHigh,
uint dwFileOffsetLow,
UIntPtr dwNumberOfBytesToMap
);
Your code uses ulong which is always 64 bits wide. And your process is a 32 bit process which explains why the P/invoke marshaller has detected a stack imbalance.
The 5th parameter should be an uint, not ulong.
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap;)
For P/Invoke, you can use sample code from pinvoke.net.
http://www.pinvoke.net/default.aspx/kernel32.mapviewoffile

Access violation calling Win API from C# using DllImport

The task is to determine the last write time for the registry key. As standard RegistryKey class doesn't provide this feature, I have to use WinAPI function "RegQueryInfoKey". To get the key handle I open it by "RegOpenKeyEx".
This is the WinAPI prototype of the function (taken from MSDN):
LONG WINAPI RegOpenKeyEx(
__in HKEY hKey,
__in LPCTSTR lpSubKey,
DWORD ulOptions,
__in REGSAM samDesired,
__out PHKEY phkResult
);
I use the following declaration:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegOpenKeyEx(UIntPtr hkey, string lpSubKey, uint samDesired, ref UIntPtr phkResult);
Then I call it in the following way:
UIntPtr hKey = UIntPtr.Zero;
string myKeyName = "blablabla";
UIntPtr HKEY_USERS = (UIntPtr)0x80000003;
uint KEY_READ = 0x20019;
RegOpenKeyEx(HKEY_USERS, myKeyName, KEY_READ, ref hKey);
At this point I get "Access violation" exception. What am I doing wrong?
I think something is wrong with parameters passing, but how to do it right?
Thank you.
There are 5 parameters in the native function's prototype, and only 4 in your P/Invoke signature.
In particular, you're missing DWORD ulOptions. This parameter is "reserved and must be zero" according to the MSDN documentation, but it must still be passed in the function call.
Also, you don't need to set the SetLastError field because the RegOpenKeyEx function returns its error code; you don't have to retrieve it by calling GetLastError. Consequently, you don't need the marshaler to save that value for you automatically. Just check the return value for the error code.
Change your P/Invoke signature to look like this:
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(UIntPtr hkey, string lpSubKey,
uint ulOptions, uint samDesired,
out UIntPtr phkResult);
The wrong P/Invoke signature is almost always the cause of "access violation" errors. When you see one of those, make sure you double-check it twice!
You've missed ulOptions from your P/Invoke signature.

How to correctly hook and return GetDlgItemTextA from C++ to C# to C++ from EasyHook

I'm using EasyHook, a C# library for injecting and detouring functions from unmanaged applications. I'm trying to hook onto GetDlgItemTextA, which takes the arguments:
UINT WINAPI GetDlgItemText(
__in HWND hDlg,
__in int nIDDlgItem,
__out LPTSTR lpString,
__in int nMaxCount
);`
In my hook, I am casting it as:
[DllImport("user32.dll",
// CharSet = CharSet.Unicode,
SetLastError = true,
CallingConvention = CallingConvention.StdCall)]
static extern uint GetDlgItemTextA(IntPtr hWin, int nIDDlgItem, StringBuilder text, int MaxCount);
And my hook is:
static uint DGetDlgItemText_Hooked(IntPtr hWin, int nIDDlgItem, StringBuilder text, int MaxCount)
{
// call original API...
uint ret = GetDlgItemTextA(hWin, nIDDlgItem, text, MaxCount);
MessageBox.Show(text.ToString());
return ret;
}
Unfortunately, the moment this is called, the hooked application crashes. Is there a better cast I can use to successfully hook onto this function? Thanks!
I've compiled, editted, and confirmed the working condition of my EasyHook setup. This is just casing and hooking only.
Well, it appears that the code I had did work, but the the only difference I had to put a try catch statement in the hook for an unknown reason. StringBuilder does correctly get converted from LPCSTR and back to LPCSTR, and the program reads it just fine. The program does not crash now, so I thought I would add this as my own answer.

Categories

Resources