The software developed by the company needs to perform operations on the serial port. Each time the software is opened, the program automatically opens the serial port. Search Connect to the device on the serial port, but if the user does not know to open twice, then the program opened for the second time cannot be used normally, because the operation on the serial port is exclusive, the first program exclusively uses the serial port, and other programs cannot use that serial port. Of course, if there are two serial ports on the PC machine, the second program can also be used. To solve this problem Problem , You must limit that only one software can be opened for serial port operations. If you want to open the software again by mistake after opening the software, you must prompt that the software has been opened and show the software to the top of the window.
The solution for Delphi is as follows.
(Method 1)
Use mutex object
Multi-threaded software may have used mutex objects, which are often used for synchronization between threads. Technology Means. A Brief Introduction of mutex object: The mutex object uses the program that was created for the first time as the main program. In this way, it only checks whether the mutex object has been run by the main program to determine whether the program has been run, here we need to involve an API function: waitforsingleobject. The first parameter of this function is the mutex object used for detection. The first parameter represents the retention time before the function returns the result, if the function returns wait_timeout, it indicates that the mutex object already has a main program.
Note: Code All appear in the project file, not in the unit file.
VaR
Mymutex: hwnd;
Begin
// Createmutex creates a mutex object and gives it a unique name.
Mymutex: = createmutex (nil, false, 'hkonecopy ');
// The program has not been run
If waitforsingleobject (mymutex, 0) <> wait_timeout then
Begin
Application. initialize;
Application. createform (tform1, form1 );
Application. Run;
End;
End;
[Note]:
When the application runs for the first time, a mutex object named 'hkonecopy' is created in the application, and the system determines whether the mutex object exists. If not, the application is initialized.
Next we will improve this program.
We do not Hope The program is run multiple times. Instead, it is expected that some response will be made to the running program when the program is run again, for example, you can change it to the upper-level activity window to prompt that the program is running. To achieve this goal, you must obtain the handle of the running program, and then use an apisetforegroundwindow (handle) to bring the program window to the beginning and activate it. To obtain the program handle, use the Windows enumeration function enumwindows to traverse the Windows window list. This function requires a callback function as a parameter. System Until the last window or callback function returns false. [Note: the introduction to the enumwindows function is at the end of this article]. You only need to write this callback function and continuously compare the name of the currently traversed window class with the name of the main window class of our program and the name of the comparison window. Run The file name and the program name are the same until the window handle is saved. To obtain the class name and handle of the window, you need an apigetclassname. To obtain the executable file name, you need apigetmodulefilename.
The following is the detailed code.
Note: The following code runs in Delphi7. However, when the window is minimized and the program is run again, the previously run program can be prefixed and activated, but the minimization button in the title bar cannot be used. When Try The method in N is estimated to be a problem of Delphi's own tform class. The following provides a solution: put an applicationevents control in the window, which manages all the messages of the application. We can write the above Code in its onmessage event:
If msg. hwnd = form1.handle then
Begin
// 161 is pressed in the title bar Mouse
// 8 is to press the mouse on the Minimize button in the title bar
If (msg. Message = 161) and (msg. wparam = 8) then
Begin
Form1.windowstate: = wsminimized;
End;
End;
Program mythreadtest;
Uses
Windows,
Forms,
Sysutils,
Messages,
Dialogs,
Unit1 in 'unit1. pa' {form1 },
{$ R *. Res}
VaR
Mymutex,
Findhid: hwnd;
Moudlename: string;
Function enumwndproc (hwnd: thandle; Param: Cardinal): bool; stdcall;
// For API callback functions, use Windows Traditional Stdcall
VaR
Classname, winmoudlename: string;
Wininstance: thandle;
Begin
Result: = true;
Setlength (classname, 100 );
Getclassname (hwnd, pchar (classname), length (classname); // obtain the Class Name of the current traversal window
Classname: = pchar (classname); // Add the terminator after the string to determine whether the string ends.
If uppercase (classname) = uppercase (tform1.classname) Then // compare Class Name
Begin
Wininstance: = getwindowlong (hwnd, gwl_hinstance); // obtain the instance of the current traversal window
Setlength (winmoudlename, 100 );
// Obtain the program file name for the current traversal window
Getmodulefilename (wininstance, pchar (winmoudlename), length (winmoudlename ));
Winmoudlename: = pchar (winmoudlename );
Winmoudlename: = extractfilename (winmoudlename );
// Moudlename is Engineering Global variables, file name of your program
If uppercase (winmoudlename) = uppercase (moudlename) then
Begin
Findhid: = hwnd; // The findhid is the link found when the global variable of the Project is saved.
Result: = false; // The traversal ends after it is found.
End;
End;
End;
Begin
// Createmutex creates a mutex object and assigns a unique name to the object.
Mymutex: = createmutex (nil, false, 'hkonecopy ');
If waitforsingleobject (mymutex, 0) <> wait_timeout then
// The program has not been run
Begin
Application. initialize;
Application. createform (tform1, form1 );
Application. Run;
End else
Begin
Set length (moudlename, 100 );
// Obtain the program file name
Getmodulefilename (hinstance, pchar (moudlename), length (moudlename ));
Moudlename: = pchar (moudlename );
Moudlename: = extractfilename (moudlename );
Enumwindows (@ enumwndproc, 0); // call the enumeration Function
If findhid <> 0 then
Begin
Showwindow (findhid, sw_restore );
Setforegroundwindow (findhid );
End;
End;
End.
[Use enumwindows functions]:
Enumwindows lists all top-level windows on the screen.
Msdn:
The enumwindows function enumerates all top-level Windows On the screen by passing the handle to each window.
Function Format:
Bool enumwindows (wndenumproc lpenumfunc, // callback function
Lparam); // application-defined value
Wndenumproc is the callback function, which writes the operations you want to perform. When you call enumwindows, each time you encounter a window, System Call your wndenumproc once and pass the window handle to you.
Enumwindows
If the function is successful, a non-zero value is returned;
If the function fails, 0 is returned;
Enumwindowsproc returns 0, which also causes the function enumwindows to return 0.
In addition, this function does not list subwindows, except for several Style .
Msdn:
The enumwindows function does not enumerate child Windows , With the exception of a few top-level windows owned by the system that have the ws_child style.
Example:
Declare An enumwindowsproc first, for example:
Bool callback enumwindowsproc_1 (hwnd, lparam );
Then implement this function to write the things you want to do, such:
Bool callback enumwindowsproc_1 (hwnd, lparam)
{Char lpwintitle [256];
: Getwindowtext (hwnd, lpwintitle, 256-1 );
Cstring m_strtitle;
M_strtitle.format ("% s", lpwintitle );
If (m_strtitle.find ("Internet Explorer ")! =-1)
{Afxmessagebox ("this is an IE window! ");}
Return true;
}
Then you can use the callback function when calling enumwindows elsewhere, for example:
: Enumwindows (enumwindowsproc_1, 0 );
In this way, whenever you encounter an IE window, the system will prompt "this is an IE window !" .
Method 2:
No mutex object is required.
We can add global atoms to the system to prevent the running of multiple program instances. The global atom is maintained by the Windows system. It ensures that each atom is unique and manages its reference count. When the reference count of the global atom is 0 Memory . We use the globaladdatom function to add a string of less than 255 bytes to the global atom and use globalfindatom Check Whether the global atom exists. At last, use the globaldeleteatom function at the end of the program to delete the added global atom. Example:
Uses Windows
Const iatom = 'singleapp ';
Begin
If globalfindatom (iatom) = 0 then
Begin
Globaladdatom (iatom );
Application. initialize;
Application. createform (tform1, form1 );
Application. Run;
Globaldeleteatom (globalfindatom (iatom ));
End
Else
MessageBox (0, 'you can not run a second copy of this app', '', mb_ OK );
End.
Using global atomic reference counting rules, we can also determine the number of instances currently running the program:
VaR I: integer;
Begin
I: = 0;
While globalfindatom (iatom) <> 0 do
Begin
Globaldeleteatom (globalfindatom (iatom ));
I: = I + 1;
End;
Showmessage (inttostr (I ));
End;