2012-04-19 51 views
9

我已經在WINDOS XP,Vista和「7」多年運行正常一個2007年德爾福項目。這是Delphi 5的升級,因此默認情況下「MainFormOnTaskBar」爲「false」(我從來沒有在DPR中改變它)。在這種情況下,系統範圍的熱鍵在主窗體的OnCreate事件處理程序中使用以下代碼「全系統」工作。德爾福2007年 - 全系統熱鍵是不是「全系統」,如果設置「MainFormOnTaskBar:=真」

HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
if NOT RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12) then 
    ShowMessage('Unable to register Control-F12 as system-wide hot key') ; 

(I have GlobalDeleteAtom() and UnregisterHotKey() in Form.OnDestroy as expected.) 

現在,我需要一個表格,顯示在任務欄上都有自己的按鈕,所以我設置「Application.MainFormOnTaskBar:=真」在DPR。這按預期工作。但是,這具有Control-F12在系統範圍內不起作用的副作用,它只在我的應用程序具有焦點時起作用(因此,它不再是「系統範圍」了。)

我已經廣泛搜索了'Net找到了很多關於如何/爲什麼「MainFormOnTaskBar」影響某些子表單/模式表單行爲的文章。但是,我沒有發現任何關於它對上面描述的「系統範圍熱鍵」問題的影響。我已經測試並重新測試了我的應用程序,將MainFormOnTaskBar設置爲true和false,而其他所有內容保持完全相同。我可以肯定地驗證上述與系統範圍熱鍵相關的問題與MainFormOnTaskBar標誌有關。

,我將不勝感激關於工作周圍的任何指導。我確實需要兩者 - 一個系統範圍的熱鍵和一個在任務欄上有自己的按鈕的窗體。

非常感謝。

+0

你可以用* new *項目複製它嗎?我不能.. – 2012-04-19 00:53:30

+0

我也無法重現這一點。你能發佈更多的代碼嗎? (也可能嘗試在此期間,'RegisterHotkey'呼叫改變'Self.Handle'到'Application.Handle'呢?'WM_HOTKEY'消息仍然會得到您的形式,因爲應用程序的消息處理程序不會用它做任何事;它將被髮送到您的形式,就像通常) – 2012-04-19 01:03:40

+0

@KenWhite:如果'Application.Handle'用於註冊熱鍵,則'WM_HOTKEY'消息將不會被引導到TForm的,直接或間接地。它們將被定向到'TApplication',所以要捕獲這些消息,你必須使用'TApplication.OnMessage'事件和/或'TApplication.HookMainWindow()'方法。 – 2012-04-19 01:17:38

回答

14

TApplication.MainFormOnTaskbar對所有全系統熱鍵沒有影響。我可以肯定地證實這一點。無論應用程序是否專注於等,無論MainFormOnTaskbar設置爲什麼,我都能收到WM_HOTKEY消息。因此,無論您看到的是不是您認爲正在發生的事情。

最有可能的,窗體的Handle只是簡單地重新創建你背後,你呼籲RegisterHotKey()後,讓你失去的將獲得WM_HOTKEY消息HWND。除了使用OnCreate事件,你應該重寫窗體的CreateWindowHandle()DestroyWindowHandle()方法,而不是保證熱鍵總是註冊表單目前HWND無論發生什麼事情吧(你應該總是這樣,只要你配合任何類型的數據來窗體的Handle),例如:

type 
    TForm1 = class(TForm) 
    private 
    HotKey_xyz: WORD; 
    procedure WMHotKey(var Message: TMessage); message WM_HOTKEY; 
    protected 
    procedure CreateWindowHandle(const Params: TCreateParams); override; 
    procedure DestroyWindowHandle; override; 
    end; 

procedure TForm1.CreateWindowHandle(const Params: TCreateParams); 
begin 
    inherited; 
    HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
    if HotKey_xyz <> 0 then 
    RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12); 
end; 

procedure TForm1.DestroyWindowHandle(const Params: TCreateParams); 
begin 
    if HotKey_xyz <> 0 then 
    begin 
    UnregisterHotKey(Self.Handle, HotKey_xyz); 
    GlobalDeleteAtom(HotKey_xyz); 
    HotKey_xyz := 0; 
    end; 
    inherited; 
end; 

procedure TForm1.WMHotKey(var Message: TMessage); 
begin 
    ... 
end; 

一個更好的選擇是使用AllocateHWnd()分配一個單獨的專用HWND只是爲了處理熱鍵消息(那麼你就可以再次使用OnCreateOnDestroy事件),例如:

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    HotKey_xyz: WORD; 
    HotKeyWnd: HWND; 
    procedure HotKeyWndProc(var Message: TMessage); 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    HotKeyWnd := AllocateHwnd(HotKeyWndProc); 
    HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
    if HotKey_xyz <> 0 then 
    RegisterHotKey(HotKeyWnd, HotKey_xyz, MOD_CONTROL, VK_F12); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if HotKey_xyz <> 0 then 
    begin 
    UnregisterHotKey(HotKeyWnd, HotKey_xyz); 
    GlobalDeleteAtom(HotKey_xyz); 
    HotKey_xyz := 0; 
    end; 
    if HotKeyWnd <> 0 then 
    begin 
    DeallocateHWnd(HotKeyWnd); 
    HotKeyWnd := 0; 
    end; 
end; 

procedure TForm1.HotKeyWndProc(var Message: TMessage); 
begin 
    if Message.Msg = WM_HOTKEY then 
    begin 
    ... 
    end else 
    Message.Result := DefWindowProc(HotKeyWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 
+1

單獨使用'AllocHWnd'代碼示例。不錯 - 我以前從來沒有見過這樣做。我會將此標記爲將來參考。 – 2012-04-19 01:22:52

+0

@Remy:非常感謝你:CreateWindowHandle()和DestroyWindowHandle()方法 - 這就實現了。所以,不夠感謝你。我將探索「AllocateWnd()」 - 我需要更多的教育!我想UP-Vote你的答案,但堆棧溢出說我沒有足夠的「聲譽」這樣做。 – JayM 2012-04-19 05:13:52

+0

@All:感謝所有評論並花時間來測試我的主張MainFormOnTaskBar標誌是罪魁禍首的人 - 我承認,事實並非如此。再次,我非常感謝這個社區的支持和幫助的意願。 – JayM 2012-04-19 05:16:00

相關問題