Use the mutex object to let the program only run once
"How to make my program can't be turned on at runtime?" I often saw a friend asking this question in the forum. This article will be more detailed in detail and give a relatively complete solution.
Although this is not a new problem, it is still a brief explanation of this technology: This is indeed a quite useful technology. You often pay attention to the quite a few programs after running when you click Run again, it Just return to the original window without running two programs. Just as you run Delphi, when you open another project file outside, Delphi just simply puts your current engineering instead of running two Delphi. Such benefits are obvious: You don't have to worry about your program in some cases, which are maliciously running multiple times, and causing memory. Below we make a note:
Familiar with Win32 programming friends (especially multi-threaded programming), I believe that the mutual exclusive object is quite familiar with it, it is often used as a technical means of synchronization between threads. Here we use it to prevent programs from running repeatedly. We just briefly put the mutual exclusive object, do not do in-depth research: mutually exclusive objects as the main program for the first time, so that we only use the detection of mutually exclusive objects that there is a main program to determine whether the program has run In the case, it is necessary to involve an API function: WaitForsingleObject This function is the first parameter of this function to detect the mutective object to detect, the representation function of the second parameter returns the residence time before the result, if the function returns wait_timeout, indicating that the mutual exclusion Objects already have a master program. The modified project file code is as follows: (Note: The following code appears in the project file, not the unit file, and here all in the simplest Delphi default project basis)
VAR
MyMutex: hwnd;
Begin
MyMutex: = CreateMutex (NIL, FALSE, 'HKONECOPY'); // CreateMutex establishes a mutually exclusive object and gives a unique name to the mutually exclusive object.
if WaitforsingleObject (MyMutex, 0) <> wait_timeout then // The program is not running
Begin
Application.INITIALIZE;
Application.createform (TFORM1, FORM1);
Application.run;
END;
END;
The following work is to improve this program, we not only want the program to be running without being repeated, but we also hope that when the user clicks again, the program has been able to make some responses. Here we want it to become the topmost movable window to remind the user program to be run. To achieve this, we must first get the window handle that has run the program so that setForeGroundWindow (Handle) is used to activate the program window. In order to get this handle, we must use the Windows enumeration function EnumWindows to traverse Windows window list, which can use a callback function as a parameter, and use this callback function to call the window in each system until the last window or callback The function returns False so that this callback function specifies two parameters (Handle, Cardinal, just pay attention to the first handle parameter it represents the window handle that is currently traversed by the enumeration function). As long as we write this function and constantly compare the current traveled window class name and our main window class name of our program, and the name of the comparison window and the name of our programs until the same is found, it will be The window handle is saved, and the code below plus the appropriate annotation:
Function EnumWndProc (HWND: THANDLE; Param: cardinal): bool; stdcall; // Due to the API callback function, use Windows Traditional Parameter Transfer Stdcall
VAR
ClassName, WinMoudlename: String
WinInstance: Thandle;
Begin
RESULT: = true;
SETLENGTH (Classname, 100);
GetclassName (HWND, PCHAR (ClassName), Length (classname); // Get the class name of the current traversal window
ClassName: = PCHAR (ClassName); // After adding a end value after the string, determine the end of the string
if classname = tform1.classname dam // Comparison
Begin
WinInstance: = getWindowlong (hwnd, gwl_hinstance); // Get instances of the current traversal window
SETLENGTH (WinmoudleName, 100);
GetModuleFileName (WinInstance, Pchar (WinmoudleName), Length (WinmoudleName);
// Get the program file name of the current traversal window
Winmoudlename: = pchar (WinmoudleName);
If Winmoudlename = moudlename dam // moudlename is the project global variable, the file name of your own program
Begin
FindhiD: = hwnd; // FindHid Save the project global variable
Result: = false; // Find the end of the travers
END;
END;
END;
Here is all project files:
VAR
HMutex, FindhiD: hwnd;
Moudlename: String;
Begin
HMutex: = Createmutex (NIL, FALSE, 'HKONECOPY');
If WaitforsingleObject (hmutex, 0) <> wait_timeout then
Begin
... // 的 代 在 in the foreman
end
Else
Begin
SETLENGTH (Moudlename, 100);
GetModuleFileName (Hinstance, Pchar (Moudlename), Length (Moudlename);
// Get your own program file name
Moudlename: = pchar (moudlename);
Enumwindows (@ enumWndproc, 0); // call enumeration functions
IF FindhiD <> 0 THEN
SetForegroundwindow (Findhi);
END;
End.
In order to make our program more perfect, let it show more features when repeatedly run, such as the project files in Delphi as the currently open project), you can also send user messages to the found window handle, and then Doing the corresponding processing in the message processing function of the window, you must make our programs too dazzling!
references:
"Delphi Developer Guide"