为何选择visual studio community作为开发环境:

从微软官网的关于visual studio community的介绍可知,visual studio community是一款功能强大并且免费的集成开发环境。正好这功能强大和免费这两点完全符合本人需求,于是果断选择visual studio的社区版作为开发的IDE。

选择新版的visual studio对于驱动开发还有一个好处,就是visual studio已经集成了驱动开发的功能,安装windows driver kit后visual studio中会出现开发驱动项目的模板,并且内部已经集成了WinDbg。这对于驱动的开发和调试来讲,相比之前的驱动开发方式,方便了很多。如果需要详细的关于visual studio community的介绍和下载方式,请自行百度去微软官方网站下载。

废话不多,进入正题(PS,安装visual studio和windows driver kit就不要介绍了吧…)。

先配置虚拟机相关设置

打开vmware,我这里虚拟机之前都装好了,直接配置。

选择编辑虚拟机设置,在弹出的设置对话框中选择添加,给虚拟机添加新硬件。

visual studio community professional enterorise区别 visual studio community有什么用_windows


硬件类型选择串行端口,点击下一步

visual studio community professional enterorise区别 visual studio community有什么用_驱动开发_02

端口类型选择输出到命名管道,然后下一步

visual studio community professional enterorise区别 visual studio community有什么用_驱动开发_03

指定插槽第二个选项一定选择另一端是应用程序,重要的事情我就不说三遍了,但,一定要选择另一端是应用程序这个选项。(我的猜测是visual studio集成的windbg功能是与虚拟机中的调试工具进行通信,而调试工具是应用程序,而不是虚拟机,不知道想法对不对)

然后可以点击完成,开启虚拟机了。

visual studio community professional enterorise区别 visual studio community有什么用_windows_04

进入虚拟机的windows 7 x64,去控制面板,把虚拟机自带的防火墙给关了。

visual studio community professional enterorise区别 visual studio community有什么用_vmware_05

将驱动部署配置所必须的文件WDK Test Target Setup x64-x64_en-us.msi复制到虚拟机中。

32位虚拟机所对应的是WDK Test Target Setup x86-x86_en-us.msi。

这两个文件在装好windows driver kit 10或者对应其他系统版本的windows driver kit后,一般在系统C盘的C:\Program Files (x86)\Windows Kits\10\Remote\文件夹下。其中10是你对应的系统版本,如果是windows 7 的windows driver kit ,那路径中的10就应该换成是7。

文件夹下是这个样子

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_06


如果你的虚拟机是64位就去x64文件夹下找上面提到的文件。其余的类似变通一下。

将文件复制到虚拟机安装完毕后虚拟机里面的配置就告一段落了。新建一个空白WDM驱动工程:

visual studio community professional enterorise区别 visual studio community有什么用_驱动开发_07

填入代码,修改项目生成的默认inf安装文件。一切准备就绪,关键的来了。

我们选择项目—->属性,弹出属性配置对话框

visual studio community professional enterorise区别 visual studio community有什么用_vmware_08


在平台选项中更改编译生成驱动所对应的平台,我的虚拟机是64位,因此这里选择为64位。32位的Intel 架构CPU对应的位Win32。

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_09


在Target OS Version中更改编译生成对应的目标系统。例如,驱动要安装在运行windows 7操作系统的电脑上,则将OS Version选择为Windows 7。

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_10

由于windows 10 推出后,微软致力于全平台通用应用。而当前创建的驱动示例工程并不是基于通用应用的,因此还需要设置一下驱动生成的目标平台是桌面系统还是windows mobile或者通用。这里选择Desktop即桌面操作系统平台。

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_11

接下来设置驱动部署配置:

我们选择 Driver Install 中的Deployment,点击Target Device Name右边的按钮

visual studio community professional enterorise区别 visual studio community有什么用_#define_12


弹出配置对话框,选择Add New Device,我之前配置的Win7 x86调试环境咱们忽略看不见,Add New Device 配置个新的。如果你之前配置好了调试环境,这里就会出现,以后直接选就可以用了,不用每次都配置。

visual studio community professional enterorise区别 visual studio community有什么用_windows_13

给配置的调试设备起个名,Win7 x64

Network host name处填写你的虚拟机主机名,主机名可以去计算机–>属性里面看

visual studio community professional enterorise区别 visual studio community有什么用_windows_14

设置连接类型为serial (串行方式),baud rate (波特率)不用管,默认115200,pipe(命名管道)和reconnect都勾上,pipe name 命名管道的名称填上虚拟机配置时生成的命名管道值,

不确定可以去虚拟机设置里面看一眼,就是红框处的值

visual studio community professional enterorise区别 visual studio community有什么用_驱动开发_15


visual studio community professional enterorise区别 visual studio community有什么用_#define_16

点击下一步,就开始对虚拟机进行自动配置。

配置成功

visual studio community professional enterorise区别 visual studio community有什么用_#define_17

配置完成后,重启下虚拟机。

设置硬件资源ID

visual studio community professional enterorise区别 visual studio community有什么用_windows_18

点击确定,然后选择调试,

visual studio community professional enterorise区别 visual studio community有什么用_#define_19

哈哈,出错了

visual studio community professional enterorise区别 visual studio community有什么用_vmware_20

有谁知道这个错误么?知道的麻烦告诉下。

好在,解决方法我还是有。在配置管理器下把部署给勾上。

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_21


visual studio community professional enterorise区别 visual studio community有什么用_vmware_22

再次点击调试,

visual studio community professional enterorise区别 visual studio community有什么用_vmware_23


就开始部署驱动了

visual studio community professional enterorise区别 visual studio community有什么用_windows_24

驱动安装成功,可以在虚拟机设备管理器中看到我们新加入的设备。

visual studio community professional enterorise区别 visual studio community有什么用_windows_25


visual studio community professional enterorise区别 visual studio community有什么用_visual studio_26

接下来该说驱动的调试了。

按照之前的方法,可以看到驱动已经成功的部署到虚拟机中了。但是,如果你在代码中打断点,如,在驱动入口函数DriverEntry中增加断点,点击

visual studio community professional enterorise区别 visual studio community有什么用_#define_19


可以发现驱动部署后并没有命中断点。

=。- 驱动都部署完了,设备也创建了怎么可能没执行DriverEntry!不要怀疑代码,代码没有问题。目前我也没有好的调试方法可以命中断点而操作又简单。但,解决方法总有的,好不要用,凑合用吧。

解决方法:

点击

visual studio community professional enterorise区别 visual studio community有什么用_#define_19

后,visual studio 开始往虚拟机中捣鼓驱动和安装驱动,当这个

visual studio community professional enterorise区别 visual studio community有什么用_#define_19

变成

visual studio community professional enterorise区别 visual studio community有什么用_windows_30

,两条竖杠时,点击,然后虚拟机系统就会进入中断break,

visual studio community professional enterorise区别 visual studio community有什么用_visual studio_31


等虚拟机break了之后,再点击继续或者在调试命令中输入g来恢复。

visual studio community professional enterorise区别 visual studio community有什么用_#define_32

这样就可以命中断点了。不过得补充一句,要在驱动开始部署前break,而且要及时恢复让驱动继续部署到虚拟机上。

visual studio community professional enterorise区别 visual studio community有什么用_驱动开发_33

附上文中所用的代码和INF文件内容
注:代码是windows驱动开发技术详解中的源代码

#ifdef __cplusplus
extern "C"
{
#endif
#include <wdm.h>
#ifdef __cplusplus
}
#endif 

typedef struct _DEVICE_EXTENSION
{
    PDEVICE_OBJECT fdo;
    PDEVICE_OBJECT NextStackDevice;
    UNICODE_STRING ustrDeviceName;  // 设备名
    UNICODE_STRING ustrSymLinkName; // 符号链接名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#define arraysize(p) (sizeof(p)/sizeof((p)[0]))

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject);
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
    IN PIRP Irp);
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,
    IN PIRP Irp);
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject);

extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath);

#pragma INITCODE 
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath)
{
    KdPrint(("Enter DriverEntry\n"));
    pRegistryPath;

    pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
    pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
        pDriverObject->MajorFunction[IRP_MJ_CREATE] =
        pDriverObject->MajorFunction[IRP_MJ_READ] =
        pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
    pDriverObject->DriverUnload = HelloWDMUnload;

    KdPrint(("Leave DriverEntry\n"));
    return STATUS_SUCCESS;
}

#pragma PAGEDCODE
void Dump(IN PDRIVER_OBJECT pDriverObject)
{
    KdPrint(("----------------------------------------------\n"));
    KdPrint(("Begin Dump...\n"));
    KdPrint(("Driver Address:0X%08X\n", pDriverObject));
    KdPrint(("Driver name:%wZ\n", &pDriverObject->DriverName));
    KdPrint(("Driver HardwareDatabase:%wZ\n", pDriverObject->HardwareDatabase));
    KdPrint(("Driver first device:0X%08X\n", pDriverObject->DeviceObject));

    PDEVICE_OBJECT pDevice = pDriverObject->DeviceObject;
    int i = 1;
    for (; pDevice != NULL; pDevice = pDevice->NextDevice)
    {
        KdPrint(("The %d device\n", i++));
        KdPrint(("Device AttachedDevice:0X%08X\n", pDevice->AttachedDevice));
        KdPrint(("Device NextDevice:0X%08X\n", pDevice->NextDevice));
        KdPrint(("Device StackSize:%d\n", pDevice->StackSize));
        KdPrint(("Device's DriverObject:0X%08X\n", pDevice->DriverObject));
    }

    KdPrint(("Dump over!\n"));
    KdPrint(("----------------------------------------------\n"));
}

#pragma PAGEDCODE
void DumpDeviceStack(IN PDEVICE_OBJECT  pdo)
{
    KdPrint(("----------------------------------------------\n"));

    KdPrint(("Begin Dump device stack...\n"));

    PDEVICE_OBJECT pDevice = pdo;
    int i = 0;
    for (; pDevice != NULL; pDevice = pDevice->AttachedDevice)
    {
        KdPrint(("The %d device in device stack\n", i++));
        KdPrint(("Device AttachedDevice:0X%08X\n", pDevice->AttachedDevice));
        KdPrint(("Device NextDevice:0X%08X\n", pDevice->NextDevice));
        KdPrint(("Device StackSize:%d\n", pDevice->StackSize));
        KdPrint(("Device's DriverObject:0X%08X\n", pDevice->DriverObject));
    }

    KdPrint(("Dump over!\n"));
    KdPrint(("----------------------------------------------\n"));
}

/************************************************************************
* 函数名称:HelloWDMAddDevice
* 功能描述:添加新设备
* 参数列表:
DriverObject:从I/O管理器中传进来的驱动对象
PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象
* 返回 值:返回添加新设备状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject)
{
    PAGED_CODE();
    KdPrint(("Enter HelloWDMAddDevice\n"));

    NTSTATUS status;
    PDEVICE_OBJECT fdo;
    UNICODE_STRING devName;
    RtlInitUnicodeString(&devName, L"\\Device\\MyWDMDevice");
    status = IoCreateDevice(
        DriverObject,
        sizeof(DEVICE_EXTENSION),
        (PUNICODE_STRING)&devName,
        FILE_DEVICE_UNKNOWN,
        0,
        FALSE,
        &fdo);
    if (!NT_SUCCESS(status))
        return status;
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
    pdx->fdo = fdo;
    pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
    UNICODE_STRING symLinkName;
    RtlInitUnicodeString(&symLinkName, L"\\DosDevices\\HelloWDM");

    pdx->ustrDeviceName = devName;
    pdx->ustrSymLinkName = symLinkName;
    status = IoCreateSymbolicLink((PUNICODE_STRING)&symLinkName, (PUNICODE_STRING)&devName);

    if (!NT_SUCCESS(status))
    {
        IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
        status = IoCreateSymbolicLink(&symLinkName, &devName);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    }

    fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
    fdo->Flags &= ~DO_DEVICE_INITIALIZING;


    Dump(DriverObject);
    DumpDeviceStack(PhysicalDeviceObject);

    KdPrint(("Leave HelloWDMAddDevice\n"));
    return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:DefaultPnpHandler
* 功能描述:对PNP IRP进行缺省处理
* 参数列表:
pdx:设备对象的扩展
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
{
    PAGED_CODE();
    KdPrint(("Enter DefaultPnpHandler\n"));
    IoSkipCurrentIrpStackLocation(Irp);
    KdPrint(("Leave DefaultPnpHandler\n"));
    return IoCallDriver(pdx->NextStackDevice, Irp);
}

/************************************************************************
* 函数名称:HandleRemoveDevice
* 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理
* 参数列表:
fdo:功能设备对象
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
    PAGED_CODE();
    KdPrint(("Enter HandleRemoveDevice\n"));

    Irp->IoStatus.Status = STATUS_SUCCESS;
    NTSTATUS status = DefaultPnpHandler(pdx, Irp);
    IoDeleteSymbolicLink((PUNICODE_STRING)&pdx->ustrSymLinkName);

    //调用IoDetachDevice()把fdo从设备栈中脱开:
    if (pdx->NextStackDevice)
        IoDetachDevice(pdx->NextStackDevice);

    //删除fdo:
    IoDeleteDevice(pdx->fdo);
    KdPrint(("Leave HandleRemoveDevice\n"));
    return status;
}

/************************************************************************
* 函数名称:HelloWDMPnp
* 功能描述:对即插即用IRP进行处理
* 参数列表:
fdo:功能设备对象
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
    IN PIRP Irp)
{
    PAGED_CODE();

    KdPrint(("Enter HelloWDMPnp\n"));
    NTSTATUS status = STATUS_SUCCESS;
    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    static NTSTATUS(*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) =
    {
        DefaultPnpHandler,      // IRP_MN_START_DEVICE
        DefaultPnpHandler,      // IRP_MN_QUERY_REMOVE_DEVICE
        HandleRemoveDevice,     // IRP_MN_REMOVE_DEVICE
        DefaultPnpHandler,      // IRP_MN_CANCEL_REMOVE_DEVICE
        DefaultPnpHandler,      // IRP_MN_STOP_DEVICE
        DefaultPnpHandler,      // IRP_MN_QUERY_STOP_DEVICE
        DefaultPnpHandler,      // IRP_MN_CANCEL_STOP_DEVICE
        DefaultPnpHandler,      // IRP_MN_QUERY_DEVICE_RELATIONS
        DefaultPnpHandler,      // IRP_MN_QUERY_INTERFACE
        DefaultPnpHandler,      // IRP_MN_QUERY_CAPABILITIES
        DefaultPnpHandler,      // IRP_MN_QUERY_RESOURCES
        DefaultPnpHandler,      // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
        DefaultPnpHandler,      // IRP_MN_QUERY_DEVICE_TEXT
        DefaultPnpHandler,      // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
        DefaultPnpHandler,      // 
        DefaultPnpHandler,      // IRP_MN_READ_CONFIG
        DefaultPnpHandler,      // IRP_MN_WRITE_CONFIG
        DefaultPnpHandler,      // IRP_MN_EJECT
        DefaultPnpHandler,      // IRP_MN_SET_LOCK
        DefaultPnpHandler,      // IRP_MN_QUERY_ID
        DefaultPnpHandler,      // IRP_MN_QUERY_PNP_DEVICE_STATE
        DefaultPnpHandler,      // IRP_MN_QUERY_BUS_INFORMATION
        DefaultPnpHandler,      // IRP_MN_DEVICE_USAGE_NOTIFICATION
        DefaultPnpHandler,      // IRP_MN_SURPRISE_REMOVAL
    };

    ULONG fcn = stack->MinorFunction;
    if (fcn >= arraysize(fcntab))
    {                       // unknown function
        status = DefaultPnpHandler(pdx, Irp); // some function we don't know about
        return status;
    }                       // unknown function

#if DBG
    static char* fcnname[] =
    {
        "IRP_MN_START_DEVICE",
        "IRP_MN_QUERY_REMOVE_DEVICE",
        "IRP_MN_REMOVE_DEVICE",
        "IRP_MN_CANCEL_REMOVE_DEVICE",
        "IRP_MN_STOP_DEVICE",
        "IRP_MN_QUERY_STOP_DEVICE",
        "IRP_MN_CANCEL_STOP_DEVICE",
        "IRP_MN_QUERY_DEVICE_RELATIONS",
        "IRP_MN_QUERY_INTERFACE",
        "IRP_MN_QUERY_CAPABILITIES",
        "IRP_MN_QUERY_RESOURCES",
        "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
        "IRP_MN_QUERY_DEVICE_TEXT",
        "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
        "",
        "IRP_MN_READ_CONFIG",
        "IRP_MN_WRITE_CONFIG",
        "IRP_MN_EJECT",
        "IRP_MN_SET_LOCK",
        "IRP_MN_QUERY_ID",
        "IRP_MN_QUERY_PNP_DEVICE_STATE",
        "IRP_MN_QUERY_BUS_INFORMATION",
        "IRP_MN_DEVICE_USAGE_NOTIFICATION",
        "IRP_MN_SURPRISE_REMOVAL",
    };

    KdPrint(("PNP Request (%s)\n", fcnname[fcn]));
#endif // DBG

    status = (*fcntab[fcn])(pdx, Irp);
    KdPrint(("Leave HelloWDMPnp\n"));
    return status;
}

/************************************************************************
* 函数名称:HelloWDMDispatchRoutine
* 功能描述:对缺省IRP进行处理
* 参数列表:
fdo:功能设备对象
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,
    IN PIRP Irp)
{
    PAGED_CODE();
    fdo;
    KdPrint(("Enter HelloWDMDispatchRoutine\n"));
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;  // no bytes xfered
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    KdPrint(("Leave HelloWDMDispatchRoutine\n"));
    return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:HelloWDMUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
DriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
{
    PAGED_CODE();
    DriverObject;
    KdPrint(("Enter HelloWDMUnload\n"));
    KdPrint(("Leave HelloWDMUnload\n"));
}

INF安装文件内容:

[Version]
Signature="$WINDOWS NT$"
Class=BigSoft
ClassGuid={EF2962F0-0D55-4bff-B8AA-2221EE8A79B0}
Provider=BigSoft
DriverVer=
CatalogFile=BigSoft.cat

[DestinationDirs]
DefaultDestDir = 12


[SourceDisksNames]
1 = %DiskName%,,,""

[SourceDisksFiles]
HelloDriver.sys=1

[ClassInstall32]
AddReg=RegAdd

[Manufacturer]
%ManufacturerName%=Standard,NTx86,NTIA64,NTAMD64

[Standard.NTx86]
%DeviceDesc%=ModelInstall,PCI\VEN_9999&DEV_9999
[Standard.NTIA64]
%DeviceDesc%=ModelInstall,PCI\VEN_9999&DEV_9999
[Standard.NTAMD64]
%DeviceDesc%=ModelInstall,PCI\VEN_9999&DEV_9999

[RegAdd]
HKR,,,,%ClassName%  
HKR,,Icon,,"-5"  

[ModelInstall.NT]
CopyFiles=MyDriverFile

[ModelInstall.NT.Services] 
AddService=WDMDriver,0x02,ServicesInstall

[ServicesInstall]
DisplayName=%SvcDesc% 
ServiceType=0x1
StartType=0x2
ErrorControl=0x1
ServiceBinary= %12%\HelloDriver.sys  

[MyDriverFile]  
HelloDriver.sys  

[Strings]
ManufacturerName="BigSoft"
ClassName="BigSoft Virtual Device"
DiskName="HelloDriver Source Disk"
DeviceDesc="Virtual Driver Device"
SvcDesc="BigSoftService"