Developing a device driver is one of the toughest task in the programming career of any developer. This is especially the case if he is a beginner in the programming filed and have very little knowledge about device driver and C/C++ programing language.
Over a few years I myself felt the need of a video tutorial about device driver development so as to assist the developers in my company KTS InfoTech. This article and its accompanying video tutorial is the outcome of this thinking.
In this tutorial, I will show you how to develop a basic Hello World Device Driver and call its functions from a basic C#.NET windows Application.
Watch the YouTube Video Tutorial From the Link below
Main Portion of the Code Snippets
MyDriver.c Source
//This program demonstrates a basic Hello world Device Driver component that can be invoked and called form
//a User mode application 4th march 2013
//Author Tom Thomas , KTS InfoTech PVT LTD
//
#include <ntddk.h>
#define BUFFERSIZE 100
PVOID gpEventObject = NULL;
typedef struct _REGISTER_EVENT
{
HANDLE hEvent;
char EventParameter[BUFFERSIZE];
} REGISTER_EVENT , *PREGISTER_EVENT ;
REGISTER_EVENT* driverExtension=0;
#define SIZEOF_REGISTER_EVENT sizeof(REGISTER_EVENT )
//Function pointer forward declaration
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
NTSTATUS DispatchCreate (IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp);
NTSTATUS DispatchClose (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS DispatchRead (IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp);
NTSTATUS DispatchWrite (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS DeviceIoEvent (IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp);
NTSTATUS Example_UnSupportedFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
DRIVER_INITIALIZE DriverEntry;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT driverObject,
IN PUNICODE_STRING registryPath
);
DRIVER_UNLOAD DriverUnload;
VOID
DriverUnload(
IN PDRIVER_OBJECT driverObject
);
#ifdef ALLOC_PRAGMA //This Macro make every call associated with PAGE resident and locked in memory
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DispatchCreate)
#pragma alloc_text(PAGE, DispatchClose)
#pragma alloc_text(PAGE, DispatchRead)
#pragma alloc_text(PAGE, DispatchWrite)
#pragma alloc_text(PAGE, DeviceIoEvent)
#pragma alloc_text(PAGE, DriverUnload)
#endif
//Driver entry point
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
UNICODE_STRING deviceName;
UNICODE_STRING bufferDeviceName;
UNICODE_STRING symLinkName;
PDEVICE_OBJECT deviceObject;
RtlInitUnicodeString(&deviceName, L"DeviceMyHwDriver");
RtlInitUnicodeString(&symLinkName, L"DosDevicesMyHwDriver");
//Create the IO devce
status = IoCreateDevice(
DriverObject,
sizeof(REGISTER_EVENT),
&deviceName,
0, //FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);
if (!NT_SUCCESS(status))
return status;
deviceObject->Flags |= DO_BUFFERED_IO;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
status = IoCreateSymbolicLink (&symLinkName, &deviceName);
if (!NT_SUCCESS(status))
{
// if it fails now, must delete Device object
IoDeleteDevice( DriverObject->DeviceObject );
return status;
}
//Implement basic Driver function pointers
// This includes Dispatch routines for Create,Close , Read, Write and IO control
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoEvent;
DriverObject->DriverUnload = DriverUnload;
DbgPrint("Hello, World from MyHwDriver DriverEntry code
");
driverExtension = ExAllocatePool(NonPagedPool, sizeof (REGISTER_EVENT));
if(!driverExtension)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(driverExtension->EventParameter, BUFFERSIZE);
RtlCopyBytes (driverExtension->EventParameter, "Hai from driver", 16);
return STATUS_SUCCESS;
}
//Called when the application unloads the driver
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING linkString;
DbgPrint("DriverUnload called");
ExFreePool(driverExtension);
RtlInitUnicodeString (&linkString, L"DosDevicesMyHwDriver");
IoDeleteSymbolicLink (&linkString);
IoDeleteDevice(DriverObject->DeviceObject);
}
//Called when the application creates this device
NTSTATUS DispatchCreate (PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
DbgPrint("Inside Dispatch Create Routine");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//Called when the application reads data from this device
NTSTATUS DispatchRead (PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
DbgPrint("Inside Dispatch Read Routine");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//Called when the application writes data to this device
NTSTATUS DispatchWrite (PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
DbgPrint("Inside Dispatch Write Routine");
//Read the data form the User Mode Application..
if(pIrp->AssociatedIrp.SystemBuffer!=NULL)
{
DbgPrint(pIrp->AssociatedIrp.SystemBuffer);
}
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//Called when the application closes the device Handle
NTSTATUS DispatchClose (IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp)
{
DbgPrint("Inside Create Dispatch Close Routine");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//Called when the application the application invokes IO control Events
NTSTATUS DeviceIoEvent (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
DbgPrint("Inside DeviceIoEvent Routine");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// MyDriverTestConsoleApp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
long ulReturnedLength=0;
HANDLE hDevice = CreateFile(L".MyHwDriver",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Failed to create MyHwDriver File
");
return 1;
}
else
{
//Now Write and Read something
printf("MyHwDriver Device Opened
");
DWORD NoOfWordsWritten=0;
char InputOutputString[100]="Hell World From User Mode Test App";
WriteFile(hDevice,InputOutputString,strlen(InputOutputString),&NoOfWordsWritten,NULL);
printf("Send Message To The Device
");
ReadFile(hDevice,InputOutputString,20,&NoOfWordsWritten,NULL);
}
CloseHandle(hDevice);
printf("Press any Character To Continue
");
getch();
return 1;
}
// MyUserModeComponent.h
#pragma once
#include <windows.h>
using namespace System;
namespace MyUserModeComponent {
public ref class MyComponent
{
// TODO: Add your methods for this class here.
HANDLE hDevice;
public:
bool OpenAndSendCommandToDriver(void)
{
long ulReturnedLength=0;
hDevice = CreateFile(L".MyHwDriver",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
if (hDevice == INVALID_HANDLE_VALUE)
{
return false;
}
else
{
//Now Write and Read something
DWORD NoOfWordsWritten=0;
char InputOutputString[100]="Hell World From User Mode Test App";
WriteFile(hDevice,InputOutputString,strlen(InputOutputString),&NoOfWordsWritten,NULL);
ReadFile(hDevice,InputOutputString,20,&NoOfWordsWritten,NULL);
}
CloseHandle(hDevice);
return true;
}
};
}
MyApplication Main C# Project File
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MyUserModeComponent;
namespace MyApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonOpenAndSend_Click(object sender, EventArgs e)
{
MyComponent DeviceObj = new MyComponent();
DeviceObj.OpenAndSendCommandToDriver();
MessageBox.Show("Command Send Successfully");
}
}
}