I read card SD like file. I use this method:
public static int ReadUSBDisk(ref byte[] buffer, int sector, string fileName)
{
ushort count = 10;
bool retValue;
int address = 512 * sector;
if (!IsUSBOpen())
hUSBDisk = OpenUSBDisk(fileName);
if ((int)hUSBDisk == -1)
return NISH_ERROR;
SetFilePointer(hUSBDisk, address
, 0,
EMoveMethod.Begin);
retValue = ReadFile(hUSBDisk, buffer, 512, ref count, IntPtr.Zero);
if (retValue)
return NISH_NO_ERROR;
else
return NISH_ERROR;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadFile(IntPtr handle,
byte[] buffer, ushort toRead, ref ushort read, IntPtr lpOverLapped);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
IntPtr hFile,
int lDistanceToMove,
int lpDistanceToMoveHigh,
EMoveMethod dwMoveMethod);
But I need to read from more space than the int. But change lDistanceToMove to long couses throw error:
A call to PInvoke '(className) :: SetFilePointer' has upset the
balance of the stack. Probable cause is a mismatch between the managed
PInvoke signature and the unmanaged target signature. Check that the
calling convention and signature parameters of the PInvoke function
match the unmanaged target signature.
Honestly, I don't know exactly how it works. Maybe someone can tell me if I can change it to read from long space in some way.
Related
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.
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)]
I'm developing a little memory scanner for a specific application. When I select a process to scan, the first thing I want to do is to verify that the process is an instance that specific application... and to do this I must find a signature that can be anywhere inside its memory.
Here is my code:
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean ReadProcessMemory([In] IntPtr processHandle, [In] IntPtr processAddress, [Out] Byte[] buffer, [In] UInt32 bytesToRead, [Out] out IntPtr bytesRead);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern UInt32 VirtualQueryEx([In] IntPtr processHandle, [In, Optional] IntPtr processAddress, [Out] out MEMORY_BASIC_INFORMATION buffer, [In] UInt32 bufferSize);
internal struct MEMORY_BASIC_INFORMATION
{
public static UInt32 Size = (UInt32)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION));
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public AllocationProtect AllocationProtect;
public IntPtr RegionSize;
public StateEnum State;
public AllocationProtect Protect;
public TypeEnum lType;
}
public void Open()
{
Byte[] toFind = new Byte[] { 31, 55, 78, 33, 00, 00, 00, 37 };
UInt32 address = 0;
do
{
MEMORY_BASIC_INFORMATION info = new MEMORY_BASIC_INFORMATION();
if (NativeMethods.VirtualQueryEx(m_Process.Handle, (IntPtr)address, out info, NativeMethods.MemoryBasicInformation.Size) == 0)
break;
Byte[] buffer = new Byte[(UInt32)info.RegionSize];
IntPtr bytesRead;
if (NativeMethods.ReadProcessMemory(m_Process.Handle, info.BaseAddress, buffer, (UInt32)buffer.Length, out bytesRead))
{
if (buffer.Contains(toFind)) // Extension Method
{
m_IsValid = true;
break;
}
}
if (address == (UInt32)info.BaseAddress + (UInt32)info.RegionSize)
break;
address = (UInt32)info.BaseAddress + (UInt32)info.RegionSize;
}
while (address <= 0x7fffffff);
}
The first problem that this method is never reaching completion and it looks like it's endlessly looping (yesterday I let it running for debug purposes for more than one hour without reaching the end). Checking for Marshal.GetLastWin32Error() inside my loop I noticed that sometimes I get an ERROR_PARTIAL_COPY (0x0000012B) after calling ReadProcessMemory... is it the possible cause?
Then I also have some questions:
1) Should I call OpenProcess before proceeding with the scan loop? I don't think so, right?
2) I would like to make my application both x32 and x64 compatible. What should I change inside my code to be sure it will properly work with both systems (address limit, value type of address, RegionSize cast, ...)?
3) While scanning the process memory in order to find my target byte array, should I check the current MEMORY_BASIC_INFORMATION's properties (AllocationProtect, State, Protect and/or lType) to see if I can skip ReadProcessMemory for the current region because it's not necessary or it can't be read?
4) Is there anything else I can do to optimize the speed of this methos, which is very important?
Oooooooook I solved it. The problem was the way I was trying to read it without using VirtualQueryEx and checking for the memory region protection!
I'm trying to write a wrapper for C library but I'm really struggling with this error.
I tried many approaches, here is one of them:
[DllImport(DRIVER_FILENAME)]
[return: MarshalAs(UnmanagedType.U4)]
private static extern uint GetData(IntPtr handle,
[MarshalAs(UnmanagedType.LPArray), In()] int[] buffer,
[MarshalAs(UnmanagedType.U4)] uint size);
Here is function GetData from the library documentation:
LONG GetData(
IN HANDLE Handle,
OUT PULONG Buffer,
IN ULONG Size
);
Function returns continuous data (about 16KB/s) in buffer which size is given in bytes. Buffer is int[16384]. My code looks like this:
public static uint GetLibData(IntPtr handle, int[] buffer, uint size)
{
size *= 4;
uint sizeRead = GetData(handle, buffer, size);
sizeRead /= 4;
return sizeRead;
}
Problematic argument is buffer, I tried manage it previously in other ways, such as IntPtr bufferPtr and then allocating memory by Marshal.AllocHGlobal but I was getting the same error:
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
How to correctly invoke this function?
The appropriate p/invoke declaration is
[DllImport(DRIVER_FILENAME)]
private static extern uint GetData(
IntPtr handle,
[Out] uint[] buffer,
uint size
);
It is your responsibility to allocate the buffer before you call the function:
uint[] buffer = new uint[16384];
uint bufferSize = buffer.Length*Marshal.SizeOf(typeof(uint));
uint sizeRead = GetData(handle, buffer, bufferSize);
uint lenRead = sizeRead/Marshal.SizeOf(typeof(uint));
The only thing that's not 100% clear is the calling convention. I'd guess that this library uses cdecl which would mean your DllImport should be
[DllImport(DRIVER_FILENAME, CallingConvention=CallingConvention.Cdecl)]
Try with the following PInvoke:
[DllImport(DRIVER_FILENAME)]
private static extern Int32 GetData
(
[In] IntPtr handle,
[Out] out IntPtr buffer,
[In] UInt32 size
);
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;
}
}