2012-04-19 39 views
9

Tôi có một dự án Delphi 2007 chạy tốt trên Windos XP, Vista và "7" trong nhiều năm. Đó là một bản nâng cấp từ Delphi 5, do đó "MainFormOnTaskBar" là "false" theo mặc định (tôi không bao giờ thay đổi nó trong DPR). Trong trường hợp này, phím nóng toàn hệ thống làm việc "toàn hệ thống" với mã sau trong trình xử lý sự kiện OnCreate của biểu mẫu chính.Delphi 2007 - Phím nóng toàn hệ thống KHÔNG phải là "toàn hệ thống" nếu thiết lập "MainFormOnTaskBar: = True"

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.) 

Bây giờ, tôi cần Biểu mẫu để hiển thị nút riêng trên Thanh tác vụ, vì vậy tôi đặt "Application.MainFormOnTaskBar: = True" trong DPR. Điều này hoạt động như mong đợi. Tuy nhiên, điều này có tác dụng phụ mà Control-F12 KHÔNG hoạt động trên toàn hệ thống, nó hoạt động CHỈ NẾU ứng dụng của tôi có tiêu điểm (vì vậy, nó KHÔNG còn là "toàn hệ thống" nữa.)

Tôi đã tìm kiếm rộng rãi 'Net đã tìm thấy nhiều bài báo liên quan đến cách thức/tại sao "MainFormOnTaskBar" ảnh hưởng đến một số hành vi biểu mẫu con/dạng thức nhất định. Tuy nhiên, tôi đã không tìm thấy gì liên quan đến hiệu ứng của nó trên một vấn đề "Hệ thống toàn khóa nóng" mà tôi mô tả ở trên. Tôi đã thử nghiệm và kiểm tra lại ứng dụng của tôi với MainFormOnTaskBar được đặt thành true và false trong khi tất cả các ứng dụng khác vẫn giữ nguyên. Tôi có thể xác minh tích cực rằng vấn đề được mô tả ở trên với phím nóng toàn hệ thống liên quan đến cờ MainFormOnTaskBar.

Tôi sẽ đánh giá rất cao mọi hướng dẫn liên quan đến công việc. Tôi cần BOTH - một phím nóng toàn hệ thống và một biểu mẫu với nút riêng của nó trên thanh tác vụ.

Cảm ơn rất nhiều.

+0

Bạn có thể sao chép nó bằng một dự án * mới * không? Tôi không thể .. –

+0

Tôi cũng không thể tái tạo điều này. Bạn có thể đăng thêm mã không? (Và có thể thử thay đổi 'Self.Handle' thành' Application.Handle' trong cuộc gọi 'RegisterHotkey' trong thời gian chờ đợi? Thông điệp' WM_HOTKEY' sẽ vẫn nhận được biểu mẫu của bạn, bởi vì trình xử lý tin nhắn của ứng dụng không làm bất cứ điều gì với nó ; nó sẽ được gửi vào biểu mẫu của bạn giống như bình thường.) –

+0

@KenWhite: nếu 'Application.Handle' được sử dụng để đăng ký khóa nóng, thì các thông điệp' WM_HOTKEY' S W KHÔNG được chuyển tới TForm, trực tiếp hoặc gián tiếp. Chúng sẽ được chuyển hướng đến 'TApplication' thay vào đó, vì vậy để nắm bắt những thông điệp đó, bạn phải sử dụng sự kiện' TApplication.OnMessage' và/hoặc phương thức 'TApplication.HookMainWindow()'. –

Trả lời

14

TApplication.MainFormOnTaskbar không ảnh hưởng đến các phím nóng toàn hệ thống. Tôi có thể xác nhận tích cực điều đó. Tôi có thể nhận được WM_HOTKEY tin nhắn bất kể những gì MainFormOnTaskbar được đặt thành, bất kể ứng dụng có tập trung hay không, v.v. Vì vậy, bất cứ điều gì bạn đang thấy không phải là những gì bạn nghĩ đang xảy ra.

Rất có thể, Biểu mẫu Handle chỉ đơn giản là được tạo lại sau lưng bạn sau khi bạn gọi là RegisterHotKey(), vì vậy bạn sẽ mất HWND để nhận được thông báo WM_HOTKEY. Thay vì sử dụng sự kiện OnCreate, bạn nên ghi đè các phương thức CreateWindowHandle()DestroyWindowHandle() của Biểu mẫu thay vì đảm bảo khóa nóng luôn được đăng ký cho Hình thức HWND hiện tại của bất kể điều gì xảy ra với nó (bạn nên luôn làm điều đó bất cứ khi nào bạn liên kết bất kỳ loại dữ liệu nào của Mẫu Handle), ví dụ:

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; 

một lựa chọn tốt hơn là sử dụng AllocateHWnd() để phân bổ một riêng biệt dành riêng HWND chỉ để xử lý các thông điệp chính nóng (sau đó bạn có thể sử dụng OnCreateOnDestroy sự kiện một lần nữa), ví dụ:

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

+1 cho ví dụ mã 'AllocHWnd'. Nice - Tôi chưa bao giờ thấy nó được thực hiện như thế trước đây. Tôi sẽ đánh dấu điều này để tham khảo trong tương lai. –

+0

@Remy: Cảm ơn bạn rất nhiều vì: phương thức CreateWindowHandle() và DestroyWindowHandle() - đã thực hiện điều đó. Vì vậy, không thể cảm ơn đủ. Tôi sẽ khám phá "AllocateWnd()" - Tôi cần thêm giáo dục về điều đó! Tôi muốn UP-Vote câu trả lời của bạn nhưng Stack Overflow nói rằng tôi không có đủ "danh tiếng" để làm như vậy. – JayM

+0

@All: Cảm ơn tất cả những người đã nhận xét và dành thời gian để kiểm tra ý kiến ​​của tôi rằng cờ MainFormOnTaskBar là thủ phạm - tôi đã giáo dục rằng nó không phải là. Một lần nữa, tôi rất cảm kích sự ủng hộ của cộng đồng và sự sẵn lòng giúp đỡ. – JayM

Các vấn đề liên quan