<< Back Home UK uk   Donate Donate

Building NT kernel mode drivers in MS Visual C 6.0

Yes, I did it. At last I'm publishing detailed step-by-step instruction for creating valuable kernel-mode driver project in MS Visual Studio 6.0


Set environment variables

Set BASEDIRNT4, BASEDIR2K, BASEDIRXP environment variables (I would recommend system ones, not user-specific) like this:

BASEDIR2K  = C:\Develop\DDK2000

Set BASEDIR environment variable to point to your favorite DDK (I prefer NT4, because I'm writing highly compatible drivers). For example:


Create project

  • File -> New... -> Projects
  • Chose Win32 Dynamic-link Library
  • Enter project name and directory path (as usually)
  • OK -> An empty DLL project -> Finish -> OK

Change project settings

  • Project -> Settings
  • Chose "All Configurations" in "Settings for" combo (top-left corner)
  • ... -> C/C++
    • Chose "General" in "Category" combo
      • Chose "Program Database" in "Debug info" combo for "Win32 Debug" configuration.
    • Chose "Code Generation" in "Category" combo
      • Chose "__stdcall" in "Calling convention" combo
      • Chose "8 Bytes *" in "Struct member alignment" combo
    • Chose "Preprocessor" in "Category" combo
      • Enter paths to DDK INCLUDE directories into "Additional include directories" edit:
        Note 1: here the separator character is comma. Do not take paths in quotation marks.
        Note 2: If you use .MAK files, type names of BASEDIRxxx variables in proper case. They must be typed in the same way as appear in environment variable management dialog.
      • Enter the following predefined constants into "Preprocessor definitions" edit (thanks to Emusic from This will make all .H being compiled properly:
        WIN32, _WINDOWS, i386=1, _X86_=1, STD_CALL, CONDITION_HANDLING=1,
        NT_INST=0, _NT1X_=100, WINNT=1,
        _WIN32_WINNT=0x0400 /* minimum required OS version */
        WIN32_LEAN_AND_MEAN=1, DEVL=1, FPO=1
        Add the following defines to "Win32 Debug" configuration:
        DBG, DEBUG, _DEBUG
        Note 1: here the separator character is comma. Do not take items in quotation marks.
        Note 2: If you use precompiled headers, you can place these defines to your .H used for building .PCH or some common .H file. Look for example with *.cpp files in pch_cpp folder and with *.c files in pch_c inside driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb) archive.
    • Remove "/GZ" from "Project Options" edit in "Win32 Debug" configuration. In most cases this will save us from such trouble as "Debug build works, but Release doesn't". Builds will not differ in bug reproducing (uninitialized variables and memory blocks, overflows, etc.). In addition, this pretty switch instructs compiler to include stack consistency check code into output. This check leads to unresolved external _chkesp on link stage.
  • ... -> Link
    • Chose "General" in "Category" combo
      • Enter driver binary'es name (e.g. "driver_template.sys") in "Output file name" edit (separately for each configuration).
      • Uncheck "Link incrementally") box.
    • Chose "Input" in "Category" combo
      • Check "Ignore all default libraries" box
      • Change list of standart import libraries for required DDK libraires in "Object/library modules" edit. For example
        Note 1: here the separator character is space character. Do not take paths in quotation marks.
        Note 2: If you use .MAK files, type names of BASEDIRxxx variables in proper case. They must be typed in the same way as appear in environment variable management dialog.
        Note 3: $(BASEDIR2k)\libchk\i386\ntoskrnl.lib library
        is included along with
        (and definitly after it) in order to take imports from NT4 versions, and in the same time make available imports from newer ServicePacks of NT4.
        Note 4: Previously I recommended to add $(BASEDIR)\Lib\i386\Checked\Ntdll.lib. I was wrong. If you really need exports from ntdll.dll, use kernel-mode GetProcAddress(). First, your driver may become not loadable (should I tell you what is Unresolved External?). Second, you must use ZxXxx(), not NtXxx(), since each newer Windows has more strong checks for this.
    • Chose "Output" in "Category" combo
      • Enter "DriverEntry" value in "Entry point symbol" edit
    • Chose "Debug" in "Category" combo
      • Uncheck "Separate types" checkbox. This will instruct linker to place information about used data types (especially important for structure definitions) in single .PDB together with source browse information. This information will be used by debuggers (SoftIce, WinDbg). On command line parameters layer this is equal to replacement of /pdbtype:sept for /pdbtype:con.
      • For old SoftIce set type of .PDB file to "COFF" checkbox. (In my project templates "MS" is used).
    • Change "/subsystem:xxxxx" to (or add if not present) "/subsystem:native" or even "/subsystem:native,4.00" in "Project Options" edit (separately for each configuration).
    • Add "/driver" to "Project Options" edit (separately for each configuration).
  • OK
  • File -> Save Workspace
  • If you prefere building projects from command line or from script with nmake utility, you can export .MAK and .DEP files:
    • Project -> Export Makefile
    • Check "Write dependencies when writing makefile" box
    • Check box near .MAK filename
    • OK
    • If you like, you can also create in this folder file named Makefile containing something like this:
      !INCLUDE my_driver_project.mak
      Then you will not be required to pass name of the .MAK file to nmake.
  • And now copy this empty project somewhere for future use as template for your driver projects :) For example: driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb)
  • PS. since version 6 I've added sample driver project for VS8 to pch_cpp subfolder along with VS6 project. driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb)

Adding files

  • Just add files to your project
  • If you have a big project with .LIBs and .DLLs, built from separate .DSP files, it worth adding these files to your project too. It will help VC6 to understand, that the module must be rebuilt if for example some .LIB is updated.
  • If you decided to use .PCH, do not forget to insert the following line in all added *.C and *.CPP files
    #include "stdafx.h"
    instead of
    #include <ntddk.h>


thanks to Emusic from for additional #define's


thanks to Axxie for bugfixes


See also:

<< Back designed by Alter aka Alexander A. Telyatnikov powered by Apache+PHP under FBSD © 2002-2024