如何用C語言寫一個獲取視窗控制程式碼和其他資訊的小程式.

北赤道逆流發表於2018-09-07

博主是一個SDK程式設計的初學者,始終堅持學技術要任務驅動的觀念,在學習了有關Windows程式,核心物件,程式管理和控制的知識之後,就迫不及待地想要設計一個記憶體修改器練練手,然而在獲取當前執行的各視窗的控制程式碼這一步就卡住了,經過一番查閱和鑽研,終於寫出瞭如下的CUI小程式,解決了獲取視窗及子視窗控制程式碼,獲取ClassName,獲取WindowText的問題。
不知道這個小程式能不能替代SPY++的部分功能……

//CUI:相對於GUI(Graphical User Interface)圖形使用者介面而言的Command User Interface命令列使用者介面。

PS:博主才疏學淺,程式中如有錯誤,歡迎各位指正!

該程式基於下列四個API實現
EnumWindows()

EnumWindows()
//BOOL EnumWindows(WNDENUMPROC,LPARAM)
//WNDENUMPROC 為回撥函式的地址
//LPARAM為你自已定義的引數,將會傳遞給回撥函式.

EnumChildWindows()

函式原型: 

  BOOL EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc, LPARAM lParam);
  //HWND hWndParent 父視窗控制程式碼 
  //WNDENUMPROC lpEnumFunc 回撥函式的地址 
  //LPARAM lParam 自定義的引數 
  //注意:回撥函式的返回值將會影響到這個API函式的行為。如果回撥函式返回true,則列舉繼續直到列舉完成;如果返回false,則將會中止列舉。 

GetClassName()

GetClassName(hwnd,classname,256);
//GetClassName();hwnd是需要傳入的控制程式碼/classname是需要傳入的LPTSTR緩衝區,用於接收類名/256是int,指定classname的大小,單位位元組.
//獲取成功將返回返回值為拷貝到指定緩衝區的字元個數,如果函式失敗,返回值為0.

GetWindowText()

//與GetClassName引數完全一致,不再贅述。

//關於它們的引數列表和解釋會在下面的程式碼註釋中體現,想要了解以上四個函式的使用方法的話也可以作為參考。

基本思路比較簡單,先呼叫EnumWindows,遍歷所有父窗體,在遍歷時再呼叫EnumChildWindows,在每一個父窗體下遍歷其子窗體,如果有的話即輸出。

以下為原始碼:

/*
程式名稱: 簡易Windows窗體檢視器
程式功能: 檢視當前狀態下所有窗體的classname,windowtext,hwnd(窗體控制程式碼).
程式類別: CUI WIN32應用程式 
作者:     北赤道逆流 
聯絡方式: zhangjunshuo_sdu@outlook.com 
注意:     本程式編譯環境為 WindowsXP x86 Dev-C++ 5.4.2
                         Windows10 x64 Dev-C++ 5.9.2 
          經測試64位版本與32位版本狀態均良好,其餘環境未經測試. 
*/

#define Primary false //關閉初級使用者模式 //使用者可以在此處選擇開啟(true)或是關閉初級使用者模式
                      //在初級使用者模式下,程式將不會顯示子窗體的資訊,同時也會隱藏沒有WindowText的窗體。 

#include<stdio.h>
#include<windows.h>
#include<string.h> 
//EnumWindows()和EnumChildWindows()需要回撥函式.
//先寫EnumChildWindows()的回撥函式enumchildwindows_callback(),因為在enumwindows_callback()裡面要用它.
BOOL CALLBACK enumchildwindows_callback(HWND hwnd, LPARAM lParam)
//關於函式引數等的具體解釋見下面的enumwindows_callback()!
//因為enumwindows_callback()函式寫的比較完整,所以在它裡面加了詳細註釋,就不在這裡加了.
//如果閱讀該函式有困難,建議先閱讀下面的enumwindows_callback(); 
{
    TCHAR classname[256];
    TCHAR windowtext[256];
    int cn = GetClassName(hwnd,classname,256);
    int wt = GetWindowText(hwnd,windowtext,256);
    if(cn==0)
    {
        if(wt==0)
        {
            printf("    Error in EnumChildWindows_CALLBACK\n");
            return FALSE;
        }
        else if(wt!=0)
        {
            printf("    NULL ||| %18s ||| %d\n",windowtext,hwnd);   //%18s表示該字串最少佔用18個個字元空間,printf格式控制符。 
            return TRUE;
        }
    } 
    else if(cn!=0)
    {
        if(wt==0)
        {
                printf("    %-18s ||| NULL ||| %d\n",classname,hwnd);   //-是格式控制字元,表示左對齊。 
                return TRUE;
        }
        else if(wt!=0)
        {
            printf("    %-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
            return TRUE;
        }
    } 
} 
BOOL CALLBACK enumwindows_callback(HWND hwnd, LPARAM lParam)
//hwnd就是系統傳遞給該回撥函式的窗體控制程式碼,lParam是控制引數,將會由呼叫函式(EnumWindows)傳入,以控制回撥函式的行為,預設值為0; 
{
    TCHAR classname[256];//此處務必事先指定變數的記憶體大小!如果使用LPTSTR指標形式,也務必立即使用malloc分配合適的記憶體,避免野指標.
    TCHAR windowtext[256];
    int cn = GetClassName(hwnd,classname,256);
    //GetClassName();hwnd是需要傳入的控制程式碼/classname是需要傳入的LPTSTR緩衝區,用於接收類名/256是int,指定classname的大小,單位位元組.
    //獲取成功將返回返回值為拷貝到指定緩衝區的字元個數,如果函式失敗,返回值為0. 
    int wt = GetWindowText(hwnd,windowtext,256);
    //解釋同GetClassName();
    if(cn==0)
    {
        if(wt==0)
        {
            printf("Error in EnumWindows_CALLBACK\n");
            return FALSE;   //理論上不會存在既沒有類名又沒有標題名的窗體 
        }
        else if(wt!=0)
        {
            printf("NULL ||| %18s ||| %d\n",windowtext,hwnd);
            return TRUE;    //這種情況至今沒有見到過! 
        }
    } 
    else if(cn!=0)
    {
        if(wt==0)
        {
            if(Primary==true)return TRUE;//隱藏輸出,以面向初級使用者,而且不顯示子窗體資訊. 
            else if(Primary==false)
            {
                printf("------------------------------------------------------------\n");//父窗體與父窗體之間的分割線. 
                printf("%-18s ||| NULL ||| %d\n",classname,hwnd);
                int check=EnumChildWindows(hwnd,(WNDENUMPROC)enumchildwindows_callback,0);//在此處呼叫顯示子窗體的EnumChildWindows.
                if(check == 0) printf("    ->NoneChildWindow\n");//如果沒有子窗體我們要這樣回顯. 
                return TRUE;
            }
        }
        else if(wt!=0)
        {
            if(Primary==true)
            {
                printf("%-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
                return TRUE;
            }
            else if(Primary==false)
            {
                printf("------------------------------------------------------------\n");//父窗體與父窗體之間的分割線. 
                printf("%-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
                int check=EnumChildWindows(hwnd,(WNDENUMPROC)enumchildwindows_callback,0);
                if(check == 0) printf("    ->NoneChildWindow\n");
                return TRUE;
            }
        }
    } 
}

int main()
{
    //先建立一個標題欄 
    printf("WINDOWS_EXPLORER\n");
    if(Primary==true)printf("PRIMARY_MODE\n\n");
    else if(Primary==false)printf("ADVANCED_MODE\n\n");
    printf("CLASSNAME----WINDOWTEXT----(int)HWND\n\n");

    int check = EnumWindows((WNDENUMPROC)enumwindows_callback,0);
    //BOOL EnumWindows(WNDENUMPROC,LPARAM)
    //WNDENUMPROC 為回撥函式的地址
    //LPARAM為你自已定義的引數,將會傳遞給回撥函式.
    if(check == 0)printf("Error in EnumWindows\n");
    system("pause");
    return 0;
}

最後附上該原始碼的Github地址

https://github.com/ZhangJunshuo/WindowsInformationExplorer.git

相關文章