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
Related
I'm building a library for reading memory that I'd like to expand to Mac OS.
Among many other functions, the one main function used by many of the methods is ReadProcessMemory;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ReadProcessMemory(
[In] IntPtr hProcess,
[In] IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
[In] SIZE_T nSize,
[Out] out SIZE_T lpNumberOfBytesRead
);
I'm now wondering what the equivalent for this is on Mac. Looking around online (of course it's hardly documented at all), I think the method signature should look something like this;
[DllImport("...")]
[return: MarshalAs(UnmanagedType.I4)]
static extern int vm_read_overwrite(
[In] IntPtr target_task,
[In] IntPtr address,
[In] SIZE_T size,
[Out] byte[] data,
[Out] out SIZE_T outsize
);
vm_read_overwrite is also what's used by several Rust libraries.
What library/package is vm_read_overwrite part of? Is the signature correct? Perhaps additionally, can I use conditional compilation to use the different functions, or do I have to use RuntimeInformation.IsOSPlatform?
[DllImport("libc")]
static extern int vm_read_overwrite(
[In] IntPtr target_task,
[In] IntPtr address,
[In] uint size,
[Out] byte[] data,
[Out] out uint outsize
);
This works on my machine. Hope it helps.
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.
I have function to write memory, but I want to import address from string, how to do this?
Code:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress,
byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);
and this:
WriteProcessMemory((int)processHandle, 0xffffffff, buffer, buffer.Length, ref bytesWritten);
I want to replace this "0xffffffff" to string, but I don't know how to do this. I try convert string with address to int, but this not working.
Use something like:
string str = "0xffffffffffffffff";
if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
str = str.Substring(2);
}
IntPtr ptr = (IntPtr)long.Parse(str, NumberStyles.HexNumber);
Note that long.Parse doesn't support the 0x, so if present I remove it.
I'm using the long.Parse to support 64bit systems and 32bits systems.
Note that the PInvoke signature you are using is wrong... It will work for 32 bits, but the general one compatible with 32 and 64 bits is:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
IntPtr dwSize,
out IntPtr lpNumberOfBytesWritten);
If you need to manipilate the IntPtr you should always convert them to long, because a IntPtr can be 32 or 64 bits, so a long can always contain it.
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.
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.