2013-01-21 31 views
5

Xem thêm:
How can I tell if another instance of my program is already running?Delphi: Làm thế nào để sử dụng ShowWindow đúng trên ứng dụng bên ngoài

tôi sử dụng đoạn mã sau trước khi bắt đầu ứng dụng của tôi, để kiểm tra xem một ví dụ của nó là đã bắt đầu:

var _PreviousHandle : THandle; 
begin 
    _PreviousHandle := FindWindow('TfrmMainForm',nil); 
    if _PreviousHandle <> 0 then 
    begin 
    ShowMessage('Application "" is already running!'); 
    SetForegroundWindow(_PreviousHandle); 
    ShowWindow(_PreviousHandle, SW_SHOW); 
    Application.Terminate; 
    Exit; 
    end; 
... 

Tuy nhiên, nếu nó đã bắt đầu, tôi cần phải hiển thị ứng dụng đó. Vấn đề là sau khi nó được hiển thị theo cách này, nút thu nhỏ không còn hoạt động nữa, và khi tôi nhấp vào biểu tượng trên thanh tác vụ, nó "unminimizes" và hoạt ảnh được hiển thị như thể nó đã được thu nhỏ. Tui bỏ lỡ điều gì vậy? là có một cách thích hợp để kích hoạt và hiển thị ứng dụng bên ngoài trong khi nó được giảm thiểu?

+7

bạn nên sử dụng 'Mutex' để thực hiện việc kiểm tra và phát thông báo này để thông báo cho trường hợp hiện tại – teran

+0

Vấn đề không phải là làm cách nào để biết chương trình của tôi có đang chạy hay không, mà là cách kích hoạt nó đúng cách từ một phiên bản khác của chương trình đó. – ertx

+2

gửi tin nhắn quảng bá với mã đã biết ('RegisterWindowMessage'), sau đó xử lý thông báo này trong chương trình và để chương trình tự khôi phục. – teran

Trả lời

5

Đây là một dự án hoàn chỉnh, chỉ tiếp tục chạy một phiên bản của ứng dụng, và điều này sẽ làm cho cửa sổ thể hiện đang chạy đến trước.

Bạn có thể tải về một testing project hoặc thử mã, mà sau:

Project1.dpr

program Project1; 

uses 
    Forms, 
    Windows, 
    Unit1 in 'Unit1.pas' {Form1}; 

{$R *.res} 

var 
    Mutex: THandle; 
const 
    AppID = '{0AEEDBAF-2643-4576-83B1-8C9422726E98}'; 
begin 
    MessageID := RegisterWindowMessage(AppID); 

    Mutex := CreateMutex(nil, False, AppID); 
    if (Mutex <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then 
    begin 
    PostMessage(HWND_BROADCAST, MessageID, 0, 0); 
    Exit; 
    end; 

    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TForm1, Form1); 
    Application.Run; 
end. 

Unit1.pas

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StrUtils, StdCtrls; 

type 
    TForm1 = class(TForm) 
    private 
    function ForceForegroundWindow(WndHandle: HWND): Boolean; 
    function ForceRestoreWindow(WndHandle: HWND; Immediate: Boolean): Boolean; 
    protected 
    procedure WndProc(var AMessage: TMessage); override; 
    end; 

var 
    Form1: TForm1; 
    MessageID: UINT; 

implementation 

{$R *.dfm} 

{ TForm1 } 

function TForm1.ForceForegroundWindow(WndHandle: HWND): Boolean; 
var 
    CurrThreadID: DWORD; 
    ForeThreadID: DWORD; 
begin 
    Result := True; 
    if (GetForegroundWindow <> WndHandle) then 
    begin 
    CurrThreadID := GetWindowThreadProcessId(WndHandle, nil); 
    ForeThreadID := GetWindowThreadProcessId(GetForegroundWindow, nil); 
    if (ForeThreadID <> CurrThreadID) then 
    begin 
     AttachThreadInput(ForeThreadID, CurrThreadID, True); 
     Result := SetForegroundWindow(WndHandle); 
     AttachThreadInput(ForeThreadID, CurrThreadID, False); 
     if Result then 
     Result := SetForegroundWindow(WndHandle); 
    end 
    else 
     Result := SetForegroundWindow(WndHandle); 
    end; 
end; 

function TForm1.ForceRestoreWindow(WndHandle: HWND; 
    Immediate: Boolean): Boolean; 
var 
    WindowPlacement: TWindowPlacement; 
begin 
    Result := False; 
    if Immediate then 
    begin 
    WindowPlacement.length := SizeOf(WindowPlacement); 
    if GetWindowPlacement(WndHandle, @WindowPlacement) then 
    begin 
     if (WindowPlacement.flags and WPF_RESTORETOMAXIMIZED) <> 0 then 
     WindowPlacement.showCmd := SW_MAXIMIZE 
     else 
     WindowPlacement.showCmd := SW_RESTORE; 
     Result := SetWindowPlacement(WndHandle, @WindowPlacement); 
    end; 
    end 
    else 
    Result := SendMessage(WndHandle, WM_SYSCOMMAND, SC_RESTORE, 0) = 0; 
end; 

procedure TForm1.WndProc(var AMessage: TMessage); 
begin 
    inherited; 
    if AMessage.Msg = MessageID then 
    begin 
    if IsIconic(Handle) then 
     ForceRestoreWindow(Handle, True); 
    ForceForegroundWindow(Application.Handle); 
    end; 
end; 

end. 

Tested trên các phiên bản hệ điều hành:

  • Windows 8.1 64-bit
  • Windows 7 SP1 64-bit Home Premium
  • Windows XP SP 3 32-bit Professional

Các vấn đề và giới hạn đã biết:

  • MainFormOnTaskbar không được tính đến; nó phải được đặt thành True tại thời điểm này
+0

Nó giống như mã của tôi. Dường như vấn đề không phải là có được xử lý theo một cách khác, nhưng gọi ShowWindow từ một ứng dụng khác. (nút thu nhỏ vẫn không hoạt động) – ertx

+0

Bạn có hệ điều hành nào? Tôi đã thử nghiệm này trên Windows 7 và nó có vẻ làm việc tốt. – TLama

+0

Sự cố này vẫn tồn tại trên Windows 7 Professional, không phải người dùng quản trị viên (có thể có một số ảnh hưởng) – ertx

2

Tác phẩm sau hoạt động tốt cho tôi. Tôi không chắc chắn 100% tôi đã hiểu hết câu hỏi, vì vậy hãy cho tôi biết nếu tôi đã sai.

var 
    _PreviousHandle: HWND; 
    WindowPlacement: TWindowPlacement; 
.... 
WindowPlacement.length := SizeOf(WindowPlacement); 
GetWindowPlacement(_PreviousHandle, WindowPlacement); 
if WindowPlacement.flags and WPF_RESTORETOMAXIMIZED<>0 then 
    WindowPlacement.showCmd := SW_MAXIMIZE 
else 
    WindowPlacement.showCmd := SW_RESTORE; 
SetWindowPlacement(_PreviousHandle, WindowPlacement); 
SetForegroundWindow(_PreviousHandle); 

Lưu ý rằng đúng loại cho _PreviousHandleHWND và không THandle.

+0

SW_RESTORE luôn luôn "kích thước lại" phiên bản của cửa sổ chính của ứng dụng, Nó không hoàn toàn là hành vi mong đợi. – ertx

+0

@ertx Hành vi mong đợi là gì? – jachguate

+0

Để xem chương trình khác theo cách như thể nó được kích hoạt từ người dùng. Nó không quan trọng mà ShowWindow() lệnh tôi sử dụng, hình thức được kích hoạt, nhưng các cửa sổ nghĩ rằng nó vẫn còn giảm thiểu, do đó, các nút thu nhỏ không hoạt động. – ertx

4

Bạn đang yêu cầu biểu mẫu chính của mình hiển thị, nhưng có thể xảy ra chính ứng dụng cửa sổ ẩn được giảm thiểu khi bạn thu nhỏ ứng dụng vào thanh tác vụ, trong trường hợp MainFormOnTaskBar là sai.

Không gọi phương thức ShowWindow từ bên ngoài.IMHO sẽ tốt hơn nếu bạn chuyển một tin nhắn tới ứng dụng và trả lời từ bên trong, gọi phương thức Application.Restore `, thực hiện các cuộc gọi ShowWindow thích hợp trong số những thứ khác.

+0

Sertac, TApplication.Restore đưa vào tài khoản MainFormOnTaskBar và ShowMainForm, vì vậy tốt hơn nên sử dụng nó. – jachguate

+0

@Sertac, tôi đã thêm làm rõ, cảm ơn. – jachguate

3

Đây là vấn đề rất phổ biến với các ứng dụng VCL và đã được hỏi và trả lời nhiều lần trong các diễn đàn Borland/CodeGear/Embarcadero qua nhiều năm. Sử dụng ShowWindow() theo cách này không hoạt động cho các cửa sổ VCL rất tốt vì cách thức MainForm tương tác với đối tượng TApplication khi chạy, đặc biệt là trong các phiên bản khác nhau của Delphi. Những gì bạn nên làm thay vì có trường hợp thứ hai gửi một tin nhắn tùy chỉnh cho trường hợp đầu tiên, và sau đó để cho ví dụ đầu tiên khôi phục chính nó khi cần thiết khi nó nhận được tin nhắn, chẳng hạn như bằng cách thiết lập thuộc tính MainForm.WindowState hoặc gọi Application.Restore(), v.v. hãy để VCL giải thích chi tiết cho bạn, như @jachguate đề xuất.

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