ShellExecute用关联的程序打开一个文件,我想在这个文件关闭后做一些动作
但是我还没找到判断这个文件是否关闭的方法。
请给些思路或是代码,谢谢!

解决方案 »

  1.   

    运行,检查和关闭Option Explicit
    Private sAppName As String, sAppPath As String
    Private sFilename As String
    Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
    Const SW_SHOWNORMAL = 1Private Sub cmdCheck_Click()
           
        'check if application is running
        If IsTaskRunning(sAppName) Then
            MsgBox "Application '" & sAppName & "' is running!"
        Else
            MsgBox "Application '" & sAppName & "' is not running!"
        End If
    End SubPrivate Sub cmdClose_Click()
        'close application
        
         Call EndTask(sAppName)
    End SubPrivate Sub cmdStart_Click()
        ShellExecute Me.hwnd, vbNullString, "c:\label.txt", vbNullString, "C:\", SW_SHOWNORMALEnd SubPrivate Sub Form_Load()
        sFilename = "c:\label.txt"
        sAppName = Mid(sFilename, InStrRev(sFilename, "\") + 1) & " - 记事本"
    End Sub=============================
    我歌月徘徊,我舞影零乱。醒时同交欢,醉后各分散。 永结无情游,相期邈云
    汉。
      

  2.   

    上面的代码需要调用一个检查的函数检查任意执行的程序,如果你是想在程序里是想让ShellExecute具有等待功能你可以看看下面的代码
    VB 中,常以Shell指令来执行外部程式,然而它在Create该外部process 後,立刻就会回到vb 的下一行程式,无法做到等待该Process结束时,才执行下一行指令,或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完成。   第一个问题,如何等待shell所Create的process结束後才往後执行vb的程式。   首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来区别每个 Process,这个Process ID(PID)主要可用来取得该Process相对应的一些资讯,然而要对该Process的控制,却大多透过 Process Handle(hProcess)。VB Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来取得 hProcess而OpenProcess()的第一个参数,指的是所取得的hProcess所具有的   能力,像 PROCESS_QUERY_INFORMATION 便是让GetExitCode()可取得hProcess所指的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..)的指令能够生效,也就是说,不同参数设定,使hProcess所具有的权限、能力有所不同。取得 hProcess後便可以使用WaitForSingleObject()来等待hProcess状态的改变,也就是说,它会等待 hProcess所指的process执行完,这个指令才结束,它   第二个参数所指的是 WaitForSingleObject()所要等待的时间(in milliseconds ),如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它无限的等下去,就设定为INFINITE。pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) ExitEvent = WaitForSingleObject(hProcess, INFINITE) Call CloseHandle(hProcess)  
    上例会无限等待shell指令create之process结束後,才再做後面的vb指令。有时觉得那会等太久,所以有第二个解决方式:等process结束时再通知vb 就好,即:设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结束。当Process还在执行时,GetExitCodeProcess会传&H103给其第二个参数,直到结束时才传另外的数值,如果程式正常结束,那Exitcode = 0,否则就得看它如何   结束了。或许有人在其他地方看到 loop的地方是Loop while Exitcode <> 0,那有一点危险,如果以这个例子来看,您不是用F4来离开pe2而是用右上方 X 的结束dos window那麽,会因为ExitCode的值永远不会是0,而进入无穷的回圈。 Dim pid As Long pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) isDone = False Do Call GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Call CloseHandle(hProcess) isDone = True  
    另外,如果您的shell所Create的程式,有视窗且为立刻Focus者,可另外用以下的方式Dim pid As Long Dim hwnd5 As Long pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus) hwnd5 = GetForegroundWindow() isDone = False Do While IsWindow(hwnd5) DoEvents Loop isDone = True  
      而如何强迫shell所Create的process结束呢,那便是Dim aa As Long If hProcess <> 0 Then aa = TerminateProcess(hProcess, 3838) End If  
    hProcess便是先前的例子中所取得的那个Process Handle, 3838所指的是传给GetExitCodeProcess()中的第二参数,这是我们任意给的,但最好不要是0,因为0一般是代表正常结束,当然这样设也不会有错。当然不可设&H103,以这个例子来看,如果程式正处於以下的LOOPDoCall GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Debug.print ExitCode    而执行了 TerminateProcess(hProcess, 3838)那会看到ExitCode = 3838。然而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个参数要更改成 PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE 这样才能Work。不过良心的建议,非到最後关头,不要使用TerminateProcess(),因不正常的结束,往往许多程式结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再执行某些程式时会有问题,例如:本人常使用MS-dos Shell Link 的方式执行一程式,透过Com port与大电脑的联结,如果Ms-dos Shell Link 不正常结束,下次再想Link时,会发现too Many Opens,这便是一例。 
      另外,有人使用Shell来执行.bat档,即:pid = Shell("c:\aa.bat", vbNormalFocus)   可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)   那是执行Command.com,而Command.com指定执行c:\aa.bat 而且结束时自动Close 
    所有程式如下:Private Declare Function OpenProcess Lib "kernel32" _ (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _ ByVal dwProcessId As Long) As Long Private Declare Function WaitForSingleObject Lib "kernel32" _ (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Private Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long Private Declare Function GetExitCodeProcess Lib "kernel32" _ (ByVal hProcess As Long, lpExitCode As Long) As Long Private Declare Function TerminateProcess Lib "kernel32" _ (ByVal hProcess As Long, ByVal uExitCode As Long) As Long Private Declare Function GetForegroundWindow Lib "user32" () As Long Private Declare Function IsWindow Lib "user32" _ (ByVal hwnd As Long) As Long 
    Const PROCESS_QUERY_INFORMATION = &H400 Const STILL_ALIVE = &H103 Const INFINITE = &HFFFF 
    Private ExitCode As Long Private hProcess As Long Private isDone As Long Private Sub Command1_Click() Dim pid As Long pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) isDone = False Do Call GetExitCodeProcess(hProcess, ExitCode) Debug.Print ExitCode DoEvents Loop While ExitCode = STILL_ALIVE Call CloseHandle(hProcess) isDone = True End Sub 
    Private Sub Command2_Click() Dim pid As Long Dim ExitEvent As Long pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus) hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid) ExitEvent = WaitForSingleObject(hProcess, INFINITE) Call CloseHandle(hProcess) End Sub 
    Private Sub Command3_Click() Dim aa As Long If hProcess <> 0 Then aa = TerminateProcess(hProcess, 3838) End If 
    End Sub 
    Private Sub Command4_Click() Dim pid As Long Dim hwnd5 As Long pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus) hwnd5 = GetForegroundWindow() isDone = False Do While IsWindow(hwnd5) DoEvents Loop isDone = True End Sub Private Sub Command5_Click() Dim pid As Long 'pid = Shell("c:\windows\command\xcopy c:\aa.bat a:", vbHide) pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus) End Sub  =============================
    我歌月徘徊,我舞影零乱。醒时同交欢,醉后各分散。 永结无情游,相期邈云
    汉。
      

  3.   

    IsTaskRunning(sAppName)判断,其中sAppName是窗口标题
      

  4.   

    另外还有一个api容易被人忽略CreateProcessByNum 异步方式调用,你可以研究一下
      

  5.   

    另外还有一个api容易被人忽略CreateProcessByNum 异步方式调用,你可以研究一下
      

  6.   

    给你个简单例子
    Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    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 LongConst SYNCHRONIZE = &H100000
    Const INFINITE = &HFFFFFFFF
    Private Sub Command1_Click()
    Dim pId As Long, pHnd As Long ' 分别声明 Process Id 及 Process Handle 变数
    pId = Shell("Notepad", vbNormalFocus) ' Shell 传回 Process Id
    pHnd = OpenProcess(SYNCHRONIZE, 0, pId) ' 取得 Process Handle
    If pHnd <> 0 Then
    Call WaitForSingleObject(pHnd, INFINITE) ' 无限等待,直到程序结束
    Call CloseHandle(pHnd)
    End If
    End Sub
      

  7.   

    ch21st(风尘鸟) 非常谢谢你的指导。shell,CreateProcess都是create一个可执行程序的Process
    我需要打开任意的文件,比如说我要打开一个word文件,他相关的进程是winword.exe
    那是不是要在打开文件前判断文件的类型,打开特定类型的程序,在打开这个文件。所以我用的是ShellExecute,能不能说说这中方式下怎样判断文件是否关闭。不知道你是否明白我的意思了,或者是我没有理解你上面所给出的含义。
    请再指教
      

  8.   

    我现在有个想法:
    现在用ShellExecute打开一个文件,但不知道怎么得到打开的那个所在窗口的句柄
    如果知道那个句柄,可以用GetWindowText检测窗口的标题,标题为空就可以认为是文件关闭拉这样可行吗?如果可行,那个窗口的句柄怎么得到说明一下:打开的窗口不一定是后一个兄弟窗口,我试着做为子窗口打开,好象也得不到窗口标题
      

  9.   

    kingfist(红双喜) 
    我需要打开任意文件 所以那个文件类型("Notepad")我要怎么得到
    要每次都判断吗?
      

  10.   

    这样的话你要有ShellExecuteEx 代替ShellExecute
    在Private Type SHELLEXECUTEINFO
    cbSize As Long
    fMask As Long
    hwnd As Long
    lpVerb As String
    lpFile As String
    lpParameters As String
    lpDirectory As String
    nShow As Long
    hInstApp As Long
    lpIDList As Long
    lpClass As String
    hkeyClass As Long
    dwHotKey As Long
    hIcon As Long
    hProcess As Long
    End Type
    结构中有hProcess 然后你就可以利用
    Do
    DoEvents
    retval = WaitForSingleObject(ShellStructure.hProcess, 0)Loop While retval = WAIT_TIMEOUT
    完成wait功能
    以上是概述,仅仅是方法具体代码你可以查查资料
      

  11.   

    还是我给你写一个吧
    Private Type SHELLEXECUTEINFO
        cbSize As Long
        fMask As Long
        hwnd As Long
        lpVerb As String
        lpFile As String
        lpParameters As String
        lpDirectory As String
        nShow As Long
        hInstApp As Long
        lpIDList As Long
        lpClass As String
        hkeyClass As Long
        dwHotKey As Long
        hIcon As Long
        hProcess As Long
    End Type
    Private Const SEE_MASK_NOCLOSEPROCESS = &H40
    Private Const SW_SHOWNORMAL = 1
    Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (lpExecInfo As _
        SHELLEXECUTEINFO) As Long
    Private Const SE_ERR_FNF = 2
    Private Const SE_ERR_NOASSOC = 31
    Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal _
        dwMilliseconds As Long) As Long
    Private Const INFINITE = &HFFFF
    Private Const WAIT_TIMEOUT = &H102
    Private Sub Command1_Click()
        Dim sei As SHELLEXECUTEINFO  ' structure used by the function
        Dim retval As Long  ' return value
        
        With sei
            .cbSize = Len(sei)
            .fMask = SEE_MASK_NOCLOSEPROCESS
            .hwnd = Form1.hwnd
            .lpVerb = "open"
            .lpFile = "C:\1.txt"
            .lpParameters = ""
            .lpDirectory = "C:\"
            .nShow = SW_SHOWNORMAL
        End With
    retval = ShellExecuteEx(sei)
        If retval = 0 Then
            Select Case sei.hInstApp
            Case SE_ERR_FNF
                Debug.Print "没有找到目标文件."
            Case SE_NOASSOC
                Debug.Print "没有找到与目标文件相关联的应用程序"
            Case Else
                Debug.Print "未知错误"
            End Select
        Else
            Do
                DoEvents
                retval = WaitForSingleObject(sei.hProcess, 0)
            Loop While retval = WAIT_TIMEOUT
            Debug.Print "Debug.Print "应用程序被关闭."
            MsgBox "Finish"
        End If
    End Sub
      

  12.   

    我用了FindExecutable得到关联的程序,再把文件路径做为参数就可以了
    谢谢两位的帮忙
    非常感谢!