精华内容
下载资源
问答
  • win32汇编下软件皮肤的使用,使用的是 skin++皮肤
  • 打开D:\masm32\qeditor.exe再集成环境下汇编, 或运行var.bat设置环境变量后再命令行下汇编 @echo off set include=D:\masm32\include set lib=D:\masm32\lib set path=D:\masm32\bin;%path% echo on
  • Win10下汇编语言Debug安装配置-附件资源
  • 8086汇编Win32汇编

    2017-04-21 13:30:00
    8086汇编是指在某环境下汇编编译产生的程序,用机器去执行每条指令的长度为16位(可小于16),如DOS操作系统;WIN32汇编是32位环境下的汇编,如Windows(Windows也有64位的,XP和VISTA都有相应的版本)。大体是...
    8086汇编是指在某环境下汇编编译产生的程序,用机器去执行每条指令的长度为16位(可小于16),如DOS操作系统;WIN32汇编是32位环境下的汇编,如Windows(Windows也有64位的,XP和VISTA都有相应的版本)。
    大体是差不多,当然,各自也有些细微的差别,WIN32下多了一些寄存器的操作,简化了一些运算,还有就是Windows把一些关键的东东都封装起来了,所以在Windows下WIN32汇编的程序员一般都感到不能像在DOS下那样欢快的游弋了,因为WIN32汇编用户不可能像在以前对硬件直来直去的操作了。

    转载于:https://www.cnblogs.com/lvdongjie/p/6743146.html

    展开全文
  • win32 汇编教程

    2009-03-30 11:33:49
    汇编教程 win32汇编教程 windows 条件汇编编程
  • win32汇编教程

    2013-02-13 21:50:24
    非常详细的WIN32汇编教程,实现WINDOWS的编程,需要16位汇编基础,很详细的教程。
  • win32汇编程序

    2011-11-04 22:22:46
    罗云彬的windows32位程序设计,win32汇编程序
  • WIN10学习汇编语言的环境所用到的程序,亲测OK,里面还有个demo程序。 这里面包括了dosbox0.74,debug.exe, masm.exe, link.exe 对应教程:https://blog.csdn.net/qq_22655017/article/details/106820240
  • Win32汇编教程

    千次阅读 2004-12-19 03:06:00
    Win32汇编教程 8. 图形界面的操作有关GDI和位图 GDI 即图形设备界面,是 Windows 最重要的部分之一,它大部分由 GDI32.DLL 库中的 API 来处理,GDI 的主要目的之一是支持与设备无关的图形编程,对于 Dos 的...
    
    
    8.         图形界面的操作

    有关GDI和位图

        GDI 即图形设备界面,是 Windows 最重要的部分之一,它大部分由 GDI32.DLL 库中的 API 来处理,GDI 的主要目的之一是支持与设备无关的图形编程,对于 Dos 下的图形编程,很多人可能“心有余悸”,因为PC 中有太多种类的显示卡,而几乎每个显示卡的处理都是不同的,即使后来有了 Vesa 编程,我们还是不能全部撇开具体的硬件,Windows GDI 使我们对图形的编程变得相对简单了很多,由于GDI 是 Windows 最庞大的部分,并不是几句话能讲清楚的,本节要讲的是 Windows 下GDI 的基本处理步骤和简单的位图处理,并没有涉及到 Directx 一类的编程。只希望能对朋友们有所启发。
        Windows 并不允许程序员访问显示硬件,它的所有对屏幕的操作是通过环境设备(DC)来处理的,屏幕上的每一个窗口对应一个DC,你可以把一个DC 想象成这个窗口的视频缓冲区,你对DC的操作结果会反映到屏幕上,在窗口的DC之外,你也可以自己建立DC,这相当于建立一个内存中的缓冲区,你对这个DC的操作结果保存在内存中。你也可以用 API 在不同的DC之间拷贝数据,比如说你可以在内存DC 中先建立好数据,然后拷贝到窗口的DC中,就相当于完成了屏幕的刷新。
        与DC的取得、建立取消有关的API有以下几种:

    1. GetDC(hWnd) - 取得某个窗口的DC,API 返回对应的 DC 句柄
    2. ReleaseDC(hWnd,hDC) - 释放用 GetDC 取得的 DC 句柄
    3. CreateCompatibleDC(hDC) - 从一个已知的 DC 句柄中建立一个内存 DC,各种参数、属性参考已知的 DC
    4. DeleteDC(hDC) - 删除用CreateCompatibleDC 建立的 DC

    上面的4个API,必须成对出现,用 GetDC 取得的DC 必须用 ReleaseDC 释放,而用 CreateCompatibleDC 建立的 DC 必须用 DeleteDC 删除,不能混淆。DC 的作用范围:用 GetDC 取得的窗口 DC 必须尽快释放,你不应该在 Windows 的不同消息之间保存 DC 句柄,而用 CreateCompatibleDC 建立的 DC 可以长期保存,举例说明,如果你在 WM_PAINT 和 WM_SIZE 消息中都要对窗口的 DC 进行操作,你不能在 WM_INIT 时先 GetDC,然后保存句柄,最后在 WM_CLOSE 消息时 ReleaseDC,而是必须在 WM_PAINT 和 WM_SIZE 开始的地方 GetDC,在消息结束的地方就 ReleaseDC,而用 CreateCompatibleDC 建立的则相反,你可以在 WM_INIT 时建立,在 WM_CLOSE 时删除。
        如果想把一个位图画到 DC 中,你只需简单的用 invoke SelectObject,hDc,hBitmap 就行了,是不是很简单?但图形操作并不是单单把位图放入屏幕就行了,还要涉及到位的操作,如把前景位图的边缘去掉贴入背景位图等。 Windows 的 GDI 提供了下面一些 DC 间的拷贝 API,中间就包括了拷贝的模式:

    1. BitBlt hDcDest,XDest,YDest,Width,Height,hDcSource,XSrc,YSrc,dwRop
      这个 API 把 hDcSource 的 XSrc,YSrc 坐标处的内容拷贝到 hDcDest 的 XDest,YDest 处,拷贝大小为 Width,Height。
    2. PatBlt hDc,X,Y,Width,Height,dwRop 是用预定义的刷子等 Object 填充 DC
    3. StretchBlt,hDcDest,XDest,YDest,Width,Height,hDcSource,XSrc,YSrc,WidthSrc,HeightSrc,dwRop 是拷贝并自动缩放大小,你可以注意到它和 BitBlt 相比多了两个参数 WidthSrc 和 HeightSrc,别的都是一样的。

    以上API 中的 dwRop 参数是最关键的,它的值有 SRCCOPY,SRCPAINT,SRCAND,DSTINVERT 等,表示源DC 拷贝到目标DC后象素的计算方法,SRCCOPY 表示用源DC覆盖目标DC,SRCPAINT是执行 OR 操作,SRCAND 是执行 AND 操作,DSTINVERT 是取反,举例说明,如果源DC中的某一点是黑色,目标DC对应的点是红色,那么用 SRCCOPY后,目标DC的点变成黑色,用SRCPAINT 后还是红色,因为黑 (000000) or 红(0000ff) =红(0000ff)。
         对应一般对屏幕或窗口进行图形操作的步骤如下。

    1. 用GetDC 取得目标窗口的 DC
    2. 用 CreateCompatibleDC 建立一个内存中的 DC用作缓冲区
    3. 用 SelectObject 填充内存DC 或别的办法对内存DC进行操作,一句话,先把要显示的东西处理好
    4. 用 BitBlt 把内存DC 拷贝到窗口 DC中,完成屏幕刷新。

    本节的例子程序是一个屏幕放大镜,它把鼠标移动到的地方的屏幕内容放大一倍显示到自己的窗口中。

    源程序 - 汇编源文件

    
    

    程序的分析和要点

        在程序的初始化中,我们用GetDc 取的桌面的屏幕的 DC,再用 CreateCompatibleDC 建立一个内存DC做缓冲区,建立一个位图再用 SelectObject 把 hDcMem 设置为这个位图是为了是 hDcMem 的大小变为 80x80。

    
    

    然后在程序的每 0.1 秒一次的 WM_TIMER 定时器消息中,我们先用 GetDC 取得桌面和对话框中文本框的句柄,然后用 PatBlt 把内存DC清除为黑色,再用 StretchBlt 从桌面DC中拷贝 40x40的区域到内存 DC 中,新的大小是 80x80(放大功能就是这样实现的),拷贝的位置是用 GetCursorPos 取得的,也就是鼠标的当前位置,最后用 BitBlt 把内存DC 拷贝到对话框中。如果直接把桌面DC 拷贝到对话框中也可以,但是当鼠标移动到屏幕边缘上时,由于屏幕外的点是无效的,所以对话框中的一部分会花屏,大家可以改动程序试试。








    概述

        在前面八篇的 Win32asm 教程中,已经初步讲述了消息框、对话框、菜单、资源、GDI 等内容,基本上已经设计到了 Windows 界面的大部分内容,
    在继续新的 Windows 其他部分的内容如多线程、文件操作、内存操作之前,我先综合前面的内容并加上一些新内容,写上一篇综合篇。
    本篇的例子程序是一个复杂形状的窗口,窗口的形状是根据位图自动计算得到的,这也就是在我编写的小闹钟中使用的技术(大家可以到我的软件发布中下载一个看看),
    由于以前在网上看到的有关特殊形状窗口的例子最多就是画一个圆形,或者几个方块和椭圆结合的形状,
    没有一篇文章指出如何画出如“唐老鸭”这样一个造型的窗口。本文使用的算法可以自动根据位图的形状计算窗口形状。
    在源程序中,很多代码都是前面教程提到的,主要有以下部分:

    • 首先建立一个标准的窗口。(参考窗口一节)
    • 设置窗口为特殊形状。(见下面的程序分析)
    • 在窗口的 WM_PAINT 消息中更新窗口的图片。(参考图形界面一节)
    • 由于窗口没有标题栏,所以在右击窗口时弹出一个菜单。(参考菜单一节)
    • 菜单中有个“关于本程序”项,里面有超联结文本。(参考窗口子类化一节)

    Windows 里有专门的 API 来实现特殊形状的窗口,步骤是首先建立区域(Region),Region 可以合并,
    这样一来就可以用几个简单的区域合并出一个复杂的区域,建立、合并区域和设置窗口的 API 主要有以下几条:

    • CreateRectRgn(Left,Top,Right,Bottom) - 建立矩型区域
    • CreateEllipticRgn(Left,Top,Right,Bottom) - 建立椭圆区域
    • CreatePolygonRgn(lpPoints,NumberOfPoints,Mode) - 建立多边形区域,这些API返回区域句柄
    • CombineRgn(hDest,hSource1,hSource2,CombineMode) - 合并区域
    • SetWindowRgn(hWnd,hRgn,bRedraw) - 根据区域设置窗口形状

    本程序的方法是扫描位图的点,按行设置区域,然后合并到总的区域中。

    源程序 - 汇编源文件

    程序的分析和要点

        创建窗口的时候,窗口风格为 WS_POPUP,所以创建的窗口没有标题栏,这样的窗口适合于设置成特殊形状的窗口

    但是当窗口没有标题栏后,我们就无法用拖动标题栏的办法来移动窗口,如果让窗口一动不动呆在屏幕中间显然是不行的,这里有一个替代办法,
    我们可以响应按下鼠标左键的消息,在 WM_LBUTTONDOWN 消息中想窗口发送 WM_NCLBUTTONDOWN (非客户区鼠标按下消息) 位置在 HTCAPTION 来模拟鼠标按在标题栏中来实现移动的功能。









    10. 定时器的应用

    概述

        Windows 的定时器是一种输入设备,它周期性地在指定的间隔时间通知应用程序。它可以用向指定窗口发送 WM_TIMER 消息或者调用指定的过程来执行用户的程序。定时器的应用主要包括下面一些地方:

    1. 时钟程序 - 显然,这是定时器最直接的应用。
    2. 多任务 - 如果程序有大量的数据处理,除了用多线程的办法,还可以用定时器,在每一个定时器消息中处理一小块内容。
    3. 定时显示程序的状况 - 定时器就相当于 Dos 编程中的自己挂接在 int 1ch 上面的要定时处理的程序,它可以定时显示程序运行的情况,如发送了多少内容,接收了多到内容等等。
    4. 在游戏程序中使用定时器可以消除在不同处理器下用延时来保持速度一致所造成的误差。
    5. 用于数据流处理 - 在音频、视频的播放中,需要隔一段时间处理一段数据。

    总的来说,在 Dos 下实现精确定时的唯一方法是在 int 1ch 时钟中断中处理程序,但你使用起来必须遵守很多的规范,而在 Windows 的定时器中,你可以用 SetTimer 函数分配不止一个的定时器,比如说,在你的文本编辑程序中,你可以使用一个间隔1秒的定时器来在状态栏中显示时钟,
    同时分配一个10分钟的定时器来实现定时存盘的功能。定时器实际上是 Windows 对时钟中断的一种扩展,
    它的本质还是基于时钟中断的,所以你实际上无法把定时器的间隔设置到55毫秒以下,另外,定时器的精度也是以55毫秒为倍数的,比如说,你设置了一个1秒的定时器,它实际上是在每989毫秒的时候发生的。和在 Dos 下使用时钟中断,windows 的定时器还有下面一些要点:

    1. 在 Dos 中,你的程序随时可能被 int 1ch 打断,而在Windows 中,Windows 通过 WM_TIMER 消息把定时器消息放入正常的消息队列中,所以你不必担心你的程序在别的处理中被定时器打断。
    2. 不可能有同时两条以上的 WM_TIMER 消息,如果在一个还在消息队列中,窗口再得到一条 WM_TIMER 消息,两条消息会被合并为一条,所以在程序比较忙的时候可能会丢失 WM_TIMER 消息。
    3. WM_TIMER 消息的级别是很低的,程序只有在消息队列中没有其他消息的情况下,才会接收 WM_TIMER 消息,你可以通过下马方法验证:在一个设置了定时器的窗口上按住标题栏移动窗口,你会发现定时器停止了工作,当你松开鼠标后,在这个过程中丢失的 WM_TIMER 消息并没有被补上,
    4. 所以如果你设计一个时钟程序,你不能使用定时器消息来计数,而必须在消息中每次获取正确的系统时间。

    讲了这么多定时器的特点,下面是定时器相关的API,你会发现除了在使用中要注意的这些特性,定时器的API真是又少又简单:

    1. 建立定时器
      SetTimer(
      HWND hWnd, // handle of window for timer messages
      UINT nIDEvent, // timer identifier
      UINT uElapse, // time-out value
      TIMERPROC lpTimerFunc // address of timer procedure
      );
      hWnd 是 windows 发送 WM_TIMER 的窗口,nIDEvent 是定时器的编号,在 WM_TIMER 中出现在 wParam 参数中,
    2. 用来区分在多个定时器的情况下,这条消息是由哪个定时器产生的。uElapse 是定时器间隔的毫秒数,
    3. 如果你要设置一个1秒的定时器,这个值就是1000,lpTimerFunc 是处理定时器消息的过程,
    4. 如果这个参数不是 NULL,windows 在到时间后会调用lpTimerFunc 指定的过程,
    5. 调用的参数是 CALLBACK TimerProc(hwnd,WM_TIMER,iTimerID,dwTime),iTimerID 是定时器 ID,dwTime 是系统时间;
    6. 如果 lpTimerFunc 参数是 NULL,Windows 会把 WM_TIMER 消息放入消息循环中,消息的 hWnd 是第一个参数中指定的 hWnd,也就是说向这个窗口发送了 WM_TIMER 消息。
      另外,如果你的程序没有窗口,你也可以用这种办法建立定时器:invoke SetTimer,NULL,NULL,uElapse,TimerProc,函数会返回一个系统定义的 TimerID供你在 KillTimer 中使用。
    7. 取消定时器
      KillTimer(
      HWND hWnd, // handle of window that installed timer
      UINT uIDEvent // timer identifier
      );
      取消定时器只需对应 SetTimer 时的 hWnd 和 uIDEvent 调用 KillTimer 函数就行了。

    在本节的例子程序中,我在对话框中的 WM_INIT 消息中用 SetTimer 建立两个定时器,时间分别是500ms 和 200ms,
    然后在间隔0.5秒的定时器消息中更换按钮上的图片,在间隔 0.2 秒的定时器消息中更换标题栏上的小图标,你就可以看到动画的效果了。

    源程序 - 汇编源文件

    程序的分析和要点

        有了上面的介绍,这个程序是很容易看懂的,在 WM_TIMER 消息中,通过 wParam 中的 TimerID 可以区分是哪个定时器产生的消息。在 WM_CLOSE 消息中,通过 KillTimer 来取消定时器。本程序中的的图标定义在资源文件中,
    在对话框建立的时候,先用 LoadIcon 装入,然后为两个定时器分别保存一个图片编号 dwCounter1 和 dwCounter2,在定时器消息中分别用 WM_SETICON 和 BM_SETIMAGE 消息来对窗口标题的图标和按钮的图标进行设置。





    11. 进程控制

    概述

    进程控制简单的说相当于在一个程序中执行另一个程序,你可以把它想象成在 Dos 下用 int 21h/4bh 功能来执行另外一个程序,如果单从执行另一个程序的目的来讲,在 Windows 中有不少方法,如使用 ShellExecute 等,
    但这些 Api 仅仅是“执行”而已,进程控制的意义在于可以创建一个进程,并可以通过进程句柄结束进程,同样你也可以通过进程句柄来跟踪程序,还可以用 ReadProcessMemory 和 WriteProcessMemory 来读写子进程的内存空间。

    进程控制要使用的相关 API 有下面这些:

    创建进程的函数为CreateProcess,该函数比较复杂,共有十个参数,但有个好消息是使用时大部分可以用 NULL。

    BOOL CreateProcess(
    LPCTSTR lpApplicationName, // 执行程序文件名
    LPTSTR lpCommandLine, // 参数行
    LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全参数
    LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全参数
    BOOL bInheritHandles, // 继承标记
    DWORD dwCreationFlags, // 创建标记
    LPVOID lpEnvironment, // 环境变量
    LPCTSTR lpCurrentDirectory, // 运行该子进程的初始目录
    LPSTARTUPINFO lpStartupInfo, // 创建该子进程的相关参数
    LPPROCESS_INFORMATION lpProcessInformation // 创建后用于被创建子进程的信息
    );


    各个参数的说明如下:

    • lpApplicationName:为执行程序的文件名,你也可以把执行文件名包括在下一个参数 lpCommandLine 中,然后把该参数置为NULL。
    • lpCommandLine:为参数行,如果无参数可以为NULL,在有参数传递给进程时可以如下设置:lpApplicationName=文件名;lpCommandLine=参数,或者 lpApplicationName=NULL;lpCommandLine=文件名 + 参数。
    • lpProcessAttributes,lpThreadAttributes:分别描述了创建的进程和线程安全属性,如果使用NULL表示使用默认的安全描述。
    • bInheritHandles:表示当前进程中的打开的句柄是否能够被创建的子进程所继承。
    • dwCreationFlags:表示创建标记,通过该标记可以设置进程的创建状态和优先级别。常用的有下面的标记:
      CREATE_NEW_CONSOLE:为子进程创建一个新的控制台。
      CREATE_SUSPENDED:子进程在创建时为挂起状态。如果指定了这个参数,那么执行 CreateProcess 后进程只是被装入内存,但不是马上开始执行,而是必须等主程序调用 ResumeThread 后才继续执行。
      HIGH_PRIORITY_CLASS/NORMAL_PRIORITY_CLASS:高/普通优先级别。
    • lpEnvironment:表示子进程所使用的环境变量,如果为NULL,则表示与当前进程使用相同的环境变量。
    • lpCurrentDirectory:表示子进程运行的初始目录。
    • lpStartupInfo:STARTUPINFO 结构,用于在创建子进程时设置各种属性。
    • lpProcessInformation:PROCESS_INFORMATION 结构,用来在进程创建后接收相关信息,该结构由系统填写。

    调用 CreateProcess 函数有三个参数是必需的,一在 lpApplicationName 或 lpCommandLine 指定文件名,二是 lpStartupInfo 结构,三是 PROCESS_INFORMATION 结构,
    因为 PROCESS_INFORMATION 结构返回了进程建立后的句柄,以后的一切操作将要用到这些返回的句柄,它是由系统填写的,结构说明如下:

    typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess; //进程句柄
    HANDLE hThread; //进程的主线程句柄
    DWORD dwProcessId; //进程ID
    DWORD dwThreadId; //进程的主线程ID
    } PROCESS_INFORMATION;

    另外还有一个关键的结构 STARTUPINFO,该结构定义如下:

    typedef struct STARTUPINFO {
    DWORD cb; //结构长度
    LPTSTR lpReserved; //保留
    LPTSTR lpDesktop; //保留
    LPTSTR lpTitle; //如果为控制台进程则为显示的标题
    DWORD dwX; //窗口位置
    DWORD dwY; //窗口位置
    DWORD dwXSize; //窗口大小
    DWORD dwYSize; //窗口大小
    DWORD dwXCountChars; //控制台窗口字符号宽度
    DWORD dwYCountChars; //控制台窗口字符号高度
    DWORD dwFillAttribute; //控制台窗口填充模式
    DWORD dwFlags; //创建标记
    WORD wShowWindow; //窗口显示标记,如同ShowWindow中的标记
    WORD cbReserved2; //
    LPBYTE lpReserved2; //
    HANDLE hStdInput; //标准输入句柄
    HANDLE hStdOutput; //标准输出句柄
    HANDLE hStdError; //标准错误句柄
    } STARTUPINFO, *LPSTARTUPINFO;

    结构中 dwFlags 指定了其它的一些字段是否有效,如:dwFlags包含 STARTF_USESIZE 表示dwXSize和dwYSize有效,
    包含STARTF_USEPOSITION表示dwX和dwY有效,等等。如果不是有特殊的要求,我们不用自己去填写这个结构,
    只需用 GetStartupInfo 让 Windows 为你填写好了,这样,建立一个进程的语句就是:

    ...
    stStartUp STARTUPINFO <?>stProcInfo PROCESS_INFORMATION <?><?>
    stProcInfo PROCESS_INFORMATION <?>
    ...

    invoke GetStartupInfo,addr stStartUp
    invoke CreateProcess,NULL,addr szFileName,NULL,NULL,NULL,NORMAL_PRIORITY_CLASS,NULL,NULL,offset stStartUp,offset stProcInfo

    ...

    如果成功的话,eax 将返回非零值,注意返回在 PROCESS_INFORMATION 结构中的 hProcess,以后很多的操作都要用到它。

    强制结束一个进程的 API 为 TerminateProcess

    BOOL TerminateProcess(
    HANDLE hProcess, // 进程句柄
    UINT uExitCode // 退出代码
    );

    你可以使用语句 invoke TerminateProcess,structProcInfo.hProcess,0 来结束进程,要注意的是如果可能的话,尽量不要在程序中强制结束别的进程,因为使用 TerminateProcess 结束的进程,它装载的 dll 不能被正确卸载。
    这样可能会引起系统资源的无效占用。最好的办法在进程中自己使用 ExitProcess 退出。

    查询一个进程状态的 API 为 GetExitCodeProcess。

    BOOL GetExitCodeProcess(
    HANDLE hProcess, // handle to the process
    LPDWORD lpExitCode // address to receive termination status
    );

    如果进程尚未退出,函数将会返回STILL_ACTIVE。这个 API 是马上返回的。

    等待进程执行可以用 WaitForSingleObject

    这个 API 并不是单用于进程的等待,其它还可以用在线程等操作,但我们一般用它来等待进程的执行,它的申明是:

    DWORD WaitForSingleObject(
    HANDLE hHandle, // handle of object to wait for
    DWORD dwMilliseconds // time-out interval in milliseconds
    );

    如果我们要等待进程执行 1 秒钟,可以 invoke WaitForSingleObject,stProcInfo.hProcess,1000 如果要等到进程结束,
    可以用 WaitForSingleObject,stProcInfo.hProcess,INFINITE ,参数 2 中的 INFINITE 在 Windows.inc 中有定义,意思是无穷等待。

    最后,当不再使用进程句柄的时候,不要忘了使用 CloseHandle 关闭 hProcess 和 hThread,否则会浪费系统句柄的资源。

    源程序 - 汇编源文件

    程序的分析和要点

        本程序在使用调用 GetOpenFileName 或者自己在文本框中输入执行文件名,然后通过 CreateProcess 建立进程,
    最后用 WaitForSingleObject 等待进程结束,如果在对话框的处理过程中等待会导致程序在进程返回前无法响应,
    所以程序中用 CreateThread 建立一个线程来实现这个过程,当子过程返回的时候,线程结束。dwFlag 中的 0 位作为标志位,
    表示是否子过程在运行中,如果这一位置 1 的话,按下“终止”按钮会用 TerminateProcess 来强制终止子进程。



    12. 管道操作

    概述

    Windows 引入了多进程和多线程机制。同时也提供了多个进程之间的通信手段,包括剪贴板、DDE、OLE、管道等,
    和其他通信手段相比,管道有它自己的限制和特点,管道实际上是一段共享内存区,进程把共享消息放在那里。
    并通过一些 API 提供信息交换。管道是两个头的东西,每个头各连接一个进程或者同一个进程的不同代码,
    按照管道的类别分有两种管道,匿名的和命名的;按照管道的传输方向分也可以分成两种,单向的双向的。
    根据管道的特点,命名管道通常用在网络环境下不同计算机上运行的进程之间的通信(当然也可以用在同一台机的不同进程中)
    它可以是单向或双向的;而匿名管道只能用在同一台计算机中,它只能是单向的。匿名管道其实是通过用给了一个指定名字的有名管道来实现的。
    使用管道的好处在于:读写它使用的是对文件操作的 api,结果操作管道就和操作文件一样。即使你在不同的计算机之间用命名管道来通信,
    你也不必了解和自己去实现网络间通信的具体细节。

    我们简单的介绍一下命名管道的使用。

    命名管道是由服务器端的进程建立的,管道的命名必须遵循特定的命名方法,就是 "//./pipe/管道名",当作为客户端的进程要使用时,使用"//计算机名//pipe/管道名" 来打开使用,具体步骤如下:

    1. 服务端通过函数 CreateNamedPipe 创建一个命名管道的实例并返回用于今后操作的句柄,或为已存在的管道创建新的实例。
    2. 服务端侦听来自客户端的连接请求,该功能通过 ConnectNamedPipe 函数实现。
    3. 客户端通过函数 WaitNamedPipe 来等待管道的出现,如果在超时值变为零以前,有一个管道可以使用,则 WaitNamedPipe 将返回 True,并通过调用 CreateFile 或 CallNamedPipe 来呼叫对服务端的连接。
    4. 此时服务端将接受客户端的连接请求,成功建立连接,服务端 ConnectNamedPipe 返回 True
    5. 建立连接之后,客户端与服务器端即可通过 ReadFile 和 WriteFile,利用得到的管道文件句柄,彼此间进行信息交换。
    6. 当客户端与服务端的通信结束,客户端调用 CloseFile,服务端接着调用 DisconnectNamedPipe。最后调用函数CloseHandle来关闭该管道。

    由于命名管道使用时作为客户端的程序必须知道管道的名称,所以更多的用在同一“作者”编写的服务器/工作站程序中,你不可能随便找出一个程序来要求它和你写的程序来通过命名管道通信。
    而匿名管道的使用则完全不同,它允许你和完全不相干的进程通信,条件是这个进程通过控制台“console”来输入输出,典型的例子是老的 Dos 应用程序,
    它们在运行时 Windows 为它们开了个 Dos 窗口,它们的输入输出就是 console 方式的。还有一些标准的 Win32 程序也使用控制台输入输出,如果在 Win32 编程中不想使用图形界面,
    你照样可以使用 AllocConsole 得到一个控制台,然后通过 GetStdHandle 得到输入或输出句柄,再通过 WriteConsole 或 WriteFile 把结果输出到控制台(通常是一个象 Dos 窗口)的屏幕上。
    虽然这些程序看起来象 Dos 程序,但它们是不折不扣的 Win32 程序,如果你在纯 Dos 下使用,就会显示“The program must run under Windows!”。

    一个控制台有三个句柄:标准输入、标准输出和和标准错误句柄,标准输入、标准输出句柄是可以重新定向的,你可以用匿名管道来代替它,这样一来,你可以在管道的另一端用别的进程来接收或输入,
    而控制台一方并没有感到什么不同,就象 Dos 下的 > 或者 < 可以重新定向输出或输入一样。通常控制台程序的输入输出如下:

    (控制台进程output) write ----> 标准输出设备(一般是屏幕)
    (控制台进程input) read <---- 标准输入设备(一般是键盘)

    而用管道代替后:

    (作为子进程的控制台进程output) write ----> 管道1 ----> read (父进程)
    (作为子进程的控制台进程input) read <----> 管道2 <---- write (父进程)

    使用匿名管道的步骤如下:

    1. 使用 CreatePipe 建立两个管道,得到管道句柄,一个用来输入,一个用来输出
    2. 准备执行控制台子进程,首先使用 GetStartupInfo 得到 StartupInfo
    3. 使用第一个管道句柄代替 StartupInfo 中的 hStdInput,第二个代替 hStdOutput、hStdError,即标准输入、输出、错误句柄
    4. 使用 CreateProcess 执行子进程,这样建立的子进程输入和输出就被定向到管道中
    5. 父进程通过 ReadFile 读第二个管道来获得子进程的输出,通过 WriteFile 写第一个管道来将输入写到子进程
    6. 父进程可以通过 PeekNamedPipe 来查询子进程有没有输出
    7. 子进程结束后,要通过 CloseHandle 来关闭两个管道。

    下面是具体的说明和定义:

    1. 建立匿名管道使用 CreatePipe 原形如下:

    BOOL CreatePipe(
    PHANDLE hReadPipe, // address of variable for read handle
    PHANDLE hWritePipe, // address of variable for write handle
    LPSECURITY_ATTRIBUTES lpPipeAttributes, // pointer to security attributes
    DWORD nSize // number of bytes reserved for pipe
    );

    当管道建立后,结构中指向的 hReadPipe 和 hWritePipe 可用来读写管道,当然由于匿名管道是单向的,你只能使用其中的一个句柄,参数中的 SECURITY_ATTRIBUTES 的结构必须填写,定义如下:

    typedef struct_SECURITY_ATTRIBUTES{
    DWORD nLength: //定义以字节为单位的此结构的长度
    LPVOID lpSecurityDescriptor; //指向控制这个对象共享的安全描述符,如果为NULL这个对象将被分配一个缺省的安全描述
    BOOL bInheritHandle; //当一个新过程被创建时,定义其返回是否是继承的.供系统API函数使用.
    }SECURITY_ATTRIBUTES;

    2. 填写创建子进程用的 STARTUPINFO 结构,一般我们可以先用 GetStartupInfo 来填写一个缺省的结构,然后改动我们用得到的地方,它们是:

    • hStdInput -- 用其中一个管道的 hWritePipe 代替
    • hStdOutput、hStdError -- 用另一个管道的 hReadPipe 代替
    • dwFlags -- 设置为 STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW 表示输入输出句柄及 wShowWindow 字段有效
    • wShowWindow -- 设置为 SW_HIDE,这样子进程执行时不显示窗口。

    填写好以后,就可以用 CreateProcess 来执行子进程了,具体有关执行子进程的操作可以参考上一篇教程《进程控制

    3. 在程序中可以用 PeekNamedPipe 查询子进程有没有输出,原形如下:

    BOOL PeekNamedPipe(
    HANDLE hNamedPipe, // handle to pipe to copy from
    LPVOID lpBuffer, // pointer to data buffer
    DWORD nBufferSize, // size, in bytes, of data buffer
    LPDWORD lpBytesRead, // pointer to number of bytes read
    LPDWORD lpTotalBytesAvail, // pointer to total number of bytes available
    LPDWORD lpBytesLeftThisMessage // pointer to unread bytes in this message
    );

    我们可以将尝试读取 nBuffersize 大小的数据,然后可以通过返回的 BytesRead 得到管道中有多少数据,如果不等于零,则表示有数据可以读取。

    4. 用 ReadFile 和 WriteFile 来读写管道,它们的参数是完全一样的,原形如下:

    ReadFile or WriteFile(
    HANDLE hFile, // handle of file to read 在这里使用管道句柄
    LPVOID lpBuffer, // address of buffer that receives data 缓冲区地址
    DWORD nNumberOfBytesToRead, // number of bytes to read 准备读写的字节数
    LPDWORD lpNumberOfBytesRead, // address of number of bytes read,实际读到的或写入的字节数
    LPOVERLAPPED lpOverlapped // address of structure for data 在这里用 NULL
    );

    5. 用 CloseHandle 关闭管道一和管道二的 hReadPipe和 hWritePipe 这四个句柄。

    下面给出了一个例子程序,这个程序是上篇教程《进程控制》的例子的扩充,如果你对有的 api 感到陌生的话,请先阅读上一篇教程。

    源程序 - 汇编源文件

    程序的分析和要点

        在程序中,我先建立了一个 Richedit 控件用来显示子进程的输出,同时将 RichEdit 子类化,截取它的键盘输入以便把它发给子进程

    invoke SetWindowLong,hWinText,GWL_WNDPROC,offset _InputProc

    这条语句将 RichEdit 的过程指到了 _InputProc 中,然后在 _InputProc 的 WM_CHAR 中将键入的字符 WriteFile 到管道中,
    我在程序中先建立了两个管道,然后执行 c:/command.com,这样就得到了一个 dos 的命令行进程,
    然后在循环中通过 PeekNamedPipe 检测子进程有无输出,如果有的话则通过 ReadFile 读出,在显示到 RichEdit 中。

    在运行例子程序的时候要注意,你可以在这个“Command.com” 中执行几乎所有的别的程序,但是不要执行
    如 ucdos,pctools 之类不使用标准输入输出的程序(就是在 dos 下用不了“>”或者“<”重定向的程序),由于我们在装载子进程的时候用了 WS_HIDE,
    所以原来的 command.com 的窗口是隐藏的,如果你执行了这种程序那就意味着你失去的对子进程的控制,因为它们不使用标准输入来接收键盘,你也就无法通过管道让它们退出。

    在这里还可以引申出匿名管道的另一个用法,如果你执行的不是 command.com 而是类似于 arj.exe 的程序,然后也不用把它的输出显示到 RichEdit 中,而是在程序中处理,
    那么,你就可以编写一个 winarj,当然你只需编写窗口界面和 arj.exe 之间的配合而已。


    13. INI 文件的操作

    概述

    在程序中经常要用到设置或者其他少量数据的存盘,以便程序在下一次执行的时候可以使用,比如说保存本次程序执行时窗口的位置、大小、一些用户设置的数据等等,
    在 Dos 下编程的时候,我们一般自己产生一个文件,由自己把这些数据写到文件中,然后在下一次执行的时候再读出来使用。
    在 Win32 编程中当然你也可以这样干,但 Windows 已经为我们提供了两种方便的办法,那就是使用注册表或者 ini 文件(Profile)来保存少量数据。本文中先介绍一下 .ini 文件的使用。

    ini 文件是文本文件,中间的数据格式一般为:
    [Section1 Name]
    KeyName1=value1
    KeyName2=value2
    ...

    [Section2 Name]
    KeyName1=value1
    KeyName2=value2

    ini 文件可以分为几个 Section,每个 Section 的名称用 [] 括起来,在一个 Section 中,可以有很多的 Key,每一个 Key 可以有一个值并占用一行,格式是 Key=value,Win32 对 ini 文件操作的 api 中,
    有一部分是对 win.ini 操作的,有一部分是对用户自定义的 ini 文件操作的。Win.in 和 system.ini 是Windows的两个非常重要的初始化文件,Windows将用户所作的选择以及各种变化的系统信息记录在这两个文件中。
    System.ini 描述了系统硬件的当前状态,Win.ini 文件则包含了Windows 系统运行环境的当前配置。由于 Win.ini 文件的重要性和常用性,Win32 中有专门对 Win.ini 进行操作的 api,它们是:

    1. GetProfileInt - 从 Win.ini 文件的某个 Section 取得一个 key 的整数值,它的原形是:

      GetProfileInt(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      INT nDefault // 如果 Key 值没有找到,则返回缺省的值是多少
      );


      如果 Key 值没有找到的话,返回值是 nDefault 指定的缺省值,如果 Key 中的值是负数,则返回 0,如果 Key 指定的是数字和字符串的混合,则返回数字部分的值,比如说 x=1234abcd,则返回 1234

    2. GetProfileString - 从 Win.ini 文件的某个 Section 取得一个 key 的字符串,它的原形是:

      GetProfileString(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      LPCTSTR lpDefault, // 如果 Key 值没有找到,则返回缺省的字符串的地址
      LPTSTR lpReturnedString, // 返回字符串的缓冲区地址
      DWORD nSize // 缓冲区的长度
      );


      返回的字符串在缓冲区内,返回的 eax 值是返回的字符串的长度(不包括尾部的0)

    3. GetProfileSection - 从 Win.ini 文件中读出整个 Section 的内容,它的原形是:

      GetProfileSection(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPTSTR lpReturnedString, // 返回数据的缓冲区地址
      DWORD nSize // 返回数据的缓冲区长度
      );


    4. WriteProfileSection - 将一个整个 Section 的值 写入 Win.ini 文件的指定 Section 中,它的原形是:

      WriteProfileSection(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpString // 要写入的数据的地址
      );


      如果 Win.ini 没有指定的 Section,API 会新建立一个并写入数据,如果已经存在,则先删除原来 Seciton 中所有的 Key 值然后写入新的。

    5. WriteProfileString - 将一个 Key 值写入 Win.ini 文件的指定 Section 中,它的原形是:

      WriteProfileString(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      LPCTSTR lpString // 要写的字符串地址
      );


      如果 Win.ini 没有指定的 Section,API 会新建 Section,如果没有指定的 Key 则新建一个 Key 并写入数据,如果已经存在,则用字符串代替原来的值。

    以上的 Api 是对 Win.ini 操作的,当然对于我们来说,用的更多的是在程序运行的目录中建立自己的 ini 文件,如果需要对自己的 ini 文件操作,就要用到另一组 Api,这一组 api 和上面的很象,
    只要把上面一组的 Profile 换成 PrivateProfile(私有的)就可以了,参数中也相应的多了一个 ini 文件名的参数。
    例如 GetPrivateProfileInt、GetPrivateProfileSection、WritePrivateProfileString 等等, 下面分别介绍:

    1. GetPrivateProfileInt - 从 ini 文件的某个 Section 取得一个 key 的整数值,它的原形是:

      GetPrivateProfileInt(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      INT nDefault // 如果 Key 值没有找到,则返回缺省的值是多少
      LPCTSTR lpFileName // ini 文件的文件名
      );


      中间参数和返回值的定义和 GetProfileInt 是一样的。

    2. GetPrivateProfileString - 从 ini 文件的某个 Section 取得一个 key 的字符串,它的原形是:

      GetPrivateProfileString(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      LPCTSTR lpDefault, // 如果 Key 值没有找到,则返回缺省的字符串的地址
      LPTSTR lpReturnedString, // 返回字符串的缓冲区地址
      DWORD nSize // 缓冲区的长度
      LPCTSTR lpFileName // ini 文件的文件名
      );


    3. GetPrivateProfileSection - 从 ini 文件中读出整个 Section 的内容,它的原形是:

      GetPrivateProfileSection(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPTSTR lpReturnedString, // 返回数据的缓冲区地址
      DWORD nSize // 返回数据的缓冲区长度
      LPCTSTR lpFileName // ini 文件的文件名
      );


      这个 api 可以读出整个 section 的内容,当你不知道 section 中有哪些 key 的时候,可以使用这个 api 将整个 section 读出后再处理。

    4. GetPrivateProfileSectionNames - 从 ini 文件中获得 Section 的名称,它的原形是:

      GetPrivateProfileSectionNames(
      LPTSTR lpszReturnBuffer, // 返回数据的缓冲区地址
      DWORD nSize // 返回数据的缓冲区长度
      LPCTSTR lpFileName // ini 文件的文件名
      );


      如果 ini 中有两个 Section: [sec1] 和 [sec2],则返回的是 'sec1',0,'sec2',0,0 ,当你不知道 ini 中有哪些 section 的时候可以用这个 api 来获取名称

    5. WritePrivateProfileSection - 将一个整个 Section 的内容入 ini 文件的指定 Section 中,它的原形是:

      WritePrivateProfileSection(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpString // 要写入的数据的地址
      LPCTSTR lpFileName // ini 文件的文件名
      );


    6. WritePrivateProfileString - 将一个 Key 值写入 ini 文件的指定 Section 中,它的原形是:

      WritePrivateProfileString(
      LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
      LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
      LPCTSTR lpString // 要写的字符串地址
      LPCTSTR lpFileName // ini 文件的文件名
      );


      如果 ini 中没有指定的 Section,API 会新建 Section,如果没有指定的 Key 则新建一个 Key 并写入数据,

    如果已经存在,则用字符串代替原来的值。当指定的 ini 也不存在的时候,API 会自动建立一个新的文件,

    所以使用 ini 的好处是我们不必为了保存少量的数据涉及到文件操作,就连查找文件是否存在的操作都不必要。

    使用要点:

    在我们实际使用的时候,用的最多的是 GetPrivateProfileString 和 WritePrivateProfileString,但在对自定义 ini
    文件操作的时候要注意的是,如果 lpFileName 指定的文件没有路径的话,Api 会去 Windows 的安装目录去找而不会在当前目录找,
    但是每次用到 ini 函数要获取当前路径显然太麻烦了,这里有一个变通的办法,
    你只要在 ini 文件名前面加上 ./ 就可以了,比如说要对本目录下的 user.ini 操作,那么文件名就是 './user.ini' 这样显然比较方便。
    另外,当你要把一个 Key 清除的时候,可以使用把 lpString 指向一个空的字符串然后使用 WritePrivateProfileString。
    当你要把一个 section 的全部内容清空的时候,也不必把 key 一个个的清除,
    可以使用把 lpString 指向一个空的字符串然后使用 WritePrivateProfileSection。


    14.Win32ASM经验点滴

    Q1. 如何隐藏/显示任务栏?
    Q2.

    如何禁止/允许/显示/隐藏开始按钮?
    Q3. 如何创建一个真正的"总在最上面"窗口?
    Q4. 如何创建热键?比如CTRL + ALT + A
    Q5. 如何获得Windows目录和系统目录?
    Q6. 如何从我的程序打开开始菜单?
    Q7. 如何关闭被正激活的程序?
    Q8. 如何去掉窗口标题?
    Q9. 如何知道窗口是否在任务栏中(或可见) ?
    Q10. 如何隐藏一个窗口?
    Q11. 如何将窗口置于前台?
    Q12. 如何屏蔽CTRL+ALT+DEL,ALT+TAB+CTRL+ESC这些键?
    Q13. 如何确定Windows任务栏的自动隐藏特性是否被激活?
    Q14. 如何使用默认的浏览器或邮件程序?
    Q15. 如何用Win32 API显示网络连接对话框?

    - 如何隐藏/显示任务栏?

    shell db "Shell_TrayWnd",0 ; 任务栏的类名
    invoke FindWindow,addr shell,NULL ; 先获得句柄,之后隐藏.
    .if eax != 0
    invoke ShowWindow,eax,SW_HIDE ;
    SW_SHOW显示
    .endif


    - 如何禁止/允许/显示/隐藏开始按钮?

    .data?
    buffer db 127 dup(?)

    .data
    shell db "Shell_TrayWnd",0
    sbar db "BUTTON",0
    child dd ?
    slen dd ?

    .code

    invoke FindWindow,addr shell,NULL ; 获得状态栏句柄
    mov tray, eax
    invoke GetWindow,tray, GW_CHILD ;
    获得状态栏的子窗口(如果有的话)
    mov child, eax
    .if child != 0
    invoke GetClassName,child,offset buffer, sizeof buffer ;
    获得子窗口类名
    .if eax > 0
    invoke lstrlen, offset buffer ;
    获得类名长度
    mov slen,eax
    invoke CharUpperBuff,offset buffer,slen ;
    转为大写
    invoke lstrcmp,addr buffer, addr sbar ;将类名与'BUTTON'比较
    .if eax == 0
    invoke ShowWindow,child,SW_HIDE ;
    隐藏开始按钮
    ; invoke ShowWindow,child,SW_SHOW ; 显示开始按钮
    ; invoke EnableWindow,child,FALSE ; 禁止开始按钮
    ; invoke EnableWindow,child,TRUE ; 允许开始按钮
    .endif
    .endif
    .endif


    - 如何创建一个真正的"总在最上面"窗口?

    invoke SetWindowPos,hWin, HWND_TOPMOST,NULL,NULL,NULL,NULL,SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE


    - 如何创建热键?比如CTRL + ALT + A

    .data
    hmsg db "HotKey CTRL + ALT + A Works good!",0
    hcap db "Hotkey Example",0

    .code
    .if uMsg == WM_CREATE
    invoke RegisterHotKey,hWnd,065h,MOD_CONTROL or MOD_ALT, 041h ; CTRL + ALT + A (041h is 65 - 065h is 101)

    .elseif uMsg == WM_HOTKEY
    invoke MessageBox,hWin,addr hmsg,addr hcap, MB_OK or MB_ICONINFORMATION

    .elseif uMsg == WM_DESTROY
    invoke UnregisterHotKey,hWin,065h
    invoke PostQuitMessage,NULL
    return 0
    .endif


    -如何获得Windows目录和系统目录

    .data
    buffer db 50 dup(?)
    hCap db "WindowsDirectory",0

    .code
    invoke GetWindowsDirectory, addr buffer, sizeof buffer ;
    Windows目录于缓冲区中
    ; invoke GetSystemDirectory, addr buffer, sizeof buffer ;置系统目录于缓冲区中
    invoke MessageBox,hWnd, addr buffer, addr hCap, MB_OK or MB_ICONINFORMATION


    - 如何从我的程序打开开始菜单?

    invoke SendMessage,hWnd,WM_SYSCOMMAND,SC_TASKLIST,NULL


    - 如何关闭正被激活的程序 ?

    .data
    fwin dd ?

    .code
    invoke GetForegroundWindow
    mov fwin,eax
    invoke SendMessage, fwin, WM_CLOSE,NULL


    - 如何去掉窗口标题 ?

    invoke GetWindowLong,hWnd,GWL_STYLE ; 获得当前窗口类
    and eax,not WS_CAPTION ; 去掉WS_CAPTION
    invoke SetWindowLong,hWnd,GWL_STYLE,eax ;
    设置窗口类

     


    - 如何知道窗口是否在任务栏中(或可见)?

    invoke IsWindowVisible,hWin
    .if eax == TRUE
    ;
    窗口可见
    .else
    ;
    窗口不可见
    .endif

     


    - 如何隐藏一个窗口?

    .data
    mirc db "mIRC32",0
    mhand dd ?

    .code
    invoke FindWindow,addr mirc, NULL ;
    寻找mIRC32
    mov mhand,eax
    .if mhand != 0 ;
    找到?
    invoke ShowWindow,mhand,SW_SHOW ;
    显示窗口
    ; invoke ShowWindow,mhand,SW_HIDE ; 隐藏窗口
    .else
    ; mIRC32
    未运行...
    .endif

     


    - 如何将窗口置于前台?

    invoke SetForegroundWindow, mhand

     


    - 如何屏蔽CTRL+ALT+DEL,ALT+TAB+CTRL+ESC这些键?

    invoke SystemParametersInfo,SPI_SCREENSAVERRUNNING,1,NULL,NULL
    ; Windows98 only 1
    关闭 0 允许

     


    - 如何确定Windows任务栏的自动隐藏特性是否被激活?

    .data
    AppBar APPBARDATA {} ; {}

    指使用默认值... Thanks to TTom

    .code
    mov AppBar.cbSize, sizeof AppBar
    invoke SHAppBarMessage, ABM_GETSTATE, addr AppBar ; ShellApi
    命令
    and eax, ABS_AUTOHIDE
    .if eax == TRUE
    ;
    任务栏被隐藏
    .else
    ;
    任务栏未被隐藏
    .endif

    - 如何使用默认的浏览器或邮件程序?

    .data
    lpPage db "http://win32asm.cjb.net",0
    lpMail db "ates@anet.net.tr",0
    lpOperation db "open",0

    .code
    invoke ShellExecute,hWin,addr lpOperation, addr lpPage, NULL, NULL, SW_SHOWNORMAL
    invoke ShellExecute,hWin,addr lpOperation, addr lpMail, NULL, NULL, SW_SHOWNORMAL


    - 如何用Win32 API显示网络连接对话框?

    include /MASM32/INCLUDE/mpr.inc
    includelib /MASM32/LIB/mpr.lib
    invoke WNetConnectionDialog,hWnd,RESOURCETYPE_DISK


    Designed By Atilla Yurtseven

    Chinese Translation By Orochi,2000.12.16

    展开全文
  • Win32汇编环境配置

    2019-10-04 18:31:35
    放假了,发现自己知识面窄,趁有时间就打算折腾下Win32汇编。其实在学校也上过汇编课,是基于dos的。那时老师不务正业,老跟我们讲政治经济文化,唯独不怎么讲课;再加上自己的问题,导致了dos汇编学得好烂(几乎没学),但...

    放假了,发现自己知识面窄,趁有时间就打算折腾下Win32汇编。其实在学校也上过汇编课,是基于dos的。那时老师不务正业,老跟我们讲政治经济文化,唯独不怎么讲课;再加上自己的问题,导致了dos汇编学得好烂(几乎没学),但发现dos汇编比较少用,所以直接学Win32汇编了,基础知识薄弱遇到再补上去。我只是多了解其他知识,不求精通。如果要学好还是应该先写好dos汇编的。

    介绍

    Win32可执行环境的开发过程如下图

    常用的编译器有Microsoft的MASM系列和Borland的TASM系列。但都存在一些缺点:

    MASM:没有当做完整的开发包发布,会发现在不同版本中都会缺少一些工具,需要在其他地方获得。

    TASM:优化方面不好,使用会有点麻烦。

    则可以选择使用MASM32 SDK软件包。它是不同工具软件的集合,它的汇编编译器用的是微软MASM软件包中的Ml.exe,资源编译器和32位链接器使用的是Microsoft Visual Studio中的Rc.exe,Link.exe,同时包含了Microsoft Visual Studio中的其他一些工具,如Lib.exe和DumpPe.exe等,所有的工具都是适合于Win32编程的版本。

    安装

    MASM32 SDK下载地址:http://www.masm32.com/masmdl.htm。

    下载后是一个安装文件install.exe。双击打开一直确定或下一步就能完成安装,在这个过程中会有个选择安装目录,并且会测试是否能安装。最终在安装目录出现masm32文件夹。

    masm32文件夹中的信息:

    目    录

    介    绍

    \masm32

    IDE环境、内带的文本编辑程序和模板生成程序等

    \masm32\include

    所有的头文件,Windows.inc为数据结构和预定义值的定义文件,Resource.h为资源文件的头文件,其他 .inc文件为对应同名DLL文件中的API函数声明文件

    \masm32\lib

    所有的导入库文件,每个.lib文件是对应DLL文件的导入库

    \masm32\bin

    可执行文件目录,里面包括Ml.exe,Link.exe和Rc.exe等

    \masm32\help

    帮助文件目录

    \masm32\m32lib

    一些常用C子程序的汇编实现源程序,如熟悉的stdin和stdout等,有一定的参考价值

    其他目录

    主要为例子和可用可不用的小工具,例子广泛收集自网上不同作者的作品,很有参考价值

    如果不用内带的IDE环境,不看附带的例子和帮助文件,那么有了bin,include和lib这三个目录中的内容,就可以进行Win32汇编编程了,其他目录中的文件仅起辅助作用。

    使用

    设置环境变量

    可以在计算机中高级系统设置的环境变量中写死或者每次要编译连接时先执行一个批处理文件Var.bat,退出后所设置的环境变量也会消失掉。

    Var.bat

    View Code
    1 @echo off
    2 rem 请根据 Masm32 软件包的安装目录修改下面的 Masm32Dir 环境变量!
    3 set Masm32Dir=D:\masm32
    4 set include=%Masm32Dir%\include;%include%;D:\Program Files\Programing\Microsoft Visual Studio 10.0\VC\include;D:\masm32\include\others_dk\INCLUDE;D:\masm32\include\others_dk\MFC;
    5 set lib=%Masm32Dir%\lib;%lib%
    6 set path=%Masm32Dir%\bin;%Masm32Dir%;%path%;
    7 echo on

     

    编写程序

    源代码HelloWorld.asm

    View Code
            .386
            .model flat,stdcall
            option casemap:none
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; Include 文件定义
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    include        windows.inc
    include        user32.inc
    includelib          user32.lib
    include        kernel32.inc
    includelib          kernel32.lib
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 数据段
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
            .const
    
    szCaption    db    'MessageBox',0
    szText    db    'HelloWorld!',0
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ; 代码段
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
            .code
    start:
            invoke    MessageBox,NULL,offset szText,offset szCaption,MB_OK
            invoke    ExitProcess,NULL
    ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
            end    start

     

    资源文件HelloWorld.rc(只有个文件名,内容为空。暂时用不到)

    执行

    运行批处理文件后,在命令符中进入到源程序的目录下,并分条输入并回车(编译源程序、编译资源、链接),最终会产生可执行文件HelloWorld.exe。

    ml  /c /coff  HelloWorld.asm
    rc    HelloWorld.rc
    Link /subsystem:windows    HelloWorld.obj  HelloWorld.res

    运行后

    扩展

    每次在命令符都要输入指令,比较麻烦。可以使用make工具(Microsoft中叫nmake.exe,可以在Visual C++的bin目录下找到)。把MakeFile放到源程序的文件目录下,要编译运行源程序只要在命令符输入的编译等指令时替换成nmake就可以。

    MakeFile

    View Code
     1 NAME = HelloWorld
     2 OBJS = $(NAME).obj
     3 RES  = $(NAME).res
     4 
     5 LINK_FLAG = /subsystem:windows
     6 ML_FLAG = /c /coff
     7 
     8 $(NAME).exe: $(OBJS) $(RES)
     9     Link $(LINK_FLAG) $(OBJS) $(RES)
    10 
    11 .asm.obj:
    12     ml $(ML_FLAG) $<
    13 .rc.res:
    14     rc $<
    15 
    16 clean:
    17     del *.obj
    18     del *.res

     

     

     

     参考:罗云彬的《Windows环境下32位汇编语言程序设计》

    转载于:https://www.cnblogs.com/dann/p/2909668.html

    展开全文
  • 汇编win7tasm

    2013-10-23 23:05:09
    win7 实现 汇编,简单易操作,下载即可直接使用,解压后,直接在该文件进行dos操作
  • 罗云彬Win32汇编

    千次阅读 2012-07-14 17:30:37
    今天看了下罗老师的Win32汇编,感觉跟DOS下汇编的确差别比较大。  感觉Win32汇编好像有高级语言的味道,实现方式是通过加载Windows的DLL库,程序书写方式也跟C语言比较相似,感觉更像的一点的通过汇编可以直接调用...

            今天看了下罗老师的Win32汇编,感觉跟DOS下汇编的确差别比较大。

            感觉Win32汇编好像有高级语言的味道,实现方式是通过加载Windows的DLL库,程序书写方式也跟C语言比较相似,感觉更像的一点的通过汇编可以直接调用Windows的API接口,简单方便之时,感觉会不会Windows已经把核心给封装了,Win32汇编已经不能操作太底层的硬件了。

            第一天看,发点小感慨,继续研究吧,真实情况应该跟我今天的感觉不同吧。

    展开全文
  • win7执行汇编程序

    2013-06-25 10:17:43
    可以在win7等高版本环境运行汇编程序,可以玩一些经典的DOS游戏!该版本为win7 64位系统安装程序!
  • Win32汇编语言教程

    2011-07-16 12:15:13
    Windows环境32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以用来开发出大型的软件,而且是了解操作系统运行细节的最佳方式。本书从编写应用程序的角度,从“Hello World!”这个简单的...
  • win32中只有代码和数据以及堆栈段之分 另外程序中不必定义堆栈段,系统会自动分配堆栈空间  .data .data? .const  第一类为可读写已定义的变量  第二类为可读写未定义的变量  第三类数据为一些常量 只可读...
  • nasm-2.13.02-win64 汇编

    2018-04-28 09:10:30
    nasm-2.13.02-win64 汇编器 windows 64 位汇编器 nasm-2.13.02-win64 汇编
  • .386 .model flat, stdcall option casemap:none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Incude 文件定义 ...>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ...include windows
  • Win64下汇编写对话框

    2014-08-21 16:03:19
    汇编写界面当然是自己zhet
  • Win32汇编入门概述

    2014-11-06 21:25:22
    在一个月前我打算学Win32汇编,发现汇编的基础不是太好,便花了近一个月的时间把王爽老师的《汇编语言》看了一遍。现在再来看Win32汇编,比...Windows环境32位汇编语言是一种全新的编程语言。它使用与C++语言相同的A
  • Windows环境32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以用来开发出大型的软件,而且是了解操作系统运行细节的最佳方式。本书从编写应用程序的角度,从“Hello World!”这个简单的...
  • Win32下汇编语言常用批处理文件 2009-05-17 15:16 Win32下汇编语言常用批处理文件 http://bavon.bokee.com/2771350.html 关键词: 汇编 批处理 在Win32下进行汇编语言编程时,经常需要在汇编、资源转换...
  • 基于win32下汇编语言的加密解密,可以实现简单的文件加密解密。
  • Win32汇编语言 罗云彬

    2009-09-06 14:24:35
    Windows环境32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以用来开发出大型的软件,而且是了解操作系统运行细节的最佳方式。本书从编写应用程序的角度,从“Hello World!”这个简单...
  • 初探下Win64汇编(1)

    千次阅读 2014-04-03 00:08:04
    现在是64位的时代了,可惜不会64汇编怎么行...可惜本菜水平实在有限……大牛勿看了…… 个MASM64,OK很好~里面有很多例子 不过俺先看看64位哪里改变了吧 #include int main() { 000000013F181010 40 57...
  • win8-win7运行debug命令 汇编 附带了方法 已经测试 可用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,539
精华内容 615
关键字:

win下汇编