windows驱动读写文件不成功

做的虚拟显示器有个功能是设置显示器的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了!


猜你喜欢

转载自blog.csdn.net/dailongjian2008/article/details/78621980