无忧启动论坛

标题: 本人做的PEWaitKill,附源码,希大家帮测试。 [打印本页]

作者: lxl1638    时间: 2006-10-20 10:30
标题: 本人做的PEWaitKill,附源码,希大家帮测试。
基本是根据asbai大侠VC源码的思路去写,区别有:
1、取消30秒的黙认延迟。
目的是防止不明这个程式功能的用户拼命双击它,因为它允许多副本同时运行,当用户双击它发现没有任何提示可能会在30秒内连续多次双击它,这样就会出现多个副本同时运行。
2、增加对WinPE系统环境的检测,在非WinPE环境执行时显示帮助说明。
目的是使用户在非WinPE环境中了解它的功能和作用。
3、简化延迟时间参数,参数只用秒表示。
这种情况下用分、小时表示意义不大,支持小数秒。
4、取消异常处理。

以下是Delphi源码,附件也有,不明一点,为什么这个比VC做的还小很多?


  1. program PEWaitKill;

  2. uses
  3.   tlHelp32,
  4.   Windows,
  5.   SysUtils;

  6. //查找进程函数
  7. //入口参数: 进程文件名
  8. //返 回 值: 进程ID(0表示进程不存在或找不到)。
  9. function FindProcess(ProcessEXEName: string): integer;
  10. var
  11.   hSnap: THandle;
  12.   ProcessEntry: TProcessEntry32;
  13.   ProcessID: integer;
  14.   Proceed: Boolean;
  15. begin
  16.   ProcessID := 0;
  17.   hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  18.   if not (HSnap = 0) then begin
  19.     ProcessEntry.dwSize := SizeOf(TProcessEntry32);
  20.     Proceed := Process32First(hSnap, ProcessEntry);
  21.     while Proceed do begin
  22.       if UpperCase(ProcessEXEName) = UpperCase(StrPas(ProcessEntry.szEXEFile)) then
  23.       begin
  24.         ProcessID := ProcessEntry.Th32ProcessID;
  25.         break;
  26.       end;
  27.       Proceed := Process32Next(hSnap, ProcessEntry);
  28.     end;
  29.     CloseHandle(hSnap);
  30.   end;
  31.   result := ProcessID;
  32. end;

  33. //杀进程过程,入口参数为进程文件名。
  34. procedure KillProcess(ProcessEXEName: string);
  35. var
  36.   ProcessID: integer;
  37.   ProcessHndle: THandle;
  38.   uexitcode: byte;
  39. begin
  40.   ProcessID := FindProcess(ProcessEXEName);
  41.   if ProcessID <> 0 then begin
  42.     ProcessHndle := OpenProcess(PROCESS_TERMINATE, false, ProcessID);
  43.     TerminateProcess(ProcessHndle, uexitcode);
  44.     CloseHandle(ProcessHndle);
  45.   end;
  46. end;

  47. //延时过程,入口参数毫秒。
  48. procedure TimeDelay(TimeToWait: Cardinal);
  49. var StartTime: Cardinal;
  50. begin
  51.   StartTime := GetTickCount;
  52.   repeat
  53.     Windows.Sleep(200);
  54.   until ((GetTickCount - StartTime) > TimeToWait);
  55. end;

  56. //延迟指定时间后,杀进程。
  57. procedure WaitToKillProcess(TimeToWait: Cardinal);
  58. begin
  59.   TimeDelay(TimeToWait);
  60.   //其实下面两行通过创建一个进程执行 XPEinit -9 可能更可靠。
  61.   KillProcess('Smss.exe');
  62.   KillProcess('Winlogon.exe');
  63. end;

  64. //显示帮助说明。
  65. procedure DisplayHelp();
  66. var AppName: string;
  67. begin
  68.   AppName := ExtractFileName(ParamStr(0));
  69.   MessageBox(0, Pchar(
  70.     '功能: 为了防止WinPE在24小时后重启,等待一定时间后在后台结束' + #13 +
  71.     '      Winlogon.exe 和 Smss.exe 进程。' + #13 + #13 +
  72.     '用法: ' + AppName + ' [TimeToWait]' + #13 +
  73.     '      TimeToWait - 等待指定的时间(秒)后,试图结束那两个进程。' + #13 + #13 +
  74.     '例子: ' + AppName + ' 12.345  -  等待12.345秒。' + #13 + #13 +
  75.     '注意: 本进程只能在WinPE系统环境中执行,在指定的等待时间后,' + #13 +
  76.     '      若找不到目标进程或已结束目标进程,本进程也结束。'),
  77.     Pchar(AppName + ' By 老九'), MB_OK)
  78. end;

  79. //取得命令行延迟时间函数,返回数值(毫秒)。
  80. function GetTimeToWait(): Cardinal;
  81. var TMP: Single;
  82.   Code: integer;
  83. begin
  84.   Val(ParamStr(1), TMP, Code);
  85.   if Code = 0 then result := Round(TMP * 1000)
  86.   else result := 0;
  87. end;

  88. //主体过程。
  89. procedure MainProcedure();
  90. var TimeToWait: Integer;
  91.   Parameters: string;
  92.   StartupInfo: TStartupInfo;
  93.   ProcessInfo: TProcessInformation;
  94. begin
  95.   if UpperCase(GetEnvironmentVariable('SystemDrive')) = 'X:' then
  96.     case ParamCount of
  97.       1: begin // 1个参数,由xpeinit调用的前台进程
  98.           TimeToWait := GetTimeToWait();
  99.           if TimeToWait > 0 then begin
  100.             Parameters := ParamStr(0) + ' ' + ParamStr(1) + ' /DaemonFork';
  101.             FillChar(StartUpInfo, SizeOf(StartUpInfo), 00);
  102.             StartUpInfo.dwFlags := STARTF_USESHOWWINDOW;
  103.             StartUpInfo.wShowWindow := SW_HIDE;
  104.             CreateProcessA(nil, PChar(Parameters), nil, nil, False, 0,
  105.               nil, nil, StartupInfo, ProcessInfo);
  106.           end;
  107.         end;
  108.       2: begin // 2个参数,由本身启动的后台进程。
  109.           TimeToWait := GetTimeToWait();
  110.           if ((TimeToWait > 0) and (ParamStr(2) = '/DaemonFork')) then
  111.             WaitToKillProcess(TimeToWait);
  112.         end;
  113.     else DisplayHelp(); //不是1个或2个参数都显示帮助说明。
  114.     end
  115.   else DisplayHelp(); //非WinPE系统环境。
  116. end;

  117. begin
  118.   MainProcedure();
  119. end.
复制代码

PEWaitKill.rar

21.77 KB, 下载次数: 101, 下载积分: 无忧币 -2


作者: 老毛桃    时间: 2006-10-20 10:39
第一个下!支持。
作者: hahahei    时间: 2006-10-20 10:40
我问下,需不需要指定延迟时间,比如30秒或者什么的?
作者: hahahei    时间: 2006-10-20 10:41
原帖由 老毛桃 于 2006-10-20 10:39 AM 发表
第一个下!支持。

毛桃不厚道,我刚才有点事情就让你占先了
作者: 老毛桃    时间: 2006-10-20 10:51
原帖由 hahahei 于 2006-10-20 10:40 发表
我问下,需不需要指定延迟时间,比如30秒或者什么的?

当然需要的,你看说明吧
作者: 老毛桃    时间: 2006-10-20 10:51
  1. var StartTime: Cardinal;
  2. begin
  3.   StartTime := GetTickCount;
  4.   repeat
  5.     Windows.Sleep(200);
  6.   until ((GetTickCount - StartTime) > TimeToWait);
  7. end;
复制代码

有一点需要请教一下,既然我们默认的延时是以秒为单位的,Windows.Sleep 后面的毫秒数可不可以增大一点,比如 500 ?这样的话在同样的时间内执行的循环会比较少。至于时间精确度,那倒无所谓的,只是用来 Kill 进程,主要不是用来计时。

因为我以前在 ASP 中做延时函数(ASP 默认没有)的时候,发现时间跳跃单位越小,资源占用情况越大。像以下的代码,在执行期间,CPU 的占用率几乎是 95%~100%
  1. Sub TimeDelay(DelaySeconds)                                                        '老毛桃自己写的延时函数,可以精确到毫秒级
  2.         dim Time1
  3.         Time1=Timer()
  4.         While Timer()<Time1+DelaySeconds
  5.         Wend
  6. End Sub
复制代码

因为它没有支持支持 Windows.Sleep 这样的命令,时间跳跃单位为零,仅仅依靠反复的循环来达到拖延时间。但目前我没有更好的方法来实现这一功能。不知道老九和  asbai 兄弟可否有高见?
作者: lxl1638    时间: 2006-10-20 11:02
原帖由 老毛桃 于 2006-10-20 10:51 AM 发表
var StartTime: Cardinal;
begin
  StartTime := GetTickCount;
  repeat
    Windows.Sleep(200);
  until ((GetTickCount - StartTime) > TimeToWait);
end;
有一点需要请教一下,既然我们默认的延时 ...

好吧,就用老毛桃的建议,Sleep(500),大侠原来的是Sleep(150)。你的ASP本人不了解,帮不上。
作者: asbai    时间: 2006-10-20 11:11
原帖由 lxl1638 于 2006-10-20 10:30 AM 发表
不明一点,为什么这个比VC做的还小很多 ...

呵呵,兄台辛苦了。这个问题嘛,嘿嘿,就好像两个程序,调 printf 输出 “Hellow World” 的版本比直接调操作系统 API (例如:WriteConsole)输出同样字符串的版本体积要大是一样的:
1. printf 的功能远远不止简单字符串输出,导致它的体积较大。
2. printf 有额外的缓冲和错误处理机制。

比如:用来分析命令行参数的 CCmdArgParser 类,可以灵活配置成和 Win32 Console 解释器(cmd.exe)或 unix sh 兼容的命令行分析器。对换码符、Windows/Unix 风格的环境变量代换以及参数分析方面都可以灵活配置。

再比如 CProcess 类的功能也不仅仅是创建和杀死进程,还有例如远程创建、以其它用户身份创建、隐藏和管道重定向;调整进程调度策略和基础优先级;获取进程加载模块;控制进程内存使用等很多其它功能。而且在出错时也有较为完善和一致的错误处理方式等等。

其它诸如文件操作的功能类也与此相似,所以在开发这类小工具时这些地方带来的体积膨胀就会比较明显。:)
作者: lxl1638    时间: 2006-10-20 11:19
原帖由 asbai 于 2006-10-20 11:11 AM 发表

呵呵,兄台辛苦了。这个问题嘛,嘿嘿,就好像两个程序,调 printf 输出 “Hellow World” 的版本比直接调操作系统 API (例如:WriteConsole)输出同样字符串的版本体积要大是一样的:
1. printf 的功能远远不 ...


又学会了不少,只可惜,还是那句,因工作关系,10年没模过VC了(96年前后玩过TC 2.0、TC 3.0)。要是本人再年轻些,一定拜大侠为师。
作者: asbai    时间: 2006-10-20 11:20
原帖由 老毛桃 于 2006-10-20 10:51 AM 发表
var StartTime: Cardinal;
begin
  StartTime := GetTickCount;
  repeat
    Windows.Sleep(200);
  until ((GetTickCount - StartTime) > TimeToWait);
end;
有一点需要请教一下,既然我们默认的延时 ...

在这个用例中,轮询粒度设成 50 ms 还是 500 毫秒其实根本无关紧要,呵呵。因为轮询的成本很低,只不过是做一次整型运算和比较而已。即使把粒度设成 10ms 也不太可能看到 CPU 有任何波动。:)

至于 ASP 偶也没玩过,不过一般在不支持延迟的环境下实现等待通常用一种变通方法:执行一个阻塞操作,例如:连接一个不存在的 IP 地址,连接超时就是你的 wait 值。连接数据库、超时等待一个信号等等。
作者: asbai    时间: 2006-10-20 11:22
原帖由 lxl1638 于 2006-10-20 11:19 AM 发表


又学会了不少,只可惜,还是那句,因工作关系,10年没模过VC了(96年前后玩过TC 2.0、TC 3.0)。要是本人再年轻些,一定拜大侠为师。

哪里,兄台太过谦了。。。。。:L:$
作者: 老毛桃    时间: 2006-10-20 11:28
原帖由 asbai 于 2006-10-20 11:20 发表
在这个用例中,轮询粒度设成 50 ms 还是 500 毫秒其实根本无关紧要,呵呵。因为轮询的成本很低,只不过是做一次整型运算和比较而已。即使把粒度设成 10ms 也不太可能看到 CPU 有任何波动。:)
嘿嘿,受教了!
原帖由 asbai 于 2006-10-20 11:20 发表
至于 ASP 偶也没玩过,不过一般在不支持延迟的环境下实现等待通常用一种变通方法:执行一个阻塞操作,例如:连接一个不存在的 IP 地址,连接超时就是你的 wait 值。连接数据库、超时等待一个信号等等。

感谢提醒,我改天将我的程序尝试看看能不能这样延时!

不瞒你说,我曾经用过更加“无奈”的方法,让 ASP 执行数百万次的整数或浮点运算,后来发现这样执行时的 CPU 占用率更高!但是对于更加牛 B 的机器,运算速度过快,却仍然达不到延时的效果,才写了 6 楼的那个延时函数。
作者: lxl1638    时间: 2006-10-20 11:39
原帖由 老毛桃 于 2006-10-20 11:28 AM 发表
嘿嘿,受教了!

感谢提醒,我改天将我的程序尝试看看能不能这样延时!

不瞒你说,我曾经用过更加“无奈”的方法,让 ASP 执行数百万次的整数或浮点运算,后来发现这样执行时的 CPU 占用率更高!但是对于更加 ...

ASP本人只见朋友玩过,功能比起VC是有点无奈。
其实以你老毛桃的聪明和年轻,精通VC也就半年8个月的事,眼前这位大侠就是很好的老师。
作者: asbai    时间: 2006-10-20 11:46
原帖由 老毛桃 于 2006-10-20 11:28 AM 发表
感谢提醒,我改天将我的程序尝试看看能不能这样延时! ...

这个。。。。。咳。。咳。。请毛桃兄三思。通常在网络服务端做同步等待是十分有害的行为。因为这会显著增加每个用户请求所占用的服务器资源。在并发数稍高的环境下,这样的做法会迅速消耗服务器的工作线程池、可用句柄、内存等敏感资源。所以除了较廉价的家用宽带路由器等仅为1、2个并发用户设计的 web 配置界面以外,很少有人在服务器端用延迟伺服。:(

通常的解决办法是把这种事务拆成两个用户请求(由 session id 或 cookie 来标识),延迟的动作在客户端浏览器中以角本、Java Apple 或 ActiveX 控件等形式实现。这样就避免了服务器长时间为每个用户请求保留大量系统资源。

对可靠性、效率和强度要求更高的场合通常使用非阻塞或异步IO方式来解决这个问题。比如大型网游和 web 服务器引擎大多使用每活动连接一线程的异步方式工作。对于网络应用中各种模型的进一步说明可以参考大牛 Dan Kegel 的著名论文: 《The C10K Problem》。:)

[ 本帖最后由 asbai 于 2006-10-20 11:48 AM 编辑 ]
作者: 老毛桃    时间: 2006-10-20 12:17
原帖由 asbai 于 2006-10-20 11:46 发表

这个。。。。。咳。。咳。。请毛桃兄三思。通常在网络服务端做同步等待是十分有害的行为。因为这会显著增加每个用户请求所占用的服务器资源。在并发数稍高的环境下,这样的做法会迅速消耗服务器的工作线程池、可 ...

感谢提醒,我到《我是网管》看了看,似乎能够找到更好一些的方案了。不过不跑题了,我们继续讨论该讨论的,哈哈!




欢迎光临 无忧启动论坛 (http://wuyou.net./) Powered by Discuz! X3.3