You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化加速C#中P/Invoke原生调用(DeviceIoControl场景)性能

版主注:我认为这不是重复问题,因为我已经尝试过下述多个已提及的解决方案。

有没有办法可以加速这个调用?我已经遵循了微软的相关指南,完成了以下操作:

  • 添加了SuppressUnmanagedCodeSecurity特性
  • 将相关代码放在名为UnsafeNativeMethods.cs的文件中
  • 为方法存根定义了特定类型

相关方法代码

[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
);

MemOperation结构体定义(推测为需要封送的输入缓冲区)

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;
}

调用示例

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);
}

性能分析器显示P/Invoke是我的热点路径。我的应用运行速度已经达到了我认为C#能实现的上限,但由于应用需要执行极多内存操作,几乎三分之一的执行时间都消耗在P/Invoke上。我希望尽可能削减这部分耗时,允许使用不安全方案。

我曾尝试编写DeviceIoControl的封装函数从C++ DLL导入,但没有产生任何优化效果,表现和之前完全一致,相关代码如下:

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);
}

我当前使用的是.NET 6.0和最新版本的C#。


我还尝试了对输出缓冲区的修改方案:

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);
}

修改后的GetStructure实现如下:

public static unsafe T GetStructure<T>(byte* bytes) where T: unmanaged {
    T structure = *(T*)bytes;
    return structure;
}

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:06:06