Windows下如何让非NT程序像NT程序一样毫无踪迹在后台运行?
Windows版本:Windows 10
Delphi版本:Delphi 10.3
需求说明:让正常的图形界面程序或DOS程序,能够彻底隐藏踪迹,像NT程序一样在后台悄悄运行!!正常的程序,如果在运行时候,会有程序窗口,如果加入了在任务栏显示代码,最小化会在任务栏有图标!!这些我都不想要,我就想让这些正常程序运行时候,根本任何运行痕迹都看不到!!!
解决过程:
通常这样的程序,把运行的参数设置为SW_HIDE就可以了,但是,对于有些程序,这样设置是不可以的,当最小化时候,会在任务栏留有图标!!怎么办?创建虚拟桌面,让这个运行的程序在这个虚拟桌面中,这样,在当前运行程序的桌面中就看不到任何踪迹了!!
Delphi实现代码:
uses TLHelp32; // 判断进程是否运行用的单元 const DesktopName: PChar = 'NewDesktop'; //虚拟桌面名称 var desktopHandle: THandle; // 桌面handle { 像NT程序一样在后台运行程序,前台看不到被运行程序 说明:无论要运行的程序是正常的图形界面程序,还是DOS程序,在运行程序的桌面中看不到它的任何运行的踪迹, 被运行的程序像NT程序一样悄悄在后台运行,即使这个程序正常运行时候最小化会在任务栏有图标!! 在任务管理器中会查看到被运行程序的进程!! 参数: fullExe:要运行程序的全路径名称 exeParam:要运行程序的参数 tempDesktopName:创建的虚拟桌面名称 tempDesktopHandle:创建的虚拟桌面Handle 返回值:是否运行成功 } function RunInbackGround(fullExe: string; exeParam: string; tempDesktopName: string; var tempDesktopHandle: THandle): boolean; var isSuccess: boolean; // 是否运行成功的返回值 CmdLine: string; // 要执行的命令(要执行程序的全路径名称+参数) WorkingDirP: PChar; // 工作目录 StartupInfo: TStartupInfo; // 进程启动参数 ProcessInfo: TProcessInformation; // 进程信息 ErrorCode: integer; // 进程启动的错误代码 exeName: string; // 要执行程序名称 // 是否程序正在运行 function isExeRunning(exeName: string): boolean; var lppe: TProcessEntry32; isFound: boolean; Hand: THandle; tempName: string; // 程序名称 temp: boolean; // 返回值变量 judgePos: integer; // 扩展名判断位置 begin Hand := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); lppe.dwSize := SizeOf(lppe); // 必须设置此值 isFound := Process32First(Hand, lppe); temp := false; // 返回的布尔值 // 程序名称变量 tempName := trim(exeName); // 扩展名分隔符位置 judgePos := Pos('.', tempName); // 判断是否有扩展名 if judgePos = 0 then begin tempName := tempName + '.exe'; // 添加".exe"扩展名 end else begin if Length(copy(tempName, judgePos, 4)) < 4 then begin // 删除不符合添加的扩展名 Delete(tempName, judgePos, (Length(tempName) - judgePos + 1)); // 添加".exe"扩展名 tempName := tempName + '.exe'; end; end; // 循环判断是否有相同名称程序 while isFound do begin // 判断当前程序名称和指定程序名称相同 if lppe.szExeFile = tempName then begin temp := true; Break; end; // Memo1.Lines.Add(IntToStr(i) + ' : ' +IntToStr(lppe.th32ProcessID)+' '+ StrPas(lppe.szExeFile)); isFound := Process32Next(Hand, lppe); end; result := temp; end; // 杀死进程 procedure KillProc(procName: string); const PROCESS_TERMINATE = $0001; var ExeFileName: String; ContinueLoop: Bool; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32; begin ExeFileName := procName; FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize := SizeOf(FProcessEntry32); ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32); while integer(ContinueLoop) <> 0 do begin if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(ExeFileName))) then TerminateProcess(OpenProcess(PROCESS_TERMINATE, Bool(0), FProcessEntry32.th32ProcessID), 0); ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32); end; end; begin isSuccess := true; // 是否运行成功的返回值的默认值 { 一,创建用于存放要运行程序的虚拟桌面 } // 如果虚拟桌面没有创建,则创建 if tempDesktopHandle = 0 then begin tempDesktopHandle := CreateDesktop(PChar(tempDesktopName), nil, nil, 0, GENERIC_ALL, nil); end; { 二,运行指定的程序 } try // 要执行的命令(要执行程序的全路径名称+参数) CmdLine := '"' + trim(fullExe) + '" ' + trim(exeParam); WorkingDirP := nil; // 工作目录 exeName := ExtractFileName(fullExe); // 得到要运行的程序名称 // 如果要运行程序运行中,则先杀死它 if isExeRunning(exeName) = true then begin KillProc(exeName); // 杀死正在运行的程序 end; ZeroMemory(@StartupInfo, SizeOf(StartupInfo)); StartupInfo.cb := SizeOf(StartupInfo); StartupInfo.lpDesktop := DesktopName; // 设置启动程序的虚拟桌面(注意:这个参数才真正让运行的程序隐藏起来) StartupInfo.dwFlags := STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_HIDE; // 常规的隐藏运行程序窗口参数 // 创建要运行程序的进程(CREATE_NO_WINDOW是创建无窗口程序的参数) if not CreateProcess(nil, PChar(CmdLine), nil, nil, false, CREATE_NO_WINDOW, nil, WorkingDirP, StartupInfo, ProcessInfo) then begin isSuccess := false; ErrorCode := GetLastError; end; with ProcessInfo do begin CloseHandle(hThread); CloseHandle(hProcess); end; except on e: exception do begin isSuccess := false; end; end; result := isSuccess; end;
Delphi示例代码:
procedure TForm2.Button3Click(Sender: TObject); var FileName, Parameters: string; begin FileName := '要运行的程序,可以是图形界面也可以是DOS程序'; Parameters :='要运行程序的参数,没有就空'; if RunInbackGround(FileName, Parameters, DesktopName, desktopHandle) = true then begin showMessage('虚拟创建桌面完毕:' + IntToStr(desktopHandle)); showMessage('指定程序已经运行:' + FileName); end else begin showMessage('虚拟创建失败,指定程序没能运行!'); end; end;
未完待续,后面会加入FreePascal实现的代码。。。