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

📄 lion-tut-c04.htm

📁 内有一些代码
💻 HTM
字号:
<html>

<head>
<link rel="stylesheet" href="../../asm.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion 的 Win32asm 教程</title>
</head>

<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center"><font size="5"><u><strong><font color="#0000FF">第四课 绘制文本</font></strong></u></font></p>
<hr size="1">
<p> 本课中,我们将学习如何在窗口的客户区“绘制”字符串。我们还将学习关于“设备环境”的概念。</p>
<p> <font color="#FF0000">理论:</font></p>
<p> Windows 中的文本是一个GUI(图形用户界面)对象。每一个字符实际上是由许多的像素点组成,这些点在有笔画的地方显示出来,这样就会出现字符。这也是为什么我说“绘制”字符,而不是写字符。通常您都是在您应用程序的客户区“绘制”字符串(尽管您也可以在客户区外“绘制”)。Windows 
  下的“绘制”字符串方法和 Dos 下的截然不同,在 Dos 下,您可以把屏幕想象成 85 x 25 的一个平面,而 Windows 下由于屏幕上同时有几个应用程序的画面,所以您必须严格遵从规范。Windows 
  通过把每一个应用程序限制在他的客户区来做到这一点。当然客户区的大小是可变的,您随时可以调整。</p>
<p>在您在客户区“绘制”字符串前,您必须从 Windows 那里得到您客户区的大小,确实您无法像在 DOS 下那样随心所欲地在屏幕上任何地方“绘制”,绘制前您必须得到 
  Windows 的允许,然后 Windows 会告诉您客户区的大小,字体,颜色和其它 GUI 对象的属性。您可以用这些来在客户区“绘制”。</p>
<p> 什么是“设备环境”(DC)呢? 它其实是由 Windows 内部维护的一个数据结构。一个“设备环境”和一个特定的设备相连。像打印机和显示器。对于显示器来说,“设备环境”和一个个特定的窗口相连。</p>
<p>“设备环境”中的有些属性和绘图有关,像:颜色,字体等。您可以随时改动那些缺省值,之所以保存缺省值是为了方便。您可以把“设备环境”想象成是Windows 
  为您准备的一个绘图环境,而您可以随时根据需要改变某些缺省属性。</p>
<p> 当应用程序需要绘制时,您必须得到一个“设备环境”的句柄。通常有几种方法。</p>
<ul>
  <li>在 WM_PAINT 消息中使用 call BeginPaint</li>
  <li>在其他消息中使用 call GetDC</li>
  <li> call CreateDC 建立你自己的 DC</li>
</ul>
<p> 您必须牢记的是,在处理单个消息后你必须释放“设备环境”句柄。不要在一个消息处理中获得 “设备环境”句柄,而在另一个消息处理中在释放它。</p>
<p>我们在Windows 发送 WM_PAINT 消息时处理绘制客户区,Windows 不会保存客户区的内容,它用的是方法是“重绘”机制(譬如当客户区刚被另一个应用程序的客户区覆盖),Windows 
  会把 WM_PAINT 消息放入该应用程序的消息队列。重绘窗口的客户区是各个窗口自己的责任,您要做的是在窗口过程处理 WM_PAINT 的部分知道绘制什么和何如绘制。 
</p>
<p>您必须了解的另一个概念是“无效区域”。Windows 把一个最小的需要重绘的正方形区域叫做“无效区域”。当 Windows 发现了一个”无效区域“后,它就会向该应用程序发送一个 
  WM_PAINT 消息,在 WM_PAINT 的处理过程中,窗口首先得到一个有关绘图的结构体,里面包括无效区的坐标位置等。您可以通过调用BeginPaint 
  让“无效区”有效,如果您不处理 WM_PAINT 消息,至少要调用缺省的窗口处理函数 DefWindowProc ,或者调用 ValidateRect 
  让“无效区”有效。否则您的应用程序将会收到无穷无尽的 WM_PAINT 消息。</p>
<p>下面是响应该消息的步骤: </p>
<ol>
  <li>取得“设备环境”句柄</li>
  <li>绘制客户区</li>
  <li>释放“设备环境”句柄</li>
</ol>
<p> 注意,您无须显式地让“无效区”有效,这个动作由 BeginPaint 自动完成。您可以在 BeginPaint 和 Endpaint 之间,调用所有的绘制函数。几乎所有的GDI 
  函数都需要“设备环境”的句柄作为参数。</p>
<p> <font color="#FF0000">内容: </font></p>
<p>我们将写一个应用程序,它会在客户区的中心显示一行 "Win32 assembly is great and easy!"</p>
<p><font color="#006666">.386 <br>
  .model flat,stdcall <br>
  option casemap:none </font></p>
<p><font color="#006666">WinMain proto :DWORD,:DWORD,:DWORD,:DWORD </font>
<p><font color="#006666">include \masm32\include\windows.inc <br>
  include \masm32\include\user32.inc <br>
  includelib \masm32\lib\user32.lib <br>
  include \masm32\include\kernel32.inc <br>
  includelib \masm32\lib\kernel32.lib </font>
<p><font color="#006666">.DATA <br>
  ClassName db "SimpleWinClass",0 <br>
  AppName&nbsp; db "Our First Window",0 <br>
  OurText&nbsp; db "Win32 assembly is great and easy!",0 </font>
<p><font color="#006666">.DATA? <br>
  hInstance HINSTANCE ? <br>
  CommandLine LPSTR ? </font>
<p><font color="#006666">.CODE <br>
  start: <br>
  &nbsp;&nbsp;&nbsp; invoke GetModuleHandle, NULL <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; hInstance,eax <br>
  &nbsp;&nbsp;&nbsp; invoke GetCommandLine<br>
  &nbsp;&nbsp;&nbsp;&nbsp;mov CommandLine,eax<br>
  &nbsp;&nbsp;&nbsp; invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT 
  <br>
  &nbsp;&nbsp;&nbsp; invoke ExitProcess,eax </font>
<p><font color="#006666">WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, 
  CmdShow:DWORD <br>
  &nbsp;&nbsp;&nbsp; LOCAL wc:WNDCLASSEX <br>
  &nbsp;&nbsp;&nbsp; LOCAL msg:MSG <br>
  &nbsp;&nbsp;&nbsp; LOCAL hwnd:HWND <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.cbSize,SIZEOF WNDCLASSEX <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.style, CS_HREDRAW or CS_VREDRAW <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.lpfnWndProc, OFFSET WndProc <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.cbClsExtra,NULL <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.cbWndExtra,NULL <br>
  &nbsp;&nbsp;&nbsp; push&nbsp; hInst <br>
  &nbsp;&nbsp;&nbsp; pop&nbsp;&nbsp; wc.hInstance <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.hbrBackground,COLOR_WINDOW+1 <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.lpszMenuName,NULL <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.lpszClassName,OFFSET ClassName <br>
  &nbsp;&nbsp;&nbsp; invoke LoadIcon,NULL,IDI_APPLICATION <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.hIcon,eax <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.hIconSm,eax <br>
  &nbsp;&nbsp;&nbsp; invoke LoadCursor,NULL,IDC_ARROW <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; wc.hCursor,eax <br>
  &nbsp;&nbsp;&nbsp; invoke RegisterClassEx, addr wc <br>
  &nbsp;&nbsp;&nbsp; invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hInst,NULL <br>
  &nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp; hwnd,eax <br>
  &nbsp;&nbsp;&nbsp; invoke ShowWindow, hwnd,SW_SHOWNORMAL <br>
  &nbsp;&nbsp;&nbsp; invoke UpdateWindow, hwnd <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .WHILE TRUE <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  invoke GetMessage, ADDR msg,NULL,0,0 <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  .BREAK .IF (!eax) <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  invoke TranslateMessage, ADDR msg <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  invoke DispatchMessage, ADDR msg <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ENDW <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp; eax,msg.wParam 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret <br>
  WinMain endp </font>
<p><font color="#006666">WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
  <br>
  &nbsp;&nbsp;&nbsp; LOCAL hdc:HDC <br>
  &nbsp;&nbsp;&nbsp; LOCAL ps:PAINTSTRUCT <br>
  &nbsp;&nbsp;&nbsp; LOCAL rect:RECT <br>
  &nbsp;&nbsp;&nbsp; .IF uMsg==WM_DESTROY <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke PostQuitMessage,NULL <br>
  &nbsp;&nbsp;&nbsp; .ELSEIF uMsg==WM_PAINT <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke BeginPaint,hWnd, ADDR ps <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; hdc,eax <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke GetClientRect,hWnd, ADDR rect 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke DrawText, hdc,ADDR OurText,-1, 
  ADDR rect, \ <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  DT_SINGLELINE or DT_CENTER or DT_VCENTER <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke EndPaint,hWnd, ADDR ps <br>
  &nbsp;&nbsp;&nbsp; .ELSE <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoke DefWindowProc,hWnd,uMsg,wParam,lParam 
  <br>
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret <br>
  &nbsp;&nbsp;&nbsp; .ENDIF <br>
  &nbsp;&nbsp;&nbsp; xor&nbsp;&nbsp; eax, eax <br>
  &nbsp;&nbsp;&nbsp; ret <br>
  WndProc endp <br>
  end start </font>
<p> <font color="#FF0000">分析: </font></p>
<p>这里的大多数代码和第三课中的一样。我只解释其中一些不相同的地方。</p>
<p> <font color="#006666">LOCAL hdc:HDC<br>
  LOCAL ps:PAINTSTRUCT<br>
  LOCAL rect:RECT</font></p>
<p> 这些局部变量由处理 WM_PAINT 消息中的 GDI 函数调用。hdc 用来存放调用 BeginPaint 返回的“设备环境”句柄。ps 是一个 
  PAINTSTRUCT 数据类型的变量。通常您不会用到其中的许多值,它由 Windows 传递给 BeginPaint,在结束绘制后再原封不动的传递给 
  EndPaint。rect 是一个 RECT 结构体类型参数,它的定义如下:</p>
<p> <font color="#006666">RECT Struct left LONG ?<br>
  top LONG ?<br>
  right LONG ?<br>
  bottom LONG ?<br>
  RECT ends</font></p>
<p> left 和 top 是正方形左上角的坐标。right 和 bottom 是正方形右下角的坐标。客户区的左上角的坐标是 x=0,y=0,这样对于 x=0,y=10 
  的坐标点就在它的下面。</p>
<p> <font color="#006666">invoke BeginPaint,hWnd, ADDR ps<br>
  mov hdc,eax<br>
  invoke GetClientRect,hWnd, ADDR rect<br>
  invoke DrawText, hdc,ADDR OurText,-1, ADDR rect, \ <br>
  DT_SINGLELINE or DT_CENTER or DT_VCENTER<br>
  invoke EndPaint,hWnd, ADDR ps</font></p>
<p> 在处理 WM_PAINT 消息时,您调用BeginPaint函数,传给它一个窗口句柄和未初始化的 PAINTSTRUCT 型参数。调用成功后在 eax 
  中返回“设备环境”的句柄。下一次,调用 GetClientRect 以得到客户区的大小,大小放在 rect 中,然后把它传给 DrawText。DrawText 
  的语法如下: </p>
<p><font color="#006666">DrawText proto hdc:HDC, lpString:DWORD, nCount:DWORD, 
  lpRect:DWORD, uFormat:DWORD </font> </p>
<p>DrawText是一个高层的调用函数。它能自动处理像换行、把文本放到客户区中间等这些杂事。所以您只管集中精力“绘制”字符串就可以了。我们会在下一课中讲解低一层的函数 
  TextOut,该函数在一个正方形区域中格式化一个文本串。它用当前选择的字体、颜色和背景色。它处理换行以适应正方形区域。它会返回以设备逻辑单位度量的文本的高度,我们这里的度量单位是像素点。让我们来看一看该函数的参数: 
</p>
<ul>
  <li>hdc: “设备环境”的句柄。 </li>
  <li>lpString:要显示的文本串,该文本串要么以NULL结尾,要么在nCount中指出它的长短。</li>
  <li> nCount:要输出的文本的长度。若以NULL结尾,该参数必须是-1。</li>
  <li> lpRect: 指向要输出文本串的正方形区域的指针,该方形必须是一个裁剪区,也就是说超过该区域的字符将不能显示。</li>
  <li> uFormat:指定如何显示。我们可以用 or 把以下标志或到一块: 
    <ul>
      <li> DT_SINGLELINE:是否单行显示。</li>
      <li> DT_CENTER:是否水平居中。 </li>
      <li>DT_VCENTER :是否垂直居中。</li>
    </ul>
    <p>&nbsp;</p>
  </li>
</ul>
<p>结束绘制后,必须调用 EndPaint 释放“设备环境”的句柄。 好了,现在我们把“绘制”文本串的要点总结如下:</p>
<ol>
  <li>必须在开始和结束处分别调用 BeginPaint 和 EndPaint;</li>
  <li> 在 BeginPaint 和 EndPaint 之间调用所有的绘制函数;</li>
  <li> 如果在其它的消息处理中重新绘制客户区,您可以有两种选择:<br>
    (1)用GetDC和ReleaseDC代替BeginPaint和EndPaint;<br>
    (2)调用InvalidateRect或UpdateWindow让客户区无效,这将迫使WINDOWS把WM_PAINT放入应用程序消息队列,从而使得客户区重绘。 
  </li>
</ol>
<hr size="1">
<div align="center">
  <script language="JavaScript1.1" src=http://ad.t2t2.com/textclick.asp?user=bigluo&style=4&bkcolor=no></script>
  <br>
</div>
<!-- 10:1 文本广告交换 --> 
<div align="center"> 
  <script language="JavaScript1.1" src=http://coolsite21.com:90/c21.dll?Type=PT&id=1047&col=6&ReferID=1047&v=0></script>
  <!-- 10:1 文本广告交换 --> </div>
<hr size="1">
<br>
<div align="center"> 翻译:Lxx,校对:LuoYunBin's Win32 ASM Page,<a href="http://asm.yeah.net">http://asm.yeah.net</a></div>

</body>
</html>

⌨️ 快捷键说明

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