为何选择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集成的windbg功能是与虚拟机中的调试工具进行通信,而调试工具是应用程序,而不是虚拟机,不知道想法对不对)
然后可以点击完成,开启虚拟机了。
进入虚拟机的windows 7 x64,去控制面板,把虚拟机自带的防火墙给关了。
将驱动部署配置所必须的文件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。
文件夹下是这个样子
如果你的虚拟机是64位就去x64文件夹下找上面提到的文件。其余的类似变通一下。
将文件复制到虚拟机安装完毕后虚拟机里面的配置就告一段落了。新建一个空白WDM驱动工程:
填入代码,修改项目生成的默认inf安装文件。一切准备就绪,关键的来了。
我们选择项目—->属性,弹出属性配置对话框
在平台选项中更改编译生成驱动所对应的平台,我的虚拟机是64位,因此这里选择为64位。32位的Intel 架构CPU对应的位Win32。
在Target OS Version中更改编译生成对应的目标系统。例如,驱动要安装在运行windows 7操作系统的电脑上,则将OS Version选择为Windows 7。
由于windows 10 推出后,微软致力于全平台通用应用。而当前创建的驱动示例工程并不是基于通用应用的,因此还需要设置一下驱动生成的目标平台是桌面系统还是windows mobile或者通用。这里选择Desktop即桌面操作系统平台。
接下来设置驱动部署配置:
我们选择 Driver Install 中的Deployment,点击Target Device Name右边的按钮
弹出配置对话框,选择Add New Device,我之前配置的Win7 x86调试环境咱们忽略看不见,Add New Device 配置个新的。如果你之前配置好了调试环境,这里就会出现,以后直接选就可以用了,不用每次都配置。
给配置的调试设备起个名,Win7 x64
Network host name处填写你的虚拟机主机名,主机名可以去计算机–>属性里面看
设置连接类型为serial (串行方式),baud rate (波特率)不用管,默认115200,pipe(命名管道)和reconnect都勾上,pipe name 命名管道的名称填上虚拟机配置时生成的命名管道值,
不确定可以去虚拟机设置里面看一眼,就是红框处的值
点击下一步,就开始对虚拟机进行自动配置。
配置成功
配置完成后,重启下虚拟机。
设置硬件资源ID
点击确定,然后选择调试,
哈哈,出错了
有谁知道这个错误么?知道的麻烦告诉下。
好在,解决方法我还是有。在配置管理器下把部署给勾上。
再次点击调试,
就开始部署驱动了
驱动安装成功,可以在虚拟机设备管理器中看到我们新加入的设备。
接下来该说驱动的调试了。
按照之前的方法,可以看到驱动已经成功的部署到虚拟机中了。但是,如果你在代码中打断点,如,在驱动入口函数DriverEntry中增加断点,点击
可以发现驱动部署后并没有命中断点。
=。- 驱动都部署完了,设备也创建了怎么可能没执行DriverEntry!不要怀疑代码,代码没有问题。目前我也没有好的调试方法可以命中断点而操作又简单。但,解决方法总有的,好不要用,凑合用吧。
解决方法:
点击
后,visual studio 开始往虚拟机中捣鼓驱动和安装驱动,当这个
变成
,两条竖杠时,点击,然后虚拟机系统就会进入中断break,
等虚拟机break了之后,再点击继续或者在调试命令中输入g来恢复。
这样就可以命中断点了。不过得补充一句,要在驱动开始部署前break,而且要及时恢复让驱动继续部署到虚拟机上。
附上文中所用的代码和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"