2006年12月20日

装了office2007,发现不会添加页码了,在网上找了一些方法,要到选项里面设置模板,比较麻烦,而且每次都要重新设置。经过研究,终于发现了office2007添加页码的正确方法:点击“插入”-〉“页脚”-〉“编辑页脚”,然后在出来的设计工具条中点击“文档部件”-〉“构建基块管理器”,选择所需模板,点击插入即可。

这时,如果你不需要页眉的横线,可以选中页眉后在样式里面选择正文即可。

2006年07月11日

作者:北南南北
来自:LinuxSir.Org

目录

1、程序和进程;

1.1 进程分类;
1.2 进程的属性;
1.3 父进程和子进程;
2、进程管理;

2.1 ps 监视进程工具;

2.1.1 ps参数说明;
2.1.2 ps 应用举例;
2.2 pgrep

3、终止进程的工具 kill 、killall、pkill、xkill;

3.1 kill
3.2 killall
3.3 pkill
3.4 xkill
4、top 监视系统任务的工具;

4.1 top 命令用法及参数;
4.2 top 应用举例;
5、进程的优先级: nice和renice;
6、关于本文;
7、后记;
8、参考文档;
9、相关文档;

++++++++++++++++++++++++++++++++++++++
正文
++++++++++++++++++++++++++++++++++++++

 

1、程序和进程;

程序是为了完成某种任务而设计的软件,比如OpenOffice是程序。什么是进程呢?进程就是运行中的程序。

一个运行着的程序,可能有多个进程。 比如 LinuxSir.Org 所用的WWW服务器是apache服务器,当管理员启动服务后,可能会有好多人来访问,也就是说许多用户来同时请求httpd服务,apache服务器将会创建有多个httpd进程来对其进行服务。

1.1 进程分类;

进程一般分为交互进程、批处理进程和守护进程三类。

值得一提的是守护进程总是活跃的,一般是后台运行,守护进程一般是由系统在开机时通过脚本自动激活启动或超级管理用户root来启动。比如在Fedora或Redhat中,我们可以定义httpd 服务器的启动脚本的运行级别,此文件位于/etc/init.d目录下,文件名是httpd,/etc/init.d/httpd 就是httpd服务器的守护程序,当把它的运行级别设置为3和5时,当系统启动时,它会跟着启动。

[root@localhost ~]# chkconfig –level 35 httpd on

由于守护进程是一直运行着的,所以它所处的状态是等待请求处理任务。比如,我们是不是访问 LinuxSir.Org ,LinuxSir.Org 的httpd服务器都在运行,等待着用户来访问,也就是等待着任务处理。

1.2 进程的属性;

进程ID(PID):是唯一的数值,用来区分进程;
父进程和父进程的ID(PPID);
启动进程的用户ID(UID)和所归属的组(GID);
进程状态:状态分为运行R、休眠S、僵尸Z;
进程执行的优先级;
进程所连接的终端名;
进程资源占用:比如占用资源大小(内存、CPU占用量);

1.3 父进程和子进程;

他们的关系是管理和被管理的关系,当父进程终止时,子进程也随之而终止。但子进程终止,父进程并不一定终止。比如httpd服务器运行时,我们可以杀掉其子进程,父进程并不会因为子进程的终止而终止。

在进程管理中,当我们发现占用资源过多,或无法控制的进程时,应该杀死它,以保护系统的稳定安全运行;

2、进程管理;

对于Linux进程的管理,是通过进程管理工具实现的,比如ps、kill、pgrep等工具;

2.1 ps 监视进程工具;

ps 为我们提供了进程的一次性的查看,它所提供的查看结果并不动态连续的;如果想对进程时间监控,应该用top工具;

2.1.1 ps 的参数说明;

ps 提供了很多的选项参数,常用的有以下几个;

l  长格式输出;
u  按用户名和启动时间的顺序来显示进程;
j  用任务格式来显示进程;
f  用树形格式来显示进程;
a  显示所有用户的所有进程(包括其它用户);
x  显示无控制终端的进程;
r  显示运行中的进程;
ww 避免详细参数被截断;
我们常用的选项是组合是aux 或lax,还有参数f的应用;

ps aux 或lax输出的解释;

USER 进程的属主;
PID 进程的ID;
PPID  父进程;
%CPU 进程占用的CPU百分比;
%MEM 占用内存的百分比;
NI    进程的NICE值,数值大,表示较少占用CPU时间;
VSZ 进程虚拟大小;
RSS  驻留中页的数量;
WCHAN
TTY  终端ID
STAT 进程状态

D    Uninterruptible sleep (usually IO)
R    正在运行可中在队列中可过行的;
S    处于休眠状态;
T    停止或被追踪;
W    进入内存交换(从内核2.6开始无效);
X    死掉的进程(从来没见过);
Z    僵尸进程;

<           优先级高的进程
N    优先级较低的进程
L    有些页被锁进内存;
s    进程的领导者(在它之下有子进程);
l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+         位于后台的进程组;

WCHAN 正在等待的进程资源;
START 启动进程的时间;
TIME 进程消耗CPU的时间;
COMMAND 命令的名称和参数;

2.1.2 ps 应用举例;

实例一:ps aux 最常用

[root@localhost ~]# ps -aux |more

可以用 | 管道和 more 连接起来分页查看;

[root@localhost ~]# ps -aux > ps001.txt
[root@localhost ~]# more ps001.txt

这里是把所有进程显示出来,并输出到ps001.txt文件,然后再通过more 来分页查看;

实例二:和grep 结合,提取指定程序的进程;

[root@localhost ~]# ps aux |grep httpd
root 4187 0.0 1.3 24236 10272 ? Ss 11:55 0:00 /usr/sbin/httpd
apache 4189 0.0 0.6 24368 4940 ? S 11:55 0:00 /usr/sbin/httpd
apache 4190 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4191 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4192 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4193 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4194 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4195 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
apache 4196 0.0 0.6 24368 4932 ? S 11:55 0:00 /usr/sbin/httpd
root 4480 0.0 0.0 5160 708 pts/3 R+ 12:20 0:00 grep httpd

实例二:父进和子进程的关系友好判断的例子

[root@localhost ~]# ps auxf |grep httpd
root 4484 0.0 0.0 5160 704 pts/3 S+ 12:21 0:00 \_ grep httpd
root 4187 0.0 1.3 24236 10272 ? Ss 11:55 0:00 /usr/sbin/httpd
apache 4189 0.0 0.6 24368 4940 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4190 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4191 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4192 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4193 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4194 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4195 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd
apache 4196 0.0 0.6 24368 4932 ? S 11:55 0:00 \_ /usr/sbin/httpd

这里用到了f参数;父与子关系一目了然;

2.2 pgrep

pgrep 是通过程序的名字来查询进程的工具,一般是用来判断程序是否正在运行。在服务器的配置和管理中,这个工具常被应用,简单明了;

用法:

#ps 参数选项 程序名

常用参数

-l 列出程序名和进程ID;
-o 进程起始的ID;
-n 进程终止的ID;

举例:

[root@localhost ~]# pgrep -lo httpd
4557 httpd
[root@localhost ~]# pgrep -ln httpd
4566 httpd
[root@localhost ~]# pgrep -l httpd
4557 httpd
4560 httpd
4561 httpd
4562 httpd
4563 httpd
4564 httpd
4565 httpd
4566 httpd
[root@localhost ~]# pgrep httpd
4557
4560
4561
4562
4563
4564
4565
4566

3、终止进程的工具 kill 、killall、pkill、xkill;

终止一个进程或终止一个正在运行的程序,一般是通过 kill 、killall、pkill、xkill 等进行。比如一个程序已经死掉,但又不能退出,这时就应该考虑应用这些工具。

另外应用的场合就是在服务器管理中,在不涉及数据库服务器程序的父进程的停止运行,也可以用这些工具来终止。为什么数据库服务器的父进程不能用这些工具杀死呢?原因很简单,这些工具在强行终止数据库服务器时,会让数据库产生更多的文件碎片,当碎片达到一定程度的时候,数据库就有崩溃的危险。比如mysql服务器最好是按其正常的程序关闭,而不是用pkill mysqld 或killall mysqld 这样危险的动作;当然对于占用资源过多的数据库子进程,我们应该用kill 来杀掉。

3.1 kill

kill的应用是和ps 或pgrep 命令结合在一起使用的;

kill 的用法:

kill [信号代码]   进程ID
注:信号代码可以省略;我们常用的信号代码是 -9 ,表示强制终止;

举例:

[root@localhost ~]# ps auxf |grep httpd
root 4939 0.0 0.0 5160 708 pts/3 S+ 13:10 0:00 \_ grep httpd
root 4830 0.1 1.3 24232 10272 ? Ss 13:02 0:00 /usr/sbin/httpd
apache 4833 0.0 0.6 24364 4932 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4834 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4835 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4836 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4837 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4838 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4839 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd
apache 4840 0.0 0.6 24364 4928 ? S 13:02 0:00 \_ /usr/sbin/httpd

我们查看httpd 服务器的进程;您也可以用pgrep -l httpd 来查看;

我们看上面例子中的第二列,就是进程PID的列,其中4830是httpd服务器的父进程,从4833-4840的进程都是它4830的子进程;如果我们杀掉父进程4830的话,其下的子进程也会跟着死掉;

[root@localhost ~]# kill 4840 注:杀掉4840这个进程;
[root@localhost ~]# ps -auxf |grep httpd 注:查看一下会有什么结果?是不是httpd服务器仍在运行?
[root@localhost ~]# kill 4830 注:杀掉httpd的父进程;
[root@localhost ~]# ps -aux |grep httpd 注:查看httpd的其它子进程是否存在,httpd服务器是否仍在运行?

对于僵尸进程,可以用kill -9 来强制终止退出;

比如一个程序已经彻底死掉,如果kill 不加信号强度是没有办法退出,最好的办法就是加信号强度 -9 ,后面要接杀父进程;比如;

[root@localhost ~]# ps aux |grep gaim
beinan 5031 9.0 2.3 104996 17484 ? S 13:23 0:01 gaim
root 5036 0.0 0.0 5160 724 pts/3 S+ 13:24 0:00 grep gaim

[root@localhost ~]# pgrep -l gaim
5031 gaim
[root@localhost ~]# kill -9 5031

3.2 killall

killall 通过程序的名字,直接杀死所有进程,咱们简单说一下就行了。

用法:killall 正在运行的程序名

killall 也和ps或pgrep 结合使用,比较方便;通过ps或pgrep 来查看哪些程序在运行;

举例:

[root@localhost beinan]# pgrep -l gaim
2979 gaim
[root@localhost beinan]# killall gaim

3.3 pkill

pkill 和killall 应用方法差不多,也是直接杀死运行中的程序;如果您想杀掉单个进程,请用kill 来杀掉。

应用方法:

#pkill 正在运行的程序名

举例:

[root@localhost beinan]# pgrep -l gaim
2979 gaim
[root@localhost beinan]# pkill gaim

3.4 xkill

xkill 是在桌面用的杀死图形界面的程序。比如当firefox 出现崩溃不能退出时,点鼠标就能杀死firefox 。当xkill运行时出来和个人脑骨的图标,哪个图形程序崩溃一点就OK了。如果您想终止xkill ,就按右键取消;

xkill 调用方法:

[root@localhost ~]# xkill

4、top 监视系统任务的工具;

和ps 相比,top是动态监视系统任务的工具,top 输出的结果是连续的;

4.1 top 命令用法及参数;

top 调用方法:

top 选择参数

参数:

-b 以批量模式运行,但不能接受命令行输入;
-c 显示命令行,而不仅仅是命令名;
-d N 显示两次刷新时间的间隔,比如 -d 5,表示两次刷新间隔为5秒;
-i 禁止显示空闲进程或僵尸进程;
-n NUM 显示更新次数,然后退出。比如 -n 5,表示top更新5次数据就退出;
-p PID 仅监视指定进程的ID;PID是一个数值;
-q 不经任何延时就刷新;
-s 安全模式运行,禁用一些效互指令;
-S 累积模式,输出每个进程的总的CPU时间,包括已死的子进程;

交互式命令键位:

 

space 立即更新;
c 切换到命令名显示,或显示整个命令(包括参数);
f,F 增加显示字段,或删除显示字段;
h,? 显示有关安全模式及累积模式的帮助信息;
k 提示输入要杀死的进程ID,目的是用来杀死该进程(默人信号为15)
i 禁止空闲进程和僵尸进程;
l 切换到显法负载平均值和正常运行的时间等信息;
m 切换到内存信息,并以内存占用大小排序;
n 提示显示的进程数,比如输入3,就在整屏上显示3个进程;
o,O 改变显示字段的顺序;
r 把renice 应用到一个进程,提示输入PID和renice的值;
s 改变两次刷新时间间隔,以秒为单位;
t 切换到显示进程和CPU状态的信息;
A 按进程生命大小进行排序,最新进程显示在最前;
M 按内存占用大小排序,由大到小;
N 以进程ID大小排序,由大到小;
P 按CPU占用情况排序,由大到小
S 切换到累积时间模式;
T 按时间/累积时间对任务排序;
W 把当前的配置写到~/.toprc中;

4.2 top 应用举例;

 

[root@localhost ~]# top

然后根据前面所说交互命令按个尝试一下就明白了,比如按M,就按内存占用大小排序;这个例子举不举都没有必要了。呵。。。。。。

当然您可以把top的输出传到一个文件中;

[root@localhost ~]# top > mytop.txt

然后我们就可以查看mytop文件,以慢慢的分析系统进程状态;

5、进程的优先级:nice和renice;

在Linux 操作系统中,进程之间是竟争资源(比如CPU和内存的占用)关系。这个竟争优劣是通过一个数值来实现的,也就是谦让度。高谦让度表示进程优化级别最低。负值或0表示对高优点级,对其它进程不谦让,也就是拥有优先占用系统资源的权利。谦让度的值从 -20到19。

目前硬件技术发展极速,在大多情况下,不必设置进程的优先级,除非在进程失控而疯狂占用资源的情况下,我们有可能来设置一下优先级,但我个人感觉没有太大的必要,在迫不得已的情况下,我们可以杀掉失控进程。

nice 可以在创建进程时,为进程指定谦让度的值,进程的优先级的值是父进程SHELL的优先级的值与我们所指定谦让度的相加和。所以我们在用nice设置程序的优先级时,所指定数值是一个增量,并不是优先级的绝对值;

nice 的应用举例:

[root@localhost ~]# nice -n 5 gaim & 注:运行gaim程序,并为它指定谦让度增量为5;

所以nice的最常用的应用就是:

nice -n 谦让度的增量值 程序

renice 是通过进程ID(PID)来改变谦让度,进而达到更改进程的优先级。

renice 谦让度 PID

renice 所设置的谦让度就是进程的绝对值;看下面的例子;

[root@localhost ~]# ps lax   |grep gaim
4     0  4437  3419  10  -5 120924 20492 -      S<   pts/0      0:01 gaim
0     0  4530  3419  10  -5   5160   708 -      R<+  pts/0      0:00 grep gaim

[root@localhost ~]# renice -6  4437
4437: old priority -5, new priority -6

[root@localhost ~]# ps lax   |grep gaim
4     0  4437  3419  14  -6 120924 20492 -      S<   pts/0      0:01 gaim
0     0  4534  3419  11  -5   5160   708 -      R<+  pts/0      0:00 grep gaim

6、关于本文;

进程管理还是需要的,虽然在桌面应用上,我们点鼠标就能完成大多的工作,但在服务器管理中,进程管理还是十分重要的。

有的弟兄会说,为什么您不说说在桌面环境中的图形管理的进程工具。我感觉没有太大的必要,如果您会点鼠标就应该能找到有关进程管理的工具。

还有的弟兄会说:Windows的进程管理真的很方便,按一下CTRL+ALT+DEL就可以调出来,随便你怎么杀和砍。我感觉Windows的进程管理并不怎么样,如果有的程序真的需要CTRL+ALT+DEL的话,呵,那肯定会出现系统假死现象。或者程序错误之类的提示。弄不好就得重启,这是事实吧。

Windows 的进程管理并不优秀,只是一个友好的界面而已,我想我说的没错吧;

7、后记;

近些天一直在为网络基础文档做计划,当然也随手写一写自己能写的文档, 比如本篇就是; 也想把论坛中的一些弟兄优秀的教程整理出来,但后来一想,如果提交到 LinuxSir.Org 首页上,肯定得做一些修改,如果我来修改倒不如让作者自己来修改,自己写的东西自己最明白,对不对???

在准备网络文档计划的过程中,向etony兄请教了一些基本的网络基础知识。我对网络基础理论基本不懂。听tony兄解说的同时,我也做了笔记。同时也和tony兄讨论了网络基础篇的布局和谋篇的事,这关系到初学者入手的问题,好象是小事,其实事情比较大。如果写的文档,新手读不懂,老鸟又认为没有价值,我看倒不如不写。。

 

摘自www.csdn.net 作者:heiyeluren 责任编辑:liyalin 一、服务管理 winnt操作系统的服务管理是比较强的,它内置有一个服务管理器,能够非常方便的管理操作系统内的服务。Linux也同样有管理服务的特有方式。 Linux的服务都是以脚本的方式来运行的,存在于 /etc/rc.d/init.d目录下所有的脚本就是我们的服务脚本,它具有两项作用,一项是能够在系统启动的时候自动启动那些脚本中所要求启动的程序,另外,我们还能够通过该脚本来对服务进行控制,比如启动,停止等。 我们先看看下面有那些服务: # ls /etc/rc.d/init.d anacron cups iptables killall nfslock random single ypbind apmd firstboot irda kudzu nscd rawdevices sshd atd functions isdn netfs ntpd rhnsd syslog autofs gpm kdcrotate network pcmcia saslauthd xfs crond halt keytable nfs portmap sendmail xinetd 里面列出的就是我们目前系统中所有的服务脚本,每次系统启动的时候就会启动。我们打开一个脚本来看看: # cat /etc/rc.d/init.d/smb case "$1" in start) start ;; stop) stop ;; status) status rpc.mountd status nfsd ;; restart) $0 stop $0 start ;; reload) /usr/sbin/exportfs -r touch /var/lock/subsys/nfs ;; *) echo $"Usage: nfs {start|stop|status|restart|reload}" exit 1 esac exit 0 我们可以看出里面基本上有几个服务,启动、停止、重启、状态等等,我们看看下面的表: 服务脚本操作 ————————————————————————– 操作 作用 ————————————————————————– start 启动服务,等价于服务脚本里的start命令 stop 停止服务,等价于副外长脚本stop命令 restart 关闭服务,然后重新启动,等价于脚本restart命令 reload 使服不重新启动而重读配置文件,等价与服务脚本的reload命令 status 提供服务的当前状态,等价于服务脚本的status命令 condrestart 如果服务锁定,则这个来关闭服务,然后再次启动,等价于condrestart命令 ————————————————————————– 比如,我们要重新启动Samba,则可以用root用户运行下面两个命令,效果一样: # /etc/rc.d/init.d/smb restart # service smb restart 那么到这里就明白了,假如我们要把那个服务让它系统启动的时候自动启动,那么就配置好一个服务脚本,放到/etc/rc.d/init.d里面就OK了,相应的,如果你要删除那个服务,把脚本移走就可以了.

2006年05月08日

为什么游戏越来越不好玩的终极原因!(含人生哲理)

看到很多人在抱怨现在的PS2游戏画面越来越好 但反而不如以前“小时侯”的FC什么的好玩了

这里关键问题不是游戏的问题,这里没有区分,说是FC游戏好还是PS2游戏好,这没有区别,因为游戏的本质是一样的。关键的词是“小时侯”

你可想过你的童年,那时的你那么单纯,不知道金钱,权力,爱情,你看大人们拼了命的追求那些东西,你感到很奇怪,很奇怪大人为什么这么喜欢这些东西?他们有什么意思?在你看来那些东西还不如花丛里的一只蝴蝶好玩,你会去追那只蝴蝶,因为她是那么漂亮那么绚丽。而大人会告诉你说:“你去追她干什么?不要浪费时间!”你望着他们无法理解:这蝴蝶这么美丽为什么大人不喜欢呢?在你看来大人花那么多时间去追求一张张纸,所谓的”钱“,才是没意义的,才是浪费时间。然而你被压抑了,他们告诉你你是错的,你是无知的,你想:或许我错了吧!因为大人无法理解你在想什么,同样你也无法理解大人在想什么。

你是那么天真无邪,那么纯真,没有杂念,所以你可以完全的投入,投入任何东西,这就是天真,这就是孩子,他在海边捡贝壳,完全专注于那件事,世界都忘了,只剩下他和那个贝壳,他捡贝壳没有目的,他不是为了金钱和权力,他是为了捡而捡,完全发自于内心。而大人做事总是有目的的,不是为了钱就是为了权力,亦或名誉,有了目的就会紧张,因为这是欲望,你想要得到,你害怕失败,而当你紧张的时候你还会完全投入吗?

小孩不一样,你想过你玩FC的时候吗?你是那么的投入游戏,甚至忘记了整个世界,那时的你只是单纯的玩,没有目的,你就是为了玩而玩。你不是为了什么成就感,也不是为了证明自己的什么东西,不是为了极限挑战全要素,甚至不是为了很多人现在所说的”快乐“。不是吗?当你拿起手柄的时候,你想过”快乐“这个词吗?你什么都没想,你只是玩,完全投入地玩,然而当你完全投入的时候,快乐自然而然升起来了,就是这么回事,没有目的,然而目的自然达成。

可惜的是你长大了,你懂事了,社会灌输给你各种欲望,他们要你疯狂,要你追逐。他要你变成一个有钱的人,有权力的人,有漂亮太太的人,他告诉你,这才是你要的东西,你去追求他们才是对的。于是你开始浮躁了,你无法静下来了,甚至是在玩游戏的时候!不是吗?你想想,当你拖着疲惫的身体回到家的时候,你在想:放松一下吧,玩玩游戏,可是你已经有目的了,你连玩游戏都已经有目的了,所以注定你不可能放松了,你玩了一会,放下手柄:什么破游戏啊!?关机!真相是:不是游戏破,是你想获得快乐,而你却无法从这个游戏中获的快乐,而快乐不是因为游戏而是因为你自己!小时侯你完全不知道大作神作,你可以玩一款连名字都不知道的游戏,却玩的很快乐,为什么?因为你完全投入了
而现在呢?你在玩游戏的时候,内心却在疯狂,你在想工作,你在想学习,你在计较工资得失,你在想老婆怎么还没打电话给我?你甚至在想:快点让这游戏通关,我好做其他事,游戏变成了 任务。这样的你怎么可能静下来?怎么可能投入?怎么可能获得快乐呢?

问题的关键不是游戏,也不是你的心态,而是你长大了,你永远也无法回到那个单纯的过去,单纯的快乐了。你可以说:没有啊?现在我玩游戏依然很快乐啊,对!我知道你很快乐,但你快乐的本质已经变了,知道吗?现在你的快乐是很浅的,或者说是感官上的快乐,他是来自你的头脑的,和你小时侯那种快乐不一样:那快乐是来自深处的,来自内心的。这两者有着本质的区别。

这就是原因

2006年03月17日

一、非正常关机导致文件系统破坏了

1. 确定你的linux的分区的名称,比如/dev/hda2,/dev/hda3等等
2. fsck -y /dev/hda2
3. 如果提示不能mount /proc
  mount -t proc none /proc
4. 如果提示/为read-only文件系统,用光盘启动,boot: linux rescue,
  chroot /mnt/sysimg(记得不确了。也可能是/mnt/sysimage)
  重复2

光盘启动的方法:

1) 把第一张光盘放到光驱,重启
2)在提示符boot: linux rescue

3) 根据提示选择语言和你的root分区
4) 根据提示执行 chroot /mnt/sysimage

5) fsck -a /dev/hdax 一个个的设备检查, 检查完了重启就好了

二、RedHat非正常关机的自动磁盘修复

有时候遇到断电或者是工作人员图省事会直接关掉电源,这时就有可能出现磁盘错误。用过RH的人都知道,在这种情况下重启机器后屏幕会出现选单,如果在5秒内按"Y"键则开始fsck的磁盘修复,超时则服务器不进行磁盘修复继续执行启动操作。如果不进行磁盘修复,日积月累可能造成文件严重损坏。而我们的服务器显示器、键盘都拔掉了,该怎么办呢??
可以先登录到服务器,然后在/etc/sysconfig里增加一个文件autofsck,内容如下:
AUTOFSCK_DEF_CHECK=yes
PROMPT=yes
注意大小写,存盘退出以后一切OK!!!
现在你可以试一下直接关掉电源,开机后是不是看见它等了5秒之后开始自动扫描了???
呵呵,现在你可以放心地把显示器、键盘都拔掉了
哪怕是叫个看门老太太来负责关机都没关系了

2005年10月26日

一、前言:
  国庆节黄金周居然要加班,真是郁闷啊,朋友给了一个网址:http://games.sina.com.cn/z/mm/

说是好多网络游戏MM在里面,据称里面还真有特别漂亮的,呵呵。我实在经不起诱惑,打开一看,原来是

sina搞的一个活动,活动名称就叫“中国第一届游戏MM风采秀”,随便看了几个MM的视频,还真是漂亮哈

。不过,作为一个喜欢找系统空子的人,我很快就盯上了其中的投票系统,嘿嘿。sina为这次活动举办了

一次网友投票,来评选最受欢迎的网络MM,每个MM都有那么一个得票数,最后据说要选出5个得票最多的

MM参加总决赛。
 
二、初步实验及简单投票器设计:
  随便找了一个MM做实验,004016号的纳兰如意MM,准备瞧瞧sina的在线投票系统是不是有缺陷。
  实验一,首先我在本机投了一票之后,又找了一台内网的机器再测试,还可以继续投,说明sina并没

有限制每个IP的投票次数。在仔细地看了这个投票系统之后,发现实质上投票只不过是提交一个连接,就

拿004016号MM来说,其实只要提交http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?

usernum=004016&title=纳兰如意,就可以增加一票。
  实验二,打开一个新的IE窗口,提交上面的连接,返回的内容是“感谢您的参与!纳兰如意 的票数为

000xxxx 票”,这次投票成功,继续,用这个IE窗口第二次提交上面的连接,发现返回的内容是“请不要

重复提交信息!”。看来sina还是设置了一次连接的投票次数限制,不过,总觉得有点问题,继续做下面

的实验。
  实验三,打开两个IE窗口,同时提交上面的连接,发现增加了两票,这一点说明sina也没有限制两次

投票的间隔时间。怪了,刚才一个IE窗口提交两次连接怎么不成功。
  啃了一个苹果后,突然恍然大悟,哈哈,原来sina是这样设置的,一次tcp连接只能投票一次,当检

测到本次连接已经投过票之后,就会返回“请不要重复提交信息!”。而关掉这个已经投过票的IE时,这

次连接就失效了。重新再打开IE提交投票连接时,就可以继续投票了。呵呵,sina的投票系统果然有很大

的缺陷。下面就可以轻松地写出自动投票程序了,主要的代码如下:
void vote()
{
  char url[200] = "http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?

usernum=004016&title=纳兰如意";
  //可以改成任意MM的投票连接
  HINTERNET hinternet=0;
  hinternet=InternetOpen("Microsoft Internet

Explorer",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
  if(hinternet==0)
  {
  return;
  }
  HINTERNET hInternetFile;
  hInternetFile = InternetOpenUrl(hinternet,url, NULL, 0, INTERNET_FLAG_TRANSFER_BINARY |

INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0);
  if (!hInternetFile)
  {
  return;
  }
  char buffer[2*1024] = "0";
  DWORD dwBytesRead = 0;
  InternetReadFile(hInternetFile,buffer,sizeof(buffer),&dwBytesRead);
  printf("%s\n\n",buffer);
  InternetCloseHandle(hinternet);
  return;
}
  上面这个vote()函数实现的功能就是提交一次投票连接,可以增加一票。由于限制了每次tcp连接的

投票次数,所以,仅仅不停地调用这个函数是无法连续投票的,但是,呵呵,你可以绕一下,把这个函数

编译成exe文件,然后用另外一个程序去不停地CreateProcess这个exe文件,假设上面的代码编译连接成

toupiao.exe,你就可以用下面的代码来调用:
void main()
{
  printf("code by xiaobai\n\n");
  int num = 0;
  printf("请输入投票次数: ");
  scanf("%d", &num);
  int i = 0;
  while(i<num)
  {
  STARTUPINFO startinfo;
  GetStartupInfo(&startinfo);
  startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
  startinfo.wShowWindow = SW_HIDE;
  PROCESS_INFORMATION processinfo;
  if(CreateProcess(NULL, "toupiao.exe", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL,

NULL, &startinfo, &processinfo) == 0)
  {
  printf("Create process error!\n");
  return;
  }
  CloseHandle(processinfo.hProcess);
  Sleep(1000);
  printf("%d ", i);
  i++;
  }
  return;
}
  这样一来,你就可以不停地投票了。为了程序的稳定性,我设置了每投一次票就sleep一秒钟,现在

,你一个小时就可以投3600票,呵呵,是不是有点过分了,嘿嘿。
 
三、突破IP限制的隐蔽式投票器设计
  前面我们已经设计了一个简单的投票器,虽然简单,不过,投票效率可是够高的,呵呵。但是,总觉

得好象疏忽了点什么,感觉上不太对劲。哦,原来是IP的问题,我们刚才运行投票器后,总是自己本机一

个IP地址在投票,如果对方记录了IP地址,那么,显示的票都是从这一个IP地址来的,那岂不是弄巧成拙

。虽然现在看来sina好象并没有过滤一个IP地址的重复票的问题,但是,作为我们这种爱走“旁门左道”

的人来说,我们总不能碰到问题就放手吧,嘿嘿。现在我们就来设计一个隐蔽性比较好的投票器,即使对

方设置了IP地址的重复投票过滤,也可以成功地进行批量投票。
  我们这个隐蔽式投票器的设计思想就是利用HTTP代理服务器。在网络上,我们可以很轻松地得到很多

的http proxy,现在就利用代理来隐藏自己的IP,让http proxy代替我们来提交投票的请求,这样,显示

在投票系统服务器上的IP地址就是http proxy的IP地址,就成功地隐蔽了自己的IP。所以,只要你有足够

的http proxy,就可以投很多的票。

//———————-
socktp.cpp
code by xiaobai
//———————-
#include <Winsock2.h>
#include <winsock.h>
#pragma comment(lib,"WS2_32.lib")
void main(int argc,char* argv[])
{
  WSADATA wsadata;
  char lpbuffer[MAX_PATH*2+50]="0";
  sockaddr_in addrin;
  SOCKET sock;
  if (WSAStartup(MAKEWORD( 2, 2 ),&wsadata)!=0)
  return;
  sock=socket(AF_INET,SOCK_STREAM,0);
  addrin.sin_addr.s_addr = inet_addr(argv[1]);
  addrin.sin_port =htons(atoi(argv[2]));
  addrin.sin_family=AF_INET;
  int rtn = connect(sock,(sockaddr*) &addrin,sizeof(addrin));
  lstrcpy(lpbuffer,"GET http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?

usernum=004016&title=纳兰如意");
  //可以修改成任何一个MM
  send(sock,lpbuffer,lstrlen(lpbuffer),0);
  closesocket(sock);
  return;
}
  上面就是投票器的主要实现代码,通过参数传递进去http proxy的IP地址和端口,就可以让代理去提

交投票的连接,这样的话,显示在服务器上的IP就是http proxy的IP。这段代码可以利用你给的http

proxy投一次票。编译连接成toupiao.exe文件后,把你所有的http proxy地址和端口按照一定格式保存为

一个txt文件。跟上面的简单投票器一样,再利用另外一段程序,读取每个http proxy,读取后利用

CreateProcess传递给toupiao.exe文件,就可以不停地投票了。
  通过上面的代码,我们就成功地实现了具有隐蔽功能的投票器,即使投票服务器限制了IP地址的票数

,也不怕了,因为http proxy在网络上简直是无限的。所以,只要你找到足够多的http proxy,你就可以

投票足够多次,也不会出现大多数票都来自一个IP的情况了,呵呵。
 
四、解决对策与探讨
  上面我们设计了可以突破IP限制的隐蔽式投票器,不过说到底,我们希望得到的是一个公平的竞争环

境,我们都不喜欢作弊者。所以,我们要对在线投票系统的公平性要做些努力。
  首先,对于sina的这次活动,给我的印象是sina不负责任。对于如此的投票缺陷,sina竟然无动于衷

。在刚投票开始的时候,我就想把相关的缺陷情况反映给sina,可是,活动相关的信箱,自投票以来这几

天,始终提示信箱已满,无法投递mail。论坛中无数人都在询问关于刷票的问题,始终没有人给一个负责

的解释。
 
  不过,话说回来,这其实也就是一个商业活动,对于投票的结果,sina不关注,赞助商也不会关注,

他们关注的是最后达到的广告效应和即得的经济利益。
  呵呵,话扯远了,还是回到技术的层面。为了防止在线投票系统作弊,应该做到下面几个步骤:
  1、首先,设置投票IP限制,或者要求每个IP只能投一票,这样,可以有效地防止作弊。但是,现在

由于IP地址并不充足,所以,有很多都是代理或者NAT来上网,所以,有可能很多人使用的是一个IP地址

。所以,限制IP并不是一个很好的办法,有可能让很多人都没有投票的机会,这样本身就造成了不公平。
  2、设置每个IP地址的投票延时,碰到1那种不合适的情况,就可以采用这个办法,每个IP地址在投票

之后,要经过一段时间的延时才可以第二次投票。这样也是一种防止单个IP地址刷票的办法。
  3、其实上面的方法对于我们设计的突破IP限制的隐蔽式投票器来说,都是没有任何意义的,那该怎

么办呢?还是就以sina为对象来说,设置成为只有sina的会员投票,并且每个会员的投票次数都是有限制

的,这样,对于防止所有类型的投票器都是很有效的,并且,为了加强效果,可以设置成每次投票都要输

入一个随即产生的校验码。这样,再配合前面两种方法,就可以大大降低作弊的可能性。

  其实,并不是我们想钻空子,我们只是想让这个网络对所有人都有一个公平的竞争环境。
 
 
10月10日晚7点补充:
  昨天sina的投票就已经结束了,今天再看的时候就已经开始第二轮投票了,这次的投票方法改变了一

下,不会让你很容易地发现投票提交的信息了,呵呵,看来安全了一些。就拿冰风传奇MM投票页来看吧,

具体的连接是_jz.shtml">http://games.sina.com.cn/z/mm/vote_jz.shtml,要求投票者分配手中的30个

点数,然后最后点击提交按钮来投票。由于不象以前那种可以直接得到投票的提交信息了,所以,表面上

看起来好象作弊的难度大了。
 
  但是,嘿嘿,还是有办法的。这就要请出我们的Sniffer来了,截获你在点击提交按钮时与sina服务

器的交互过程,不就可以得到投票提交连接了么,呵呵。说做就做,打开Iris,监视80端口的信息。在冰

风传奇MM投票页上,给1号填上2分,2号填上3分,19号填上4分,最后的姓名填上xiaobai,电话填上

1234567,OK!,提交吧。哈哈,想要的东西来了,看下面截获的内容:
 
  第一个数据包:
  POST /cgi-bin/survey/games/mms2003/vote.cgi HTTP/1.1..Accept: image/gif, image/x-

xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-

powerpoint, application/vnd.ms-excel, application/msword, */*..Referer: _jz.shtml..Accept-

Language">http://games.sina.com.cn/z/mm/vote_jz.shtml..Accept-Language: zh-cn..Content-Type:

application/x-www-form-urlencoded..Accept-Encoding: gzip, deflate..User-Agent: Mozilla/4.0

(compatible; MSIE 6.0; Windows NT 5.0)..Host: stat.sina.com.cn..Content-Length:

500..Connection: Keep-Alive..Cache-Control: no-cache..Cookie:

regplace=China………..X…6..
 
  第二个数据包:
  MMS_Game=%B1%F9%B7%E7%B4%AB%C6%E6&MMS_Result1=2&MMS_Result2=3&MMS_Result3=0%B7%

D6&MMS_Result4=0%B7%D6&MMS_Result5=0%B7%D6&MMS_Result6=0%B7%D6&MMS_Result7=0%B7%

D6&MMS_Result8=0%B7%D6&MMS_Result9=0%B7%D6&MMS_Result10=0%B7%D6&MMS_Result11=0%B7%

D6&MMS_Result12=0%B7%D6&MMS_Result13=0%B7%D6&MMS_Result14=0%B7%D6&MMS_Result15=0%B7%

D6&MMS_Result16=0%B7%D6&MMS_Result17=0%B7%D6&MMS_Result18=0%B7%

D6&MMS_Result19=4&MMS_Result20=0%B7%

D6&User_Name=xiaobai&User_Phone=1234567&User_Code=&User_Address=&User_Email=l=…
 
  上面就是sniffer得到的东西,我只保留了http的部分。呵呵,看到了吧,用POST来提交/cgi-

bin/survey/games/mms2003/vote.cgi,而内容则是后面第二个数据包的内容。第二个数据包的内容很容

易理解,看里面1号选手对应的MMS_Result1=2,2号选手对应的MMS_Result2=3,19号选手对应的

MMS_Result19=4,其他的都是0,还有后面的User_Name=xiaobai,User_Phone=1234567,呵呵,是不是我

们刚才输入的内容。
 
  既然提交的内容都得到了,那就来组合一下,就有了如下的内容:
  http://stat.sina.com.cn/cgi-bin/survey/games/mms2003/vote.cgi?MMS_Game=%B1%F9%B7%E7%

B4%AB%C6%E6&MMS_Result1=2&MMS_Result2=3&MMS_Result3=0%B7%D6&MMS_Result4=0%B7%

D6&MMS_Result5=0%B7%D6&MMS_Result6=0%B7%D6&MMS_Result7=0%B7%D6&MMS_Result8=0%B7%

D6&MMS_Result9=0%B7%D6&MMS_Result10=0%B7%D6&MMS_Result11=0%B7%D6&MMS_Result12=0%B7%

D6&MMS_Result13=0%B7%D6&MMS_Result14=0%B7%D6&MMS_Result15=0%B7%D6&MMS_Result16=0%B7%

D6&MMS_Result17=0%B7%D6&MMS_Result18=0%B7%D6&MMS_Result19=4&MMS_Result20=0%B7%

D6&User_Name=xiaobai&User_Phone=1234567&User_Code=&User_Address=&User_Email=l=…
 
  现在,只要打开IE,提交上面格式的请求,就可以很容易地增加票数了。你只需要把你想投票的MM找

到对应的MMS_Result,后面加上你要投的票数,由于sina做了限制,每次只能最大是30。然后,改一下后

面的User_Name和User_Phone,提交,呵呵,就投票成功了。我们想得到的已经得到了,投票器也可以轻

松地写出来了。不过这次投票器的设计有一点点麻烦,每投一次票,都要随机再产生一个User_Name和

User_Phone,呵呵。

2005年08月26日

在VB中用API实现多媒体主要是调用Windows的mmsystem.dll库。以下为调用API的声明(这些代码放在程序的声明部分中):

1. ‘播放CD和AVI所需要的声明。

  Declare Function mciSendString Lib "MMSYSTEM"(ByVal lpstrCommand _

    as String,ByVal lpstrReturnStr as Any,ByVal wRetumLen as Integer, _

    ByVal hCallBack as Integer) as Long

  ’播放WAV所需要的声明

  Declare Function sndPlaySound Lib "MMSYSTEM.DLL"(ByVal lpszSoundName _

    as String,ByVal wF1ags as Integer) as Integer

  ’检测声卡所需要的声明

  Declare Function auxGetNaumDevs Lib "MMSYSTEM"()as Integer

  ’所用到的全局变量声明

  Global Const SND_SYNC=&H0000   ’播放WAV用到的全局变量

  Global Const SND_ASYNC=&H0001 ‘播放WAV用到的全局变量

  Global Const SND_NODEFAULT=&H0002 ‘播放WAV用到的全局变量

  Global Const SND_LOOP=&H0008 ‘播放WAV用到的全局变量

  Global Const SND_NOSTOP=&H0010 ‘播放WAV用到的全局变量

  ’接下来是调用这些声明

  Function auxTest()as Boolean

    Dim i As Integer

    i=auxGetNumDevs()

    If i>0 Then

      AuxTest=True ‘如果有声卡则返回真

      Exit Function

    Else

      AuxTest=False ‘如果未检测到声卡则返回假

      Exit Function

    End If

  End Function

2.播放CD的源代码

  Sub PlayCD(b As Integer)

  ’b为所播的音轨号

    Dim a As Long

    a=mciSendString("open cdaudio alias cd wait",0&,0,0)’初始化驱动

    a=mciSendString("set cd time format tmsf",0&,0,0)

    a=mciSendString("play cd from"& Str(b),0&,00) ‘播放音轨

  End Sub

3.播放AVI的源代码

  Sub playAVI(AVIFile As String)

    Dim RVal as Long

    AVIFile="play"+AVIFile+"fullscreen" ‘全屏幕播放AVI文件

    RVal=mciSendString(AVIFile,0&,0,0&)

  End Sub

4.播放WAV的源代码

  Sub playWAV(WAVFile As String)

    Dim Flag as Integer

    Dim a as Integer

    wFlag=SND_ASYNC or SND_NODEFAULT

    a=sndPlaySound(WAVFile,Flag)

  End Sub

Public Declare Function PRINTDLG Lib "comdlg32.dll" Alias "PrintDlgA" (pPrintdlg As PRINTDLG) As Long
Type PRINTDLG
lStructSize As Long
hwndOwner As Long
hDevMode As Long
hDevNames As Long
hdc As Long
flags As Long
nFromPage As Integer
nToPage As Integer
nMinPage As Integer
nMaxPage As Integer
nCopies As Integer
hInstance As Long
lCustData As Long
lpfnPrintHook As Long
lpfnSetupHook As Long
lpPrintTemplateName As String
lpSetupTemplateName As String
hPrintTemplate As Long
hSetupTemplate As Long
End Type

  通过单击窗体上的Command1按钮即可调出打印对话框。
Private Sub Command1_Click()
Dim p As PRINTDLG
p.lStructSize = Len(p)
p.hwndOwner = Me.hWnd
p.nFromPage = 1
p.nToPage = 1
p.nMinPage = 1
p.nMaxPage = 1
p.nCopies = 1
x = PRINTDLG(p)
On Error Resume Next
Printer.Print "用API调用打印对话框"
End Sub

2005年08月21日

 

Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Function sqrx(ByVal x As Double) As String ‘计算平方根(比VB DOUBLE 类型精度高)
Dim temp As String, i As Long, j As Long
Shell "Calc.EXE", vbMinimizedNoFocus ‘运行计算器
temp = x & "y0.5="
For i = 1 To Len(temp)
SendKeys Mid(temp, i, 1), True ‘向计算器顺序发送按键消息X (X^Y) 0.5=
Next
temp = String(64, Chr(0))
i = FindWindow(vbNullString, "计算器") ‘窗口句柄
j = FindWindowEx(i, ByVal 0&, "Edit", vbNullString) ‘编辑框句柄
SendMessage j, &HD, Len(temp), ByVal temp ‘发送编辑框文本至temp
SendKeys "%{F4}", True ‘调用ALT+F4关闭计算器窗口
sqrx = temp
End Function

Private Sub Command1_Click()
Dim i As Integer
For i = 17 To 24
Debug.Print "sqrx(" & i & ")=" & sqrx(i)
Next
End Sub

 

返回:
sqrx(17)=4.1231056256176605498214098559741                              
sqrx(18)=4.2426406871192851464050661726291                              
sqrx(19)=4.3588989435406735522369819838596                              
sqrx(20)=4.4721359549995793928183473374626                              
sqrx(21)=4.582575694955840006588047193728                               
sqrx(22)=4.6904157598234295545656301135445                              
sqrx(23)=4.7958315233127195415974380641627                              
sqrx(24)=4.8989794855663561963945681494118                              

 


作者Blog:http://blog.csdn.net/northwolves/
2005年08月14日

VB中,常以Shell指令来执行外部程序,然而它在Create该外部process 后,立刻就会回到vb的下一行程序,无法做到等待该Process结束时,才执行下一行指令,或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完成。

第一个问题是如何等待shell所Create的process结束后才往后执行vb的程序。

首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来区别每个 Process,这个Process ID(PID)主要可用来取得该Process相对应的一些资讯,然而要对该Process的控制,却大多透过 Process Handle(hProcess)。

VB Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来取得 hProcess而OpenProcess()的第一个叁数,指的是所取得的hProcess所具有的能力,像 PROCESS_QUERY_INformATION 便是让GetExitCode()可取得hProcess所指的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..)的指令能够生效,也就是说,不同叁数设定,使hProcess所具有的权限、能力有所不同。取得 hProcess后便可以使用WaitForSingleObject()来等待hProcess状态的改变,也就是说,它会等待 hProcess所指的process执行完,这个指令才结束,它第二个叁数所指的是WaitForSingleObject()所要等待的时间(in milliseconds ),如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它无限的等下去,就设定为INFINITE。

pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)
hProcess = OpenProcess(PROCESS_QUERY_INformATION, 0, pid)
ExitEvent = WaitForSingleObject(hProcess, INFINITE)
Call CloseHandle(hProcess)

上例会无限等待shell指令create之process结束后,才再做后面的vb指令。有时觉得那会等太久,所以有第二个解决方式,等process结束时再通知vb 就好,即设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结束。当Process还在执行时,GetExitCodeProcess会传&H103给其第二个叁数,直到结束时才传另外的数值,如果程序正常结束,那Exitcode = 0,否则就得看它如何结束了。或许有人在其它地方看到 loop的地方是Loop while Exitcode <> 0,那有一点危险,如果以这程子来看,您不是用F4来离开pe2而是用右上方 X 的结束,会因为ExitCode的值永远不会是0,而进入无穷的回圈。

Dim pid As Long
pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)
hProcess = OpenProcess(PROCESS_QUERY_INformATION, 0, pid)
isDone = False
Do
Call GetExitCodeProcess(hProcess, ExitCode)
Debug.Print ExitCode
DoEvents
Loop While ExitCode = STILL_ALIVE
Call CloseHandle(hProcess)
isDone = True

另外,如果您的shell所Create的程序,有视窗且为立刻Focus者,可另外用以下的方式。

Dim pid As Long
Dim hwnd5 As Long
pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)
hwnd5 = GetForegroundWindow()
isDone = False
Do While IsWindow(hwnd5)
DoEvents
Loop
isDone = True

而如何强迫shell所Create的process结束呢,那便是

Dim aa As Long
If hProcess <> 0 Then
aa = TerminateProcess(hProcess, 3838)
End If

hProcess便是先前的例子中所取得的那个Process Handle,3838所指的是传给 GetExitCodeProcess()中的第二叁数,这是我们任意给的,但最好不要是0,因为0一般是代表正常结束,当然这样设也不会有错。

Do
Call GetExitCodeProcess(hProcess, ExitCode)
Debug.Print ExitCode
DoEvents
Loop While ExitCode = STILL_ALIVE
Debug.print ExitCode

而执行了 TerminateProcess(hProcess, 3838)那会看到ExitCode = 3838。然而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个叁数要更改成 PROCESS_QUERY_INformATION Or PROCESS_TERMINATE 这样才能Work。不过良心的建议,非到最后关头,不要使用TerminateProcess(),因不正常的结束,往往许多程序结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再执行某些程序时会有问题,例如:本人常使用MS-dos Shell Link 的方式执行一程序,透过Com port与大电脑的联结,如果Ms-dos Shell Link 不正常结束,下次再想Link时,会发现too Many Opens,这便是一例。

另外,有人使用Shell来执行.bat档,即:

pid = Shell("c:\aa.bat", vbNormalFocus)

可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做:

pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)

那是执行Command.com,而Command.com指定执行c:\aa.bat 而且结束时自动Close。

所有程序如下:

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long

Const PROCESS_QUERY_INformATION = &H400
Const STILL_ALIVE = &H103
Const INFINITE = &HFFFF

Private ExitCode As Long
Private hProcess As Long
Private isDone As Long
Private Sub Command1_Click()
Dim pid As Long
pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)
hProcess = OpenProcess(PROCESS_QUERY_INformATION, 0, pid)
isDone = False
Do
Call GetExitCodeProcess(hProcess, ExitCode)
Debug.Print ExitCode
DoEvents
Loop While ExitCode = STILL_ALIVE
Call CloseHandle(hProcess)
isDone = True
End Sub

Private Sub Command2_Click()
Dim pid As Long
Dim ExitEvent As Long
pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)
hProcess = OpenProcess(PROCESS_QUERY_INformATION, 0, pid)
ExitEvent = WaitForSingleObject(hProcess, INFINITE)
Call CloseHandle(hProcess)
End Sub

Private Sub Command3_Click()
Dim aa As Long
If hProcess <> 0 Then
aa = TerminateProcess(hProcess, 3838)
End If

End Sub

Private Sub Command4_Click()
Dim pid As Long
Dim hwnd5 As Long
pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)
hwnd5 = GetForegroundWindow()
isDone = False
Do While IsWindow(hwnd5)
DoEvents
Loop
isDone = True
End Sub

Private Sub Command5_Click()
Dim pid As Long
‘pid = Shell("c:\windows\command\xcopy c:\aa.bat a:", vbHide)
pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)
End Sub

2005年08月13日

在标准模块中添加以下代码:
Declare Function SHFileOperation Lib "Shell32.dll" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
Type SHFILEOPSTRUCT
hwnd As Long ‘窗口句柄
wFunc As Long ‘执行的操作
pFrom As String ‘原地点
pTo As String ‘目标地点
fFlags As Long ‘操作执行方式
fAnyOperationsAborted As Long ‘错误代码返回
hNameMappings As Long
lpszProgressTitle As String
End Type

Public Const FO_MOVE As Long = &H1
Public Const FO_COPY As Long = &H2
Public Const FO_DELETE As Long = &H3
Public Const FO_RENAME As Long = &H4

Public Const FOF_MULTIDESTFILES As Long = &H1
Public Const FOF_CONFIRMMOUSE As Long = &H2
Public Const FOF_SILENT As Long = &H4
Public Const FOF_RENAMEONCOLLISION As Long = &H8
Public Const FOF_NOCONFIRMATION As Long = &H10
Public Const FOF_WANTMAPPINGHANDLE As Long = &H20
Public Const FOF_CREATEPROGRESSDLG As Long = &H0
Public Const FOF_ALLOWUNDO As Long = &H40
Public Const FOF_FILESONLY As Long = &H80
Public Const FOF_SIMPLEPROGRESS As Long = &H100
Public Const FOF_NOCONFIRMMKDIR As Long = &H200
‘2 。在form1中添加以下代码以及一个commandbox:
Private Sub Command1_Click()
Dim DelFileOp As SHFILEOPSTRUCT
Dim result As Long
With DelFileOp
‘.hwnd = Me.hwnd     好象不是必需的
.wFunc = FO_DELETE ‘(删除)
‘.wfunc=fo_rename(改名) fo_move(移动) fo_copy(拷贝)
‘ Delete the files you just moved to C:\TestFolder.
‘ If you do not have these files, you can alter this
‘ sample to point to existing files.
‘ .pFrom = "C:\testfolder\file1" & vbNullChar & "c:\testfolder\file2" & vbNullChar & vbNullChar
.pFrom = "d:\testfolder\*" & vbNullChar & vbNullChar
‘.pTo = "d:\test" (移动,拷贝时有效)
‘ Allow undo–in other words, place the files into the Recycle Bin
.fFlags = FOF_ALLOWUNDO
End With
result = SHFileOperation(DelFileOp)
If result <> 0 Then ‘ Operation failed
If Err.LastDllError <> 0 Then
MsgBox Err.LastDllError ‘ Msgbox the error that occurred in the API.
End If
Else
If DelFileOp.fAnyOperationsAborted <> 0 Then
MsgBox "Operation Failed"
End If
End If
End Sub

SHFileOperation中使用了一个结构变量TShFileOpStruct。这个结构各成员的含义如下:

  hwnd 显示操作状态信息对话窗的句柄。

  wFunc 文件操作方式:FO—COPY 复制文件;FO—DELETE 删除文件;FO—MOVE 移动文件;FO—RENAME 更名文件。

  pFrom 源文件名缓冲区的指针。

  pTo包含目标文件名和路径的缓冲区指针。

  fFlags 操作选项,可以是下列值的组合:FOF—ALLOWUNDO 如果允许,可以恢复;FOF—CONFIRMMOUSE 不执行操作;FOF—FILESONLY 如果使用通配符(),只对文件操作;FOF—MULTIDESTFILES 指定多个目标文件;FOF—NOCONFIRMATION 响应对话窗的“Yes To All”按钮;FOF—NOCONFIRMMKDIR 建立目录时不提示确认;FOF—RENAMEONCOLLISION 如果目标文件存在,给出一个新文件名;FOF—SILENT不显示进度对话窗;FOF—SIMPLEPROGRESS 显示进度对话窗,但不显示操作的文件名。

  fAnyOperationsAborted 在操作完成前如果用户中止操作其值为ture,否则为false。

  hNameMappings 一个包含SHNAMEMAPPING 结构数组的文件名映射对象句柄。每个结构都包含被复制、移动、更名文件的原来路径和新路径。这个成员仅当fFlags包含 FOF—WANTMAPPINGHANDLE时使用。

  LpszProgressTitle 进度对话窗的标题,仅当 fFlags 包含 FOF—SIMPLEPROGRESS时有效。

  在编程中利用SHFileOperation API进行文件操作,不仅在文件被覆盖时提示,而且这些操作都可以撤消。