⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 013.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:

      cmp   al,CHAR_DELI

      jz    _argv_loop2

      cmp   _dwSize,1 ;如果返回缓存区满则忽略

      jle   @F

      cmp   @dwFlag,TRUE

      jne   @F

      stosb

      dec _ dwSize

      @@:

  jmp _argv_loop1 ;继续处理参数内容

 

_argv_loop2:

      lodsb

      or    al,al

      jz    _argv_end

      cmp   al,CHAR_DELI

      jz    _argv_loop1

      cmp   _dwSize,1 ;如果返回缓存区满则忽略

      jle   @F

      cmp   @dwFlag,TRUE

      jne   @F

      stosb

      dec   _dwSize

      @@:

      jmp   _argv_loop2

_argv_end:

      xor   al,al

      stosb

      popad

      ret

 

_argv     endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

这两个通用子程序被存放在_CmdLine.asm文件中,读者可以在其他的程序中用include语句将它包含使用,其中函数_argc返回命令行参数的个数,当执行文件时没有附带参数的时候,函数的返回值一般是1,这时获取的命令行字符串中仅有一个组成部分——那就是可执行文件名;_argv函数则将指定编号的参数返回到一个缓冲区中,读者可以这样使用:

  invoke  _argv,dwArgv,lpReturn,dwSize

其中dwArgv参数指定要获取的参数编号,0表示获取字符串中的第一个组成部分(一般是文件名),1表示获取第二个组成部分,也就是在文件名后面输入的第1个参数,以此类推,函数对返回的字符串已经做了处理,丢弃了中间或者两端的所有双引号。lpReturn指向用来接收参数字符串的缓冲区,dwSize指定了缓冲区的大小。

这里有一个使用这两个函数的例子,源代码在所附光盘的Chapter13\CmdLine目录中,其中CmdLine.asm的内容如下:

      .386

      .model flat,stdcall

      option casemap:none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 文件定义

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include     windows.inc

include   user32.inc

includelib    user32.lib

include   kernel32.inc

includelib    kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      .data?

szBuffer1   db    4096 dup (?)

szBuffer2   db    4096 dup (?)

szOutput     db    8192 dup (?)

 

      .const

szCaption db   ~命令行参数~,0

szFormat1 db   ~可执行文件名称:~,0dh,0ah,~%s~,0dh,0ah,0ah

  db   ~参数总数:%d~,0dh,0ah,0

szFormat2 db   ~参数[%d]:%s~,0dh,0ah,0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      .code

include   _Cmdline.asm   ;包含公用的命令行参数处理函数

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

      invoke  GetModuleFileName,NULL,\

      offset szBuffer1,sizeof szBuffer1

      invoke  _argc

    mov   ebx,eax

      invoke  wsprintf,addr szOutput,addr szFormat1,\

        addr szBuffer1,eax

 

      xor esi,esi

      .while  esi < ebx

      invoke  _argv,esi,addr szBuffer2,sizeof szBuffer2

      invoke  wsprintf,addr szBuffer1,\

      addr szFormat2,esi,addr szBuffer2

      invoke  lstrcat,addr szOutput,addr szBuffer1

      inc   esi

    .endw

      invoke  MessageBox,NULL,addr szOutput,addr szCaption,MB_OK

      invoke  ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      end   start

 




程序很简单,首先调用GetModuleFileName函数获取可执行文件的文件名,这是为了方便读者和参数中获取的文件名做个对比,然后程序调用_argc函数获得参数数量,并根据这个数量循环获取每个参数。编译链接后输入命令:

  cmdline aaa bbb "ccc ddd" eee

程序会显示出如图13.1所示的消息框。



图13.1  命令行参数例子的运行结果

可见函数正确划分了命令行参数字符串中的各个参数。需要说明的是,为了能够在某个参数中使用空格,函数同样规定可以将参数中的空格用双引号包含,所以参数字符串中的"ccc ddd"被解释为一个参数并丢弃了两端的双引号。

 


13.2 执行可执行文件

13.2.1  方法一:Shell调用 
Win32中可以通过ShellExecute和WinExec函数来执行另一个可执行文件,本节介绍这两个函数的用法。WinExec函数的使用方法是:

  invoke  WinExec,lpCmdLine,dwCmdShow

lpCmdLine参数指向一个以0结尾的字符串,这个字符串中包含可执行文件加上命令行参数,如果被执行的文件会显示一个窗口,那么函数可以在dwCmdShow参数中指定窗口的显示方式,这个参数的定义同ShowWindow函数中的dwCmdShow参数。

如果文件被成功执行,那么函数返回一个大于31的值。使用WinExec函数执行文件和在Windows“开始”菜单的“运行”中键入命令在效果上是一样的。

另一个函数ShellExecute的功能相对比较多一点,函数的语法是:

  invoke  ShellExecute,hWnd,lpOperation,lpFile,lpParam,\

  lpDirectory,dwCmdShow

这个函数既可以用来执行一个可执行文件,也可以指定一个数据文件名让Windows自动查找关联到这个数据文件的可执行文件,并执行这个可执行文件来处理指定的数据文件,数据文件名会以命令行参数的方式传递给可执行文件。函数的参数定义如下。

● hWnd——用来指定被执行文件显示的窗口所属的父窗口。

● lpFile——用来指定文件名,文件名既可以是可执行文件也可以是数据文件。

● lpOperation——指向一个表示执行方式的字符串,字符串可以是以下取值:

■ “open”——文件被打开,这时lpFile指定的文件名可以是可执行文件、目录名或数据文件名。如果lpOperation参数为空,函数默认执行open操作。

■ “print”——文件被打印,这时lpFile指定的文件名必须是数据文件。如果指定的是可执行文件,那么函数当做“open”操作。

■ “explore”——浏览lpFile参数中指定的目录。

● lpParameters——当lpFile参数指定了一个可执行文件,本参数用来指定命令行参数。如果lpFile参数指定的是数据文件,那么本参数必须是NULL。

● lpDirectory——执行或打开文件时使用的默认目录。

● dwCmdShow——如果函数执行了一个可执行文件,这个参数指定窗口的打开方式。

如果文件被成功执行,那么函数返回一个大于31的值。这里是几个使用ShellExecute函数的例子:

  .data

szFileName   db  ~Test.exe~,0

szCmdline db  ~aaa bbb ccc~,0

szEmail db  ~bigluo@telekbird.com.cn~,0

szWebPage db  ~http://asm.yeah.net~,0

szHelp   db  ~Win32asm.chm~,0

  .code

invoke   ShellExecute,0,0,addr szFileName,addr szCmdline,0,SW_SHOWNORMAL  (1)

invoke   ShellExecute,0,0,addr szEmail,0,0,SW_SHOW   (2)

invoke    ShellExecute,0,0,addr szWebPage,0,0,SW_SHOW (3)

invoke    ShellExecute,0,0,addr szHelp,0,0,SW_SHOW   (4)

例子(1)执行Test.exe文件,并将命令行参数“aaa bbb ccc”传递给它。例子(2)打开默认的邮件收发程序并显示一个“新建邮件”窗口,指定的邮件地址会被自动地填入到收件人一栏中。例子(3)打开浏览器并自动打开网站http://asm.yeah.net。例子(4)会运行chm帮助文件阅读器hh.exe,并自动打开Win32asm.chm帮助文件。

13.2.2  方法二:创建进程

用ShellExecute和WinExec函数来执行文件是很方便的,调用这两个函数从某种意义上讲相当于创建了新的进程,但是函数返回以后,这些新建的进程却脱离了我们的控制,我们无法知道它们在什么时候结束,也无法去强制结束它们。要对进程进行后续的控制,必须使用函数CreateProcess来创建进程。

当一个进程被创建的时候,系统进行以下的操作:

● 系统为进程创建一个内核对象,并将它的初始计数设置为1,与线程对象类似,进程对象只是一个比较小的数据结构,它包含进程的一些统计信息。进程对象可以通过进程句柄来引用。

● 系统为进程创建一个虚拟地址空间,并将可执行文件装载到这个地址空间中。系统同时处理可执行文件的导入表,将导入表中登记的所有dll文件装入。每个dll文件被装入的时候,DLL的入口函数被执行,如果入口函数返回初始化失败信息的话,进程的初始化失败。可执行文件本身和所有的dll文件都被看做是单独的模块,都被分配了一个实例句柄(实例句柄在数值上等于模块装入到地址空间中的线性地址)。

● 系统为进程建立一个主线程,主线程将从可执行文件的入口地址开始执行。

对于线程来说,Windows为系统中的每个线程分配一个线程句柄和线程ID以便区分它们,同样,对于进程来说,每个进程也对应一个进程句柄和一个进程ID。

当某个进程创建了一个新的进程的时候,被创建的进程称为“子进程”,创建它的进程称为“父进程”,子进程可以从父进程那里继承环境变量以及其他一些对象,在子进程中可以继续创建“孙”进程。

创建进程使用CreateProcess函数。下面是一个使用这个函数的例子程序,程序显示如图13.2所示的对话框,允许用户输入需要执行的文件名(或者通过“浏览”按钮选择文件名)和传递给文件的命令行参数,当文件开始执行时,程序将“浏览”按钮与文件名输入框等子窗口灰化,在子进程结束以后再恢复它们。程序也可以通过“终止”按钮强制结束子进程的运行(“执行”按钮在子进程开始执行后被改为“终止”按钮)。



图13.2  建立进程的例子程序

程序的源代码在所附光盘的Chapter13\Process目录中,其中的Process.rc文件定义了上面所示的对话框:

 




//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#include       

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#define ICO_MAIN       1000

#define DLG_MAIN     1000

#define IDC_FILE     1001

#define IDC_CMDLINE   1002

#define IDC_BROWSE     1003

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN     ICON         "Main.ico"

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

DLG_MAIN DIALOG 111, 104, 201, 57

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "执行文件"

FONT 9, "宋体"

{

 LTEXT "文件名", -1, 7, 8, 25, 8

 EDITTEXT IDC_FILE, 35, 5, 160, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 LTEXT "命令行", -1, 7, 25, 25, 8

 EDITTEXT IDC_CMDLINE, 35, 22, 160, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 PUSHBUTTON "浏览(&B)", IDC_BROWSE, 115, 38, 40, 14

 PUSHBUTTON "执行(&E)", IDOK, 155, 38, 40, 14, WS_DISABLED | WS_TABSTOP

}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

汇编源文件Process.asm的内容如下:

      .386

      .model flat, stdcall

      option casemap :none

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -