⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 api.htm

📁 对于学习很有帮助
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>

<TITLE>UDDF - API</TITLE>
<META NAME="Description" CONTENT="API section of the Delphi Developers FAQ" >
<META NAME="KeyWords" CONTENT="" >
</HEAD>
<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">

<CENTER>
<IMG SRC="../images/uddf.jpg"> </CENTER>

<P><HR size="6" COLOR="$00FF00"></P>
<FONT FACE="Arial Black" SIZE=7 COLOR="#ff0000"><P ALIGN="CENTER">Api</FONT> </P>

<!---------------------------------------------------------------------------------------------------------------------------------------------------->
<H1><A NAME="api0">How Can I Prevent Multiple Instances of My Application?</A></H1>
<H2> Solution 1</H2>
<I><P>From: &quot;David S. Lee&quot; &lt;davidlee@crl.com&gt;</P>
</I><P>This is the way I do it:</P>
<P>In the begin..end block of the .dpr:</P>
<PRE>begin
  if HPrevInst &lt;&gt;0 then begin
    ActivatePreviousInstance;
    Halt;
  end;
end;</PRE>
<P>Here is the unit I use:</P>
<HR><PRE>unit PrevInst;

interface

uses
  WinProcs,
  WinTypes,
  SysUtils;

type
  PHWnd = ^HWnd;

function EnumApps(Wnd: HWnd; TargetWindow: PHWnd): bool; export;

procedure ActivatePreviousInstance;

implementation

function EnumApps(Wnd: HWnd; TargetWindow: PHWnd): bool;
var
  ClassName : array[0..30] of char;
begin
  Result := true;
  if GetWindowWord(Wnd, GWW_HINSTANCE) = HPrevInst then begin
    GetClassName(Wnd, ClassName, 30);
    if STRIComp(ClassName,'TApplication')=0 then begin
      TargetWindow^ := Wnd;
      Result := false;
    end;
  end;
end;

procedure ActivatePreviousInstance;
var
  PrevInstWnd: HWnd;
begin
  PrevInstWnd := 0;
  EnumWindows(@EnumApps,LongInt(@PrevInstWnd));
  if PrevInstWnd &lt;&gt; 0 then
    if IsIconic(PrevInstWnd) then
      ShowWindow(PrevInstWnd,SW_Restore)
    else
      BringWindowToTop(PrevInstWnd);
end;

end.</PRE><HR>
<H2> Solution 2</H2>
<I><P>From: &quot;The Graphical Gnome&quot; &lt;rdb@ktibv.nl&gt;</P>
</I><P>Taken from Delphi 2 Developers Guide by Pacheco and Teixeira with heavy modifications.</P>
<P>Usage: In the Project source change to the following </P>
<HR><PRE>if InitInstance then
  begin
     Application.Initialize;
     Application.CreateForm(TFrmSelProject, FrmSelProject);
     Application.Run;
  end;
unit multinst;
{
  Taken from Delphi 2 Developers Guide by Pacheco and Teixeira
  With heavy Modifications.

  Usage:
  In the Project source change to the following

  if InitInstance then
  begin
     Application.Initialize;
     Application.CreateForm(TFrmSelProject, FrmSelProject);
     Application.Run;
  end;

   That's all folks ( I hope ;()
}


interface

uses Forms, Windows, Dialogs, SysUtils;

const
  MI_NO_ERROR          = 0;
  MI_FAIL_SUBCLASS     = 1;
  MI_FAIL_CREATE_MUTEX = 2;

{ Query this function to determine if error occurred in startup. }
{ Value will be one or more of the MI_* error flags. }

function GetMIError: Integer;
Function InitInstance : Boolean;

implementation

const
  UniqueAppStr : PChar;   {Change for every Application}

var
  MessageId: Integer;
  WProc: TFNWndProc = Nil;
  MutHandle: THandle = 0;
  MIError: Integer = 0;


function GetMIError: Integer;
begin
  Result := MIError;
end;

function NewWndProc(Handle: HWND; Msg: Integer; wParam,
                    lParam: Longint): Longint; StdCall;
begin

  { If this is the registered message... }
  if Msg = MessageID then begin
    { if main form is minimized, normalize it }
    { set focus to application }
    if IsIconic(Application.Handle) then begin
      Application.MainForm.WindowState := wsNormal;
      ShowWindow(Application.Mainform.Handle, sw_restore);
    end;
    SetForegroundWindow(Application.MainForm.Handle);
  end
  { Otherwise, pass message on to old window proc }
  else
    Result := CallWindowProc(WProc, Handle, Msg, wParam, lParam);
end;

procedure SubClassApplication;
begin
  { We subclass Application window procedure so that }
  { Application.OnMessage remains available for user. }
  WProc := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC,
                                    Longint(@NewWndProc)));
  { Set appropriate error flag if error condition occurred }
  if WProc = Nil then
    MIError := MIError or MI_FAIL_SUBCLASS;
end;

procedure DoFirstInstance;
begin
  SubClassApplication;
  MutHandle := CreateMutex(Nil, False, UniqueAppStr);
  if MutHandle = 0 then
    MIError := MIError or MI_FAIL_CREATE_MUTEX;
end;

procedure BroadcastFocusMessage;
{ This is called when there is already an instance running. }
var
  BSMRecipients: DWORD;
begin
  { Don't flash main form }
  Application.ShowMainForm := False;
  { Post message and inform other instance to focus itself }
  BSMRecipients := BSM_APPLICATIONS;
  BroadCastSystemMessage(BSF_IGNORECURRENTTASK or BSF_POSTMESSAGE,
                         @BSMRecipients, MessageID, 0, 0);
end;

Function InitInstance : Boolean;
begin
  MutHandle := OpenMutex(MUTEX_ALL_ACCESS, False, UniqueAppStr);
  if MutHandle = 0 then
  begin
    { Mutex object has not yet been created, meaning that no previous }
    { instance has been created. }
    ShowWindow(Application.Handle, SW_ShowNormal);
    Application.ShowMainForm:=True;
    DoFirstInstance;
    result := True;
  end
  else
  begin
    BroadcastFocusMessage;
    result := False;
  end;
end;

initialization

begin
   UniqueAppStr := Application.Exexname;
   MessageID := RegisterWindowMessage(UniqueAppStr);
   ShowWindow(Application.Handle, SW_Hide);
   Application.ShowMainForm:=FALSE;
end;

finalization
begin
  if WProc &lt;&gt; Nil then
    { Restore old window procedure }
    SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(WProc));
end;
end.</PRE><HR>

<H2> Solution 3</H2>
<I><P>From: &quot;Jerzy A.Radzimowski&quot; &lt;jerzyara@odn.zgora.pl&gt;</P>
</I>

<HR><PRE>VAR MutexHandle:THandle;
Var UniqueKey  : string;

FUNCTION IsNextInstance:BOOLEAN;
BEGIN
 Result:=FALSE;
 MutexHandle:=0;
 MutexHandle:=CREATEMUTEX( NIL,TRUE, UniqueKey);
 IF MutexHandle&lt;&gt;0 THEN
  BEGIN
   IF GetLastError=ERROR_ALREADY_EXISTS THEN
    BEGIN
     Result:=TRUE;
     CLOSEHANDLE(MutexHandle);
     MutexHandle:=0;
    END;
  END;
END;

begin
  CmdShow:=SW_HIDE;
  MessageId:=RegisterWindowMessage(zAppName);
  Application.Initialize;
  IF IsNextInstance
   THEN
     PostMessage(HWND_BROADCAST, MessageId,0,0)
   ELSE
    BEGIN
     Application.ShowMainForm:=FALSE;
     Application.CreateForm(TMainForm, MainForm);
     MainForm.StartTimer.Enabled:=TRUE;
    Application.Run;
    END;
  IF MutexHandle&lt;&gt;0 THEN CLOSEHANDLE(MutexHandle);
end.</PRE><HR>
<P>in MainForm you need add code for process private message</P>
<HR><PRE>PROCEDURE TMainForm.OnAppMessage( VAR M:TMSG; VAR Ret:BOOLEAN );
BEGIN
 IF M.Message=MessageId THEN
  BEGIN
   Ret:=TRUE;
// BringWindowToTop  !!!!!!!!
  END;
END;

INITIALIZATION
 ShowWindow(Application.Handle, SW_Hide);
END.</PRE><HR>

<!---------------------------------------------------------------------------------------------------------------------------------------------------->
<H1><A NAME="api1">Performing an action when Windows shuts down a Delphi app</A></H1>
<I><P>From: wesjones@hooked.net (Wes Jones)</P>

</I><P>I did a little investigation, and here is what seems to be happening:</P>
<P>Normally, when you exit a Delphi application by using the system menu or by calling the Form's Close method,
 the following event handlers are called:</P>
<OL>
	<LI> FormCloseQuery - the default action sets the variable CanClose=TRUE so form close will continue.
	<LI>FormClose
	<LI>FormDestroy
</OL>
<P>If the application is active and you attempt to exit Windows, the event handlers are called in the following sequence:</P>
<OL>
	<LI>FormCloseQuery
	<LI> FormDestroy
</OL>
<P>The FormClose method never seems to be called.</P>
<P>Here is the flow of events when the user chooses to end the Windows session:</P>
<OL>
	<LI>Windows sends out a WM_QUERYENDSESSION message to all application windows one by one and awaits a response
	<LI>Each application window receives the message and returns a non-zero value if it is OK to terminate, or 0 if it is not OK to terminate.
	<LI>If any application returns 0, the Windows session is not ended, otherwise, Windows sends a WM_ENDSESSION message to all 
	application windows
	<LI>Each Application Window responds with a TRUE value indicating that Windows can terminate any 
time after all applications have returned from processing this message. This appears to be the location of the Delphi problem: 
Delphi applications seem to return TRUE and the FormDestroy method is called immediately, bypassing the FormClose method.
	<LI>Windows exits
</OL>
<P>One solution is to respond to the WM_QUERYENDSESSION message in the Delphi application and prevent Windows 
from exiting by returning a 0 result. This can't be done in the FormCloseQuery method because there is no way to 
determine the source of the request (it can either be the result of the WM_QUERYENDSESSION message or the user just simply 
closing the application). </P>
<P>Another solution is to respond to the WM_QUERYENDSESSION message by calling the same cleanup procedure you call in 
the FormClose method.</P>
<P>Example:</P>

<HR><PRE>unit Unit1;
interface
uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,
Dialogs;
type
  TForm1 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
  {---------------------------------------------------------------}
  { Custom procedure to respond to the WM_QUERYENDSESSION message }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -