在桌面中嵌入窗體

前幾天在網上看到一個軟件的介紹:能夠嵌入桌面,即便是「顯示桌面」也不會影響此程序。看做者說的好像有多麼的神奇同樣。周未就回來試一下。最後發現,Windows這個桌面還真是複雜和有意思。
  首先要分析Windows桌面。
  打開老牌軟件"Spy Window"。查看一下桌面。取得一個「SysListView32」類的句柄(本系統爲XP版本)。將其最小化,能夠看出剛纔取得的控件好像是透明的。由於將其最小化以後,還能夠看到你所設置的桌面圖片。
  從新用"Spy Window"獲取桌面上的控件句柄(也能夠直接點擊"Parent Window"取得其父窗口句柄),獲得一個"SHELLDLL_DefView"類的句柄。將其最小化,能夠看到桌面圖片依然存在,難道又是一個透明控件嗎?先不理會它,咱們繼續向「下」找。再一次取得「桌面」上一個類名爲「Progman」的控件句柄。並且此時你會發現Spy Window的"Parent Window"按鈕已不可用了。
  這個類爲「Progman」的窗口「下面」真的沒有其它窗口了嗎?按「Ctrl+Alt+Del「在任務管理器裏結束「explorer」,後再使用「Spy Window」看一下,是否是又有一個類名爲「#32769」的窗口出了。試着對此窗口進行禁用,最小化,隱藏操做試一下。好像一切都是無效的。
  到此爲至,應該說把這張桌面的結構搞清楚了。至關於圖像處理中的四個圖層,並且是透明圖層。
  按類名由前至裏的排序爲:
  SysListView32
  SHELLDLL_DefView
  Progman
  #32769
  看來這個桌面果真不是通常的複雜。
  回憶一下之前用代碼來隱藏桌面的操做:
  FindWindow(''''Progman'''',Nil);
  ShowWindow(...);
  這裏的''''Progman''''就是第三層(本文中咱們就以層來稱呼它們)的窗口了。在結束進程「Explorer」時,此窗口消失,說明此窗口是由「Explorer.exe」創建的。
  下面進行將程序嵌入到桌面裏的操做。
  這裏所須要的只有一個語句:
  FrmMain.ParentWindow:=ParentHandle;其中,ParentHandle是你所要嵌人的控件句柄。
  按此實現,能夠創建一個窗體,拖入一個TButton,一個TEdit。在Button的Click事件中寫入代碼FrmMain.ParentWindow:=StrToInt(EdtHandle.Text);
  下面,先來嵌入「第一層桌面」看一下。用"Spy Window」取得當前桌面句柄,也就是第一層''''SysListView32''''。轉爲十進制後複製到EdtHandle。點擊按鈕。
  程序是否是轉爲非焦點狀態了。按一下「Win+D」(顯示桌面)。是否是窗口仍停留在桌面上。
  好像文章開頭的目的已經實現了。
  仔細測試一下當前的窗體,是否是與原來有很大的不一樣。首先,窗口的標題欄老是非焦點狀態。第二窗體上的右擊被桌面攔截了下來。
  第三Edit裏表顯不出TEdit自己對消息的響應。如點擊時,拖動時,按鍵時右擊時,Edit缺乏相應的閃爍輸入光標,抹黑所選字符,文字處理,顯示上下文菜單等。這是由於窗體得不到焦點,而得不到焦點對於TEdit控件來講,一切都是無效的。
  動態取得第一層控件句柄的方法是:
  TmpHandle:=FindWindow(''''Progman'''',Nil);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  此時TmpHandle便是桌面的句柄了。
  依照此方法,咱們能夠將窗體嵌入第二層''''SHELLDLL_DefView''''了。當嵌入第二層時,你會發現。所嵌入的程序窗口不見了。當咱們把第一層最小化時,能夠看到咱們所嵌入的窗口是存在的。只是被第一層所遮住了。因此說,第一層並非透明的!
  第一層最小化以後,能夠看到,桌面上的圖標都不見了。再看一下第一層的類名「SysListView32」,能夠肯定,第一層這個控件的做用主要就是列出系統桌面上的圖標。咱們在當前第二層中點擊一下右鍵。桌面菜單出來了吧?原來一切的消息及處理都是在這一層接收和處理的。這時能夠用「新建」命令新建一個文檔,以後再恢復第一層桌面,能夠看到,新建的文檔出現了。
  能夠這樣理解,第一層是「顯示層」,第二層是「功能層」。咱們的窗體在這裏是顯示不出來的。並且一樣得不到焦點。
  如今,將咱們的程序嵌入到第三層''''Progman'''',嵌入以後,出現了和第二層相同的結果,按功能來講這一層應該沒有什麼實際的用途,可能只是給上面兩層提供一個容器。如今''''Progman''''中有了兩個窗體,一個是原有的''''SHELLDLL_DefView'''',另外一個即是這個嵌入窗體。可是前者用盡了全部的可視區域,因此才使得嵌入的窗體顯示不出來。這種狀況彷佛平時也會遇到,那咱們在嵌入時加入一句:BringWindowToTop(FrmMain.Handle);試試;
  呵呵,看到了什麼?是否是嵌入的窗口出現了?按一下"Win+D"看一下。如何?還在吧?若是桌面上有圖標的話,此時這個窗體應該是擋遮住了一部分圖標的。
處理的辦法就是將上一層窗體縮小。如:
  TmpHandle:=FindWindow(''''Progman'''',Nil);
  TmpHandle:=GetWindow(TmpHandle,GW_CHILD);
  MoveWindow(TmpHandle,0,20,1024,740,False);
  這樣,在窗體頂部留出了二十象素的高度。能夠放一個任務欄式的窗體了。
  如今只剩下最後一層"#32769"了。只要在系統登錄前的啓動程序不變,此窗口的句柄應該是不變化的(有可能系統登錄前啓動的程序有變化此句柄也不變,具體狀況沒試過)。
  按前面的方法將窗體嵌入到此窗口中。
  窗體又是得不到焦點的狀態了。能夠看出來這和嵌入到第一層差很少。可是咱們拖動一下窗體看一下。此時窗體並非實時跟隨鼠標的。再仔細看一下,任務欄上出現了兩個此程序的按鈕。一個是程序的名稱,一個是窗口的名稱。這是一種奇怪的現象,歷來沒有見過的。或許咱們能夠這樣解釋它。Explorer會將符合要求的窗體顯示在任務欄上(非ToolsWindows,而且可見)。本窗體就符合,並且Explorer又會將窗口"#32769"裏的全部窗口放到任務欄上而無論它是否復。因此纔會獲得此結果。
  總結一下:
  Windows的桌面是分四層的。嵌入的窗體若是嵌入到第三層,並將Z軸順序移到最上的話,程序就會一個正常的嵌入桌面的程序。這符合咱們的要求。並且能夠經過調整第二層的大小來使窗體不遮住桌面圖標。因此,將窗體嵌入到此是很理想的。
  第一層的嵌入也是能夠的。可是在這裏窗體會得不到焦點和使用不了右鍵。因此這裏的窗體受不少限制。
  第二層是一個根本不考慮嵌入窗體的地方,由於這裏的窗體根本顯示不出來。並且與第一層相同的得不到焦點。
  第四層是個意外的層。嵌在這裏的窗體會表顯出異樣的狀況。惟一值得咱們嵌入的理由是:它不會隨Explorer.exe進程的結束而關閉。
用mfc實現就是這樣的代碼 HWND hDesktop = ::FindWindow("Progman", NULL); hDesktop = ::GetWindow(hDesktop, GW_CHILD); CWnd* pWndDesktop = CWnd::FromHandle(hDesktop); this->SetParent(pWndDesktop);
相關文章
相關標籤/搜索