windows驱动读写文件不成功

来源:互联网 发布:thinkphp5 网站源码 编辑:程序博客网 时间:2024/05/22 01:53
做的虚拟显示器有个功能是设置显示器的Edid,Edid的数据是由应用程序传进来的,为防止每次开机、重启都要进行Edid的设置,需要对EDID信息进行保存。为了保存Edid,我需要在驱动里面操作文件,然而在操作文件的时候会出现一些问题。
读文件如下:
BOOL CvMonitor::SyncEdidFromFile(){if (PASSIVE_LEVEL < KeGetCurrentIrql()) {return FALSE;}HANDLE hEdidfile;UNICODE_STRING filename;IO_STATUS_BLOCK iostatus;OBJECT_ATTRIBUTES objectAttributes;RtlInitUnicodeString(&filename, EDID_FILE_PATH);InitializeObjectAttributes(&objectAttributes, &filename, OBJ_CASE_INSENSITIVE, nullptr, nullptr);NTSTATUS ntStatus = ZwCreateFile(&hEdidfile, GENERIC_READ, &objectAttributes, &iostatus, nullptr, FILE_ATTRIBUTE_NORMAL,0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, nullptr, 0);if (!NT_SUCCESS(ntStatus)) {return FALSE;}FILE_STANDARD_INFORMATION fsi;ntStatus = ZwQueryInformationFile(hEdidfile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);if (!NT_SUCCESS(ntStatus) || fsi.AllocationSize.QuadPart == 0) {ZwClose(hEdidfile);return FALSE;}ntStatus = ZwReadFile(hEdidfile,nullptr, nullptr, nullptr, &iostatus,m_edid, min(fsi.AllocationSize.LowPart, EDIT_LENGTH),NULL, nullptr);ZwClose(hEdidfile);return NT_SUCCESS(ntStatus);}
写文件如下:
void CvMonitor::SyncEdidToFile(){if (PASSIVE_LEVEL < KeGetCurrentIrql()) {return;}HANDLE hEdidfile;UNICODE_STRING filename;IO_STATUS_BLOCK iostatus;OBJECT_ATTRIBUTES objectAttributes;RtlInitUnicodeString(&filename, EDID_FILE_PATH);InitializeObjectAttributes(&objectAttributes, &filename, OBJ_CASE_INSENSITIVE, nullptr, nullptr);NTSTATUS ntStatus = ZwCreateFile(&hEdidfile, GENERIC_WRITE, &objectAttributes, &iostatus, nullptr, FILE_ATTRIBUTE_NORMAL,0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, nullptr, 0);if (!NT_SUCCESS(ntStatus)) {return;}ZwWriteFile(hEdidfile, nullptr, nullptr, nullptr,&iostatus, m_edid, sizeof(m_edid), nullptr, nullptr);ZwClose(hEdidfile);}
调试过程中发现读文件可以成功,写文件不成功,修改了很多的参数还是不行。
最终发现是由于IRQL导致的,由于我设置Edid是由应用程序下发的,通信方式使用DeviceIoControl,走到驱动层的IRQL为dispatch-level,该level下是不能操作文件的,所以需要进行处理:
void CvMonitor::SetEdid(const BYTE *byEdid, ULONG nLength){/* 需要将中断权限降低,否则无法操作文件 */KIRQL oldirql = KeGetCurrentIrql();if (oldirql >= DISPATCH_LEVEL) {KeLowerIrql(PASSIVE_LEVEL);}if (memcmp(byEdid, m_edid, min(sizeof(m_edid), nLength)) != 0) {memcpy(m_edid, byEdid, min(sizeof(m_edid), nLength));if (!EdidValid()) {memcpy(m_edid, s_defaultEdid, sizeof(m_edid));}else {SyncEdidToFile();}/* 模拟将显示器插拔,插拔后系统重新读取edid */Reset();}KfRaiseIrql(oldirql);}
先将IRQL降到PASSIVE_LEVEL,操作完后还原。文件操作就OK了!