(본 글의 모든 저작권은 하제소프트가 가지고 있습니다)

디바이스 드라이버코딩과 관련된 이야기

프로그램 코딩은 마치 작품과 같이, 개발자의 개성에 따르는 부분이 있긴하지만 일정부분은 사용자에게 제공하는 좋은 제품을 만드는 측면이 강하다고 생각한다
그런면에서 볼때 버그를 잘 유발하지 않을 법한 좋은 코딩을 습관화해야 할 필요가 있다고 본다.
드라이버를 코딩하다 보면, 계획하지 않은 여러경우의 런타임 오류에 대한 에러처리를 확실히 해주어야 할 필요를 느낀다.
이러한 에러에 대한 처리코드를 추가하다보면 코드가 많이 지저분해지고, 실수로 빼먹은 에러처리가 있는지 신경이 쓰이곤 한다.
그래서 ‘에러처리를 위한 간결한 코딩’이라는 주제로 내가 사용하는 코드를 소개한다.
우선 간결함에 대해 고려하지 않은 코드를 보자.

// 간결히 하지 않은 DriverEntry코드의 예(일반적 파일시스템드라이버 DriverEntry코드를 예시로함)

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING nameString;
UNICODE_STRING uniWin32NameString;
NTSTATUS status;
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION deviceExtension;
PFAST_IO_DISPATCH fastIoDispatch = NULL;
PVOID dataBuffer1 = NULL;
PVOID dataBuffer2 = NULL;
ULONG i;

RtlInitUnicodeString(&nameString, L”\\Device\\FsSample”);
status = IoCreateDevice(
DriverObject,
sizeof( DEVICE_EXTENSION ),
&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&deviceObject
);

if (!NT_SUCCESS(status))
{
return status;
}

deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
dataBuffer1 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer1)
{
IoDeleteDevice(deviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
dataBuffer2 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer2)
{
ExFreePool(dataBuffer1);
IoDeleteDevice(deviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
deviceExtension->DataBuffer1 = dataBuffer1;
deviceExtension->DataBuffer2 = dataBuffer2;
DriverObject->DriverUnload = DriverUnload;
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = FileSysPassThrough;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = FileSysCreate;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] =
FileSysFsControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
FileSysDeviceIoControl;
DriverObject->MajorFunction[IRP_MJ_READ] = FileSysReadWriteControl;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileSysReadWriteControl;
fastIoDispatch = ExAllocatePool(PagedPool, sizeof(FAST_IO_DISPATCH));
if (!fastIoDispatch)
{
ExFreePool(dataBuffer1);
ExFreePool(dataBuffer2);
IoDeleteDevice(deviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible =
FileSysFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = FileSysFastIoRead;
fastIoDispatch->FastIoWrite = FileSysFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = FileSysFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo =
FileSysFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = FileSysFastIoLock;
fastIoDispatch->FastIoUnlockSingle = FileSysFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = FileSysFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = FileSysFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = FileSysFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = FileSysFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo =
FileSysFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = FileSysFastIoMdlRead;
fastIoDispatch->MdlReadComplete = FileSysFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = FileSysFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = FileSysFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = FileSysFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed =
FileSysFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed =
FileSysFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed =
FileSysFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = FileSysFastIoQueryOpen;
DriverObject->FastIoDispatch = fastIoDispatch;

RtlInitUnicodeString(&uniWin32NameString,
L”\\DosDevices\\FsSample”);
status = IoCreateSymbolicLink(&uniWin32NameString,
&nameString);
if (!NT_SUCCESS(status))
{
ExFreePool(dataBuffer1);
ExFreePool(dataBuffer2);
ExFreePool(fastIoDispatch);
IoDeleteDevice(g_DeviceObject);
return status;
}

status = IoRegisterFsRegistrationChange(DriverObject,
FileSysFsNotification);
if (!NT_SUCCESS(status))
{
IoUnregisterFsRegistrationChange(DriverObject, NULL);
ExFreePool(dataBuffer1);
ExFreePool(dataBuffer2);
ExFreePool(fastIoDispatch);
IoDeleteDevice(deviceObject);
return status;
}
return status;
}

에러발생시 코드 여러곳에서 그 곳까지 진행되었던것을 되돌리는 코드를 수행하고, 바로 에러코드와 함께 리턴한다.
문제는 좀 더 많이 진행된상황일수록 되돌리는 작업도 많아진다는 것이다.
또한 경우에 따라 되돌리는 작업의 순서를 신경써야할수도 있으며, 혹시 되돌리는 작업의 코드일부를 실수로 빼먹을 수도 있다.
소심한 사람은 웬지 불안감을 느낄수 있을것이다.(참고로 나는 A형이다. 그래서 그런지 공개된 곳에 글올리는것 좋아하진 않는데, 회사에서 독촉이 있어서 지금도 스트레스 받으며 작성중이다)
자 그럼 조금만 간결히 해보자.

// 간결한 버전 샘플 1
// 코드 중간중간의 에러처리를 함수종료 직전에 한번에 처리토록 함
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING nameString;
UNICODE_STRING uniWin32NameString;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
PFAST_IO_DISPATCH fastIoDispatch = NULL;
PVOID dataBuffer1 = NULL;
PVOID dataBuffer2 = NULL;
ULONG i;

RtlInitUnicodeString(&nameString, L”\\Device\\FsSample”);
status = IoCreateDevice(
DriverObject,
sizeof( DEVICE_EXTENSION ),
&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&deviceObject
);

if (!NT_SUCCESS(status))
{
goto l_exit;
}

deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
dataBuffer1 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer1)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto l_exit;
}
dataBuffer2 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer2)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto l_exit;
}
deviceExtension->DataBuffer1 = dataBuffer1;
deviceExtension->DataBuffer2 = dataBuffer2;

DriverObject->DriverUnload = DriverUnload;

for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = FileSysPassThrough;
}

DriverObject->MajorFunction[IRP_MJ_CREATE] = FileSysCreate;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FileSysFsControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileSysDeviceIoControl;
DriverObject->MajorFunction[IRP_MJ_READ] = FileSysReadWriteControl;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileSysReadWriteControl;

fastIoDispatch = ExAllocatePool(PagedPool, sizeof(FAST_IO_DISPATCH));
if (!fastIoDispatch)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto l_exit;
}

RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible = FileSysFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = FileSysFastIoRead;
fastIoDispatch->FastIoWrite = FileSysFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = FileSysFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = FileSysFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = FileSysFastIoLock;
fastIoDispatch->FastIoUnlockSingle = FileSysFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = FileSysFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = FileSysFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = FileSysFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = FileSysFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = FileSysFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = FileSysFastIoMdlRead;
fastIoDispatch->MdlReadComplete = FileSysFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = FileSysFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = FileSysFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = FileSysFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = FileSysFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed = FileSysFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed = FileSysFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = FileSysFastIoQueryOpen;

DriverObject->FastIoDispatch = fastIoDispatch;

RtlInitUnicodeString(&uniWin32NameString, L”\\DosDevices\\FsSample”);
status = IoCreateSymbolicLink(&uniWin32NameString, &nameString);
if (!NT_SUCCESS(status))
{
goto l_exit;
}

status = IoRegisterFsRegistrationChange(DriverObject, FileSysFsNotification);
if (!NT_SUCCESS(status))
{
IoUnregisterFsRegistrationChange(DriverObject, NULL);
goto l_exit;
}

l_exit:
if (!NT_SUCCESS(status))
{
if (dataBuffer1)
{
ExFreePool(dataBuffer1);
}
if (dataBuffer2)
{
ExFreePool(dataBuffer2);
}
if (fastIoDispatch)
{
ExFreePool(fastIoDispatch);
}
if (deviceObject)
{
IoDeleteDevice(deviceObject);
}
}
return status;
}

모든 에러발생시에 대해서 goto 구문을 사용해서 함수의 맨 끝부분으로 가도록 하였다.
그리고 그 곳에서 모든 에러에 대한 처리를 한다.
코드여러곳에서 에러처리 하지 않으니 코드가 훨씬 간결해보인다.
또한 에러처리 구문들이 한쪽에 몰려 있으니, 실수할 만한 부분이 줄어들게 된다(소심한 나도 이제 조금 안심이 된다)
나는 이러한 용도로 사용하는 goto구문에 대해 그다지 부정적으로 보지 않는데 어떤이들은 goto구문 자체를 극도로 부정으로 보는 사람도 있을것이다(goto쓰면 빨갱이야!)

그렇다면 아래처럼 다른 방식으로 해볼수도 있다.

// 간결한 버전 샘플 2
// 코드 중간중간의 에러처리를 함수종료 직전에 한번에 처리토록 함(goto 구문대신 do while 구문으로 대체)
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING nameString;
UNICODE_STRING uniWin32NameString;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
PFAST_IO_DISPATCH fastIoDispatch = NULL;
PVOID dataBuffer1 = NULL;
PVOID dataBuffer2 = NULL;
ULONG i;

do
{
RtlInitUnicodeString(&nameString, L”\\Device\\FsSample”);
status = IoCreateDevice(
DriverObject,
sizeof( DEVICE_EXTENSION ),
&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
0,
FALSE,
&deviceObject
);

if (!NT_SUCCESS(status))
{
break;
}

deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
dataBuffer1 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer1)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
dataBuffer2 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer2)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
deviceExtension->DataBuffer1 = dataBuffer1;
deviceExtension->DataBuffer2 = dataBuffer2;

DriverObject->DriverUnload = DriverUnload;

for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = FileSysPassThrough;
}

DriverObject->MajorFunction[IRP_MJ_CREATE] = FileSysCreate;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FileSysFsControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileSysDeviceIoControl;
DriverObject->MajorFunction[IRP_MJ_READ] = FileSysReadWriteControl;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileSysReadWriteControl;

fastIoDispatch = ExAllocatePool(PagedPool, sizeof(FAST_IO_DISPATCH));
if (!fastIoDispatch)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}

RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible = FileSysFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = FileSysFastIoRead;
fastIoDispatch->FastIoWrite = FileSysFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = FileSysFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = FileSysFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = FileSysFastIoLock;
fastIoDispatch->FastIoUnlockSingle = FileSysFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = FileSysFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = FileSysFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = FileSysFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = FileSysFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = FileSysFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = FileSysFastIoMdlRead;
fastIoDispatch->MdlReadComplete = FileSysFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = FileSysFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = FileSysFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = FileSysFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = FileSysFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed = FileSysFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed = FileSysFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = FileSysFastIoQueryOpen;

DriverObject->FastIoDispatch = fastIoDispatch;

RtlInitUnicodeString(&uniWin32NameString, L”\\DosDevices\\FsSample”);
status = IoCreateSymbolicLink(&uniWin32NameString, &nameString);
if (!NT_SUCCESS(status))
{
break;
}

status = IoRegisterFsRegistrationChange(DriverObject, FileSysFsNotification);
if (!NT_SUCCESS(status))
{
IoUnregisterFsRegistrationChange(DriverObject, NULL);
break;
}
}
while (0);

if (!NT_SUCCESS(status))
{
if (dataBuffer1)
{
ExFreePool(dataBuffer1);
}
if (dataBuffer2)
{
ExFreePool(dataBuffer2);
}
if (fastIoDispatch)
{
ExFreePool(fastIoDispatch);
}
if (deviceObject)
{
IoDeleteDevice(deviceObject);
}
}
return status;
}

이게 더 좋을까? 모르겠다. 내가 보기엔 똑같다.
마지막으로, 에러처리 코드부분을 좀 더 간결히 해보자.

// 간결한 버전 샘플 3
// 코드 중간중간의 에러처리를 함수종료 직전에 한번에 처리토록 함(goto 구문대신 do while 구문으로 대체)
// ExFreePoolvz함수를 이용하여, 메모리 할당오류에 대한 오류처리 구문을 좀 더 간결히 함

// 메모리 해제 유틸리티 함수
VOID ExFreePoolvz(ULONG PtrCount, …)
{
va_list vaList;
PVOID *ptr;
ULONG i;

va_start(vaList, PtrCount);
for (i = 0; i < PtrCount; i++)
{
ptr = (PVOID *)va_arg(vaList, PVOID);
if (ptr)
{
if (*ptr)
{
ExFreePool(*ptr);
*ptr = NULL;
}
}
}
va_end(vaList);
}
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
UNICODE_STRING nameString;
UNICODE_STRING uniWin32NameString;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = NULL;
PFAST_IO_DISPATCH fastIoDispatch = NULL;
PVOID dataBuffer1 = NULL;
PVOID dataBuffer2 = NULL;
ULONG i;
do
{
RtlInitUnicodeString(&nameString, L”\\Device\\FsSample”);
status = IoCreateDevice( DriverObject, sizeof( DEVICE_EXTENSION ), &nameString, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &deviceObject );
if (!NT_SUCCESS(status))
{
break;
}
deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
dataBuffer1 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer1)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
dataBuffer2 = ExAllocatePool(PagedPool, 0×1000);
if (!dataBuffer2)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
deviceExtension->DataBuffer1 = dataBuffer1;
deviceExtension->DataBuffer2 = dataBuffer2;

DriverObject->DriverUnload = DriverUnload;

for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = FileSysPassThrough;
}

DriverObject->MajorFunction[IRP_MJ_CREATE] = FileSysCreate;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FileSysFsControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileSysDeviceIoControl;
DriverObject->MajorFunction[IRP_MJ_READ] = FileSysReadWriteControl;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileSysReadWriteControl;

fastIoDispatch = ExAllocatePool(PagedPool, sizeof(FAST_IO_DISPATCH));
if (!fastIoDispatch)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}

RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible = FileSysFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = FileSysFastIoRead;
fastIoDispatch->FastIoWrite = FileSysFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = FileSysFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = FileSysFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = FileSysFastIoLock;
fastIoDispatch->FastIoUnlockSingle = FileSysFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = FileSysFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = FileSysFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = FileSysFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = FileSysFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = FileSysFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = FileSysFastIoMdlRead;
fastIoDispatch->MdlReadComplete = FileSysFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = FileSysFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = FileSysFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = FileSysFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = FileSysFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed = FileSysFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed = FileSysFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = FileSysFastIoQueryOpen;

DriverObject->FastIoDispatch = fastIoDispatch;

RtlInitUnicodeString(&uniWin32NameString, L”\\DosDevices\\FsSample”);
status = IoCreateSymbolicLink(&uniWin32NameString, &nameString);
if (!NT_SUCCESS(status))
{
break;
}

status = IoRegisterFsRegistrationChange(DriverObject, FileSysFsNotification);
if (!NT_SUCCESS(status))
{
IoUnregisterFsRegistrationChange(DriverObject, NULL);
break;
}
}
while (0);

if (!NT_SUCCESS(status))
{
// 3개의 파라미터 각각에 대하여 NULL이 아니면 메모리 해제함
ExFreePoolvz(3, &dataBuffer1, &dataBuffer2, &fastIoDispatch);
if (deviceObject)
{
IoDeleteDevice(deviceObject);
}
}
return status;
}

내가 만들어 사용하고 있는 ExFreePoolvz 함수를 소개한다.
이 함수를 사용해서 여러줄의 코드를 1줄로 축약하니 훨씬 보기 좋다.

오늘 소개한 것처럼 코드를 간결히 하니, 에러도 덜 발생할것 같고 나중에 코드를 보아도 코드 이해가 수월했었던 것 같다.