2011年1月5日 星期三

控制外部程式開啟檔案的方法

發信人: tommy.bbs@bbs.cs.nthu.edu.tw (在雲中游泳的魚), 看板: Programming
標  題: Re: [VB6 ] 控制外部程式開啟檔案的方法?
發信站: 楓橋驛站 (Sun Jan 31 09:02:02 2010)
轉信站: ptt!news.ntu!ctu-gate!ctu-peer!news.nctu!news.csie.ncyu!news.cs.nthu!M

※ 引述《SNG.bbs@ptt.cc》之銘言:
> ※ [本文轉錄自 Visual_Basic 看板]
> 作者: SNG () 看板: Visual_Basic
> 標題: [VB6 ] 控制外部程式開啟檔案的方法?
> 時間: Sat Jan 30 15:43:08 2010
> 請問版友
> 該如何控制外部程式 開啟檔案呢?
> (不用shell加參數)
> 例如以 Notepad 為例子
> Private Declare Function GetMenu Lib "user32.dll" (ByVal hWnd As Long) As Long
> Private Declare Function SendMessage Lib "user32.dll" Alias _
> "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
> Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
> (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
> Private Declare Function GetMenuItemID Lib "user32.dll" (ByVal hMenu As Long, ByVal nPos As Long) As Long
> Private Declare Function GetSubMenu Lib "user32.dll" (ByVal hMenu As Long, ByVal nPos As Long) As Long
> Private Const WM_COMMAND As Long = &H111
> Private Sub Command1_Click()
> Dim hWnd As Long, hMenu As Long, MenuID As Long
> hWnd = FindWindow(vbNullString, "未命名 - 記事本")
> If hWnd <> 0 Then
> hMenu = GetMenu(hWnd)
> hMenu = GetSubMenu(hMenu, 0)
> MenuID = GetMenuItemID(hMenu, 1)
> SendMessage hWnd, WM_COMMAND, MenuID, ByVal 0
> Else
> Shell "notepad", vbNormalFocus
> End If
> End Sub
> 目前遇到的問題是有成功呼叫出 開啟舊檔的對話視窗 (CommonDialog)
> 但是接下來就卡住了,可以請版友提供一下建議嗎?

        重點:

        1. 將 SendMessage() 改成 PostMessage(). (Windows API)

        2. 加 SendKeys 在 PostMessage()後:      (VB指令)
           SendKeys "C:\WINDOWS\FAQ.TXT" + vbCr, True

           語法: SendKeys 訊息文字, 等候回應 (請查VB線上說明)

        說明:
            SendMessage() 是同步的. 會等到整個動作完成才回來.

            開啟舊檔的功能表動作一直到「對話盒」關閉才算完成, 所以你會卡
            在那裡.(由於對話盒沒有獲得新的輸入指令, 一直在哪裡等. 你必須
            手動關掉對話盒, 程式才會返回.)

            你的原意是要繼續自動的指定檔名, 所以不能使用同步的SendMessage(),
            因為檔名還未指定.(新的訊息)

            PostMessage() 是非同步的. 送完立刻回來. 不會等整個動作完成.

            因此API 送完功能表執行指令後, 你可以繼續再傳送新的指令給已打
            開的「對話盒」.

            第二行 SendKeys() (VB指令)  就是送新的訊息給「對話盒」. 指定
            開啟的檔名. vbCr 是代替你按 Enter (Return) 鍵.  結果就是出現
            開啟的資料, 在你的程式執行完後.

            注意! VB指令的SendKeys(), 其傳送對象是「現行活動的視窗」. 所
            以當你以訊息觸發筆記本的開啟舊檔功能表後, 對話盒自動成為活動
            視窗. 因此SendKeys()才會找對對象.

            如果你的SendKeys()沒有正確結果. 要注意的是「開啟舊檔對話盒」
            是否在SendKeys()前已正確開啟.

            因為執行需要時間. PostMessage() 不會等功能表完成動作才返回,
            所以有時候系統太忙, 來不及開對話盒而你的程式早就跑到下一行執
            行了, 所以SendKeys()可能會失敗.

            最簡單的指令就是前面標題的「重點」所言. 但是更穩定的控制, 你
            要偵測動作是否完成. 使用底下的兩種型式來改進:

            1. 加Sleep (Windows API)暫停你的VB指令, 等對方完成動作.
               Sleep 1500 '傻等1.5秒 (一個夠長的時間) 不一定有效或有效率.
               SendKeys ...

            2. 使用FindWindow() 看看是否視窗已打開. 否則繼續睡覺.
               cnt = 0
               Do until FindWindow(vbNullString, "開啟舊檔") <> 0
                   Sleep 100 '每次小睡0.1秒.
                   cnt = cnt + 1: If cnt = 100 Then Exit Do '避免死當. 等10秒
               Loop
               '* 未逾時則執行.
               If cnt < 100 Then SendKeys "C:\WINDOWS\FAQ.TXT" + vbCr, True

        宣告: PostMessage() 和 SendMessage() 只差名稱四個字, 其它參數一樣.

    Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

    註: FindWindow()找 "開啟舊檔" 還是有不穩定的情況在, 很可能多工狀態出
        現兩個對話框. 最常見的巧合就是你的自動程式背景跑, 你在前景使用筆
        記本. 正好程式跑到開筆記本, 而你也打開對話框. 所以傻瓜程式分不出
        是哪一個, 因此先後程序錯亂產生異常.

        請注意這點, 不要用在關鍵任務中, 雖然機率很小, 但是系統很忙時, 間
        隙會變得比你想的還要來得大! 請研究清楚再用.

        「絕對不能錯」的任務就是「絕對」不能錯! 你不會希望軍艦因為當機而
        被拖回港.

                                                            Tommy 99/01/31
                                                            [B75628A1:Tom]

--
  ▄       ◢ ▄▄▄ ▄▄▄ ▄     ▄▄▄ [1;37m 清大資工 [m
[1;37;44m  █ █◣◢█ █▄█ █▄█ █     █▄▄  [33mtommy [37m 從 [33m 61.229.168.125            [m
  █ █◥◤█ █  █ █     █▄▄ █▄▄ [1;37m【楓橋驛站】 telnet://imaple.tw [m

沒有留言:

張貼留言

您好.本資料庫並非第一手資料.如果你有對文章作者的詢問,意見與需求,請自行找尋文章作者並提供意見,謝謝.