有一个DOS程序,在98下运行,每当我试图关闭时,都会弹出"windows无法自动关闭此程序,建议使用退出命令退出."并且问"是否终止该程序并放弃程序中未保存的信息.",同样在关机,重启或注销时,这个对话框会弹出,这一点很不好,因为这样就没法正常关机了,我希望在关机的时候他可以自动关掉,不会拖泥带水,于是编了另一程序,编这个程序的初衷是可以拦截到系统向dos程序发送的关机消息,在此之前关掉dos程序,但失败了,于是前两天发了个贴子求助,某位仁兄提供了一个"保证没错"的代码,结果还是不成功,于是我想是不是1.在它的电脑里面他编的那个程序可以在dos程序之前接受到关机消息,2.dos程序绝对不能接受到关机消息,否则必然会弹出那个该死的对话框?,3.如何设定这两个程序接受到关机消息的先后顺序,4.可不可以为dos程序设定一个模块来拦截关机消息? 5.两个程序接受到关机消息的时间差可以忽略不及么? 6.到底怎么才能完美的实现:通过运行一个自编的应用程序,保证另一个dos程序在关机时不会弹出任何对话框,从而保证正常关机?
[email protected]
所以我又添加了一个timer函数,在timer中用另外一个程序关闭这个窗口,调试成功,有新的问题再次联系。测试方法如下
先打开两个dos窗口
运行project1.exe
再打开两个dos窗口
注销,dos窗口先打开的直接被关闭,后打开的出现立即结束窗口后被关闭,速度取决于timer的设定测试环境: xp, vb6代码如下'窗体
Option ExplicitPrivate Sub Form_Load()
Me.AutoRedraw = True
oldwinproc = GetWindowLong(Me.hwnd, GWL_WNDPROC)
SetWindowLong Me.hwnd, GWL_WNDPROC, AddressOf OnMenu
End Sub
Private Sub Form_Unload(Cancel As Integer)
SetWindowLong Me.hwnd, GWL_WNDPROC, oldwinproc
End SubPrivate Sub Timer1_Timer()
CloseConsole1
End Sub'模块
Option ExplicitPublic Const WM_SYSCOMMAND = &H112
Public Const WM_QUERYENDSESSION = &H11
Public Const PROCESS_TERMINATE = &H1
Public Const GWL_WNDPROC = (-4)
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
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
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public oldwinproc As Long
Public g__caption As String
Public g__hwnd As Long
'查询是否关机并且关闭dos窗口
Public Function OnMenu(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case wMsg
Case WM_QUERYENDSESSION
Form1.WindowState = 0
Form1.Cls
Form1.Print "系统要关机了"
CloseConsole
Case WM_SYSCOMMAND
Case Else
End Select
OnMenu = CallWindowProc(oldwinproc, hwnd, wMsg, wParam, lParam)
End Function
'枚举并且关闭
Public Function CloseConsole() As Long
EnumWindows AddressOf EnumProc, 0
CloseConsole = 1
End Function'枚举回调函数
Public Function EnumProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim s As String * 255
Dim s1 As String
Dim i As Integer
GetClassName hwnd, s, 255
For i = 1 To 255
If Mid(s, i, 1) <> Chr(0) Then
s1 = s1 & Mid(s, i, 1)
Else
Exit For
End If
Next i
If s1 = "ConsoleWindowClass" Then
GetWindowText hwnd, s, 255
TerminateProcessByHWND hwnd
Form1.Print s
Form1.Print hwnd
End If
EnumProc = 1
End Function'关闭任何普通应用程序的窗口
Public Function TerminateProcessByHWND(ByVal hCloseWnd As Long) As Boolean
Dim hProcessID As Long
Dim hProcess As Long
On Error GoTo PROC_EXIT
If hCloseWnd = 0 Then GoTo PROC_EXIT
If GetWindowThreadProcessId(hCloseWnd, hProcessID) = 0 Then GoTo PROC_EXIT
hProcess = OpenProcess(PROCESS_TERMINATE, False, hProcessID)
If hProcess = 0 Then GoTo PROC_EXIT
If TerminateProcess(hProcess, 0&) = 0 Then GoTo PROC_EXIT
TerminateProcessByHWND = True
PROC_EXIT:
If Err.Number <> 0 Then
Debug.Print Err.Description
Err.Clear
End If
End Function'定时查询是否有无法结束的dos窗口
Public Function CloseConsole1() As Long
Dim console As Long
console = FindWindow("ConsoleWindowClass", vbNullString) '查找是否有dos窗口
Dim s As String * 255
g__caption = ""
Dim i As Integer
If console Then
GetWindowText console, s, 255
For i = 1 To 255
If Mid(s, i, 1) <> Chr(0) Then
g__caption = g__caption & Mid(s, i, 1)
Else
Exit For
End If
Next i
'Debug.Print g__caption
g__hwnd = console
EnumWindows AddressOf EnumProc1, 0
End If
CloseConsole1 = 1
End Function
'枚举是否出现立即结束的窗口
Public Function EnumProc1(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim s As String * 255
Dim s1 As String
Dim i As Integer
GetClassName hwnd, s, 255
For i = 1 To 255
If Mid(s, i, 1) <> Chr(0) Then
s1 = s1 & Mid(s, i, 1)
Else
Exit For
End If
Next i
If s1 = "#32770" Then
s1 = ""
GetWindowText hwnd, s, 255
For i = 1 To 255
If Mid(s, i, 1) <> Chr(0) Then
s1 = s1 & Mid(s, i, 1)
Else
Exit For
End If
Next i
If s1 = "结束程序 - " & g__caption Then
TerminateProcessByHWND hwnd
TerminateProcessByHWND g__hwnd
End If
End If
EnumProc1 = 1
End Function
1.该dos程序是由你的程序用shell语句运行的。
这种情况最好办,你运行该程序时用x=shell(“abc.exe”),返回值x是该进程的id,要关闭它时,根据x的值取得进程句柄,然后用terminateproess把它杀死然后关机。由于你在98下工作,如果是一般的win32程序,terminateproess是不会问你存不存盘啊之类就直接杀死目标程序的,很方便。但dos程序不知行不行。另外注意,terminateproess在nt、2000下无效。
2.该dos程序是另外运行的。
一个笨方法,有兴趣试试:
用findwindow找到它的句柄。
用setforegroundwindow把它调到前面来。
向它发送WM_CLOSE消息叫它关闭。
延时一会儿等待对话框出现。
当那个“该死的对话框”出现后,用sendkey发送确认命令,具体发送什么键要看你实际情况。
关机。