Using DevicIOControl with VC# [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have created two different Visual C# dll's that make use of DeviceIOControl calls and I have defined them as below:
In first dll:
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref Internal_COMMAND lpInBuffer,
DWORD nInBufferSize,
ref ulong lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
public struct Internal_COMMAND
{
public ulong Address;
public ulong Command;
};
In second dll:
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref char[] lpInBuffer,
DWORD nInBufferSize,
ref char[] lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
But now I have to make them as a single dll within the same class. So I tried to use the below.
[DllImport("kernel32.dll", SetLastError = true)]
static extern BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
ref char[] lpInBuffer,
DWORD nInBufferSize,
ref char[] lpOutBuffer,
DWORD nOutBufferSize,
ref DWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
as common definition and passed the variables by converting structure to character array. But the driver does not work as expected
Please guide me with the correct procedure to follow

Method overload just worked just as #Hans Passant pointed out
This means I can use both definitions in a single .cs file and method overload takes effect, allowing to use the same function with different parameters

Related

Speed up C# native call pinvoke

mod note: I do not believe this to be a duplicate, due to me having already tried several mentioned solutions as described below.
Is there a way I can speed this up? I've already followed the Microsoft guides on this, and here's what I've done:
Added SuppressUnmanagedCodeSecurity
Placed this in a file named UnsafeNativeMethods.cs
Defined specific types for the method stub
Here is the method:
[DllImport("kernel32.dll")]
[SuppressUnmanagedCodeSecurity]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint IoControlCode,
[In] MemoryManager.MemOperation InBuffer,
int nInBufferSize,
[Out] byte[] OutBuffer,
uint nOutBufferSize,
ref int pBytesReturned,
IntPtr Overlapped
);
Here is the contents of MemOperation (the inbuffer that has to be marshal'd I'm guessing):
public struct MemOperation
{
public int Pid;
public int UserPid;
public int Size;
public int protection_mode;
public int allocation_type;
public IntPtr Addr;
public IntPtr WriteBuffer;
[MarshalAs(UnmanagedType.LPWStr)]
public string module_selection;
}
Here's is an example of usage:
public UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte[] buffer = new byte[48]; // 8 + 8 + 4 + 8 + 4 + 4 + 4 MEMORY_BASIC_INFORMATION
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), buffer, (uint)buffer.Length, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
In the profiler, my hotpath is the pinvoke. My application runs incredibly fast, as fast I think it can in C#. However, almost a third of all execution time is spent pinvoking due to how many memory operations the application is doing. I would like to cut this time down in any way possible, including unsafe ways.
I have seen that you can instead write a DeviceIoControl wrapper and import it from a C++ dll, however this did not lead to any changes for me, it appeared to function the exact same. Here's the source for that:
devicecontrol.cpp
#include <iostream>
#include "DeviceControl.h"
bool __cdecl DeviceIoRequestWrapper(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlappedk)
{
return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlappedk);
}
devicecontrol.h
#pragma once
#include <Windows.h>
extern "C" {
__declspec(dllexport) bool __cdecl DeviceIoRequestWrapper(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlappedk);
}
I am on .net 6.0 and the latest version of C#.
Proposed change to out buffer:
public unsafe UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) {
var memOperation = new MemOperation();
byte* buffer = stackalloc byte[48];
memOperation.Pid = this.Pid;
memOperation.Addr = address;
int bytes = 0;
bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), (IntPtr)buffer, 48, ref bytes, IntPtr.Zero);
return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer);
}
Where GetStructure is now:
public static unsafe T GetStructure<T>(byte* bytes) where T: unmanaged {
T structure = *(T*)bytes;
return structure;
}
Here's what helped the most and I'll accept this as the answer to my own thread in a few hours.
In addition to the above steps I mentioned, I have now done the following:
Converted MemOperation to be fully blittable. The string "module_selection" was only ever used once per program start, so I have instead now added a fully blittable version of MemOperation. Thank you #Flydog57
Changed buffer to be quickly allocated (non zero'd out), and pass a PTR, rather than allocating and then marshalling a byte[] to void/char* (which is what I think likely happens when you pass it a byte[] object). Thank you #Charlieface
Running the profiler in visual studio, it appears to have eliminated the hotpath. Now the total CPU % correctly lies within kernel32.dll (the deviceiocontrol call to the device). Whether this leads to tangible performance benefits, I don't know, don't have an easy way to setup a full benchmark for this.

Writing a byte array to an address

Deleted my old post and decided to reupload with more direct questions.
I'm trying to write bytes to a memory address for my C# menu, writing singular a singular byte or int isn't an issue. I have an issue trying to write multiple bytes.
The code below is writing a singular byte to increase the player speed to 555, which works perfectly fine.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
byte[] memory = { 555 };
WriteProcessMemory(Game.hProc, Player.PlayerSpeedOffSet, memory, memory.Length, out _);
The part I'm having issues with is when I try and write multiple bytes to an address.
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
byte[] memory = { 90, 90, 90 };
WriteProcessMemory(Game.hProc, Player.UnlimitedAmmoOffSet, memory, memory.Length, out _);
"90 90 90" being unlimted ammo and to disable it, i'd write to the same address with "89 50 04".
This worked just fine with memory.dll so the handle and offset is just fine, it's just something to do with my writing to memory.
Look at the definition of the function WriteProcessMemory:
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);
Note the type of the nSize parameter, it's SIZE_T. How wide is this type? You can look it up here: https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
typedef ULONG_PTR SIZE_T;
Okay, then what is the width of ULONG_PTR? The same documentation tells:
#if defined(_WIN64)
typedef unsigned __int64 ULONG_PTR;
#else
typedef unsigned long ULONG_PTR;
#endif
So, its either 32 bits or 64 bits wide, depending on whether the process calling this function is a 32-bit or 64-bit process. (In Windows, unsigned long is 32-bit wide.)
Now look at your P/Invoke definition:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
You have defined nSize as a 32-bit integer. If your program is compiled to run as a 32-bit process, you got lucky and the 32-bit integer matches the 32-bit SIZE_T.
But if your program is running as a 64-bit process, your 32-bit integer does not match the 64-bit SIZE_T.
I hope using IntPtr instead of int for the nSize parameter should fix your issue.

How to get number of bytes written successfully?

I'm doing a project that convert code from C++ to C# for printer.
I replace WriteFile() in C++ with SerialPort.Write() in C#.
C#
public void Write(
byte[] buffer,
int offset,
int count
)
C++
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
In C++ i can get number of bytes written in lpNumberOfBytesWritten. How to do the same thing in C#?
In c# We can use API call like below,
[DllImport("kernel32.dll")]
static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer,
uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);
For more information see http://www.pinvoke.net/default.aspx/kernel32.writefile

Call Win32 CalculatePopupWindowPosition from C#

I'm trying to call the WinAPI function CalculatePopupWindowPosition in C# using P/Invoke. From
http://msdn.microsoft.com/en-us/library/windows/desktop/dd565861(v=vs.85).aspx
I see that it's syntax is:
BOOL WINAPI CalculatePopupWindowPosition(
_In_ const POINT *anchorPoint,
_In_ const SIZE *windowSize,
_In_ UINT flags,
_In_opt_ RECT *excludeRect,
_Out_ RECT *popupWindowPosition
);
I then tried to import it using the following code in C#
[DllImport("User32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CalculatePopupWindowPosition
(
[In] ref POINT anchorPoint,
[In] ref SIZE windowSize,
[In] ref UInt32 flags,
[In,Optional] ref RECT excludeRect,
[Out] out SIZE popupWindowPosition
);
I also implemented the RECT, POINT and SIZE structures and initialized them. Finally I called the function like so.
CalculatePopupWindowPosition(ref nIconPos, ref windowSize, ref flags, ref nIconRect, out windowSize);
This doesn't seem to work though, windowSize contains nothing but zeros, which it shouldn't. Any ideas what I'm doing wrong here?
The flags parameter needs to be passed by value rather than by reference:
[DllImport("User32.dll", SetLastError = true)]
public static extern bool CalculatePopupWindowPosition
(
ref POINT anchorPoint,
ref SIZE windowSize,
uint flags,
ref RECT excludeRect,
out RECT popupWindowPosition
);
Some general advice. When an API call fails, check the return value. In this case if the function returns false then call Marshal.GetLastWin32Error to find out the error status code.

How to use InternetQueryOption in C# interop?

In my C# code I want to use InternetQueryOption which is defined in MSDN such as:
BOOL InternetQueryOption(
__in HINTERNET hInternet,
__in DWORD dwOption,
__out LPVOID lpBuffer,
__inout LPDWORD lpdwBufferLength
);
In my C# code I wrote:
[DllImport("wininet.dll", SetLastError = true)]
static extern bool InternetQueryOption(
IntPtr hInternet,
uint dwOption,
IntPtr lpBuffer,
ref int lpdwBufferLength);
My C++ code:
...
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST","/BM-Login/auth-cup", NULL, NULL, accept, secureFlags, 0);
DWORD dwFlags;
DWORD dwBuffLen = sizeof(dwFlags);
InternetQueryOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID)&dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
dwFlags |= SECURITY_FLAG_IGNORE_REVOCATION;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE;
InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags, sizeof (dwFlags) );
...
How to write the same in C#? Thanks. (Sorry for my very bad English)
I'd recommend using manged code for this instead of doing this via interop. Have a look at the WebRequest Class. Also, have a look at my answer to the stackoverflow question C# https login and download file for a working example of how this class can be used.

Categories