一个端口访问器的编写 — Windows XP驱动程序举例 VS.NET+WIN XP DDK+DriverStudio3.2开发环境版

Slides:



Advertisements
Similar presentations
软件开发技术基础 第 3 章 操作系统及程序设计 讲授教师:卫颜俊. 主 要 内 容 主 要 内 容 操作系统及其功能 进程管理应用程序设计 内存管理应用程序设计 设备与文件管理应用程序设计 人机接口管理应用程序设计.
Advertisements

现代电子技术实验 ——综合实验之单片机部分
项目7 面向对象高级.
无锡商业职业技术学院 机电工程学院党总支孙蓓雄
全面了解入党程序 认真履行入党手续 第一讲 主讲人:陈亭而.
中共湖北大学知行学院委员会党校 入党材料规范填写指导 学工处 李华琼 二〇一三年十二月.
云南财经大学2010年党员发展培训—— 党员发展工作培训 校党委组织部 2010年9月17日.
医师变更执业注册申请审核表 填写说明 医务部.
四資二甲 第三週作業 物件導向程式設計.
經濟部工業局 產業升級創新平台輔導計畫 (創新優化計畫)
第一章 C语言概述 计算机公共教学部.
几种常见应用文体示例.
2014年工作总结 暨2015年工作展望.
公 文 写 作 第一讲 主讲教师:娄淑华          学时:32.
第八章 诉讼法 第一节 诉讼法概述 第二节 民事诉讼法 第三节 行政诉讼法 第四节 刑事诉讼法.
第8章 机床操作 主讲:臧红彬 博士.
BIOS设置.
第 5 章 流程控制 (一): 條件分支.
客户端入门十二小时 FOOLFLY DEMO DESIGN 讲师:林伟.
第二章 JAVA语言基础.
吉林大学远程教育课件 Windows A P I编 程 (第四十五讲) 主讲人 : 翟慧杰 学 时:48.
Chapter 13 輸入/輸出系統 (I/O Systems)
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
通 知 通知是批转下级机关的公文,转发上级机关和不相隶属机关的公文,传达要求下级机关办理和需要有关单位周知或执行的事项,任免人员时使用的公文。
CH2 開發環境介紹 最簡單的互動設計 – Arduino一試就上手 孫駿榮、吳明展、盧聰勇.
第一章 计算机基础知识 计算机基础知识.
第二章 C# 基础知识.
Timer & KEYPAD 11/24.
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
Windows98/2000驱动程序编写方法 (下) 杨全胜.
EBNF 请用扩展的 BNF 描述 C语言里语句的结构; 请用扩展的 BNF 描述 C++语言里类声明的结构;
基于无线充电的心 率脉搏监测系统 IDT无线充电应用创新大赛.
程式敘述執行順序的轉移 控制與重複、方法 Lecturer:曾學文.
第3章 語法入門 第一個Java程式 文字模式下與程式互動 資料、運算 流程控制.
第二讲 搭建Java Web开发环境 主讲人:孙娜
C 程式設計— 控制敘述 台大資訊工程學系 資訊系統訓練班.
第4讲 Windows编程基础 此为封面页,需列出课程编码、课程名称和课程开发室名称。
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第三章 C++中的C 面向对象程序设计(C++).
把COM口设置到没有使用的 COM1 – COM4
大学计算机基础 典型案例之一 构建FPT服务器.
辅导课程六.
第3章 Windows 应用程序基础 2018/12/6 第2讲 Windows 应用程序基础 VC++面向对象与可视化程序设计.
第十一讲 MFC常用控件的使用(3) 严宣辉 数学与计算机科学学院
MFC WinSock类的编程 为简化套接字网络编程,更方便地利用Windows的消息驱动机制,微软的基础类库(Microsoft Foundation Class Libary,简称MFC),提供了两个套接字类,在不同的层次上对Windows Socket API函数进行了封装,为编写Windows.
网络游戏开发语言基础 ——Windows程序设计
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
JTAG INTERFACE SRAM TESTER WITH C-LCM
如何生成设备节点 广州创龙电子科技有限公司
第三章 C# 基础知识.
程式結構&語法.
判別下列何者是 x 的多項式。以「○」表示是x的多項式,「×」表示不是 x的多項式 :
基础篇 微型计算机系统 硬件系统 软件系统 操作系统基础 作业 计算机编码和数制 系统综述.
第二章 Java基本语法 讲师:复凡.
主标题 副标题 日期.
Xxxx集团有限公司 封面页.
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第二章 Java语法基础.
iSIGHT 基本培训 使用 Excel的栅栏问题
第10章媒体控制接口 10.1 MCI设备类型 10.2 MCI编程步骤 10.3使用MCIWnd窗口类.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
Go 语言编程 —— 平台研发部 吴植民.
单片机应用技术 (C语言版) 第4章 C51程序设计入门
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
第2章 Java语言基础.
第二章 Java基础语法 北京传智播客教育
8的乘法口诀 导入 新授 练习.
Presentation transcript:

一个端口访问器的编写 — Windows XP驱动程序举例 VS.NET+WIN XP DDK+DriverStudio3.2开发环境版 东南大学计算机科学与工程学院 杨全胜

本讲义假设阅读者已经熟悉VC++. NET和VS 本讲义假设阅读者已经熟悉VC++.NET和VS.NET(2002)的使用。如果对Window XP驱动程序的编写尚不熟悉,请参阅本人所编写的《Windows XP驱动程序编写方法——Step by Step》电子讲义。 注意:程序中暗红色显示的部分是我们添加或修改过的语句,其他是DriverWorks自动生成的。蓝色显示的部分是要删除的语句。省略号的部分是不变的。语句中T.Trace(TraceInfo, __FUNCTION__“xxxx”)这样的语句是向调试软件输出信息,该信息可在DriverMonitor或其他调试监视器中看到。

2次

由于一个可能是DriverStudio 3.2中的BUG,所以及时生成的一个空工程项目也无法编译通过,需要对生成的工程文件做以下手工修改: 把MyIOPort项目中的sources文件中的:  TARGETLIBS=$ (DDK_LIB_PATH)\ntstrsafe.lib $ (DDK_LIB_PATH)\csq.lib   这一行去掉就可以编译通过了

在“MyIOPortDevice.h”文件的 class MyIOPortDevice : public KPnpDevice定义中添加下面的变量定义。 protected: // Member data KIoRange m_ParPortIos; 注意:程序中暗红色显示的部分是我们添加或修改过的语句,其他是DriverWorks自动生成的。蓝色显示的部分是要删除的语句。省略号的部分是不变的。语句中T.Trace(TraceInfo, __FUNCTION__“xxxx”)这样的语句是向调试软件输出信息,该信息可在DriverMonitor或其他调试监视器中看到。

修改下面函数代码: NTSTATUS MyIOPortDevice::OnStartDevice(KIrp I) { T.Trace(TraceInfo, __FUNCTION__"++. IRP %p\n", I); NTSTATUS status = STATUS_SUCCESS; I.Information() = 0; // Get the list of raw resources from the IRP PCM_RESOURCE_LIST pResListRaw = I.AllocatedResources(); // Get the list of translated resources from the IRP PCM_RESOURCE_LIST pResListTranslated = I.TranslatedResources(); // TODO: Add device-specific code to initialize/start your hardware device. // The base class will handle completion of the IRP status = m_ParPortIos.Initialize( 0x00, // PC机I/O地址空间的首地址是00H TRUE, // 在CPU I/O空间内 8, // 设备读写数据的字节宽度 TRUE // 映射到系统空间 ); T.Trace(TraceInfo, __FUNCTION__"--. IRP %p, STATUS %x\n", I, status); return status; }

下面的函数保留和添加下述语句,其他全部删除 NTSTATUS MyIOPortDevice::MYIOPORT_IOCTL_Read_Handler(KIrp I) { T.Trace(TraceInfo, __FUNCTION__"++. IRP %p\n", I); NTSTATUS status = STATUS_SUCCESS; ULONG outputSize = I.IoctlOutputBufferSize(); char buff1[50],buff2[50]; struct ioport { int port; UCHAR data; } *iopt; ULONG fwLength=0; iopt=(ioport *)I.IoctlBuffer(); // 指针直接指向IRP的BUFF区域这里进 //来的时候有用户程序的信息,出去的时候放返回信息 //显示从应用程序得到的要读的端口号。 T.Trace(TraceInfo, __FUNCTION__"Read port is 0x%d\n", iopt->port );

// 从端口读一个字节的数据 iopt->data= (UCHAR)m_ParPortIos.inb(iopt->port); fwLength = 8; if (outputSize >= fwLength) // 如果读入缓冲够长 { I.Information() = fwLength; // 返回信息长度 T.Trace(TraceInfo, __FUNCTION__"Read Data is 0x%d\n", iopt->data); // 显示从应用程序得到的命令串。 } else { I.Information() = 0; // 否则信息长度为0 T.Trace(TraceInfo, __FUNCTION__"buff size too small\n"); T.Trace(NT_SUCCESS(status)?TraceInfo:TraceWarning, __FUNCTION__"--. IRP %p, STATUS %x\n", I, status); return status;

NTSTATUS MyIOPortDevice::MYIOPORT_IOCTL_Write_Handler(KIrp I) { T.Trace(TraceInfo, __FUNCTION__"++. IRP %p\n", I); NTSTATUS status = STATUS_SUCCESS; char buff1[50],buff2[50]; struct ioport { int port; UCHAR data; } *iopt; ULONG fwLength=0; iopt=(ioport *)I.IoctlBuffer(); // 指针直接指向IRP的BUFF区域这里进来的时候有用户程序的信息,出去的时候放返回信息 T.Trace(TraceInfo, __FUNCTION__"Write port is 0x%d, Write data is 0x%d\n", iopt->port , iopt->data ); // 显示从应用程序得到的命令串。 m_ParPortIos.outb(iopt->port,iopt->data); // 向端口写一个字节的数据 I.Information() = 0; T.Trace(NT_SUCCESS(status)?TraceInfo:TraceWarning, __FUNCTION__"--. IRP %p, STATUS %x\n", I, status); return status; }

下面我们来修改应用程序,该程序访问硬件端口来获得CMOS中的数据以及让主板小喇叭发声。首先要修改一下应用程序项目的属性中的字符集。缺省的字符集是“使用 Unicode 字符集”,把它改成“未设置”。 右键点击

接下来我们修改资源文件。下图是系统自动生成的应用程序界面,这并不适合我们的需要。删除这些控件,换上下页显示的控件。 全部删除

Static Text List Control Button 在对话框中分别建立如图的三个按钮,一个列表控件(List Control)和一个静态文本框。其中,列表控件和按钮的属性如下页的图设置。

在“MyIOPortApp.h”文件中增加下列函数声明 UCHAR ReadOneByte(int port); // 从port读一个字节 void WriteOneByte(int port, UCHAR value); // 向端口port写一个字节 BOOL OpenMyDevice(); // 打开设备 void Silence( void ); // 静音 void Sound(DWORD freq ); // 发频率为freq的声音 void OnReadcmos(HWND hDlg); // 读CMOS

在“MyIOPortApp.cpp”文件中增加下列函数: UCHAR ReadOneByte(int port) { char buff[200]; ULONG nOutput; // Count written to bufOutput struct ioport { int port; UCHAR data; } iopt,iopt2; iopt.port=port; if (!DeviceIoControl(g_hDevice, MYIOPORT_IOCTL_Read, &iopt, //输出到驱动程序 sizeof(iopt), //IOCTL_INBUF_SIZE, &iopt2, // 从驱动程序得到返回值 8, &nOutput, NULL) )

{ sprintf(buff,"ERROR: DeviceIoControl returns %0x.", GetLastError()); ::MessageBox(NULL,buff,"错误", MB_OK|MB_ICONSTOP); return 0; } else return iopt2.data;

void WriteOneByte(int port, UCHAR value) { char buff[200]; ULONG nOutput; struct ioport { int port; UCHAR data; } iopt,iopt2; iopt.port=port; iopt.data=value; if (!DeviceIoControl(g_hDevice, MYIOPORT_IOCTL_Write, &iopt, //输出到驱动程序 sizeof(iopt), //IOCTL_INBUF_SIZE, &iopt2, // 从驱动程序得到返回值 8, &nOutput, NULL) )

{ sprintf(buff,"ERROR: DeviceIoControl returns %0x.", GetLastError()); ::MessageBox(NULL,buff,"错误", MB_OK|MB_ICONSTOP); return ; }

BOOL OpenMyDevice() { DWORD lastError; HDEVINFO hDeviceInfo; DWORD bufferSize; SP_DEVICE_INTERFACE_DATA interfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail; // Find devices that have our interface hDeviceInfo = SetupDiGetClassDevs( (LPGUID)&GUID_DEVINTERFACE_MYIOPORT, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

if (hDeviceInfo == INVALID_HANDLE_VALUE) { lastError = GetLastError(); MyIOPortOutputText(_T("SetupDiGetClassDevs failed, GetLastError() = %d"), lastError); return FALSE; } // Setup the interface data struct interfaceData.cbSize = sizeof(interfaceData); if(SetupDiEnumDeviceInterfaces(hDeviceInfo,NULL, (LPGUID)&GUID_DEVINTERFACE_MYIOPORT, 0,&interfaceData)) if (!SetupDiGetDeviceInterfaceDetail( hDeviceInfo,&interfaceData, NULL,0,&bufferSize,NULL))

if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { MyIOPortOutputText(_T("Error: couldn't get interface detail, (%d)"), GetLastError()); return FALSE; } // Allocate a big enough buffer to get detail data deviceDetail= (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(bufferSize); if (deviceDetail == NULL) MyIOPortOutputText(_T("Error: Buffer allocation failed")); // Setup the device interface struct deviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

// Try again to get the device interface detail info if (!SetupDiGetDeviceInterfaceDetail( hDeviceInfo, &interfaceData, deviceDetail, bufferSize, NULL, NULL)) { MyIOPortOutputText(_T("Error: SetupDiGetDeviceInterfaceDetail failed (%d)"), GetLastError()); free(deviceDetail); return FALSE; } SetupDiDestroyDeviceInfoList(hDeviceInfo);

g_hDevice = CreateFile( (LPCTSTR)deviceDetail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,0); if (g_hDevice == INVALID_HANDLE_VALUE) { MyIOPortOutputText(_T("Error: CreateFile failed for device %s (%d)\n"), deviceDetail->DevicePath, GetLastError()); return FALSE; } MyIOPortOutputText(_T("Opened device %s"), deviceDetail->DevicePath); return TRUE; MyIOPortOutputText(_T("No devices found"));

void Sound(DWORD freq ) { UCHAR data; if(freq>=20 && freq<=20000) freq = 1193181 / freq; data = ReadOneByte(0x61); if((data & 3) == 0) WriteOneByte(0x61, data | 3); WriteOneByte(0x43, 0xb6); } WriteOneByte(0x42, (UCHAR)(freq%256)); WriteOneByte(0x42, (UCHAR)(freq/256));

void Silence( void ) { UCHAR data; data = ReadOneByte(0x61); WriteOneByte(0x61, data & 0xfc); }

void OnReadcmos(HWND hDlg) { // TODO: Add your control notification handler code here int i,it; char buff[23]; char cmosram[128][200]={ // CMOS每个字节的含义 "目前系统时间的秒", "报警时间秒值", "目前系统时间的分", "报警时间分值", "目前系统时间的小时", "报警时间小时值", "目前星期几", "目前系统日期", "目前系统月份", "目前系统年的后两位",

"状态寄存器A", "状态寄存器B", "状态寄存器C", "状态寄存器D", "诊断状态记录值", "当机复位指示字节", "磁盘驱动器类型:xxxx.... 软驱0类型 0001=360K 0010=1.2M ....xxxx 软驱1类型 0011=720K 0100=1.44M 0110=2.88M", "(海洋板)..x..... 硬盘0Translate 1=Yes 0=No ...x.... 硬盘1Translate 1=Yes 0=No .....x.. 1=Step rate fast 0=Step rate slow ......xx 软驱个数00=1个 01=2个 10=三个 11=四个 ", "硬盘类型:xxxx.... 硬盘驱动器0的类型 1111=使用19h单元 ....xxxx 硬盘驱动器1的类型 1111=使用1Ah单元", "字节 x....... 1=Anti-Virus 硬盘Boot区写保护 0=disable .xxx.... 软驱2类型 ....xxxx 软驱3类型",

"所安装设备的类型:xx. 00=1个软驱,01=2个软驱,. xx "所安装设备的类型:xx...... 00=1个软驱,01=2个软驱,..xx.... 00=单显 01=CGA 10=CGA 11=VGA/EGA,后四位高到低是显示、键盘、协处理器与软件机使能(=1)", "基本内存容量低字节,单位KB", "基本内存容量高字节,单位KB", "扩充内存容量低字节,单位KB", "扩充内存容量高字节,单位KB", "(海洋板)硬盘驱动器0的类型", "(海洋板)硬盘驱动器1的类型", "(海洋板)显示卡类型 VGA/monochrome", "(海洋板)....xxxx 启动顺序0=A:C: 1=C:A: 2=Screen prompt 3=Auto search 4=Network .x...... 486-CPU Cache 0=disable 1= enable ", "(海洋板)x....... 1=键盘使用缺省参数 0=使用本单元值 .xx..... 键盘延时00=0.25秒01=0.5秒10=0.75秒11=1秒 ...xxxxx 键盘重发速率,单位cps",

"(海洋板)硬盘1的柱面数", "(海洋板)硬盘1的磁头数", "(海洋板)硬盘1的扇区数", "(海洋板)硬盘0的柱面数", "(海洋板)硬盘0的磁头数", "(海洋板)硬盘0的扇区数", "(海洋板)AT-Bus clock 0=16.7Mhz 1=13.3Mhz 2=11.1Mhz 3=8.3Mhz 4=6.7Mhz 5=5.6Mhz 6=4.2Mhz", "(海洋板)memory type 00h=60nS 20h=70nS", "串口配置", "并口配置", "未使用",

"标准CMOS校验和", "扩充内存容量低字节,单位KB", "BCD码的世纪值(年的高2位,如19,20等)", "信息标志", "xxxx.... Shadow of D000 0=Vacant ....xxxx Shadow of C000 0=ROM ", "xxxx.... Shadow of F000 0=ROM ....xxxx Shadow of E000 0=Vacant ", "xxxx.... Shadow of D000 1=WP 0=Read/Write ....xxxx Shadow of C000 1=WP 0=Read/Write ", "xxxx.... Shadow of F000 1=WP 0=Read/Write ....xxxx Shadow of E000 1=WP 0=Read/Write ", "内存大小,单位兆", "(内存大小有关=160/前一单元 )", "口令代码Security Code",

"xx. 口令检测方式 0=Disable 1=Setup only 2=Powerup&Setup 3=Bootup&Setup "xx...... 口令检测方式 0=Disable 1=Setup only 2=Powerup&Setup 3=Bootup&Setup ..xxxxxx Cold-Boot Delay 冷启动延时(单位秒)*2 ", "xxxx.... 4=Full test 5=Quick scan 7=Skip test ....xx.. Xfer-Mode of 硬盘0 0=Standard 1=Poll ......xx Xfer-Mode of 硬盘1 2=Block 3=32-Bit Block ", "10h-3Dh部分单元的按字节检查和,不包括17h,18h,19h,1Ah,26h, 27h,30h,31h,32h,38h,3Ah,3Ch,3Dh单元 ", "保留",

"保留",

"保留",

"保留",

"保留", "保留" }; LVITEM lvitem; HWND hWnd; hWnd = GetDlgItem(hDlg, IDC_CMOSLIST); BOOL qu; UCHAR index,value,tmp; for(i=0;i<128;i++) { lvitem.mask = LVIF_TEXT|LVIF_STATE; lvitem.iItem = i; lvitem.iSubItem = 0; sprintf(buff,"%02XH",i); lvitem.pszText = buff;

SendMessage(hWnd,LVM_INSERTITEM,0,(LPARAM)&lvitem); lvitem.mask = LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 1; tmp = (UCHAR)i; index = 0x80 | tmp; WriteOneByte(0x70,index); value = ReadOneByte(0x71); sprintf(buff,"%02XH",value); SendMessage(hWnd,LVM_SETITEM,0,(LPARAM)&lvitem); lvitem.iSubItem = 2; lvitem.pszText = cmosram[i]; }

下面增加关键的消息处理: LRESULT CALLBACK MyIOPortMainDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { …… switch (uMsg) case WM_INITDIALOG: g_hDevice = INVALID_HANDLE_VALUE; // 初始化List Control hWnd = GetDlgItem(hDlg, IDC_CMOSLIST); RECT rect; GetWindowRect(hWnd,&rect); LVCOLUMN lvm;

strcpy(lvm.pszText,"偏移"); lvm.cx = (rect.right - rect.left)/10; lvm.iSubItem = 0; lvm.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; lvm.fmt = LVCFMT_CENTER; SendMessage(hWnd,LVM_INSERTCOLUMN,0,(LPARAM)&lvm); strcpy(lvm.pszText,"值"); lvm.iSubItem = 1; SendMessage(hWnd,LVM_INSERTCOLUMN,1,(LPARAM)&lvm); lvm.cx = (rect.right - rect.left)*4/5; lvm.iSubItem = 2; SendMessage(hWnd,LVM_INSERTCOLUMN,2,(LPARAM)&lvm);

if(OpenMyDevice()) { EnableWindow(GetDlgItem(hDlg, IDC_READCMOS), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_SPEAKER), TRUE); } else EnableWindow(GetDlgItem(hDlg, IDC_READCMOS), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_SPEAKER), FALSE); // 此处还有DS自动生成的程序段,需全部删除 return 1; case WM_COMMAND: switch (LOWORD(wParam)) case IDOK: if (g_hDevice != INVALID_HANDLE_VALUE)

CloseHandle(g_hDevice); g_hDevice = INVALID_HANDLE_VALUE; } // Terminate our I/O completion thread SetEvent(g_hIoCompletionThreadTerminationEvent); WaitForSingleObject(g_hIoCompletionThread, INFINITE); UnregisterDeviceNotification(g_hInterfaceNotification); EndDialog(hDlg, 0); PostQuitMessage(0); break; case IDC_SPEAKER: // C调 Sound(262); // 1 = 262 Hz Sleep(200); Silence(); Sound(288); // 2 = 294 Hz

Sound(330); // 3 = 330 Hz Sleep(200); Silence(); break; case IDC_READCMOS: OnReadcmos(hDlg); default: } ……

做完上述添加后,将下列在MyIOPortApp.cpp文件中DS自动生成的部分删除: DWORD MyIOPortEnumerateDevices(HWND hDlg) { …… // 该函数全部删除 } HANDLE MyIOPortOpenDevice(HWND hDlg) 删除下列消息的处理程序: WM_DEVICECHANGE,IDC_OPEN_BUTTON,IDC_CLOSE_BUTTON,IDC_OP_TYPE_COMBO IDC_DEVICE_INSTANCE_LIST,IDC_EXECUTE_BUTTON,IDC_CANCEL_IO_BUTTON

1)右键点击 2)选择该项目

1)右键点击 2)选择该项目