I made an MFC program under VC and wanted him to automatically delete himself after running the program. I have used some data on the Internet, and I have used some of them. I think it is more appropriate to use cmd.exe for MFC programs. Other methods are quite good, and they are quite classic, but I don't think it is appropriate to use them in the MFC program.
There are three methods in my practice:
1. Using assembly is Gary nebbett's classic code.
2. Create a clone process.
3.use shellexecuteto execute cmd.exe.
The first method of code can be easily found on the internet, and I will post it here. The disadvantage of this method is that Windows 98/NT/2000 can only be used, so XP cannot be considered.
# Include "windows. H"
Int main (INT argc, char * argv [])
{
Char Buf [max_path];
Hmodule module;
Module = getmodulehandle (0 );
Getmodulefilename (module, Buf, max_path );
Closehandle (handle) 4); // This line is not used on Windows 98. However
// Replace push unmapviewoffile with push freelibrary
_ ASM
{
Lea eax, Buf
Push 0
Push 0
Push eax
Push exitprocess
Push Module
Push deletefile
Push unmapviewoffile
RET
}
Return 0;
}
The principle of this Code is easy to understand. I also posted the explanations of others and read them several times to understand it.
The first three lines of code are not mentioned. Start with closehandle (handle) 4.
I found a lot of information on the Internet and found that handle4 is the OS hard code. closehandle (handle) 4) is used to close the file handle.
To delete a file, you must delete the operator that opens the file. If the operator opens the file, the operation fails. It has been disabled.
The following describes the content in _ ASM.
After a series of pushes. The contents in the stack form this form.
The following are the test results under win2000 SP3 vc6.0.
Value stack address in the ESP Stack
0012fe28 0 0012fe28
0012fe24 0 0012fe24
0012fe20 0012fe78 0012fe20 file full path
0012fe1c 77e7cf5c 0012fe1c exitprocess entry
0012fe18 00040000 0012fe18 Module Value
0012fe14 77e6e3a6 0012fe14 deletefile entry
0012fe10 77e6d2bd 0012fe10 unmapviewoffile
Next we will know that RET is called when the function returns. Its function is to retrieve the return address of the function from the stack pointed to by the current ESP. For the above Code, the current ESP = 0012fe10, now retrieve the value of 77e6d2bd in the stack address 0012fe10, and then jump to 77e6d2bd, which goes to the function entry of unmapviewoffile. Why is deletefile behind 0012fe10? Why does the parameter module reach fe18.
Let's write a code first.
Void main ()
{
Unmapviewoffile (null );
}
Then, disassemble the Assembly command to see how it works. As follows:
6: unmapviewoffile (null );
00401028 mov ESI, ESP
0040102a push 0
0040102c call dword ptr [_ imp _ unmapviewoffile @ 4 (001_1ac)]
00401032 cmp esi, ESP
First, the parameter 0 is input to the stack, and then we catch [_ imp _ unmapviewoffile @ 4 (001_1ac)]
. Let's see what the current stack looks like. As follows:
Intra-stack address intra-stack Value
0012ff30 0 Parameter
0012ff2c 00401032 return address
00401032 is the call function system that helped us into the stack. We did not manually add it. However, when RET is transferred to the unmapviewoffile entry, there is no inbound stack with the returned address. That is to say, push deletefile becomes the return address of the unmapviewoffile function. The push module above is the parameter of unmapviewoffile. Think about it. Okay, when the unmapviewoffile function is called, The EIP has now reached the 77e6e3a6 and deletefile entries.
But where is ESP? The value in the 0012fe1c stack should be 77e7cf5c.
After deletefile is returned, the program should jump to 77e7cf5c, that is, the exitprocess entry.
Then (0012fe1c + 4) is the deletefile parameter. That is, 0012fe78. Push eax.
When deletefile is returned, the program jumps to the 77e7cf5c and exitprocess entries. The current ESP = 0012fe24. The same principle
Push 0. This is the exitprocess parameter.
Push 0. This is the return address of exitprocess.
Because exitprocess has not returned the process and ends, the return address of exitprocess is 0, and no memory error will occur.
Now let's look at the second method. The Code is as follows:
If (_ argc = 1)
{
Handle hfile = NULL; // clone the file handle
Handle hprocess = NULL; // handle of the currently running process
Tchar pathorig [max_path] = {0 };
Tchar pathclone [max_path] = {0 };
Tchar cmdline [max_path * 2] = {0}; // Parameter
// Copy the file to a temporary file
Getmodulefilename (null, pathorig, max_path );
Gettemppath (max_path, pathclone );
Gettempfilename (pathclone, _ T ("retri"), 0, pathclone );
Copyfile (pathorig, pathclone, false );
// Delete the mark after the file is created.
Hfile = createfile (pathclone, 0, file_1__read, null, open_existing, file_flag_delete_on_close, null );
// Signal synchronization
Hprocess = OpenProcess (synchronize, true, getcurrentprocessid ());
Startupinfo;
Process_information processinfo;
Zeromemory (& startupinfo, sizeof (startupinfo ));
Zeromemory (& processinfo, sizeof (processinfo ));
Startupinfo. cb = sizeof (startupinfo );
Startupinfo. wshowwindow = sw_hide;
Wsprintf (cmdline, _ T ("% S % d/" % S/""), pathclone, hprocess, pathorig );
CreateProcess (null, cmdline, null, null, true, 0, null, null, & startupinfo, & processinfo );
// Close the handle
If (hfile)
{
Closehandle (hfile );
}
If (hprocess)
{
Closehandle (hprocess );
}
}
Else
{
Handle hprocess = NULL;
Hprocess = (handle) _ ttoi (_ argv [1]);
// Wait until the previous process ends
Waitforsingleobject (hprocess, infinite );
If (hprocess)
{
Closehandle (hprocess );
}
Deletefile (_ argv [2]);
}
This method is quite good, but it is not particularly effective. Sometimes the temporary files created will not be deleted immediately. I tested it several times. Another disadvantage is that the newly created process is the original MFC program process, so there is a window. In this way, a new MFC window will pop up. Of course, you can hide the window in some way, but I tried startupinfo. wshowwindow = sw_hide; no, add startupinfo. dwflags = startf_useshowwindow; a window is displayed. This is a small problem. You will eventually find a way to hide the window. But the key issue is that the second process is responsible for deleting the original file and automatically exiting. Generally, the MFC program does not exit automatically. users click the cross-forks to exit. Therefore, the MFC program must exit automatically after detecting the status during initialization, this requires the newly created process to hide the window and exit automatically. Therefore, I feel that this method is suitable for some automated programs or programs without windows.
For the MFC program, it is also a common feature that can be deleted using cmd.exe. The Code is as follows:
// Batch Processing
Shellexecuteinfo exeinfo;
Tchar exepath [max_path] = {0 };
Tchar parampath [max_path] = {0 };
Tchar composepath [max_path] = {0 };
Getmodulefilename (null, exepath, max_path );
Getmediapathname (exepath, exepath, max_path );
Getenvironmentvariable (_ T ("comspec"), composepath, max_path );
_ Tcscpy (parampath, _ T ("/C del "));
_ Tcscat (parampath, exepath );
_ Tcscat (parampath, _ T ("> NUL "));
Zeromemory (& exeinfo, sizeof (exeinfo ));
Exeinfo. cbsize = sizeof (exeinfo );
Exeinfo. hwnd = 0;
Exeinfo. lpverb = _ T ("open"); // execute the action, open
Exeinfo. lpfile = composepath; // full path name of the execution File
Exeinfo. lpparameters = parampath; // execution Parameter
Exeinfo. nshow = sw_hide; // The execution method to hide the window.
Exeinfo. fmask = see_mask_nocloseprocess; // after the end of the ShellExecute Function, the process exits.
// Create an execution command Window Process
If (shellexecuteex (& exeinfo ))
{
// Set the command line process level to idle, which gives the program enough time to exit.
Setpriorityclass (exeinfo. hprocess, idle_priority_class );
// Set the process to be executed in real time and exit quickly.
Setpriorityclass (getcurrentprocess (), realtime_priority_class );
Setthreadpriority (getcurrentthread (), thread_priority_time_critical );
// Notify the resource manager to delete the program
Shchangenoworkflow (shcn_delete, shcnf_path, exepath, null );
}
When the program is about to return, execute cmd.exe to delete the program. I tested this method and it is still quite easy to use.
After explaining the code, I will post it to others.
If the comments in the above Code cannot help you understand the meaning of the Code, please do not worry, we will explain the code in detail later. Now, you can start to compile the program project and run the program. Please carefully observe the program file in the Windows resource browser. Several seconds after you press the "Start suicide" button, the program file disappears from the Windows resource browser, which is also expected by the program.
After experiencing the magic of the "suicide" program, let's look back and analyze the code that implements the "suicide" function.
As we have discussed earlier, the core of the "suicide" function is to create a new process in the Command window in the program and delete the program file by passing the del command and parameters to the Command window process. The command window program is defined by the Environment Variable comspec. Win9x/me Uses command. com, winnt/2 k/XP uses cmd. com. The program passes the command string "/C del FILENAME> NUL" to the Command window, where filename is the full path file name of the file to be deleted, and the file name must be converted to the 8.3 format; the/C switch is used to exit the command window.
In the implementation code, you first need to obtain the full path of the current program module and convert it to the 8.3 format required by the Command window. In the code, the getmodulefilename (0, szmodule, max_path) function obtains the full path name of the current program mode and stores it in the variable szmodule. Then, use the get‑pathname (szmodule, szmodule, max_path) function to convert the full path name of the program module in the szmodule variable to the 8.3 format required by the Command window. In addition, the getenvironmentvariable ("comspec", szcomspec, max_path) function is called to obtain the full path of the command window program from the system environment variable comspc. Next, you need to combine the full path string of the program module in the 8.3 format in the variable szmodule into the command string "/C del" + szmodule + "> NUL ".
With this information, you can call the shellexecuteex () API function to create a new command window process. This function requires a parameter of the shellexecuteinfo type and calls shellexecuteex () the function must initialize this type parameter. For details about the shellexecuteinfo type, see msdn. This parameter is used to set the execution action of the command window process to open and the execution file to the Command window (PATH provided by szcomspec) the execution file parameters are the command strings combined above, and the display mode is the hidden mode (the hidden mode can prevent the appearance of the command window interface ).
The command window is run by calling the shellexecuteex () function as a separate process. Its window handle is defined in the hprocess member variable in the shellexectueinfo structure. A special problem needs to be solved in self-deletion, that is, the main program must exit and close the opened file handle before deleting it in the Command window. To achieve this, we must synchronize two independent and parallel processes: the current program process and the command window process. This allows you to temporarily reduce the execution priority of the command window by operating the CPU resource priority. In this way, the main program allocates all resources to the CPU until it Exits normally, and blocks the execution of any other command window until the main program ends. The following code adjusts the execution priority of two processes:
// Set the execution level of the command line process to idle,
// This gives the program enough time to exit from the memory.
Setpriorityclass (SEI. hprocess, idle_priority_class );
// Set the execution level of the program process to real-time execution,
// This program immediately obtains the CPU execution right and quickly exits.
Setpriorityclass (getcurrentprocess (), realtime_priority_class );
Setthreadpriority (getcurrentthread (), thread_priority_time_critical );
At this point, the "suicide" function is basically implemented. The last thing to do is to call the shchangenovel (shcn_delete, shcnf_path, szmodule, 0) function to notify windows resource browser that the program file has been successfully deleted. If the current Windows resource browser window is in the program file directory, this notification is very necessary, it will cause the Windows resource browser to immediately delete this program file item from the program file directory list. After completing the above work, you must call the code for exiting the program. The enddialog () function is used here. If you do not exit the program in time, the command window process cannot delete the program file normally, the cause has been studied before.