如何在控制外部程式的視窗元件(FindWindow, SendMessage)

View Snippet
                    .Introduction
        
        在開發程式中, 當碰到底層功能沒開放出來的時候, 往往最後只能在外部控制介面來處理,舉個例子, 像是碰到比較特殊的硬體裝置, 而廠商沒提供driver的原始碼, sdk的功能不完整等等問題之類的, 在只有官方的控制用應用程式的情況下, 此時也就只能寫外部程式直接來控制,以下論述實作方式.



        首先, 如下圖, 拿一個列印介面來當例子, 主要步驟有兩個部分, 首先要先取得視窗控制元件,在來世更進一步的做控制.

列印程式介面



I. Get Window HWND
        
        要取得一個windows的控制權, 首先要取得該視窗的HWND, 實作上可以使用FindWindow函式, 詳細可以看msdn.

FindWindow:
        http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499%28v=vs.85%29.aspx

        由函式的定義來看, 可以指定的參數有兩個, 一個是class名稱, 指定控制元件的類別,此部分不給也可以, 但是要防止碰到名稱一樣的控制元件,第二個是控制元件名稱, 以這個例子就是"列印", 程式碼如下
?
1
2
3
4
5
HWND wnd = FindWindow( NULL, "列印");
if(wnd)
{
    //處理    
}


II.對視窗做控制
     
        在視窗的控制方面, 有兩種方式, 以下個別做說明
如果可以確定元件id的話, 可以Send WM_COMMAND做處理
抓到最底層目標的原件, 直接送訊息

1.WM_COMMAND
        在這邊特別說明一下 WM_COMMAND, 當我們在做視窗操作時, 像是按下按鈕, 下拉選單等等, 都會觸發WM_COMMAND, 如果知道操作對象的話,某種程度直接使用WM_COMMAND就可以處理了, 詳細可以看msdn


WM_COMMAND:       
        http://msdn.microsoft.com/en-us/library/windows/desktop/ms647591%28v=vs.85%29.aspx


WM_COMMAND的訊息有三種方式
Menu
Accelerator
Control

其中Accelerator不討論,這邊看menu以及Control的方式

.WM_COMMAND - Menu
       
        實際測試了一下, 按鈕的話照menu方式直接送ID也有BN_CLICKED的效果,非按鈕的我就不確定了, 程式碼如下.

?
1
SendMessage(wnd, WM_COMMAND, IDOK, NULL);

        參考程式碼頁面,照定義送的是menu元件的話, 則wParam的高位元會是0, 低位元是id, 其實等同IDOK(送高位元放0, 低位元IDOK), 如果怕判斷會出問題的話, 可以用MAKEWPARAM即可

?
1
2
3
4
5
6
7
WPARAM MAKEWPARAM(
  WORD wLow,
  WORD wHigh
);
 
WPARAM wParam = MAKEWPARAM( IDC_OK, 0);
SendMessage(wnd, WM_COMMAND, MAKEWPARAM(IDOK,0),0);

.WM_COMMAND - Control

        Control的方式較複雜, 以下是msdn的定義
wParam
        高位元放Control-defined notification code       
        低位元放Control identifier
lParam
        Handle to the control window
      
        此例已知控制視窗的wnd, 所以處理wParam即可

?
1
SendMessage(wnd, WM_COMMAND, MAKEWPARAM(IDOK,BN_CLICKED),0);

2.抓最底層目標元件

        目前已取得目標視窗的HWND, 要在更進一步找視窗裡面的元件時, 需要使用FindWindowEX來處理, 使用方式一樣是由名稱找, 這邊範例指定class名稱, 名稱定義詳細可以看msdn, 這邊就不詳述了, 程式碼如下


?
1
2
3
HWND wndButton = FindWindowEx(wnd, NULL,"Button", "取消");;
 
SendMessage(wndButton, BM_CLICK, 0, 0);


III.實作程式碼


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void main()
{
    HWND wnd = FindWindow( NULL, "列印");
    if(wnd)
    {    
 
        //方式1..知道元件ID的話可以用, 
        //物件是按鈕的話,直接送ID也可以達到Click的效果
        //另外, 如果真的不確定id,
        //IDOK(1)通常會是windows預設介面的"確定",IDCANCEL同
     
        //menu方式
        SendMessage(wnd, WM_COMMAND, IDOK, NULL);
        SendMessage(wnd, WM_COMMAND, MAKEWPARAM(IDOK,0),0);
     
        //Control方式
        SendMessage(wnd, WM_COMMAND, MAKEWPARAM(IDOK,BN_CLICKED),0);
     
     
        //方式2, 進一步取得按鈕, 送出按下訊息
        HWND wndButton = FindWindowEx(wnd, NULL,"Button", "取消");//"列印(&P)");
        if(wndButton)
        {
            SendMessage(wndButton, BM_CLICK, 0, 0);
        }
     
     }
}


http://arkkk.blogspot.tw/2011/11/findwindow-sendmessage.html
                  

VBA \"處理程序識別碼\" PID TASK ID

View Snippet
                    https://www.google.com.tw/search?q=VBA+%22%E8%99%95%E7%90%86%E7%A8%8B%E5%BA%8F%E8%AD%98%E5%88%A5%E7%A2%BC%22&oq=VBA+%22%E8%99%95%E7%90%86%E7%A8%8B%E5%BA%8F%E8%AD%98%E5%88%A5%E7%A2%BC%22&gs_l=serp.3...28672.33460.0.33712.5.5.0.0.0.0.168.400.3j2.5.0....0...1c.1.64.serp..0.0.0.xs22cvv6zWA
                  

內碼

View Snippet
                    璉璉 2006-06-03 09:51:56 UTC
PermalinkRaw Message
VBA:
? Hex(Asc("心")) ' Big5
A4DF
? Hex(AscW("心")) ' Unicode
5FC3

所以用 VBA 包一個函數:
Function MyAsc(ByVal strChar As String) As String
MyAsc = Hex(Asc(strChar))
End Function

在工作表用
=MyAsc(A1)

http://microsoft.public.tw.excel.narkive.com/t730ls1c/big-5

https://www.youtube.com/watch?v=kcxK2xw6N0g
https://msdn.microsoft.com/zh-tw/library/s2dy91zy.aspx
http://www.programmer-club.com.tw/ShowSameTitleN/vb/21620.html

                  

VBA Clipboard - 存取剪貼簿

View Snippet
                    	Clipboard - 存取剪貼簿
« 於: 2005-09-03, 17:33:42 »
DataObject 是應用程式和剪貼簿(Clipboard)之間的橋樑,
可以透過 DataObject 物件存取剪貼簿的內容。
DataObject 內容會隨著應用程式關閉而消失,
而剪貼簿內容則只要不離開Windows就不會消失。

以下程式會宣告並用到 DataObject 物件型態,
使用前必須確定已引用 MS Forms 2.0 Object Library。
(設定引用程式庫的方式請參考下圖)

Sub 取得剪貼簿內容()
 Dim data As New DataObject
 data.GetFromClipboard
 Range("A1") = data.GetText(1)
End Sub

Sub 寫入剪貼簿()
 Dim data As New DataObject
 chars = [A1].Characters(3, 5).Text '取得A1部份內容
 data.SetText chars '寫入DataObject
 data.PutInClipboard '寫入剪貼簿
 [B1].Select
 ActiveSheet.Paste '再貼到B1
End Sub
 
Sub 清除剪貼簿內容()
 Dim data As New DataObject
 Set data = New DataObject
 data.SetText ""
 data.PutInClipboard
End Sub

你可以對 DataObject 使用 Clear 方法來清除它的內容,
但這方法在這裡並不實際,
不如直接傳送一個空字串到剪貼簿裡,如上面範例。


[附件已被管理員刪除]

http://gb.twbts.com/index.php?PHPSESSID=652f99d86b969ff33dc97941def91e52&topic=1878.msg9449#msg9449

https://www.google.com.tw/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=vba+%E5%89%AA%E8%B2%BC%E7%B0%BF+%E6%B8%85%E9%99%A4


Where is Microsoft Forms 2.0 Object Library?
Search your PC for the FM20.DLL file.

On my PC it is under C:\WINDOWS\system32

https://www.mrexcel.com/forum/excel-questions/482637-excel-2010-where-microsoft-forms-2-0-object-library.html


https://www.google.com.tw/search?q=MS+Forms+2.0+Object+Library&oq=MS+Forms+2.0+Object+Library&aqs=chrome..69i57&sourceid=chrome&ie=UTF-8
                  

功能變數清單編號轉成文字

View Snippet
                    ActiveDocument.Content.ListFormat.ConvertNumbersToText