一个VB程序, 2点要求:
1、关闭时弹出对话框要求用户进行关闭确认
2、关机时不需要确认.
这里的问题是如何识别退出和关机。
1、软件关闭确认的实现
程序退出时会进入 Form_QueryUnload,弹出对话框要求用户进行关闭确认
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) Dim res As Long res = MsgBox("Confirm?", vbYesNo) If res = vbNo Then Cancel = 1 ' cancel Else For Each f In Forms Unload f Next End ' close End If End Sub
|
2、截获关机消息
前面实现的软件关闭确认会影响正常关机:关机时也会要求确认。所以我们要截取关机消息,设置一个bool变量从而绕过软件关闭确认对话框。
添加一个模块 Module1.bas,代码如下:
Public lpPrevWndProc As Long '存放原窗口函数句柄 Public Const GWL_WNDPROC = -4& '指定替换原窗口函数常数 Public gShutdown As Boolean '关机时设置此变量从而绕过软件关闭确认对话框 Public fno As Long '调用指定窗口函数的API函数定义 Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long '设置Windows长参数的API函数定义 '(本程序中设置指定窗口函数替换原窗口函数,返回原窗口函数地址,当nIndex=GWL_WNDPROC) Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long '我们自己的窗口函数 Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long If uMsg = 17 Then ' WM_QUERYENDSESSION gShutdown = True Else If uMsg = 22 Then ' WM_ENDSESSION If wParam = 0 Then '代表将顺利关机或LogOff,这时便得做正常结束程序的操作 gShutdown = True End If End If End If '将之送往原来的Window Procedure WindowProc = CallWindowProc(lpPrevWndProc, hWnd, uMsg, wParam, lParam) End Function
|
主窗体 Form.frm 是要进行“子类处理”的窗体,其中加入代码如下:
Private Sub Form_Load() '设置Form1的新窗口函数为WindowProc,将原窗口函数地址送lpPrevWndProc lpPrevWndProc = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WindowProc) gShutdown = False End Sub
|
进行“子类处理”的窗体在卸载前要恢复原窗口函数,我们在 Form_QueryUnload 中执行下面的语句
SetWindowLong(hW, GWL_WNDPROC, lpPrevWndProc)
所以最终的 Form_QueryUnload 如下:
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) Dim Temp As Long Dim f As Form Dim res As Long ' 非关机时要求确认软件关闭操作 If gShutdown Then res = vbYes Else res = MsgBox("Confirm?", vbYesNo) End If If res = vbNo Then Cancel = 1 ' cancel Else
'恢复原窗口函数 Temp = SetWindowLong(hW, GWL_WNDPROC, lpPrevWndProc)
For Each f In Forms Unload f Next End ' close End If End Sub
|
附录:
《打印调试信息》
3种方法打印调试信息:
1、VB6.0开发环境中使用 Debug.print "message" 将信息输出到立即窗口。
2、使用文件操作将信息输出到文件。
例如:
str = Time() & "hWnd=" & hWnd & ",Msg=" & uMsg & ",wP=" & wParam & ",lP=" & lParam
fno = FreeFile
Open "c:\log.txt" For Append As fno
Print #fno, str
Close #fno
3、使用管道命令。
例如:
Shell ("cmd /c echo ” & str & “ >> c:\log.txt")
如果打印信息的频率高、量多,使用第2种方式。这种方式生成数据文件,可作进一步处理和分析。
调试时你可以在 WindowProc 中打印出所有的消息号:比较手动关闭软件和关机时窗体都截获了哪个消息(提示:利用sort命令对消息号排序),消息号 17、22 各出现1次,它们是关机时系统发送给程序的消息。
《全局变量的位置》
全局变量定义如:
Public gShutdown As Boolean
注意,不能把它定义在 Form.frm中 否则 Module1.bas 中不能引用 —— 如果你引用了,VB6.0 不会提示你不能这么做~ 然后你开始寻找一个莫名其妙的bug...
再补充一点:使用语句 Option Explicit 要求变量声明。
第一次 我在Form.frm中要求变量声明并且定义全局变量 gShutdown,然后在 Module1.bas 中引用之,结果被VB6.0玩了。
第二次 我在Form.frm中要求变量声明并且定义全局变量 gShutdown, 在Module1.bas 中也要求变量声明,然后在 Module1.bas 中引用之,结果点击Run按键时IDE挂了。
第三次 在Module1.bas中定义全局变量 gShutdown,OK。
越是高级的语言越抽象——VB太高级了~ 太抽象了~ 我还是喜欢C!
参考:
阅读(4457) | 评论(1) | 转发(0) |