1 微微微微微统 Windows98/2000 微微微微微微微微 微微 ()
Jan 20, 2016
1
微计算机系统
Windows98/2000 驱动程序编写方法
(下)
2
微计算机系统4.Driver Works 的使用1 )生成简单框架
3
微计算机系统
工程文件名
工程文件目录
4
微计算机系统
选择驱动类型
5
微计算机系统
创建功能驱动程序 创建过滤器
驱动程序
6
微计算机系统
选择相应总线
本例不驱动硬件
7
微计算机系统
驱动类名称
驱动类文件名
8
微计算机系统
选择需要处理的消
息句柄
9
微计算机系统
10
微计算机系统
11
微计算机系统
12
微计算机系统
添加和应用程序之间通信的
控制代码
13
微计算机系统
14
微计算机系统
15
微计算机系统
测试用应用程序名称
16
微计算机系统
17
微计算机系统
18
微计算机系统
驱动类
设备类
19
微计算机系统
驱动类文件
设备类文件
测试用的控制台程序文件
驱动安装指导文件
20
微计算机系统
此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在 VC集成环境下修改有关程序,增加相关的具体操作代码,然后就可以编译和调试了。
21
微计算机系统
该驱动程序框架包含了几个最基本的类,这些类是:class Sample : public KDriver // 驱动程序类,用于初始化驱动程序{ SAFE_DESTRUCTORSpublic: // 以下成员函数注意和 WDM 中有关例程联系起来看 virtual NTSTATUS DriverEntry(PUNICODE_STRING RegistryPath); virtual NTSTATUS AddDevice(PDEVICE_OBJECT Pdo); void LoadRegistryParameters(KRegistryKey &Params);
int m_Unit;
// The following data members are loaded from the registry during DriverEntryULONG m_bBreakOnEntry;
};
22
微计算机系统class SampleDevice : public KPnpDevice // 是设备类 KDvice 的派生类,用于在 WDM 环境下支持即插即用设备{
// Constructorspublic:
SAFE_DESTRUCTORS;SampleDevice(PDEVICE_OBJECT Pdo, ULONG Unit);~SampleDevice();
// Member Functions 注意和 PNP 的次功能代码联系起来看public:
DEVMEMBER_DISPATCHERSvirtual NTSTATUS OnStartDevice(KIrp I);virtual NTSTATUS OnStopDevice(KIrp I);virtual NTSTATUS OnRemoveDevice(KIrp I);virtual NTSTATUS DefaultPnp(KIrp I);virtual NTSTATUS DefaultPower(KIrp I);virtual NTSTATUS OnDevicePowerUp(KIrp I);virtual NTSTATUS OnDeviceSleep(KIrp I);void SerialRead(KIrp I);void SerialWrite(KIrp I);
23
微计算机系统NTSTATUS SAMPLE_IOCTL_Read_Handler(KIrp I);NTSTATUS SAMPLE_IOCTL_Write_Handler(KIrp I);NTSTATUS SAMPLE_IOCTL_ReadWrite_Handler(KIrp I);
#ifdef _COMMENT_ONLYvirtual NTSTATUS Create(KIrp I);virtual NTSTATUS Close(KIrp I);virtual NTSTATUS DeviceControl(KIrp I);virtual NTSTATUS SystemControl(KIrp I);virtual NTSTATUS Read(KIrp I);virtual NTSTATUS Write(KIrp I);
#endif// Member Data
protected:// Unit number for this device (0-9)ULONG m_Unit;KPnpLowerDevice m_Lower;SampleDevice_DriverManagedQueue m_DriverManagedQueue;
// TODO: Create additional driver managed queues. These might be// of the same class (SampleDevice_DriverManagedQueue),// or you might choose to derive another class.};
24
微计算机系统
先编译驱动程序工程
在 VC 的集成环境中
下面我们讲解编译、执行和调试这个驱动程序。
25
微计算机系统
26
微计算机系统
再编译测试应用程序工程
27
微计算机系统
28
微计算机系统 下面使用 DriverStudio 带的工具加载驱动程序和查看调试信息。
驱动程序监视,可实时看到驱动程序发出的调试输出语
句
驱动程序装载器,可动态调
用驱动程序
29
微计算机系统
驱动程序监视器界面
30
微计算机系统
驱动程序装载器界面
31
微计算机系统
32
微计算机系统
33
微计算机系统
34
微计算机系统
35
微计算机系统
36
微计算机系统
37
微计算机系统
下面我们来修改有关代码,以便增加驱动程序和应用程序之间相互通信的内容。需要增加的内容包括:a. 使用 Read 和 Write 方式分别从驱动程序读入字符
和 向驱动程序写字符。b. 使用 IO 控制代码方式分别从驱动程序读入字符和
向驱动程序写字符。c. 使用 IO 控制代码方式向驱动程序写字符串再从驱
动程序中读出该字符串,并返回反馈串信息。
注意:程序中暗红色显示的部分是我们添加或修改过的语句,其他是 DriverWorks 自动生成的。语句中“ t<< xxxxx” 这样的语句是向调试软件输出信息,该信息可以再 DriverMonitor 或其他调试监视器中看到。
2 )完成应用程序和驱动程序之间的信息交换
38
微计算机系统a. 使用 Read 和 Write 方式分别读写SampleDevice.cppvoid SampleDevice::SerialRead(KIrp I){
t << "Entering SampleDevice::SerialRead, " << I << EOL;NTSTATUS status = STATUS_SUCCESS;PUCHAR pBuffer = (PUCHAR) I.BufferedReadDest();// 取得返回数据 BUFF 的指针ULONG dwTotalSize = I.ReadSize(CURRENT); // Requested read sizechar buff[512];int n =512, j = (n % 26);for (int i=0; i<n; i++, j=(j + 1)%26){ buff[i] = 'a' + j; }buff[dwTotalSize]=‘\0’; // 指定串尾strcpy((char *)pBuffer,buff);
// 把给应用程序的数据拷贝给返回 BUFFt << “The string you will read is \”“ << buff << ”\“” << EOL; // 输出调试信息ULONG dwBytesRead = strlen(buff); // Count of bytes read I.Information() = dwBytesRead; // 返回给应用程序的信息的字节个数I.Status() = status;m_DriverManagedQueue.PnpNextIrp(I);
}
39
微计算机系统void SampleDevice::SerialWrite(KIrp I){
t << "Entering SampleDevice::SerialWrite, " << I << EOL;NTSTATUS status = STATUS_SUCCESS;PUCHAR pBuffer = (PUCHAR)I.BufferedWriteSource();// 取得
存放应用程序写给驱动程序的数据的 BUFF 的指针ULONG dwTotalSize = I.WriteSize(CURRENT);// 获得应用程
序写给驱动程序的信息的字节数。ULONG dwBytesSent = dwTotalSize;char buff[512];strcpy(buff, (char *)pBuffer);// 应用程序写给驱动程序的数据在
I.BufferedWriteSource() 返回的指针中。buff[dwBytesSent] = '\0'; t << "Write to driver is \"" << buff << "\"" << EOL;I.Information() = dwBytesSent; // 返回用户实际写的字节数I.Status() = status;m_DriverManagedQueue.PnpNextIrp(I);
}
40
微计算机系统Test_Sample.cppvoid doRead(int n) // 从驱动程序中读数据{
char *buf;ULONG nRead;int i, j;buf = (char *) malloc(n);if (buf == NULL){
printf("Failed to allocate buffer for read");Exit(1);
}// Read data from driverprintf("Reading from device - ");ReadFile(hDevice, buf, n, &nRead, NULL);// 参数分别是设备句柄、输入缓冲地址、缓冲大小(字
节数)、实际读的数据字节数、覆盖结构指针。
41
微计算机系统printf("%d bytes read from device (%d requested).\n", nRe
ad, nRead);// Print what was readwhile(i < nRead){
// j = min((i+26),n);// for(; i < j; i++)// {// printf("%c, ", buf[i]);// }// printf("\n");
printf("%c, ",buf[i++]);}printf("\n");free(buf);
}
这几句删除
42
微计算机系统void doWrite(int n) // 向驱动程序中写数据{
char *buf;ULONG nWritten;int i, j;buf = (char *) malloc(n);if (buf == NULL){
printf("Failed to allocate buffer for write");Exit(1);
}// start with the mod26 letter of the number of bytes to writej = (n % 26);// load buffer with dummy data (abcdefg...)for (i=0; i<n; i++, j=(j + 1)%26){
buf[i] = 'a' + j;}
43
微计算机系统// Write data to driverprintf("Writing to device - ");WriteFile(hDevice, buf, n, &nWritten, NULL);// 写数据 , 参数的含义是驱动程序句柄、写缓冲、写缓冲大
小、实际驱动程序得到的信息的字节数、覆盖结构指针。printf("%d bytes written to device (%d attempted).\n", nWri
tten, n);i = 0; // Print what was writtenwhile(i < n){
j = min((i+26),n);for(; i < j; i++) {
printf("%c, ", buf[i]);}printf("\n");
}free(buf);
}
44
微计算机系统b. 使用 IO 控制代码方式分别读写SampleDevice.cppNTSTATUS SampleDevice::SAMPLE_IOCTL_Read_Handler(KIrp I){ // 对应用程序读驱动程序的请求作响应
NTSTATUS status = STATUS_SUCCESS;t << "Entering SampleDevice::SAMPLE_IOCTL_Read_Handler, " << I << E
OL;char buff1[512]; ULONG fwLength=0;strcpy(buff1,"Welcome to driver!");fwLength = strlen(buff1)+1;if (I.IoctlOutputBufferSize() >= fwLength) {// 如果读入缓冲够长
strcpy((PCHAR)I.IoctlBuffer(),buff1); // 将信息拷给应用程序读入缓冲I.Information() = fwLength; // 返回信息长度
}else {
I.Information() = 0; // 否则信息长度为 0 t << "buff size too small" << EOL;
}return status;
}
45
微计算机系统
NTSTATUS SampleDevice::SAMPLE_IOCTL_Write_Handler(KIrp I){ // 接受从应用程序中来的信息
NTSTATUS status = STATUS_SUCCESS;t << "Entering SampleDevice :: SAMPLE_IOCTL_Write_Hand
ler , " << I << EOL;char buff[512];ULONG fwLength=0;strcpy(buff,(PCHAR)I.IoctlBuffer()); // 拷贝从应用程序得到的
命令串到驱动程序局部数据区t << “InputPut Data is \”“ << buff << ”\“” <<EOL; // 显示从应
用程序得到的命令串。I.Information() = 0;return status;
}
46
微计算机系统Test_Sample.cppvoid Test_SAMPLE_IOCTL_Read(void){
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to deviceCHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from deviceULONG nOutput; // Count written to bufOutput// Call device IO Control interface (SAMPLE_IOCTL_Read) in driverprintf("Issuing Ioctl to device - ");strcpy(bufInput,"This is a sample."); if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Read, NULL, 0,
bufOutput, IOCTL_OUTBUF_SIZE, &nOutput, NULL)){
printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); Exit(1);
}else printf("Return from driver is \"%s\"(%d)",bufOutput,nOutput);
}
47
微计算机系统
void Test_SAMPLE_IOCTL_Write(void){
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device
CHARbufOutput[IOCTL_OUTBUF_SIZE];// Output from deviceULONG nOutput; // Count written to bufOutput// Call device IO Control interface (SAMPLE_IOCTL_Write) in driverprintf("Issuing Ioctl to device - ");strcpy(bufInput,"Now let us write this string."); if (!DeviceIoControl(hDevice, SAMPLE_IOCTL_Write, bufInput,
strlen(bufInput), NULL, 0, &nOutput, NULL)) // 该函数参数分别是设备句柄、 IO 控制命令、写缓冲、写缓冲大小、读缓冲、读缓冲大小、实际读的字节数、覆盖结构指针(注意,这里的 bufInput 是指 Input 到设备,所以对应用软件这是写缓冲, bufOutput 是从设备 output 到应用程序,是读缓冲。
{printf("ERROR: DeviceIoControl returns %0x.",
GetLastError());Exit(1);
}}
48
微计算机系统c. 使用 IO 控制代码方式写并且读SampleDevice.cpp
NTSTATUS SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler(KIrp I){
NTSTATUS status = STATUS_SUCCESS;t << "Entering SampleDevice::SAMPLE_IOCTL_ReadWrite_
Handler, " << I << EOL;char buff[512],buff1[512]; ULONG fwLength=0;strcpy(buff,(PCHAR)I.IoctlBuffer());// 拷贝应用程序来的信息t << "InputPut Data is \"" << buff << "\"" <<EOL; strcpy(buff1,"this is feedback from driver! Application give me
this string \"");strcat(buff1,buff);strcat(buff1,“\”“); // 以上是组织反馈的信息
49
微计算机系统fwLength = strlen(buff1)+1;if (I.IoctlOutputBufferSize() >= fwLength){
strcpy((PCHAR)I.IoctlBuffer(),buff1);// 拷贝反馈信息I.Information() = fwLength; // 设置反馈信息字节数
}else{
I.Information() = 0;t << "buff size too small" << EOL;
}return status;
}
50
微计算机系统Test_Sample.cppvoid Test_SAMPLE_IOCTL_ReadWrite(void){
bufOutput is written by the device to return data to this application
CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to deviceCHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from deviceULONGnOutput; // Count written to bufOutput
// Call device IO Control interface (SAMPLE_IOCTL_ReadWrite) in driverprintf("Issuing Ioctl to device - ");strcpy(bufInput,"This is a sample.");if (!DeviceIoControl(hDevice, SAMPLE_IOCTL_ReadWrite, bufInput, strlen(bufInput),bufOutput, IOCTL_OUTBUF_SIZE, &nOutput, NULL) ){
printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); Exit(1);
}else
printf("Feedback is \"%s\"(%d)",bufOutput,nOutput); }
51
微计算机系统
52
微计算机系统
53
微计算机系统33 )直接对端口寄存器读写)直接对端口寄存器读写 DriverStudio提供了 KIoRange 类来将外部总线的 I/O地址空间范围映射到处理器总线的地址空间范围。
该类的成员函数主要有该类的成员函数主要有KIoRange 构造函数 (4 种格式 )Initialize 初始化和重新初始化一个实例 (3种格式 )~KIoRange 析构函数Invalidate 从已初始化状态删除该对象IsValid 测试该对象是否已经初始化inb 读一个或多个字节 (2 种形式 )Outb 写一个或多个字节 (2 种形式 )Inw 读一个或多个字 (2 种形式 )Outw 写一个或多个字 (2 种形式 )ind 读一个或多个双字 (2 种形式 )outd 写一个或多个双字 (2 种形式 )
54
微计算机系统KIoRange::KIoRangeKIoRange::KIoRange (只介绍(只介绍WDMWDM 形式)形式)FORM 3 (WDM):KIoRange( ULONGLONG CpuPhysicalAddress, ////转换成外围设备地址的转换成外围设备地址的 CPUCPU 总线上的物理地总线上的物理地址址 BOOLEAN InCpuIoSpace, //// 如果如果 IOIO范围是在范围是在 CPUCPU 总线的总线的 IOIO空间中为空间中为 TRUETRUE ,否则为,否则为 FAFALSELSE
ULONG Count, //// 以字节计的区域的大小以字节计的区域的大小 BOOLEAN MapToSystemVirtual =TRUE//// 指定是否需要构造函数创建一个非页系统指定是否需要构造函数创建一个非页系统空间的地址空间映射,如果驱动程序读写设备中的数据,就需要这种映射空间的地址空间映射,如果驱动程序读写设备中的数据,就需要这种映射);FORM 4 (WDM): ( 注意注意 : : 这种形式不被这种形式不被 DriverStudio 2.0DriverStudio 2.0 支持。支持。 )KIoRange( PCM_RESOURCE_LIST pTranslatedResourceList, //// 指向转换资源表的指针指向转换资源表的指针 ULONG Ordinal=0, //// 指定指定 pTranslatedResourceListpTranslatedResourceList 指向的资源列表中的一个特殊端口资源指向的资源列表中的一个特殊端口资源 BOOLEAN MapToSystemVirtual =TRUE);FORM 5 (WDM):KIoRange( PCM_RESOURCE_LIST pTranslatedResourceList, //// 可通过可通过 KIrp::TranslatedResourcesKIrp::TranslatedResources 获获得得 PCM_RESOURCE_LIST pRawResourceList, //// 指向原始资源表的指针指向原始资源表的指针 ULONG Ordinal=0, BOOLEAN MapToSystemVirtual =TRUE); 构造 KIoRange 类。
55
微计算机系统KIoRange::InitializeKIoRange::Initialize (只介绍(只介绍WDMWDM 形式)形式)FORM 2 (WDM):NTSTATUS Initialize( ULONGLONG CpuPhysicalAddress, BOOLEAN InCpuIoSpace, ULONG Count, BOOLEAN MapToSystemVirtual=TRUE);FORM 3 (WDM): ( 注意注意 : : 这种形式不被这种形式不被 DriverStudio 2.0DriverStudio 2.0 支持。支持。 )NTSTATUS Initialize( PCM_RESOURCE_LIST pTranslatedResourceList, ULONG Ordinal=0, BOOLEAN MapToSystemVirtual =TRUE);FORM 4 (WDM):Initialize( PCM_RESOURCE_LIST pTranslatedResourceList, PCM_RESOURCE_LIST pRawResourceList, ULONG Ordinal=0, BOOLEAN MapToSystemVirtual =TRUE);初始化或重新初始化初始化或重新初始化 KIoRangeKIoRange 的实例。的实例。
56
微计算机系统
KIoRange::inbKIoRange::inbFORM 1:UCHAR inb( ULONG ByteOffset );FORM 2:VOID inb( ULONG ByteOffset, PUCHAR Buffer, ULONG Count);从映射空间读一个或多个字节。
57
微计算机系统
KIoRange::outbKIoRange::outbFORM 1:VOID outb( ULONG ByteOffset,//// 以字节为单位的目标位置到以字节为单位的目标位置到 IOIO空间开始位置的偏移空间开始位置的偏移值值 UCHAR Data //// 要写的一个字节数据要写的一个字节数据);FORM 2:VOID outb( ULONG ByteOffset, PUCHAR Buffer,//// 指向包含要写数据的缓冲的指针指向包含要写数据的缓冲的指针 ULONG Count //// 缓冲中要写数据的字节数缓冲中要写数据的字节数);写一个或多个字节到映射的写一个或多个字节到映射的 IOIO空间。空间。
58
微计算机系统
• 写端口( 索引信息 , 地址 70H ) m_ParPortIos.outb(0,0x02); // // 准备读分钟信息准备读分钟信息
• 读端口(读分钟信息,地址 71H )UCHAR data = m_ParPortIos.inb(1);
下面我们来访问 CMOS 的数据。• 首先定义类 KIoRange 的一个实例,以定义相关地址空间。KIoRange m_ParPortIos;• 初始化实例(指定 CMOS 的端口首地址,并映射)status = m_ParPortIos.Initialize( 0x70, // CMOS// CMOS 端口首地址是端口首地址是 70H70H
TRUE, //// 在在 CPU I/OCPU I/O空间内空间内 8, // // 设备读写数据的字节宽度设备读写数据的字节宽度 TRUE // // 映射到系统空间映射到系统空间 );
59
微计算机系统44 ))截获中断和挂接中断服务例程截获中断和挂接中断服务例程 DriverStudio提供了 KInterrupt 类来截获和挂接中断。 该类的成员函数主要有KInterrupt 构造函数 (3种格式 )Initialize 在无效状态下初始化一个对象 (3种格式 )Connect 绑定 ISR (中断服务例程)到中断InitializeAndConnect 一步完成初始化与绑定工作,要用资源列表作为输入。~KInterrupt~KInterrupt 析构函数InvalidateInvalidate 在初始化状态下删除对象IsValidIsValid 检查对象是否初始化DisconnectDisconnect 使中断和 ISR与中断分离SynchronizeSynchronize 当得到一个中断自旋锁时请求同步功能
60
微计算机系统
KInterrupt::KInterrupt(KInterrupt::KInterrupt( 只介绍只介绍WDMWDM形式)形式)FORM 3: (WDM)KInterrupt( KIRQL irql, //// 即插即用设备提供的即插即用设备提供的 IRQLIRQL值值 ULONG vector, //// 即插即用设备提供的向量值即插即用设备提供的向量值 KINTERRUPT_MODE Mode,//LevelSensitive//LevelSensitive 或 或 LatchedLatched 中选一中选一 ..
BOOLEAN bShareVector=FALSE, //// 该向量是否被几个设备共享该向量是否被几个设备共享 KAFFINITY affinity=1, //this is the processor affinity mask.//this is the processor affinity mask.
BOOLEAN bSaveFloat =FALSE //// 是否需要在中断到来使保存浮是否需要在中断到来使保存浮点处理器上下文,点处理器上下文, X86X86 平台下必须使平台下必须使 FALSEFALSE
);构造类 Kinterrupt 的实例。
61
微计算机系统KInterrupt::InitializeKInterrupt::Initialize (只介绍(只介绍WDMWDM形式)形式)
FORM 2: (WDM)VOID Initialize( KIRQL irql, ULONG vector, KINTERRUPT_MODE Mode, BOOLEAN bShareVector=FALSE, KAFFINITY affinity=1, BOOLEAN bSaveFloat=FALSE);初始化对象。只在对象没有初始化的时候使用。
62
微计算机系统KInterrupt::ConnectKInterrupt::ConnectFORM 1:NTSTATUS Connect( PKSERVICE_ROUTINE Isr, //// 作为作为 ISRISR 服务的函数的地址服务的函数的地址 PVOID Context ////当系统调用当系统调用 ISRISR 的时候传递给他的无类型的参数的时候传递给他的无类型的参数);FORM 2:NTSTATUS Connect( PKSERVICE_ROUTINE Isr, PVOID Context, PKSPIN_LOCK pSpin, KIRQL SynchIrql);绑定一个中断到 ISR( 中断处理程序)。
63
微计算机系统
KInterrupt::InitializeAndConnectKInterrupt::InitializeAndConnectNTSTATUS InitializeAndConnect( PCM_RESOURCE_LIST pResourceList, //// 指向资源列表的指指向资源列表的指针针 PKSERVICE_ROUTINE Isr, PVOID IsrContext, ULONG Ordinal=0, BOOLEAN bSaveFloat=FALSE);初始化一个中断并绑定到一个初始化一个中断并绑定到一个 ISRISR 上。上。
对于 对于 WDM WDM 驱动程序,驱动程序, pResourceListpResourceList 必须是一个转必须是一个转换资源表,例如是换资源表,例如是 KIrp::TranslatedResourcesKIrp::TranslatedResources 的返回的返回值。值。
64
微计算机系统下面我们来举例说明。• 首先定义类 KInterrupt 的一个实例 KInterrupt m_TheInterrupt; • 在设备类中声明一个成员函数 TheIsr 作为中断服务例程 ISR 。 class SampleDevice : public KPnpDevice{ …… public:
MEMBER_ISR (SampleDevice, TheIsr); ……
#ifdef _COMMENT_ONLY BOOLEAN TheIsr ( void ) { return TRUE ; };
#endif ……}
65
微计算机系统• 在 OnStartDevice 例程中获取包括中断的设备资源并初始化中断和挂接 ISR
SampleDevice ::OnStartDevice(KIrp I){……PCM_RESOURCE_LIST pResList = I.TranslatedResources(); //获取设备资源//初始化中断并挂接中断服务例程 TheIsrstatus = m_TheInterrupt.InitializeAndConnect(
pResList, LinkTo(TheIsr), this);
……}
66
微计算机系统55 ))如何写如何写 Win32Win32 类型的驱动程序的测试类型的驱动程序的测试程序程序 DriverStudio 自动生成的驱动程序的测试程序是一个控制台程序,下面我们将利用该控制台程序来写一个 Win32的程序。 第一步,在由 DriverStudio 自动生成一个驱动程序工作区 (Workspace) 中添加一个新的子工程,该子工程指定为一个 MFC 的 EXE 程序。 右键点击
67
微计算机系统
68
微计算机系统第二步,手工在新的工程中添加几个文件
这几个程序需要手工添加进去,实际上这几个程序都在 DriverStudio 自动生成的原来的两个工程文件中 ( 这个例子是 MyIOPort和 Test_MyIOPort 工程 )。将他们添加到新工程中,方法是右键点击新工程中的相关文件夹,在弹出菜单中选择 Add Files to Folder… ,然后找到要添加的文件并添加。
69
微计算机系统第三步,打开 OpenByIntf.cpp 文件,在开始第一行添加#include "stdafx.h"
第四步, 1
2
3 4
5C:\PROGRAM FILES\COMPUWARE\SOFTICE C:\PROGRAM FILES\COMPUWARE\SOFTICE DRIVER SUITE\DRIVERWORKS\INCLUDEDRIVER SUITE\DRIVERWORKS\INCLUDE
70
微计算机系统第五步, 1
2
3
4
setupapi.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib setupapi.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
可以直接从自动生成的控制台工程的设置中拷贝这些库的名称
71
微计算机系统最后,在控制台程序的 Test_XXXX.CPP 程序基础上进行必要的修改。注意要保留的是打开设备、关闭设备、读写设备有关的函数。界面部分应该全部换成 Windows 界面的代码,而不是保留控制台代码。