Как написать драйвер для джойстика

  • Download source code — 54.1 KB

Introduction

When I wanted to create a Joystick driver so I could control my robot via a joystick plugged into my computer, one of the first things I did was look for a simple joystick driver that could set up everything for me and give me the readings I wanted without me having to code anything myself or even understand how it works. Unfortunately, despite all the people using joysticks in their programs and projects before me, it seems I couldn’t find anyone had created anything like what I was looking for and shared it online.

So if no one else had done it, I decided I would do it myself. Thus, I began this project to create a portable and reusable universal joystick driver that anyone could use to easily implement joystick control in their programs. This driver uses the Joystick sample program from the DirectX SDK, as its foundation.

If you know what you’re doing, it isn’t that hard to write a simple program to get some readings from a joystick. But if you don’t know what you’re doing, learning all about direct input in order to create your own joystick driver isn’t easy. Given I didn’t and still don’t know what the hell I’m doing, I decided to adapt the sample code from the SDK rather than writing a driver from scratch. This probably ended up being more difficult for me in the long run, however the sample code from the SDK is very comprehensive and robust program that will acquire and accept any joystick device you plug in, giving me what I believe is a better result than I could have produced otherwise.

My driver is meant to handle Joystick stuff only so all the GUI related code from the sample program has been removed making it all considerably smaller and simpler.

This driver packages all your joystick needs into a Joystick class which gets all your joystick readings. You can read 8 possible axis/sliders, four possible POV/hats and 128 possible buttons.

Here is a test GUI showing readings from a twist handle Joystick.

Image 1

An altered version for the test GUI of a steering wheel set.

Image 2

Just Tell Me How to Use It Already!

Step 1

Download the files and add the Joystick_Driver.h, Joystick_Driver.cpp and resource.h to your project

Step 2

Make sure the linker can find all your required external dependencies: windows.h, commctrl.h, dinput.h, dinputd.h, assert.h, and wbemidl.h and additional dependencies. If your project is in Visual Studio, right click on your project and go to properties. In the properties window, go to…

Configuration properties->linker->input->additional dependencies->edit

Then add dxguid.lib, dinput8.lib, comctl32.lib.

At the moment, I am yet to try using this in another IDE but you should need to do for whatever IDE you may be trying to use this in.

Step 3

Now for the easy part.

Declare the following:

Joystick* myJoystick; HWND hWnd; 

Where appropriate, initialize:

myJoystick = new Joystick();
hWnd = 

Step 4

Create a timer driven function call to run the joystick.

Using a while loop is a bad idea. Especially, if you have a GUI, that you don’t want to have freezing up on you.

You can check that things work using a while loop but in the end, you are going to need a timer driven function call regardless.

Configure your timer to go off 20-30 times a second or at intervals of 30ms-50ms.

Step 5

In your timer driven function, you may have something as simple as:

Void timerFunct()
{
  myJoystick->runJoystick(hWnd); 
if(myJoystick->getmsg() == WM_TIMER)
  {
  XAxis = myJoystick->getXAxis();
  YAxis = myJoystick->getYAxis();
  ZRot = myJoystick->getZRot();
  Slider1 = myJoystick->getSlider0();

  POV1 = myJoystick->getPOV0();

  Button0 = myJoystick->getButton(0);
  Button1 = myJoystick->getButton(1);
  Button2 = myJoystick->getButton(2);
  Button3 = myJoystick->getButton(3);
  Button4 = myJoystick->getButton(4);
  }
}

This should give you the gist of how to use it. For a proper working example, consider the next section.

Windows Form Application Example

Design a form application while following this example and add in the following code where needed in your form.h.

#include "Joystick_Driver.h"

public ref class Form1 : public System::Windows::Forms::Form
{
public:
    Form1(void)
    {
        InitializeComponent();
        this->JS = new Joystick();
        this->hWnd = static_cast<HWND>(this->Handle.ToPointer());
    }
    ~Form1()
    {
        if (components)
        {
            delete components;
        }
    }


private:
    Joystick* JS; private:
    HWND hWnd; 
    #pragma region Windows Form Designer generated code

    void InitializeComponent(void)
    {
                            }
    #pragma endregion

    };

In the design view, add a timer to your form:

Image 3

Don’t forget to set the timer properties:

Image 4

You will now have a function in your form:

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
}

In the design view, double click the Run and Stop buttons and use these button click event functions to enable and disable the timer.

private: System::Void Run_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = true;
}

private: System::Void Stop_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = false;
}

Add the following to the timer tick function:

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e)
{
    this->JS->runJoystick(this->hWnd);
        if(this->JS->getmsg() == WM_TIMER)
    {
        this->XAxis->Text = (this->JS->getXAxis()).ToString();
        this->YAxis->Text = (this->JS->getYAxis()).ToString();
        this->ZAxis->Text = (this->JS->getZAxis()).ToString();
        this->XRot->Text = (this->JS->getXRot()).ToString();
        this->YRot->Text = (this->JS->getYRot()).ToString();
        this->ZRot->Text = (this->JS->getZRot()).ToString();

        this->Slider1->Text = (this->JS->getSlider0()).ToString();
        this->Slider2->Text = (this->JS->getSlider1()).ToString();

        this->POV1->Text = (this->JS->getPOV0()).ToString();
        this->POV2->Text = (this->JS->getPOV1()).ToString();
        this->POV3->Text = (this->JS->getPOV2()).ToString();
        this->POV4->Text = (this->JS->getPOV3()).ToString();

        this->Button0->Checked = this->JS->getButton(0);
        this->Button1->Checked = this->JS->getButton(1);
        this->Button2->Checked = this->JS->getButton(2);
        this->Button3->Checked = this->JS->getButton(3);
        this->Button4->Checked = this->JS->getButton(4);
        this->Button5->Checked = this->JS->getButton(5);
        this->Button6->Checked = this->JS->getButton(6);
        this->Button7->Checked = this->JS->getButton(7);
        this->Button8->Checked = this->JS->getButton(8);
        this->Button9->Checked = this->JS->getButton(9);
        this->Button10->Checked = this->JS->getButton(10);
        this->Button11->Checked = this->JS->getButton(11);
        this->Button12->Checked = this->JS->getButton(12);
        this->Button13->Checked = this->JS->getButton(13);
        this->Button14->Checked = this->JS->getButton(14);
        this->Button15->Checked = this->JS->getButton(15);
        this->Button16->Checked = this->JS->getButton(16);
        this->Button17->Checked = this->JS->getButton(17);
        this->Button18->Checked = this->JS->getButton(18);
    }
}

Running the Program

All Axis and Sliders should read within the range of -1000 to 1000. The POV will give 8 different values for all 8 directions and all buttons will simply read true or false.

Notes on Functionality

You may need to delve into the driver and add your own code to it in order to do certain things. Depending on your application, you are going to have to consider…

What happens when you disconnect the joystick?

At this time, the diver will automatically look for another joystick and will accept any joystick it finds, whether it be the same joystick once it’s plugged back in or another joystick that is already plugged in or is to be plugged in.

What happens to the readings when you disconnect the joystick?

Do you want them to freeze at the last updated value or do you want everything to go back to its default zero position?

At this time, the driver freezes the readings at the last read value if the joystick disconnects.

What happens when you have two or more joysticks plugged in?

You may want to be able to choose a joystick device, or you may want to switch between joysticks while your program is running, or you may wish to have two or more joysticks working at the same time.

At this time, the driver doesn’t support multiple joysticks, but it could be adapted to do so. What it will do is create a list of joystick devices and pick one of them automatically. So you can’t choose which joystick.

You can switch devices while the program is running but this means you need to physically unplug them and plug them in.

What if you want to accept inputs only from a specific type of joystick?

The driver has the capacity to recognize the Axis and Buttons that the connected joystick has available so to some degree, you could implement this.

History

  • 10th February, 2013: Initial version

This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

  • Download source code — 54.1 KB

Introduction

When I wanted to create a Joystick driver so I could control my robot via a joystick plugged into my computer, one of the first things I did was look for a simple joystick driver that could set up everything for me and give me the readings I wanted without me having to code anything myself or even understand how it works. Unfortunately, despite all the people using joysticks in their programs and projects before me, it seems I couldn’t find anyone had created anything like what I was looking for and shared it online.

So if no one else had done it, I decided I would do it myself. Thus, I began this project to create a portable and reusable universal joystick driver that anyone could use to easily implement joystick control in their programs. This driver uses the Joystick sample program from the DirectX SDK, as its foundation.

If you know what you’re doing, it isn’t that hard to write a simple program to get some readings from a joystick. But if you don’t know what you’re doing, learning all about direct input in order to create your own joystick driver isn’t easy. Given I didn’t and still don’t know what the hell I’m doing, I decided to adapt the sample code from the SDK rather than writing a driver from scratch. This probably ended up being more difficult for me in the long run, however the sample code from the SDK is very comprehensive and robust program that will acquire and accept any joystick device you plug in, giving me what I believe is a better result than I could have produced otherwise.

My driver is meant to handle Joystick stuff only so all the GUI related code from the sample program has been removed making it all considerably smaller and simpler.

This driver packages all your joystick needs into a Joystick class which gets all your joystick readings. You can read 8 possible axis/sliders, four possible POV/hats and 128 possible buttons.

Here is a test GUI showing readings from a twist handle Joystick.

Image 1

An altered version for the test GUI of a steering wheel set.

Image 2

Just Tell Me How to Use It Already!

Step 1

Download the files and add the Joystick_Driver.h, Joystick_Driver.cpp and resource.h to your project

Step 2

Make sure the linker can find all your required external dependencies: windows.h, commctrl.h, dinput.h, dinputd.h, assert.h, and wbemidl.h and additional dependencies. If your project is in Visual Studio, right click on your project and go to properties. In the properties window, go to…

Configuration properties->linker->input->additional dependencies->edit

Then add dxguid.lib, dinput8.lib, comctl32.lib.

At the moment, I am yet to try using this in another IDE but you should need to do for whatever IDE you may be trying to use this in.

Step 3

Now for the easy part.

Declare the following:

Joystick* myJoystick; HWND hWnd; 

Where appropriate, initialize:

myJoystick = new Joystick();
hWnd = 

Step 4

Create a timer driven function call to run the joystick.

Using a while loop is a bad idea. Especially, if you have a GUI, that you don’t want to have freezing up on you.

You can check that things work using a while loop but in the end, you are going to need a timer driven function call regardless.

Configure your timer to go off 20-30 times a second or at intervals of 30ms-50ms.

Step 5

In your timer driven function, you may have something as simple as:

Void timerFunct()
{
  myJoystick->runJoystick(hWnd); 
if(myJoystick->getmsg() == WM_TIMER)
  {
  XAxis = myJoystick->getXAxis();
  YAxis = myJoystick->getYAxis();
  ZRot = myJoystick->getZRot();
  Slider1 = myJoystick->getSlider0();

  POV1 = myJoystick->getPOV0();

  Button0 = myJoystick->getButton(0);
  Button1 = myJoystick->getButton(1);
  Button2 = myJoystick->getButton(2);
  Button3 = myJoystick->getButton(3);
  Button4 = myJoystick->getButton(4);
  }
}

This should give you the gist of how to use it. For a proper working example, consider the next section.

Windows Form Application Example

Design a form application while following this example and add in the following code where needed in your form.h.

#include "Joystick_Driver.h"

public ref class Form1 : public System::Windows::Forms::Form
{
public:
    Form1(void)
    {
        InitializeComponent();
        this->JS = new Joystick();
        this->hWnd = static_cast<HWND>(this->Handle.ToPointer());
    }
    ~Form1()
    {
        if (components)
        {
            delete components;
        }
    }


private:
    Joystick* JS; private:
    HWND hWnd; 
    #pragma region Windows Form Designer generated code

    void InitializeComponent(void)
    {
                            }
    #pragma endregion

    };

In the design view, add a timer to your form:

Image 3

Don’t forget to set the timer properties:

Image 4

You will now have a function in your form:

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
}

In the design view, double click the Run and Stop buttons and use these button click event functions to enable and disable the timer.

private: System::Void Run_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = true;
}

private: System::Void Stop_Click(System::Object^  sender, System::EventArgs^  e)
{
    this->timer1->Enabled = false;
}

Add the following to the timer tick function:

private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e)
{
    this->JS->runJoystick(this->hWnd);
        if(this->JS->getmsg() == WM_TIMER)
    {
        this->XAxis->Text = (this->JS->getXAxis()).ToString();
        this->YAxis->Text = (this->JS->getYAxis()).ToString();
        this->ZAxis->Text = (this->JS->getZAxis()).ToString();
        this->XRot->Text = (this->JS->getXRot()).ToString();
        this->YRot->Text = (this->JS->getYRot()).ToString();
        this->ZRot->Text = (this->JS->getZRot()).ToString();

        this->Slider1->Text = (this->JS->getSlider0()).ToString();
        this->Slider2->Text = (this->JS->getSlider1()).ToString();

        this->POV1->Text = (this->JS->getPOV0()).ToString();
        this->POV2->Text = (this->JS->getPOV1()).ToString();
        this->POV3->Text = (this->JS->getPOV2()).ToString();
        this->POV4->Text = (this->JS->getPOV3()).ToString();

        this->Button0->Checked = this->JS->getButton(0);
        this->Button1->Checked = this->JS->getButton(1);
        this->Button2->Checked = this->JS->getButton(2);
        this->Button3->Checked = this->JS->getButton(3);
        this->Button4->Checked = this->JS->getButton(4);
        this->Button5->Checked = this->JS->getButton(5);
        this->Button6->Checked = this->JS->getButton(6);
        this->Button7->Checked = this->JS->getButton(7);
        this->Button8->Checked = this->JS->getButton(8);
        this->Button9->Checked = this->JS->getButton(9);
        this->Button10->Checked = this->JS->getButton(10);
        this->Button11->Checked = this->JS->getButton(11);
        this->Button12->Checked = this->JS->getButton(12);
        this->Button13->Checked = this->JS->getButton(13);
        this->Button14->Checked = this->JS->getButton(14);
        this->Button15->Checked = this->JS->getButton(15);
        this->Button16->Checked = this->JS->getButton(16);
        this->Button17->Checked = this->JS->getButton(17);
        this->Button18->Checked = this->JS->getButton(18);
    }
}

Running the Program

All Axis and Sliders should read within the range of -1000 to 1000. The POV will give 8 different values for all 8 directions and all buttons will simply read true or false.

Notes on Functionality

You may need to delve into the driver and add your own code to it in order to do certain things. Depending on your application, you are going to have to consider…

What happens when you disconnect the joystick?

At this time, the diver will automatically look for another joystick and will accept any joystick it finds, whether it be the same joystick once it’s plugged back in or another joystick that is already plugged in or is to be plugged in.

What happens to the readings when you disconnect the joystick?

Do you want them to freeze at the last updated value or do you want everything to go back to its default zero position?

At this time, the driver freezes the readings at the last read value if the joystick disconnects.

What happens when you have two or more joysticks plugged in?

You may want to be able to choose a joystick device, or you may want to switch between joysticks while your program is running, or you may wish to have two or more joysticks working at the same time.

At this time, the driver doesn’t support multiple joysticks, but it could be adapted to do so. What it will do is create a list of joystick devices and pick one of them automatically. So you can’t choose which joystick.

You can switch devices while the program is running but this means you need to physically unplug them and plug them in.

What if you want to accept inputs only from a specific type of joystick?

The driver has the capacity to recognize the Axis and Buttons that the connected joystick has available so to some degree, you could implement this.

History

  • 10th February, 2013: Initial version

This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

Уже много лет занимаюсь программированием под различные платформы, но написание драйверов понадобилось только сейчас. Читал различную литературу на эту тему, копался в MSDN, но в итоге в голове куча несвязанной информации, очень много непонятно. Подскажите куда копать.
Что имеется: bluetooth джойстик, который Windows видит как игровое HID устройство… И не более. Управлять им нельзя. У меня есть подробная документация по его HID репортам, и я без особых проблем могу из своей программы читать данные о нажатых кнопках, осях и пр.
Что я хочу: написать под это устройство драйвер, чтобы оно виделоcь виндой именно как игровой контроллер, чтобы игры его понимали. На данный момент драйверов под Windows для этого устройства не существует.

Я так понимаю, что kernel-mode мне и не нужен, достаточно UMDF драйвера, так?
Есть ли хоть какой-то простейший пример драйвера хотя бы виртуального джойстика? В примерах WDK я ничего такого не нашёл…
Каким образом Windows ассоциирует устройство с установленным драйвером? По информации в .inf файле? По каким именно критериям? Будет ли Windows ассоциировать драйвер с HID устройством, которое подключено по bluetooth?

Подскажите хоть в какую сторону копать…

0 / 0 / 0

Регистрация: 24.10.2016

Сообщений: 8

1

31.07.2013, 13:58. Показов 11430. Ответов 3


Добрый день. В комплекте с купленным портативным DVD-плеером, который поддерживает свои игры, поставляется некий геймпад неизвестной (скорее всего, китайской) фирмы-производителя. На обороте написано лишь JD-2018. В сети драйверов для него нет. Интерфейс USB. Семёрка определяет его как неизвестное USB-устройство. Возможно ли в таких условиях самостоятельно написать для него драйвер, чтобы система определяла его именно как игровой контроллер, и соответствующие программы цепляли.
Информации о геймпаде в сети, как уже говорил, нет. Есть базовые знания C++ и выполнявшиеся в универе лабы на нём и ассемблере. Упорство и рвение есть. Опыта программирования драйверов нет — иначе бы сам знал, в каком направлении копать) Что мне нужно делать? И возможно ли это вообще.

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Ушел с форума

Эксперт С++

16456 / 7420 / 1186

Регистрация: 02.05.2013

Сообщений: 11,617

Записей в блоге: 1

31.07.2013, 17:56

2

Цитата
Сообщение от splinefx
Посмотреть сообщение

Возможно ли в таких условиях самостоятельно написать для него драйвер, чтобы система определяла его именно как игровой контроллер, и соответствующие программы цепляли.

Возможно. Но с нуля Вы вряд ли такое напишете.
Тут и драйверную специфику нужно знать, и в USB разбираться.
Пока будете писать да отлаживать, могут пройти месяцы, годы…

Добавлено через 1 минуту
Но с некоторыми устройствами можно общаться через HID, это гораздо проще.
У меня, например, источник бесперебойного питания через HID легко программируется.
И не надо лезть в дебри USB и погружаться на уровень ядра.



1



0 / 0 / 0

Регистрация: 24.10.2016

Сообщений: 8

03.08.2013, 16:07

3

Спасибо за ответ. Как я понял, с точки зрения устройства мало быть просто геймпадом, чтобы быть HID-устройством, так? Нужно, чтобы тебя разрабатывали в соответствии с определённым стандартом. Как узнать, HID-устройство у меня или нет? Ведь оно не определяется системой, оставаясь для неё «неизвестным», что наводит на мысли.



0



Ушел с форума

Эксперт С++

16456 / 7420 / 1186

Регистрация: 02.05.2013

Сообщений: 11,617

Записей в блоге: 1

03.08.2013, 23:27

4

Цитата
Сообщение от splinefx
Посмотреть сообщение

Как я понял, с точки зрения устройства мало быть просто геймпадом, чтобы быть HID-устройством, так?

Да. Устройство должно соответствовать спецификации HID.
Вообще, геймпад, не определяющийся как HID-совместимое устройство — это несколько странно.

Цитата
Сообщение от splinefx
Посмотреть сообщение

Как узнать, HID-устройство у меня или нет? Ведь оно не определяется системой, оставаясь для неё «неизвестным», что наводит на мысли.

HID-совместимые устройства при подключении автоматически распознаются системой и
помещаются в соответствующий раздел в списке оборудования.



0



Урок 3. Сборка и запуск драйвера

Еще один, особый, вид программ – драйверы. В отличие от остальных – выполняются в особом режиме, где они имеют ряд возможностей, недоступных для обычных приложений Windows. Однако это осложняется тем, что в этом режиме практически отсутствуют средства для взаимодействия с пользователем. Для тестирования драйвера можно пользоваться функцией DbgPrint, выдающей отладочные сообщения отладчику. Но отладчика может не оказаться и этих сообщений никто в таком случае не увидит. Для обычного же взаимодействия с пользователем драйвер должен полагаться на прикладные приложения, обмениваясь с ними запросами ввода/вывода.

Сообщения, выдаваемые отладчику, проще всего увидеть при помощи программы DebugView, которую нужно запустить перед сеансом проверки.

Создание проекта будем вести следующим образом. Создаем папку DrvHello, где будем разрабатывать приложение-драйвер. Внутри нее создаем такие файлы:

• makefile

#
# DO NOT EDIT THIS FILE!!!  Edit .sources. if you want to add a new source
# file to this component.  This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)makefile.def

Над текстом этого файла не следует задумываться, он просто должен присутствовать в таком вот неизменном виде. Хотя в чужих проектах этого файла может и не быть, либо он будет работать другим образом. В общем, если он есть и содержит это содержимое – то все в порядке, если нет – необходимы дополнительные исследования.

• sources

TARGETNAME=drvhello
TARGETTYPE=DRIVER
TARGETPATH=obj
SOURCES=main.c

Задает параметры сборки. Здесь в параметре SOURCES необходимо перечислить через пробел все файлы с исходным кодом, которые нужно будет скомпилировать.

• main.c – это наш файл с исходным кодом. Может носить любое имя, их может быть много, а может быть очень много. Главное, не забыть их все перечислить в файле sources

#include "ntddk.h"

#pragma code_seg("INIT")
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath)
{
    DbgPrint("Hello, world!");			// Выдача отладочного сообщения
    return STATUS_DEVICE_CONFIGURATION_ERROR;	// Выдача ошибки заставит систему сразу же выгрузить драйвер
}
#pragma code_seg()

Основная функция у нас здесь носит название DriverEntry. Запускаться она будет при попытке загрузки драйвера. А чтобы сделать такую попытку – нужна программа-загрузчик, которую напишем чуть поздней.

Откомпилируем драйвер. Чтобы мы могли что-то увидеть в отладчике, драйвер должен быть собран в отладочном режиме. Напомню, что отладочный режим у программистов драйверов называется checked, а финальный — free (прикладные программисты так не заморачиваются и называют их debug и release соответственно). В этом режиме программный код не оптимизируется и исполняемый файл содержит много избыточной информации, совершенно не нужной для работы, но очень полезной при изучении того, что будет делать этот код.
Для сборки открываем меню Start, затем Programs/Windows Driver Kits/WDK <номер версии>/Build Environment/Windows Server 2003 (или Windows XP)/ x86 Checked Build Environment. Щелкаем и попадаем в консольное окно. Если FAR был добавлен в PATH, то можно набрать far и перейти в директорию проекта обычным способом, иначе туда придется добираться используя команду cd (и может быть смену диска). Когда добрались до папки DrvHello (там где лежат три файла, которые были созданы выше) – набираем команду nmake. Если сборка прошла без ошибок, то будет созданы директории objchk_wnet_x86/i386, а в ней уже можно обнаружить файл drvhello.sys. Это и есть наш собранный драйвер.

Теперь вернемся к загрузчику. Это у нас будет консольное приложение (см. главу 1). Имя я ему дал DrvHelloloader и разместил, как всегда, в c:Projects. Имя файла с исходным кодом такое же – main.c, содержимое:

#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib") 

void main(int argc, char* argv[])
{
	char serviceName[] = "drvhello";
	char driverBinary[MAX_PATH] = "";
	SC_HANDLE hSc;
	SC_HANDLE hService;

	// Чтобы запустить драйвер, потребуется полный путь к нему
	// Предполагаем, что он лежит в той же папке, что и экзешник
	strcpy(driverBinary, argv[0]);			// argv[0] - здесь будет имя экзешника с полным путем
	PathRemoveFileSpec(driverBinary);		// Выкидываем имя экзешника, остается только путь к папке
	strcat(driverBinary, "\drvhello.sys");	// Добавляем имя драйвера.
					// Бэкслэш в строках Си надо удваивать, из-за его специального значения.

	hSc = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);	// Открываем SCM (Service Control Management)
								// Это такая штука, которая позволяет запускать драйверы
								// из пользовательского режима
	CreateService(hSc, serviceName, serviceName,
		SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
		driverBinary, NULL, NULL, NULL, NULL, NULL);				// Загрузка в 3 этапа - создаем службу
	hService = OpenService(hSc, serviceName, SERVICE_ALL_ACCESS);	// Открываем ее
	StartService(hService, 0, NULL);	// И запускаем. Вообще-то было бы неплохо
						// еще и закрыть ее... Как нибудь потом.
}

Выбираем в меню cтудии – Build/Rebuild Solution. Произойдет пересборка проекта без запуска. В принципе, можно и запустить. Находим экзешник в папке проекта, докидываем в ту же папку drvhello.sys. Далее запускаем DebugView, включаем галочку Capture/Capture Kernel, как показано на рисунке:

Изображение
Рис. 3.1 – Настройка DebugView

Теперь запускаем программу. Если все прошло успешно – видим следующую картину:

Изображение
Рис. 3.2 – Проверка драйвера

Вот такой простой код позволяет уже очень много – работать на уровне ядра. Но следует помнить, что если допустить ошибку в прикладной программе – упадет она одна; если в драйвере – вся система. К примеру, если в код драйвера перед DbgPrint добавить строку:

int a = *((int *)0);

которая делает попытку прочесть содержимое памяти по нулевому адресу – то картинка будет уже иной:

Изображение
Рис. 3.3 – Попытка чтения из нулевого адреса

Если бы это был не драйвер, а просто программа пользовательского режима, то при выполнении этого кода она бы просто закрылась, выдав ошибку:

Изображение
Рис. 3.4 – Та же ошибка в программе пользовательского режима

Понравилась статья? Поделить с друзьями:
  • Как написать драйвер для mac os
  • Как написать драйвер для linux
  • Как написать драйвер com порта
  • Как написать драббл
  • Как написать дошол или дошел