✅ CreateFile 方法详解(WinAPI)
CreateFile 是 Windows 系统中用于打开文件、设备、串口、管道、驱动设备等对象的核心函数。其函数原型如下:
HANDLE CreateFile(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
在 C# 中,它通常通过 P/Invoke 调用,如:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
✅ 每个参数详解
| 参数名 |
类型 |
含义 |
lpFileName |
string |
文件名或设备路径,例如 "\\.\xdma0_c2h_0" 表示 DMA 通道 |
dwDesiredAccess |
uint |
访问权限,如 GENERIC_READ, GENERIC_WRITE |
dwShareMode |
uint |
共享模式,常为 0(独占访问)或 FILE_SHARE_READ |
lpSecurityAttributes |
IntPtr |
安全属性,一般为 IntPtr.Zero |
dwCreationDisposition |
uint |
创建方式,常用 OPEN_EXISTING 表示打开已存在的设备 |
dwFlagsAndAttributes |
uint |
文件/设备属性,如 FILE_ATTRIBUTE_NORMAL、FILE_FLAG_OVERLAPPED |
hTemplateFile |
IntPtr |
模板句柄(复制属性),用于文件复制时,一般为 IntPtr.Zero |
✅ 示例:打开 DMA 设备(推荐方式)
const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint OPEN_EXISTING = 3;
const uint FILE_ATTRIBUTE_NORMAL = 0x80;
SafeFileHandle handle = CreateFile(
@"\\.\xdma0_c2h_0", // DMA设备路径
GENERIC_READ, // 读取权限(C2H通道)
0, // 不允许共享(独占)
IntPtr.Zero, // 默认安全属性
OPEN_EXISTING, // 打开已存在的设备
FILE_ATTRIBUTE_NORMAL, // 标准属性(不使用异步)
IntPtr.Zero // 模板句柄,未使用
);
✅ 参数选择注意事项(尤其用于 DMA)
| 参数 |
建议值 |
说明 |
dwDesiredAccess |
GENERIC_READ 或 GENERIC_WRITE |
读取 C2H,写入 H2C |
dwCreationDisposition |
OPEN_EXISTING |
打开现有设备,不创建新文件 |
dwFlagsAndAttributes |
FILE_ATTRIBUTE_NORMAL |
如果你不使用异步 I/O,必须省略 FILE_FLAG_OVERLAPPED,否则可能失败 |
dwShareMode |
0(独占) |
硬件驱动不建议多进程共享 |
⚠️ 常见错误原因
| 错误码 |
原因 |
ERROR_INVALID_PARAMETER (87) |
buffer 未对齐或句柄未正确打开 |
INVALID_HANDLE_VALUE |
CreateFile 参数错误,路径、权限或标志位有误 |
ERROR_ACCESS_DENIED (5) |
权限不匹配,比如用 GENERIC_WRITE 打开只读设备 |
✅ Bonus:打开控制通道(寄存器操作)
var handle = CreateFile(
@"\\.\xdma0_control",
GENERIC_READ | GENERIC_WRITE,
0,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);