如何让程序非正常关闭后自动重新启动,一个名为《柳叶擦眼》的软件做到了,就是利用进程管理器将其结束,但是它马上会立刻启动,是怎么实现的?用了哪些API和技术?最好能给出代码。

解决方案 »

  1.   

    做一个守望程序,我想是可以的!
    比如说《柳叶擦眼》是你想满足要求的程序!你另外再做一个程序,叫myapp吧!
    在myapp加一个timer,interval设置为6!
    然后用findwindow时刻查看当前的《柳叶擦眼》是否存在,如果不存在(即关闭了),
    你就shell!
    不知道是不是可以满足的要求,我的语文有问题,有点不懂你的意思了:(
      

  2.   

    做2个程序 A ,B
    A启动B 用Shell 
    然后用WaitForSingleObject ,当B结束返回A继续执行上个步骤。B 程序也可以作成DLL形式来加载,会更好。至于是否是异常退出,在B里判断后,传给A,A来决定时候重起。
      

  3.   

    sorry,我误会了,我以为是关机呢。启动两个,一个正常运行,一个等待并判断是否有已运行的,如果没有,停止等待进入运行状态并启动另一个等待。
      

  4.   

    那就是作成DLL,或者是文件映射也可以。
      

  5.   

    两个也不是很耗资源,A可以没有窗体,作成托盘程序,不要用timer,用WaitForSingleObject
      

  6.   

    首先要确定单个进程能不能捕获这种足使进程崩溃的错误,并且能做出反应,如果这个错误不是致命的就好说,如果是的话,也只能用DLL方式,或者是文件映射。
      

  7.   

    如果大家都认为但进程是不可能实现的,那可以去http://www.xzcx.net.cn/pubsite/zy/soft/eye400fb.zip下《柳叶擦眼4.0》,然后执行,用进程管理器踢掉它,它会重新执行的,那么这是如何实现的,看进程列表中只有一个与其相关的进程,那是怎么回事?
      

  8.   

    利用Windows的计划任务,每隔30分钟运行一次   =)
    我是今天注册的,新手!请多多关照!
      

  9.   

    to 楼主:
    你提供的程序完全没有这个功能!我在任务管理器中踢掉了进程,然后什么也没发生!
    请问你是否使用的是Win9x或WinMe系统?如果是,那么可能仅仅是你看不到该程序的守望进程而已。该进程可能被注册成了系统服务。如果不是,请告诉我你的系统版本,我非常好奇这样的程序是什么原理!谢谢!
    注:我的系统是WinXP sp1
      

  10.   

    估计程序是用 SEH("Structured Exception Handling"),即结构化异常处理技术.对于VB是无能为力了.
      

  11.   

    最基本的观念就是She只不过是系统在终结你应用程序之前给你的一个最后处理错误的机会,从程序设计的角度来说就是给你自己设计的一个回调函数执行的机会.
      

  12.   

    又看了点相关的东西使用函数SetUnhandledExceptionFilter 
    可以试试这样行不行
    程序加载后运行 
    SetUnhandledExceptionFilter AddressOf StartMe
    在form的unload事件里执行
    Dim k As Long
    k = k / 0StartMe 是在模块里的过程
    Sub StartMe ()
    Shell 自己的程序
    End
    SetUnhandledExceptionFilter 申明
    Public Declear Function SetUnhandledExceptionFilter Lib "...." (pTopLevelExceptionFilter As Long) As Long
    因为手边没有VB,也没有些相应的工具,所以有些地方请大家补足
      

  13.   

    有地方要改进.
    加入
    Const EXCEPTION_EXECUTE_HANDLER = 1
    StartMe 改成
    Function StartMe () As Long
    Shell 自己的程序
    StartMe = EXCEPTION_EXECUTE_HANDLER
    End
      

  14.   

    Private Declare Function SetUnhandledExceptionFilter Lib "kernel32" (ByVal lpTopLevelExceptionFilter As Long) As Long
      

  15.   

    这里有篇文章是关于用SEH做API HOOK老罗的文章,ASM的哦 :)
    http://www.luocong.com/articles/show_article.asp?Article_ID=25
      

  16.   

    大家都这么说了,我去试试看,不过我还有一个基本相同的问题,那就是EXPLORER.EXE非法终止是如何自启动的呢?
      

  17.   

    那是由于任务管理器关闭程序时用的是WM_CLOSE,而不是强行关闭,就像下面的代码Private Sub Form_Unload(Cancel As Integer)
        IIf Right(App.Path, 1) <> "\", Shell(App.Path & "\" & App.EXEName & ".exe"), Shell(App.Path & App.EXEName & ".exe")
    End Sub
    我有一个自己写的强行关闭程序的小东东,如果楼主要的话,晚上回家后可以Email给你...上面的程序没有调试,在公司上网,没法调试,应该没有问题
      

  18.   

    对了,如果你真要这个功能的话,那就要自己来写关闭自己程序的代码了,做一个按钮,在CLICK中加入END就可以了
      

  19.   

    那请问如果用WM_QUIT呢?你上面的程序就有问题了,这个方法我曾经已经试过了,行不通的
      

  20.   

    可以哟,看到你的出贴,我一回家就试了一下,任务管理器关掉我的程序后,我的程序会自动启动呀,除非用强行关闭,好像98里没有强行关闭的工具,要的话,我有一个自己写的,可以关EXE,DLL等,系统自身的重要进程,如Kernel32.dll都可以关[会导致系统崩溃],要的话就跟我留言,可以Email给你,最后再把我的程序贴一下,很简单,就没有写工整,偷一下小懒....
    #注意,我的程序里都没有换行符
    '一个标准工程,窗体上加一个Commandbox控件,名字为Command1
    'in a Form,Add a commandbox,name Command1
    Private Sub Command1_Click()
        End
    End Sub
    Private Sub Form_Unload(Cancel As Integer)
        If Right$(App.Path, 1) <> "\" Then
            Shell (App.Path & "\" & App.EXEName & ".exe")
        Else
            Shell (App.Path & App.EXEName & ".exe")
        End If
    End Sub如果你真要屏蔽WM_CLOSE消息,自己写个钩钩,把WM_CLOSE消息废除就可以了给你一个简单的例子[不完整]'-----------------------截获消息模块
    Function wndproc(ByVal Hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long         '&H10就是WM_CLOSE消息
    If msg = &H10 Then
        If cAlock = False Then
            Exit Function
        End If
    End If
    '将消息返还给原进程
    wndproc = CallWindowProc(PrevWndproc, Hwnd, msg, wParam, lParam)
    End Function
      

  21.   

    Private Sub Form_Unload(Cancel As Integer)
        If Right$(App.Path, 1) <> "\" Then
            Shell (App.Path & "\" & App.EXEName & ".exe")
        Else
            Shell (App.Path & App.EXEName & ".exe")
        End If
    End Sub
    以上这段程序虽然任务管理器不能关闭,但是《柳叶擦眼》可以的,所以没有真正的做到
    你说屏蔽WM_CLOSE消息,那么只要程序运行着所有的WM_CLOSE不都失效了?!
      

  22.   

    Windows有两种杀进程的方式:1是发送WM_CLOSE,也可以理解为通知目标进程要结束,2是Windows直接使用API挂起进程并销毁其占用的资源,也可以理解为外部杀除。其实就像你用任务管理器,刚点结束进程的时候可能没有反应,其实此时系统正在等待WM_CLOSE的返回;过一会就跳出某某窗口无响应的对话框,然后会强制关闭该进程。所以你想达到目的就要:收到WM_CLOSE的情况下及时反应,重载自己;或者双进程保护,关了一个另一个自动重载被关的。很明显,既然你看不到多一个进程,那么请试试看《柳叶擦眼》杀自己能否成功?或者另一个系统级杀进程(就是上面的方式2)的工具杀《柳叶擦眼》时能否使其自动重载?如果不能,就说明《柳叶擦眼》只是对WM_CLOSE做了截获而已。如果能,那么就很值得讨论其技术了。
      

  23.   

    接收到WM_CLOSE消息,如果有这种消息,(当然先要自定义关闭消息),就是非正常关闭了,收到这类消息后,可能不可以取消关闭,因为进程管理器可以关闭,当然它会先发这个消息,我们就加一把力,收到消息后运行自己重启的程序就可以了。
      

  24.   

    不要说了,气死我了,我上次在网吧等女友,刚好写了一大段程序,她来了,一下子就关了,气死我了,我可以告诉你一个好办法,现在我在寝室,有一点时间,让你看一看,不知道行不行。
    你先设置一个没有“X”的界面。你自己写一个:
    dim kk as longpublic sub lexit() '自己设置记号
     kk=100
     end 
    end sub然后在:  '这说明是系统关闭
    Private Sub Form_Unload(Cancel As Integer)
     if kk<>100 then  
       '自己重启
      endif 
    End Sub不知道我的想法行不行,还有问题的话就再问一次。
      

  25.   

    luolovegui(东方不败)的方法在正常退出时没问题,但是非正常就不行了,而本贴就是讨论在非正常情况下怎么处理,分嘛这个只是做个样子,结帖后直接给可用分
      

  26.   

    都不行
    我试过
    总能关掉
    那软件也不行,我用《网络新手反黑客实用工具箱2.0》的关闭进程,就全部OVER
    另想办法
      

  27.   

    9x下的Ctrl+Alt+Del关闭程序会触发程序的WM_CLOSE事件。程序可以轻而易举地查到不正常的关闭并在此时结束当时的程序实例,新启动一个实例(原因是避免Win9x跳出“程序没有响应,立即关闭的对话框”,“立即关闭”将不发送任何消息直接关闭)。而WinNT下的任务管理器的“结束进程(树)”在关闭时由系统负责回收程序注册使用的所有资源,程序本身不会接受到任何结束的消息。所以必须用多进程互监法。如果你在9x下用Process Viewer杀进程,效果会和Win2000/XP下的“结束进程”效果一致。不妨试试看。
      

  28.   

    对不住了,我这两天回去了,没有时间回答,今天看看我的方法,在VB中,关闭程序的时候会发生QueryUnload事件。当事件中的参数UnloadMode=3时,就表示是任务管理器关闭程序,我们只要在这里判断就行了。我想你说的非正常关闭就是指“任务管理器”关闭吧。这次不知道我理解错没有。
      

  29.   

    仅限9x的CAD,或者WinNT的“结束任务”。而结束进程是无法拦截的。
      

  30.   

    真的没有办法使“结束进程是无法拦截”吗,我有一个好主意,就是用FindWindow()找到这个窗口,一但出现就马上用SendMessage发送WM_CLOSE就可以了。我已经写出来了。大家可以看看。
    Private Declare Function GetForegroundWindow Lib "user32" () As Long
    Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    Private Const WM_CLOSE = &H10
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Dim p As Long
    Dim i As Long
    Dim s As String
    Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
     If UnloadMode = 3 Then  '一旦出现,马上查找。
      Cancel = True
      s = ""
      Dim kk As Integer
     Do
      p = FindWindow("#32770", "结束程序 - 工程1") '“#32770”是类名。后面的名可以自己
      i = 20                                       ’想办法设置。
      If p <> 0 Then
       SendMessage p, WM_CLOSE, 0, 0
       Exit Do
      End If
      DoEvents
     Loop
     End If
    End Sub我已试过,确对没错。如果可以,请大家UP一下。
      

  31.   

    还有上面的代码中有一些API是在程序中没有用到的。多定义了。当然没有什么关系。
      

  32.   

    在9x里面注册为系统服务进程就不会在CAD列表里面显示,但是Win2000/XP的进程列表难以干涉。可不可以监视“进程列表”里面的项目?如果有和自己EXE名称相同的项就删掉?不过这是个投机取巧的办法。
      

  33.   

    高手们,你们要自己写出自己API才可以,就像改中断一样。
      

  34.   

    要先找到API的地址,就是截取API,而且要截取这个api,EnumWindows()就可以了。
      

  35.   

    上面的方法不行吗,我不相信,我写的代码,我的电脑是WinXp
      

  36.   

    可以,但是太浪费资源
    我的想法就是HOOK相关的API和消息,可以吗?(在2000/XP下)
      

  37.   

    讨论到哪个问题了?我就楼主的问题讲一下,用一个timer不停的findwindow,返回hwnd=0就shell它,就是这么简单:)
      

  38.   

    楼上的朋友不知道是哪里来的高手呀,程序都关了,还有findwindow呀,你写给我看看。我从来没有过这样想法,除非你用两个进程。
      

  39.   

    真的,你一定要写出来,就得用32位汇编写一个程序,截取EnumWindows()函数,是一定可以的。
      

  40.   

    1.改WindowsAPI不好,不可行
    2.EnumWindows()和进程没有关系吧
      

  41.   

    如果能用ASM的话,不需要拦截API(何况Win2000使用了 写中读 技术,传统的拦截API方法只对自身进程有效)
    直接利用远程线程,在系统进程中建立一个自己的线程,这样绝对找不到(那只是线程,只有一个32位线程标识符,而系统进程有好几十个线程)================================================“结束进程”的工作原理是:Windows取消该进程的运行权(该进程的所有线程不会再分配CPU资源),再释放资源================================================家里的电脑坏了
    现在在网吧
    无法实验
      

  42.   

    to zyl910(910:分儿,我又来了!)
    但是VB做不到啊to GetWindowPos(阿汪)
    现在讨论的是2000和2000以上系统
      

  43.   

    GetWindowPos(阿汪) ( ) 信誉:64  2003-10-07 14:52:00  得分:0 
     
     
      不必讨论这个问题,用VB加上纯代码不可能在2000隐藏进程,或者拦截系统消息
    只能用现在所有人都用的方法:一个线程两个进程,形成三角链互相监视
     
     
    没明白?
      

  44.   

    楼主所说的这种现象其实就是程序在运行时形成进程,而WINDOWS运行程序是按最小单位线程来分配CPU的,那么这个进程有可能自己生成一个线程将其注射到另外一个进程里,你又怎么能知道它叫什么名字呢,所以即使你能看到线程你也不知道是谁生成的这个进程,但是这样做绝对可以实现你所说的功能
      

  45.   

    线程我已经实现了,就是想知道有哪个API可以实现,但不是用线程的原理
      

  46.   

    关键是:任务管理器中断线程时根本不调用unload事件啊!
      

  47.   

    我刚才在CSDN(就是这里啦^^)上看到有篇关于如何在NT系统下通过hook阻止在任务管理器中结束程序的文章,(喘一下气先)觉得对这篇帖子有帮助。
      

  48.   

    随便写的,不知这样算不算:
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    Private Const WM_CLOSE = &H10Private Sub Form_Load()
    Timer1.Interval = 5
    End SubPrivate Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    If UnloadMode = 3 Then
        MsgBox "使用任务管理器关闭"
        Cancel = True
    End If
    End SubPrivate Sub Timer1_Timer()
    Dim l As Long
    l = FindWindow(vbNullString, "结束程序 - 限制使用次数")
    If l <> 0 Then
        SendMessage l, WM_CLOSE, 0, 0
    End If
    End Sub
      

  49.   

    vb在线上看到有类似的问题,解答如下:
    Private RunFile$Private Const NORMAL_PRIORITY_CLASS = &H20 '如果进程位于前台,则基本值是9;如果在后台,则优先值为7
    Private Const INFINITE = &HFFFFFFFF
    Private Const WAIT_TIMEOUT = &H102& '对象保持未发出信号的状态,但等待超时时间已经超过
    Private Flag As Boolean '进程活动监视标志
    '说明∶PROCESS_INFORMATION结构由CreateProcess函数将关于新建立的进程和
    '主要线索的信息写入其中成员变量
    Private Type PROCESS_INFORMATION '
    hProcess As Long
    hThread As Long
    dwProcessId As Long
    dwThreadId As Long
    End Type'说明∶STARTUPINFO结构用在CreateProcess函数中指定为新进程建立的新窗口的主要属性。这一
    '一信息影响由CreateWindows函数建立的第一个窗口
    Private Type STARTUPINFO
    cb As Long
    lpReserved As String
    lpDesktop As String
    lpTitle As String
    dwX As Long
    dwY As Long
    dwXSize As Long
    dwYSize As Long
    dwXCountChars As Long
    dwYCountChars As Long
    dwFillAttribute As Long
    dwFlags As Long
    wShowWindow As Integer
    cbReserved2 As Integer
    lpReserved2 As Long
    hStdInput As Long
    hStdOutput As Long
    hStdError As Long
    End Type
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
    Private Declare Function WaitForInputIdle Lib "user32" (ByVal hProcess As Long, ByVal dwMilliseconds As Long) As LongPrivate Sub command1_Click()
    Dim res&
    Dim sinfo As STARTUPINFO
    Dim pinfo As PROCESS_INFORMATION
    sinfo.cb = Len(sinfo)
    sinfo.lpReserved = vbNullString
    sinfo.lpDesktop = vbNullString
    sinfo.lpTitle = vbNullString
    sinfo.dwFlags = 0
    Flag = False
    Label1.Caption = "正在启动程序"
    Label1.Refresh
    ' CreateProcess函数,用于创建一个新的进程
    res = CreateProcess(RunFile, vbNullString, 0, 0, True, _
    NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, sinfo, pinfo)
    If res Then
    Label1.Caption = "程序正在运行中"
    WaitForTerm pinfo
    Label1.Caption = "程序已经结束"
    Else
    Label1.Caption = "启动程序时出错,可能未正确输入" & Chr(13) & "程序名或程序所在路径。"
    End If
    End SubPrivate Sub WaitForTerm(pinfo As PROCESS_INFORMATION)
    Dim res&
    Dim res1&
    ' 等待指定的进程进入空闲状态,,空闲(Idle)指的是进程准备处理一条消息、但目前暂时没有消息需要处理的一种状态
    Call WaitForInputIdle(pinfo.hProcess, INFINITE)
    Command1.Enabled = False
    Label1.Refresh
    Do
    If Flag Then Exit Do'等待发出信号
    res = WaitForSingleObject(pinfo.hProcess, 0)
    If res <> WAIT_TIMEOUT Then '如果对象发出了信号
    command1_ClickExit Do
    End If
    DoEvents
    'Debug.Print resLoop While True
    Command1.Enabled = True
    End SubPrivate Sub Command3_Click()
    Flag = True
    End SubPrivate Sub Form_Load()
    RunFile = "C:\Documents and Settings\hzhd\桌面\限制使用次数.exe"
    Flag = False
    Command1.Caption = "开始"
    Command3.Caption = "结束"
    End Sub