WIN32汇编语言教程:第13章 进程控制 · 13.1 环境变量和命令行参数(2)

13.1.2 命令行参数

1. 什么是命令行参数

在命令行中通过输入文件名来执行文件,在文件名后面跟的参数就是命令行参数,比如通过Telnet连接到某个远程计算机的1234号端口,可以输入:

Telnet 192.168.0.1 1234

“Telnet”后面跟的“192.168.0.1 1234”就是命令行参数,它可以被程序获取,命令行参数是当做一个以0结尾的字符串被程序获取的。

对于窗口程序来说,命令行参数并不是必需的,因为大部分的窗口程序都在菜单中提供了“打开文件”、“选项”等功能,并不需要用户在命令行参数中指定,如果窗口程序必须依靠命令行参数,那么用户就不能通过在任务管理器中双击图标来执行程序了,因为这样无法输入命令行参数。

但是某些情况下,命令行参数又是窗口程序的必然补充,比如Windows中的文本文件往往被关联到记事本程序Notepad.exe上,直接双击文本文件,Windows就会自动执行Notepad.exe,并把文本文件名通过命令行参数传递给它,所以对于Notepad.exe来说,虽然已经在菜单中提供了“打开文件”功能,但也必须处理命令行参数,否则对关联文件就无法处理。

而对于控制台程序(如系统中的Ping.exe,Format.exe和Xcopy.exe等在命令行下运行的程序)来说,它们没有自己的窗口,也就无法通过菜单来选择某些功能,这时通过命令行传递各种参数就是必然的选择。

2. 使用命令行参数

要获取命令行参数,可以使用GetCommandLine函数,这个函数没有输入参数,返回值是一个指向命令行参数字符串的指针:

   invoke GetCommandLine

   mov    lpCmdline,eax

获取命令行参数字符串以后,首先必须对它进行处理,比如对于上面的Telnet程序来说,第一个参数“192.168.0.1”指定主机名,第二个参数“1234”指定端口号,但是我们得到的却是一个连在一起的字符串,所以必须扫描字符串将两个参数分开后才能使用,而且,必须通过检查参数字符串防止用户输入了错误的参数。

Win32中并没有通用的用来扫描参数字符串的函数,有一个函数CommandLineToArgvW虽然可以用来对字符串进行扫描,但这个函数仅适用于Unicode字符串,而且仅在NT系列中得到支持,在Windows 9x系列中无法使用,为了使用这个函数而将程序限制在Windows NT下运行显然是得不偿失的。

C语言为用户考虑到了这一点,在C的初始化程序将控制权交到WinMain函数之前就已经对命令行参数进行了处理,并将参数按照空格划分成不同的部分放到argv数组中,参数数量则存放在argc变量中,在程序的任何地方都可以存取这些变量;但在Win32汇编中,这些工作就需要自己来做了,笔者在本节的例子程序中提供了两个通用函数,读者可以把它们用在其他程序中。在分析这个例子之前,先来看看在命令行参数字符串中究竟可以收到哪些内容,这些内容将决定分析字符串的算法。

读者可以编写一个很简单的测试程序Test.exe,在程序中调用GetCommandLine函数并将得到的命令行参数显示出来,假如把这个Test.exe放在“C:\Program files”目录下并使用不同的方法去执行它,执行的时候带3个参数“aaa bbb ccc”,就可以发现得到的命令行参数可能是下面的样子:

(1)test aaa bbb ccc

(2)test.exe aaa bbb ccc

(3)te″st″.exe aaa bbb ccc

(4)c:\program″″files\test aaa bbb ccc

(5)″C:\Program files\Test.exe″

(6)″C:\Program files\Test.exe″″C:\aaa bbb ccc″

结果(1)到(4)显示的命令行参数字符串是在命令提示符下输入同样的执行命令得到的。需要注意的有两点:

首先是可执行文件名被当做命令行参数的第一个组成部分被传递过来了,所以要使用真正由用户输入的命令行参数,必须首先将这部分过滤掉。

其次是对可执行文件名的处理,输入test或test.exe可以正常执行文件并不奇怪,奇怪的是输入te"st".exe或者c:\program""files\test这样的文件名也能执行,难道这也是合法的文件名吗?

答案是肯定的,这是因为Windows将空格当做参数的分隔符,但是长文件名中同样可以使用空格,这就产生了冲突,为了解决这个问题,Windows使用双引号来定界,假如文件名中存在空格的话,必须将空格包含在两个双引号中,但双引号并不是只能用一对,也并不一定要用在文件名的头尾,实际上它们可以在文件名的任何地方出现,只要是成对的并且所有空格都被包含在某一对双引号中就可以了,双引号本身不是文件名的组成部分,Windows在最后会自动将它们剔除,但是传递到命令行参数中的时候还是保留了输入时的样子。

结果(5)是在文件管理器中通过双击Test.exe执行时得到的命令行字符串,结果(6)是在C盘的根目录下建立了一个名为“aaa bbb ccc”的文件,并在“打开方式”中选择Test.exe后得到的命令行字符串。从这些结果中可以发现:只要由Windows来打开文件,那么Windows就会用很规范的方式传递文件名,具体就表现在文件名肯定是带全路径的,并且不管文件名中是否包含空格,头尾都会被加上一个双引号。

根据这些特征,就不难写出一个通用的分析命令行参数的子程序来:

CHAR_BLANK     equ    20h    ;定义空格分隔符

CHAR_DELI      equ    '"'    ;定义双引号分隔符

;####################################################################

; 取命令行参数个数 (arg count)

; 参数个数必定大于等于 1, 第1个参数为当前执行文件名

;####################################################################

_argc        proc

                 local  @dwArgc        ;需要返回的结果

 

                pushad

                 mov    @dwArgc,0

                 invoke GetCommandLine

                 mov    esi,eax

                 cld

_argc_loop:

                 lodsb

                 or    al,al

                 jz    _argc_end      ;如果到字符串尾则结束

                 cmp    al,CHAR_BLANK

                 jz    _argc_loop    ;如果是空格则忽略

;********************************************************************

; 遇到一个非空格字符表示一个参数开始

;********************************************************************

                 dec esi

                 inc    @dwArgc        ;增加参数个数的计数

_argc_loop1:

                 lodsb

                 or    al,al

                jz    _argc_end      ;如果到字符串尾则结束

                 cmp    al,CHAR_BLANK

                   jz     _argc_loop     ;再遇到一个空格表示参数结束

                 cmp    al,CHAR_DELI

                   jnz    _argc_loop1    ;如果遇到双引号则忽略空格

                 @@:

                 lodsb

                 or    al,al

                 jz    _argc_end

                 cmp    al,CHAR_DELI       ;直到遇到另一个双引号为止

                 jnz    @B

                 jmp    _argc_loop1

_argc_end:

                 popad

                 mov    eax,@dwArgc

                 ret

   

_argc        endp

;####################################################################

; 取指定位置的命令行参数

; argv 0 = 执行文件名

; argv 1 = 参数1 ...

;####################################################################

_argv        proc      _dwArgv,_lpReturn,_dwSize

                 local  @dwArgv,@dwFlag

上页:第13章 进程控制 · 13.1 环境变量和命令行参数(1) 下页:第13章 进程控制 · 13.1 环境变量和命令行参数(3)

第13章 进程控制

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号