Programming Windows程式开发设计指南 第10章 功能表及其他资源

10. 功能表及其他资源 本文来自织梦

 

copyright dedecms

大多数Windows程式都包含一个自订的图示,Windows将该图示显示在应用程式视窗标题列的左上角。当程式被列在「开始」功能表中,被显示在萤幕底部的工作列中,被列在Windows Explorer中,或者作为快捷方式显示在桌面上时,Windows也显示该程式的图示。有些程式-大部分是像小画家一类的图形绘制工具-也使用自订滑鼠游标来表示程式的不同操作。还有许多Windows程式使用功能表和对话方块。功能表、对话方块加上卷动列,这是标准Windows使用者介面的卖点。 内容来自dedecms

图示、游标、功能表和对话方块都是相互关联的,它们是Windows的全部资源型态。资源即资料,它们被储存在程式的.EXE档案中,但是它们并非驻留在程式的资料区域中。也就是说,资源不能从程式原始码中定义的变数直接存取,Windows提供函式直接或间接地把它们载入记忆体以备使用。我们已经遇到了两个这样的函式,即LoadIconLoadCursor,它们出现在范例程式,定义视窗类别结构的内容设定叙述中。它们从Windows中载入二进位图示和游标映象,并传回该图示或游标的代号。在本章中,我们先建立自己的图示,它会从程式自己的.EXE档案中载入。

织梦好,好织梦

在本书中,我们将讨论这些资源:

织梦内容管理系统

  • 图示
     
  • 游标
     
  • 字串
     
  • 自订资源
     
  • 功能表
     
  • 键盘加速键
     
  • 对话方块
     
  • 点阵图
     

前六个资源在本章讨论,对话方块在第十一章讨论,而点阵图在第十四章讨论。

本文来自织梦

图示、游标、字串和自订资源
  copyright dedecms

使用资源的好处之一,在於程式的许多元件能够连结编译进程式的.EXE档案中。如果没有资源这一个概念,如图示图像之类的二进位档案可能会存放在单独的档案中,.EXE会把它读入记忆体中使用。或者图示不得不在程式中以位元组阵列的形式定义(这样就无法看到实际的图示图像了)。作为资源,图示储存在开发者电脑上可单独编辑的档案中,但在编译程序中被连结编译进.EXE档案中。 dedecms.com

将图示添加到程式
  本文来自织梦

将资源添加到程式中需要Visual C++ Developer Studio的一些附加功能。对於图示来说,可以使用「Image Editor」(也称为「Graphics Editor」)来绘制图示的图像。该图像被储存在副档名为.ICO的图示档案中。Developer Studio还产生一个资源描述档(副档名为.RC的档案,有时也称作资源定义档案),它列出了程式的所有资源和一个让程式引用资源的表头档案(RESOURCE.H)。 本文来自织梦

因此,您可以看到这些新档案是如何组织在一起的,让我们以建立名为ICONDEMO的新专案开始。像往常一样,在Developer Studio中从 File 功能表中选择 New ,然後依次选择 专案 页面标签和 Win32 Application 。在 Project Name 栏中键入 ICONDEMO 并单击 OK 。这时,Developer Studio建立了用於支援工作区和专案的五个档案。这些档案包括文字档案ICONDEMO.DSWICONDEMO.DSPICONDEMO.MAK(假设当您从 Tools 功能表选择 Open 後,在显示的 Open 对话方块中,从 Build 页面标签中选中 Export makefile when saving project file )。现在,让我们像通常那样所做的建立C原始码档案。从 File 功能表上选择 New ,选择 Files 页面标签,并单击 C++Source File 。在 File Name 栏中键入ICONDEMO.C并单击 OK 。此时,Developer Studio就建立了一个空的ICONDEMO.C档案。键入程式10-1中的程式,或选择 Insert 功能表,然後选择 File As Text 选项,从本书附上的光碟中复制原始码。 dedecms.com

 程式10-1  ICONDEMO 
copyright dedecms
ICONDEMO.C dedecms.com 
/*-------------------------------------------------------------------------- 
本文来自织梦
        ICONDEMO.C --          Icon Demonstration Program 

织梦好,好织梦

                                              (c) Charles Petzold, 1998 

copyright dedecms

--------------------------------------------------------------------------*/ copyright dedecms 
  

dedecms.com

#include <windows.h> 织梦内容管理系统 
#include "resource.h" 

copyright dedecms

  

内容来自dedecms

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 织梦好,好织梦 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, dedecms.com 
                                                             PSTR szCmdLine, int iCmdShow) 

织梦内容管理系统

{ 
本文来自织梦
        TCHAR                          szAppName[]            = TEXT ("IconDemo") ; 本文来自织梦 
        HWND                           hwnd ; 

织梦好,好织梦

        MSG                            msg ; 
织梦内容管理系统
        WNDCLASS               wndclass ; 

copyright dedecms

  内容来自dedecms 
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; dedecms.com 
        wndclass.lpfnWndProc                          = WndProc ; 

dedecms.com

        wndclass.cbClsExtra                           = 0 ; 
本文来自织梦
        wndclass.cbWndExtra                           = 0 ; 织梦内容管理系统 
        wndclass.hInstance                            = hInstance ; 
织梦内容管理系统
        wndclass.hIcon                                = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ; 

dedecms.com

        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 
织梦内容管理系统
        wndclass.hbrBackground                = GetStockObject (WHITE_BRUSH) ; 

copyright dedecms

        wndclass.lpszMenuName                 = NULL ; 织梦内容管理系统 
        wndclass.lpszClassName                = szAppName ; 
copyright dedecms
        if (!RegisterClass (&wndclass)) 
copyright dedecms
        { 
本文来自织梦
                       MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 

copyright dedecms

                                                                     szAppName, MB_ICONERROR) ; 
织梦内容管理系统
                       return 0 ; 

本文来自织梦

     } 
内容来自dedecms
      
本文来自织梦
        hwnd = CreateWindow (  szAppName, TEXT ("Icon Demo"), 
织梦好,好织梦
                   WS_OVERLAPPEDWINDOW, 

copyright dedecms

                   CW_USEDEFAULT, CW_USEDEFAULT, 
织梦好,好织梦
                   CW_USEDEFAULT, CW_USEDEFAULT, 内容来自dedecms 
                   NULL, NULL, hInstance, NULL) ; 本文来自织梦 
      

dedecms.com

        ShowWindow (hwnd, iCmdShow) ; dedecms.com 
        UpdateWindow (hwnd) ; copyright dedecms 
      内容来自dedecms 
        while (GetMessage (&msg, NULL, 0, 0)) copyright dedecms 
        { 

织梦好,好织梦

                       TranslateMessage (&msg) ; 本文来自织梦 
                       DispatchMessage (&msg) ; 

织梦好,好织梦

        } 织梦内容管理系统 
        return msg.wParam ; 
织梦内容管理系统
} 织梦内容管理系统 
  copyright dedecms 
LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 

织梦好,好织梦

{ 

内容来自dedecms

        static HICON hIcon ; dedecms.com 
        static int   cxIcon, cyIcon, cxClient, cyClient ; 
copyright dedecms
        HDC          hdc ; 织梦内容管理系统 
        HINSTANCE    hInstance ; 
本文来自织梦
        PAINTSTRUCT  ps ; 
织梦好,好织梦
        int          x, y ; 
织梦好,好织梦
      内容来自dedecms 
        switch (message) 

内容来自dedecms

        { copyright dedecms 
        case    WM_CREATE : 

copyright dedecms

                       hInstance      = ((LPCREATESTRUCT) lParam)->hInstance ; 内容来自dedecms 
                       hIcon          = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ; 
织梦好,好织梦
                       cxIcon         = GetSystemMetrics (SM_CXICON) ; 织梦内容管理系统 
                       cyIcon         = GetSystemMetrics (SM_CYICON) ; 
织梦好,好织梦
                       return 0 ; 

dedecms.com

           dedecms.com 
        case    WM_SIZE : 

织梦好,好织梦

                       cxClient               = LOWORD (lParam) ; 

dedecms.com

                       cyClient               = HIWORD (lParam) ; dedecms.com 
                       return 0 ; copyright dedecms 
  

copyright dedecms

        case    WM_PAINT : 
copyright dedecms
                       hdc = BeginPaint (hwnd, &ps) ; 
dedecms.com
           
织梦好,好织梦
                       for (y = 0 ; y < cyClient ; y += cyIcon) copyright dedecms 
                                      for (x = 0 ; x < cxClient ; x += cxIcon) 

dedecms.com

                                                             DrawIcon (hdc, x, y, hIcon) ; 内容来自dedecms 
                
织梦好,好织梦
                                      EndPaint (hwnd, &ps) ; 
织梦内容管理系统
                                      return 0 ; 
copyright dedecms
                

本文来自织梦

        case    WM_DESTROY : 本文来自织梦 
                       PostQuitMessage (0) ; copyright dedecms 
                       return 0 ; 
本文来自织梦
        } 

织梦好,好织梦

        return DefWindowProc (hwnd, message, wParam, lParam) ; 内容来自dedecms 
} 

dedecms.com

如果您试著编译该程式,因为在程式开头引用的RESOURCE.H档案并不存在,所以会产生错误。然而,您不必直接建立RESOURCE.H档案,而是由Developer Studio为您建立一个。 copyright dedecms

您可以通过将资源描述档添加到专案中来做到这一点。从「File」功能表中选择「New」,选择「Files」页面标签,单击「Resource Script」,在「File Name」栏中键入「ICONDEMO」,单击OK。此时,Developer Studio会建立两个文字档案:ICONDEMO.RC(资源描述档)和RESOURCE.H(允许C原始码档案和资源描述档引用相同的已定义识别字)。不必直接编辑这两个档案,只要让Developer Studio来维护它们就可以。如果您想查看资源描述档和RESOURCE.H而不希望对Developer Studio产生干扰,可以用记事本打开它们。除非您对所做的动作很有把握,否则不要轻易地更改它们。请记住,只有在您下达明确的操作命令或重新编译专案时,Developer Studio才会储存这些档案的新版本。 copyright dedecms

资源描述档是文字档案。它包括这些资源的可用文字形式表达的描述,例如功能表和对话方块。资源描述档也包括对非文字资源的二进位档案的引用,例如图示和自订的滑鼠游标。

织梦内容管理系统

现在,已经存在RESOURCE.H档案,您可以试著重新编译一下ICONDEMO。现在会出现一条错误讯息,指出IDI_ICON还没被定义。这个识别字第一次出现在下面的叙述中: copyright dedecms

wndclass.hIcon  = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ; copyright dedecms 

在本书前面的程式中,这个叙述是由下面的叙述代替的:

内容来自dedecms

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; 

本文来自织梦

之所以改变叙述,是因为以前我们为应用程式使用的是标准的图示,而这里我们的目的是使用自订图示。 copyright dedecms

那么让我们建立一个图示吧!在Developer Studio的「File View」视窗中,您会看到两个档案-ICONDEMO.CICONDEMO.RC。您开启CONDEMO.C後,就可以编辑原始码。开启ICONDEMO.RC後,就可以把资源添加到档案中或编辑已存在的资源。要添加图示的话,请从「 Insert 」功能表上选择「 Resource 」选择您想添加的资源,也就是图示,然後再按下「 New 」按钮。

copyright dedecms

现在呈现的是一个空白的32×32图素的图示,您可以在其中填入颜色。您会看到带有一组绘图工具和可用颜色的浮动工具列。注意颜色工具列中包括两个与颜色无关的选项,这两种颜色选项有时被称为「萤幕颜色」跟「反萤幕颜色」。当一个图素在著色时选择了「萤幕颜色」时,它实际上是透明的。不管图示在什么表面上显示,图示未著色的部分会显示出底色。这样我们就可以建立非矩形的图示。

本文来自织梦

双击围绕图示的区域,会出现「Icon Properties」对话方块,该对话方块使您能够更改图示的ID和档案名称。Developer Studio可能已经将ID设定为IDI_ICON1,将它改为IDI_ICON,这样ICONDEMO就可以引用图示(字首IDI代表「图示的ID」)。同样地,将档案名改为ICONDEMO.ICO

织梦好,好织梦

现在选择一种有特色的颜色(如红色)并在图示上画一个大的B(代表BIG),请注意不必像图10-1那么整齐。 dedecms.com


 

copyright dedecms

dedecms.com

 

织梦好,好织梦

10-1 显示在Developer Studio中的标准(32×32ICONDEMO档案

织梦内容管理系统

 

此时程式应该能够编译并执行得很好了。Developer Studio将在ICONDEMO.RC资源描述档中划一条横线,表示下面是带有识别字(IDI_ICON)的图示档案(ICONDEMO.ICO)。RESOURCE.H表头档案中会包含IDI_ICON识别字的定义。

内容来自dedecms

Developer Studio通过资源编译器RC.EXE编译资源。文字资源描述档被转化为二进位形式,也就是具有副档名.RES的档案。然後,该已编译的资源档案随同.OBJ.LIB档案一起在LINK步骤中被指定连结。这就是资源被添加到最後产生出来的.EXE档案中的方式。 织梦内容管理系统

当您执行ICONDEMO时,程式图示显示在标题列的左上角和工作列中。如果您将程式添加到「开始」功能表中,或在桌面上放置捷径,您也会在那儿看到该图示。

dedecms.com

ICONDEMO也在显示区域水平和垂直地重复显示该图示。程式使用叙述 copyright dedecms

hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ; 
copyright dedecms

取得图示的代号。使用叙述

内容来自dedecms

cxIcon = GetSystemMetrics (SM_CXICON) ; 
copyright dedecms
cyIcon = GetSystemMetrics (SM_CYICON) ; 织梦内容管理系统 

取得图示的大小。然後,程式通过多次呼叫

本文来自织梦

DrawIcon (hdc, x, y, hIcon) ; 内容来自dedecms 

显示图示,其中xy是被显示图示其左上角的座标。

copyright dedecms

在目前使用的大多数视讯显示卡上,带有SM_CXICONSM_CYICON索引的GetSystemMetrics会回报图示的大小为32×32图素。这是我们在Developer Studio中建立的图示大小,它也是图示出现在桌面上和显示在ICONDEMO程式显示区域的大小。然而,这个大小并非显示在程式的标题列或工作列中的图示大小。小图示的大小可以由带有SM_CXSMSIZESM_CYSMSIZE索引的GetSystemMetrics获得(第一个SM表示「system metrics(系统度量)」,被包含的SM表示「small(小)」)。对於目前使用的大多数显示卡来说,小图示的大小为16×16图素。

dedecms.com

这会产生问题。当Windows32×32的图示缩小为16×16的图示时,必需减少图素的行和列。这样,对於某些比较复杂的图示,就会失真。因此,我们应该为那些图像缩小就会变形的图示建立特殊的16×16图素的图示。在Developer Studio中图示图像的上面是标识为「Device」的下拉式清单方块,在它的右边有一个按钮,按下该按钮会弹出「New Icon Image」对话方块,此时选择「Small16×16)」。现在您可以画另一个图示。如图10-2所示,画一个「S」(表示「小」)。 copyright dedecms


 

织梦好,好织梦

copyright dedecms

  内容来自dedecms

10-2 Developer Studio中显示的小(16×16ICONDEMO档案

内容来自dedecms

 

在该程式中您不必做任何事情。第二个图示图像被储存在相同的ICONDEMO.ICO档案中,并以相同的IDI_ICON识别字引用。在适当的时候,Windows会自动使用该较小的图示,例如在标题列或工作列中。当在桌面上显示快捷方式,以及程式呼叫DrawIcon装饰显示区域时,Windows会使用大图示。

内容来自dedecms

在掌握这些知识之後,让我们看一看使用图示的详细情况。 织梦内容管理系统

取得图示代号
  内容来自dedecms

如果您仔细阅读ICONDEMO.RCRESOURCE.H档案,会看到由Developer Studio产生用於维护档案的一些标记。然而,当编译资源描述档时,只有少数几行是重要的。这些从ICONDEMO.RCRESOURCE.H档案中摘录下来的关键部分被列在程式10-2中。

织梦好,好织梦

ICONDEMO.RC (摘录) 本文来自织梦 
//Microsoft Developer Studio generated resource script. 

织梦内容管理系统

#include "resource.h" 

织梦内容管理系统

#include "afxres.h" 织梦内容管理系统 
  

织梦好,好织梦

///////////////////////////////////////////////////////////////////////////// 

copyright dedecms

// Icon 内容来自dedecms 
IDI_ICON                       ICON    DISCARDABLE     "icondemo.ico" 

dedecms.com

RESOURCE.H (摘录) 本文来自织梦 
// Microsoft Developer Studio generated include file. copyright dedecms 
// Used by IconDemo.rc 
dedecms.com
  内容来自dedecms 
#define IDI_ICON       101 内容来自dedecms 

  织梦内容管理系统

程式10-2 ICONDEMO.RCRESOURCE.H档案的摘录

内容来自dedecms

 

程式10-2所显示的ICONDEMO.RCRESOURCE.H档案与您在普通的文字编辑器中手动建立的很相似,80年代的Windows程式写作者就是这样做的。唯一不同的是AFXRES.H,它是个表头档案,包含了在建立由机器产生的MFC专案时由Developer Studio使用的常用识别字。在本书中,我们不会用到AFXRES.H

dedecms.com

ICONDEMO.RC中的这行 内容来自dedecms

IDI_ICON ICON DISCARDABLE "icondemo.ico" 
织梦内容管理系统

是资源描述档的ICON叙述。该图示有一个数值识别字IDI_ICON,等於101。由Developer Studio添加的DISCARDABLE关键字指出,必要时Windows可以从记忆体中丢弃图示,以获得额外的空间。之後不需要程式任何特定的操作,Windows就能够重新载入图示。DISCARDABLE属性是内定的,不需要指定。只有在名称和目录路径包含空格时,Developer Studio才将档案名加上引号。

织梦好,好织梦

当资源编译程序将编译的资源储存在ICONDEMO.RES中,并且由连结程式将资源添加到ICONDEMO.EXE中以後,该资源就可以经由一个资源型态(RT_ICON)和一个识别字(IDI_ICON101)来标识。程式可以通过呼叫LoadIcon函式取得此图示的代号: 内容来自dedecms

hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON)) ; 

copyright dedecms

请注意ICONDEMO在两个地方呼叫这个函式,一次在定义视窗类别时,另一次在视窗讯息处理程式中取得图示的代号用於绘制。LoadIcon传回HICON型态的值,它是图示的代号。

本文来自织梦

LoadIcon的第一个参数,是指出资源来自哪个档案的执行实体代号。使用hInstance表示它来自程式自己的.EXE档案。LoadIcon的第二个参数实际上被定义为指向字串的指标。待会将会看到,可以使用字串而不是用数值识别字标识资源。巨集MAKEINTRESOURCE(把整数转换成资源字串)生成指向非数字的指标,如下所示:

copyright dedecms

#define MAKEINTRESOURCE(i)  (LPTSTR) ((DWORD) ((WORD) (i))) dedecms.com 

LoadIcon知道,如果第二个参数的高字组为0,那么低字组就为图示的数值识别字。图示的识别字必须为16位元值。

织梦内容管理系统

本书前面的范例程式使用了预先定义的图示: copyright dedecms

LoadIcon (NULL, IDI_APPLICATION) ; 织梦内容管理系统 

hInstance参数被设定为NULL,因此Windows知道这是预先定义的图示。IDI_APPLICATION也在WINUSER.H中用MAKEINTRESOURCE定义: 内容来自dedecms

#define IDI_APPLICATION MAKEINTRESOURCE(32512) 

织梦内容管理系统

LoadIcon的第二个参数带来了一个有趣的问题:图示的识别字能可以为字串吗?答案是可以。方法如下:在 Developer Studio 中,在 ICONDEMO 专案的档案列表上,选择 IDONDEMO.RC 。您会看到顶端为「IconDemo Resource」的树状结构,然後是资源型态「Icon」,再下来是「IDI_ICON」。如果用滑鼠右键单击图示识别字,并从功能表上选择「 Properties 」,您就能改变ID。实际上,您可以把名称放在引号内将其更改为字串。我用这种方法指定资源名称,并在本书的其他地方也使用该方法。 织梦好,好织梦

我喜欢为图示(以及一些其他资源)使用文字名称,因为名称可以是程式的名称。例如,假定档案被命名为MYPROG。如果您使用「Icon Properties」对话方块将图示的ID指定为「MyProg」(包括引号),资源描述档将包含下列叙述:

本文来自织梦

MYPROG ICON DISCARDABLE myprog.ico 
本文来自织梦

然而,在RESOURCE.H中并没有#define叙述,来指出MYPROG是数值识别字。资源描述档将假定MYPROG是字串识别字。 内容来自dedecms

C程式中,使用LoadIcon函式来取得图示代号。您可能已经有了表示程式名的字串: 内容来自dedecms

static TCHAR szAppName [] = TEXT ("MyProg") ; 
copyright dedecms

这意味著程式可以使用叙述:

copyright dedecms

hIcon = LoadIcon (hInstance, szAppName) ; 
织梦内容管理系统

来载入图示,这比巨集MAKEINTRESOURCE更清晰一些。

dedecms.com

但是如果您确实想用数字来命名,那么您可以用数字代替识别字或字串。在「Icon Properties」对话方块中,在ID栏中输入数字。资源描述档将有一个类似下面的ICON叙述: 本文来自织梦

125 ICON DISCARDABLE myprog.ico 织梦内容管理系统 

可以使用两种方法之一引用图示。明显易读的方式是: 织梦好,好织梦

hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (125)) ; 

本文来自织梦

另一个不易阅读的方式是:

内容来自dedecms

hIcon = LoadIcon (hInstance, TEXT ("#125")) ; 
copyright dedecms

Windows识别初始字元#作为ASCII形式中字元数值的开头。

内容来自dedecms

在程式中使用图示
 

内容来自dedecms

虽然Windows以几种方式用图示来代表程式,但是许多Windows程式仅在用WNDCLASS结构和RegisterClass定义视窗类别时指定一个图示。如我们所看到的,这样作用得很好,尤其当图示档案包含标准和较小的图像大小时,更是如此。Windows在显示图示图像时,它会在图示档案中选择最合适的图像大小。

dedecms.com

RegisterClass有一个改进版本叫做RegisterClassEx,它使用名为WNDCLASSEX的结构。WNDCLASSEX有两个附加的栏位:cbSizehIconSmcbSize栏位指出了WNDCLASSEX结构的大小,假设hIconSm被设定为小图示的图示代号。这样,在WNDCLASSEX结构中,您可以设定与两个图示档案相关的两个图示代号-一个用於标准图示,一个用於小图示。 织梦内容管理系统

有这种必要吗?没有。正如我们看到的,Windows已经从单个图示档案中提取了大小合适的图示图像。RegisterClassEx似乎没有RegisterClass聪明。如果hIconSm栏位使用了包含多个图像的图示档案,则只有第一个图像能被利用。它可能是标准大小的图示,使用时才被缩小。RegisterClassEx似乎是为了使用多个图示图像而设计的,每个图像只包含一种图示大小。因为现在可以将多个图示大小包括在同一个图示档案中,所以我建议使用WNDCLASSRegisterClass

copyright dedecms

如果您想在程式执行的时候,动态地更改程式的图示,可以使用SetClassLong来达到目的。例如,如果您有与识别字IDI_ALTICON相关的第二个图示档案,则您可以使用以下的叙述将其切换到那个图示: 本文来自织梦

SetClassLong (hwnd, GCL_HICON,  
织梦好,好织梦
     LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ALTICON))) ; 
织梦好,好织梦

如果不想储存程式图示的代号,但要使用DrawIcon函式在别处显示它,可以使用GetClassLong获得代号。例如: 本文来自织梦

DrawIcon (hdc, x, y, GetClassLong (hwnd, GCL_HICON)) ; 

内容来自dedecms

Windows文件的某些部分,LoadIcon被称为「过时的」,并推荐使用LoadImageLoadIcon/Platform SDK/User Interface Services/Resources/Icons中说明,LoadImage/Platform SDK/User Interface Services/Resources/Resources中说明)。当然LoadImage更为灵活,但它没有LoadIcon简单。您会注意到,在ICONDEMO中对同一个图示呼叫了LoadIcon两次。这不会产生问题,也没有使用额外的记忆体。LoadIcon是取得代号但不需要清除代号的少数几个函式之一。实际上有一个DestroyIcon函式,但它与CreateIconCreateIconIndirectCreateIconFromResource连在一起使用。这些函式使程式能够动态地建立图示图像。 本文来自织梦

使用自订游标
  织梦内容管理系统

在程式中使用自订的滑鼠游标与使用自订的图示相似,只是大多数程式写作者总是使用Windows提供的游标。自订游标一般为单色,大小为32×32图素。在Developer Studio中建立游标与建立图示的方法相同(从「 Insert 」功能表上选择「 Resource 」,然後单击「 Cursor 」),但不要忘记定义热点。

copyright dedecms

可以在物件类别定义中设定自订游标,叙述为: 本文来自织梦

wndclass.hCursor = LoadCursor (hInstance, MAKEINTRESOURCE (IDC_CURSOR)) ; 

本文来自织梦

如果游标用文字名称定义,则为: 织梦内容管理系统

wndclass.hCursor = LoadCursor (hInstance, szCursor) ; copyright dedecms 

每当滑鼠位於根据这个类别建立的视窗上时,就会显示与IDC_CURSORszCursor相对应的滑鼠游标。

内容来自dedecms

如果使用了子视窗,那么您可能希望游标随著所在视窗的不同而有所区别。如果程式为这些子视窗定义了视窗类别,就可以在每个视窗类别中适当地设定hCursor栏位,让每个视窗类别使用不同的游标。如果使用了预先定义的子视窗控制项,就可以使用以下方法改变视窗类别的hCursor栏位:

dedecms.com

SetClassLong (hwndChild, GCL_HCURSOR, dedecms.com 
        LoadCursor (hInstance, TEXT ("childcursor")) ; 

织梦好,好织梦

如果您将显示区域划分为较小的逻辑区域而不使用子视窗,就可以使用SetCursor来改变滑鼠游标:

织梦内容管理系统

SetCursor (hCursor) ; 内容来自dedecms 

在处理WM_MOUSEMOVE讯息处理期间,您应该呼叫SetCursor;否则,当游标移动时,Windows将使用视窗类别中定义的游标来重画游标。文件指出,如果没有改变游标,则SetCursor速度将会很快。

织梦内容管理系统

字串资源
  copyright dedecms

把字串当成资源的观念一开始可能令人觉得诡异。因为我们在使用原始码中定义为变数的一般字串时,并没有碰到任何问题。 织梦内容管理系统

字串资源主要是为了让程式转换成其他语言时更为方便。正如後面两章中将看到的一样,功能表和对话方块也是资源描述档的一部分。如果使用字串资源而不是将字串直接放入原始码中,那么程式所使用的所有文字将在同一档案-资源描述档中。如果转换了资源描述档中的文字,那么建立程式的另一种语言版本所需做的一切就是重新连结程式。这种方法比重新组织原始码安全得多(然而,除了下一个范例程式,我在本书的其他程式中不使用字串表,原因是字串表使程式码看起来更为模糊和复杂)。

dedecms.com

您可以在「 Insert 」功能表中选择「 Resource 」,再选择「 String Table 」,建立一个字串表。字串会显示在萤幕右边的列表中。通过双击字串就可以选中它。针对每个字串,您可以指定识别字和字串的内容。 copyright dedecms

在资源描述中,字串显示在一个多行的叙述中,如下所示:

本文来自织梦

STRINGTABLE DISCARDABLE 
copyright dedecms
BEGIN 织梦好,好织梦 
        IDS_STRING1, "character string 1" 织梦内容管理系统 
        IDS_STRING2, "character string 2" 本文来自织梦 
        其他字串定义 

织梦内容管理系统

END copyright dedecms 

如果您在替早期版本的Windows写程式,并在文字编辑器中手动建立这个字串表(用Developer Studio来做这件事当然更容易得多了),您可以用左右大括弧代替BEGINEND叙述。

织梦好,好织梦

资源描述可以包含多个字串表,但是每个ID必须唯一表示一个字串。每个字串占一行,最多4097个字元。\t可以作为跳位字元,\n则作为linefeed字元号。DrawTextMessageBox函式能够识别这些控制符号。 本文来自织梦

您的程式可以使用LoadString呼叫把字串复制到程式资料段的缓冲区中: dedecms.com

LoadString (hInstance, id, szBuffer, iMaxLength) ; 
内容来自dedecms

参数idID,它加在资源描述档中每个字串的前面;szBuffer是指向接收字串的字元阵列的指标;iMaxLength是送入szBuffer中的最大字元数。函式传回字串中的字元数。 内容来自dedecms

每个字串前面的ID一般是定义在表头档案中的巨集识别字。许多Windows程式写作者使用字首IDS_ 来表示字串的ID。有时,档案名称或其他资讯需要在字串显示时插入到字串中。在这种情况下,您可以将C的格式化字元放入字串,并把它用於wsprintf中作为一个格式化字串。 dedecms.com

所有资源文字-包括字串表中的文字-以Unicode格式储存在.RES编译资源档案以及最终的.EXE档案中。LoadStringW函式直接载入Unicode文字。LoadStringA函式(仅在Windows 98下有效)完成由Unicode到本地内码表的文字转换。 织梦内容管理系统

让我们来看一个程式,它使用三个字串,在讯息方块中显示三条错误资讯。RESOURCE.H表头档案为这些资讯定义了三个识别字:

织梦内容管理系统

#define IDS_FILENOTFOUND              1 织梦内容管理系统 
#define IDS_FILETOOBIG                    2 
dedecms.com
#define IDS_FILEREADONLY              3 本文来自织梦 

资源描述档具有此字串表: dedecms.com

STRINGTABLE 织梦内容管理系统 
BEGIN 本文来自织梦 
        IDS_FILENOTFOUND,                  "File %s not found." 

copyright dedecms

        IDS_FILETOOBIG,                       "File %s too large to edit." 
内容来自dedecms
        IDS_FILEREADONLY,                     "File %s is read-only." 
织梦内容管理系统
END dedecms.com 

C原始码档案也包含这个表头档案,并定义了一个显示讯息方块的函式(我假定szAppName是一个包含程式名称的整体变数)。

内容来自dedecms

OkMessage (HWND hwnd, int iErrorNumber, TCHAR *szFileName) copyright dedecms 
{ 织梦好,好织梦 
        TCHAR szFormat [40] ; 
本文来自织梦
        TCHAR szBuffer [60] ; 
织梦好,好织梦
  
copyright dedecms
        LoadString (hInst, iErrorNumber, szFormat, 40) ; 织梦好,好织梦 
        wsprintf (szBuffer, szFormat, szFilename) ; copyright dedecms 
  

本文来自织梦

        return MessageBox (    hwnd, szBuffer, szAppName, 

织梦内容管理系统

                                                             MB_OK | MB_ICONEXCLAMATION) ; copyright dedecms 
} 

织梦好,好织梦

为了显示包含「file not found」资讯的讯息方块,程式呼叫: copyright dedecms

OkMessage (hwnd, IDS_FILENOTFOUND, szFileName) ; 
dedecms.com

自订的资源
 

本文来自织梦

Windows也定义了「自订资源」,这又称为「使用者定义的资源」(使用者就是您-程式写作者,而不是那个使用您程式的幸运者)。自订资源让连结.EXE档案中的各种资料更为方便,对取得程式中的资料也是如此。资料可以是您需要的任何格式。程式用於存取自订资源的Windows函式促使Windows将资料载入记忆体并传回指向它的指标。然後您就可以对程式做任何操作。您会发现对於储存和存取各种自己的资料,这要比把资料储存在外部档案中,再使用档案输入函式存取它要方便得多。 本文来自织梦

例如,您有一个档案叫做BINDATA.BIN,它包含程式需要显示的一些资料。您可以选择这个档案的格式。如果在MYPROG专案中有MYPROG.RC资源描述档,您就可以在Developer Studio中从「 Insert 」功能表中选择「 Resource 」并按「 Custom 」按钮,来建立自订的资源。键入表示资源的名称:例如,BINTYPE。然後,Developer Studio会生成资源名称(在这种情况下是IDR_BINTYPE1)并显示让您输入二进位资料的视窗。但是您不必输入什么,用滑鼠右键单击IDR_BINTYPE1名称,并选择 Properties ,然後就可以输入一个档案名称:例如,BINDATA.BIN

内容来自dedecms

资源描述档就会包含以下的一行叙述: 本文来自织梦

IDR_BINTYPE1 BINTYPE BINDATA.BIN 

织梦好,好织梦

除了我们刚刚生成的BINTYPET资源型态外,这个叙述与ICONDEMO中的ICON叙述一样。有了图示後,您可以对资源名称使用文字的名称,而不是数字的识别字。 dedecms.com

当您编译并连结程式,整个BINDATA.BIN档案会被并入MYPROG.EXE档案中。

dedecms.com

在程式的初始化(比如,在处理WM_CREATE讯息时)期间,您可以获得资源的代号:

dedecms.com

hResource =    LoadResource (hInstance, 本文来自织梦 
                       FindResource (hInstance, TEXT ("BINTYPE"),  

内容来自dedecms

                                                                     MAKEINTRESOURCE (IDR_BINTYPE1))) ; 

copyright dedecms

变数hResource定义为HGLOBAL型态,它是指向记忆体区块的代号。不管它的名称是什么,LoadResource不会立即将资源载入记忆体。把LoadResourceFindResource函式如上例般合在一起使用,在实质上就类似於LoadIconLoadCursor函式的做法。事实上,LoadIconLoadCursor函式就用到了LoadResourceFindResource函式。 dedecms.com

当您需要存取文字时,呼叫LockResource

dedecms.com

pData = LockResource (hResource) ; copyright dedecms 

LockResource将资源载入记忆体(如果还没有载入的话),然後它会传回一个指向资源的指标。当结束对资源的使用时,您可以从记忆体中释放它:

织梦好,好织梦

FreeResource (hResource) ; copyright dedecms 

当您的程式终止时,也会释放资源,即使您没有呼叫FreeResource.内容来自dedecms

让我们看一个使用三种资源-一个图示、一个字串表和一个自订的资源-的范例程式。程式10-3所示的POEPOEM程式在其显示区域显示Edgar Allan Poe的「Annabel Lee」文字。自订的资源是档案POEPOEM.TXT,它包含了一段诗文,此文字档案以反斜线(\)结束。 织梦好,好织梦

 程式10-3  POEPOEM 

内容来自dedecms

POEPOEM.C 

织梦好,好织梦

/*--------------------------------------------------------------------------- copyright dedecms 
   POEPOEM.C -- Demonstrates Custom Resource 

本文来自织梦

                                      (c) Charles Petzold, 1998 
dedecms.com
----------------------------------------------------------------------------*/ 本文来自织梦 
  
织梦好,好织梦
#include <windows.h> dedecms.com 
#include "resource.h" 
织梦好,好织梦
  dedecms.com 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 
本文来自织梦
HINSTANCE hInst ; 织梦好,好织梦 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
dedecms.com
                                              PSTR szCmdLine, int iCmdShow) 

内容来自dedecms

{ 

织梦好,好织梦

        TCHAR                  szAppName [16], szCaption [64], szErrMsg [64] ; dedecms.com 
        HWND                   hwnd ; 
本文来自织梦
        MSG                    msg ; 
织梦内容管理系统
        WNDCLASS               wndclass ; 内容来自dedecms 
      
织梦好,好织梦
        LoadString (   hInstance, IDS_APPNAME, szAppName,  copyright dedecms 
                                      sizeof (szAppName) / sizeof (TCHAR)) ; 

织梦内容管理系统

  
内容来自dedecms
        LoadString (   hInstance, IDS_CAPTION, szCaption,  内容来自dedecms 
                                      sizeof (szCaption) / sizeof (TCHAR)) ; 
织梦内容管理系统
         
dedecms.com
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 

内容来自dedecms

        wndclass.lpfnWndProc                          = WndProc ; 

织梦好,好织梦

        wndclass.cbClsExtra                           = 0 ; 织梦内容管理系统 
        wndclass.cbWndExtra                           = 0 ; 织梦好,好织梦 
        wndclass.hInstance                    = hInstance ; 本文来自织梦 
        wndclass.hIcon                        = LoadIcon (hInstance, szAppName) ; 

copyright dedecms

        wndclass.hCursor                      = LoadCursor (NULL, IDC_ARROW) ; 内容来自dedecms 
        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
织梦好,好织梦
        wndclass.lpszMenuName                 = NULL ; 

本文来自织梦

        wndclass.lpszClassName                = szAppName ; 

织梦内容管理系统

      dedecms.com 
        if (!RegisterClass (&wndclass)) 
织梦内容管理系统
        { 本文来自织梦 
               LoadStringA (hInstance, IDS_APPNAME, (char *) szAppName,  

织梦好,好织梦

                                                                     sizeof (szAppName)) ; 

织梦内容管理系统

               LoadStringA (hInstance, IDS_ERRMSG, (char *) szErrMsg,  本文来自织梦 
                                                                     sizeof (szErrMsg)) ; 内容来自dedecms 
               MessageBoxA (NULL, (char *) szErrMsg,  本文来自织梦 
                                                             (char *) szAppName, MB_ICONERROR) ; copyright dedecms 
               return 0 ; 

织梦好,好织梦

        } 织梦好,好织梦 
      
dedecms.com
        hwnd = CreateWindow (  szAppName, szCaption, copyright dedecms 
                     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 

copyright dedecms

                     CW_USEDEFAULT, CW_USEDEFAULT, 内容来自dedecms 
                     CW_USEDEFAULT, CW_USEDEFAULT, 

dedecms.com

                     NULL, NULL, hInstance, NULL) ; 本文来自织梦 
      copyright dedecms 
        ShowWindow (hwnd, iCmdShow) ; 织梦好,好织梦 
        UpdateWindow (hwnd) ; 

dedecms.com

      本文来自织梦 
        while (GetMessage (&msg, NULL, 0, 0)) 

copyright dedecms

     { 
本文来自织梦
                       TranslateMessage (&msg) ; 本文来自织梦 
                       DispatchMessage (&msg) ; 

dedecms.com

        } copyright dedecms 
        return msg.wParam ; 

内容来自dedecms

} 内容来自dedecms 
  

dedecms.com

LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 织梦内容管理系统 
{ copyright dedecms 
        static char                    * pText ; 本文来自织梦 
        static HGLOBAL         hResource ; dedecms.com 
        static HWND                    hScroll ; 织梦内容管理系统 
        static int                            iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll ; 

本文来自织梦

        HDC                                   hdc ; 
织梦内容管理系统
        PAINTSTRUCT                           ps ; 
dedecms.com
        RECT                                  rect ; 本文来自织梦 
        TEXTMETRIC                            tm ; dedecms.com 
  

内容来自dedecms

        switch (message) copyright dedecms 
        { 内容来自dedecms 
        case WM_CREATE : 内容来自dedecms 
                       hdc                    = GetDC (hwnd) ; 

copyright dedecms

                       GetTextMetrics (hdc, &tm) ; 织梦内容管理系统 
                       cxChar         = tm.tmAveCharWidth ; 
本文来自织梦
                       cyChar         = tm.tmHeight + tm.tmExternalLeading ; 

织梦内容管理系统

                       ReleaseDC (hwnd, hdc) ; 本文来自织梦 
           织梦好,好织梦 
                       xScroll                = GetSystemMetrics (SM_CXVSCROLL) ; 
dedecms.com
                       hScroll                = CreateWindow (TEXT ("scrollbar"), NULL, 
织梦内容管理系统
                                  WS_CHILD | WS_VISIBLE | SBS_VERT, 
本文来自织梦
                                  0, 0, 0, 0, 
织梦好,好织梦
                hwnd, (HMENU) 1, hInst, NULL) ; 内容来自dedecms 
           

织梦好,好织梦

                       hResource =    LoadResource (hInst,  copyright dedecms 
                FindResource (hInst, TEXT ("AnnabelLee"), 
内容来自dedecms
                                        TEXT ("TEXT"))) ; 织梦内容管理系统 
           
本文来自织梦
                       pText = (char *) LockResource (hResource) ; 
内容来自dedecms
                      iNumLines = 0 ; 织梦内容管理系统 
           织梦内容管理系统 
                       while (*pText != '\\' && *pText != '\0') 织梦好,好织梦 
                       { 

织梦内容管理系统

                       if (*pText == '\n') 织梦好,好织梦 
                                              iNumLines ++ ; dedecms.com 
                       pText = AnsiNext (pText) ; 
dedecms.com
                       } 
内容来自dedecms
                       *pText = '\0' ; 
织梦好,好织梦
           copyright dedecms 
                       SetScrollRange (hScroll, SB_CTL, 0, iNumLines, FALSE) ; 本文来自织梦 
                       SetScrollPos   (hScroll, SB_CTL, 0, FALSE) ; 织梦内容管理系统 
                       return 0 ; 内容来自dedecms 
           
织梦好,好织梦
        case    WM_SIZE : 织梦内容管理系统 
                       MoveWindow (hScroll, LOWORD (lParam) - xScroll, 0, 

copyright dedecms

                xScroll, cyClient = HIWORD (lParam), TRUE) ; 

本文来自织梦

                       SetFocus (hwnd) ; 

dedecms.com

                       return 0 ; 
本文来自织梦
           织梦内容管理系统 
        case    WM_SETFOCUS : 本文来自织梦 
                       SetFocus (hScroll) ; 
copyright dedecms
                       return 0 ; 

内容来自dedecms

           

dedecms.com

        case    WM_VSCROLL : 内容来自dedecms 
                       switch (wParam) 织梦好,好织梦 
                       { 

本文来自织梦

                       case    SB_TOP : 

内容来自dedecms

                                      iPosition = 0 ; 

织梦好,好织梦

                                      break ; 
织梦内容管理系统
                       case    SB_BOTTOM : 
copyright dedecms
                                      iPosition = iNumLines ; 

内容来自dedecms

                                      break ; 内容来自dedecms 
                       case    SB_LINEUP : 

dedecms.com

                                      iPosition -= 1 ; dedecms.com 
                                      break ; 
内容来自dedecms
                       case    SB_LINEDOWN : 
dedecms.com
                                      iPosition += 1 ; 本文来自织梦 
                                      break ; 织梦内容管理系统 
                       case    SB_PAGEUP : 

copyright dedecms

                                      iPosition -= cyClient / cyChar ; dedecms.com 
                                      break ; 本文来自织梦 
                       case    SB_PAGEDOWN : dedecms.com 
                                      iPosition += cyClient / cyChar ; 织梦内容管理系统 
                                      break ; 内容来自dedecms 
                       case    SB_THUMBPOSITION : 内容来自dedecms 
                                      iPosition = LOWORD (lParam) ; 
dedecms.com
                                      break ; 
copyright dedecms
                       } 

copyright dedecms

                       iPosition = max (0, min (iPosition, iNumLines)) ; dedecms.com 
           本文来自织梦 
                       if (iPosition != GetScrollPos (hScroll, SB_CTL)) 

本文来自织梦

                       { 

dedecms.com

                                      SetScrollPos (hScroll, SB_CTL, iPosition, TRUE) ; copyright dedecms 
                                      InvalidateRect (hwnd, NULL, TRUE) ; dedecms.com 
                       } dedecms.com 
                       return 0 ; 

copyright dedecms

           
内容来自dedecms
        case    WM_PAINT : 
dedecms.com
                       hdc = BeginPaint (hwnd, &ps) ; 

dedecms.com

                

本文来自织梦

                       pText = (char *) LockResource (hResource) ; 内容来自dedecms 
                
内容来自dedecms
                       GetClientRect (hwnd, &rect) ; 织梦好,好织梦 
                       rect.left += cxChar ; 

织梦内容管理系统

                       rect.top  += cyChar * (1 - iPosition) ; 本文来自织梦 
                       DrawTextA (hdc, pText, -1, &rect, DT_EXTERNALLEADING) ; 
织梦好,好织梦
  
本文来自织梦
                       EndPaint (hwnd, &ps) ; 织梦好,好织梦 
                       return 0 ; 

织梦好,好织梦

                织梦内容管理系统 
        case    WM_DESTROY : 本文来自织梦 
                       FreeResource (hResource) ; 内容来自dedecms 
                       PostQuitMessage (0) ; 

织梦好,好织梦

                       return 0 ; 
copyright dedecms
        } 

本文来自织梦

        return DefWindowProc (hwnd, message, wParam, lParam) ; 

dedecms.com

} 

织梦好,好织梦

 POEPOEM.RC (摘录) 

copyright dedecms

//Microsoft Developer Studio generated resource script. 
织梦好,好织梦
#include "resource.h" 
dedecms.com
#include "afxres.h" 本文来自织梦 
  本文来自织梦 
///////////////////////////////////////////////////////////////////////////// 本文来自织梦 
// TEXT copyright dedecms 
ANNABELLEE                                    TEXT    DISCARDABLE     "poepoem.txt" 本文来自织梦 
  织梦内容管理系统 
///////////////////////////////////////////////////////////////////////////// copyright dedecms 
// Icon 
内容来自dedecms
POEPOEM                                       ICON    DISCARDABLE     "poepoem.ico" 织梦好,好织梦 
  
dedecms.com
///////////////////////////////////////////////////////////////////////////// copyright dedecms 
// String Table 织梦内容管理系统 
STRINGTABLE DISCARDABLE  
织梦好,好织梦
BEGIN 
本文来自织梦
        IDS_APPNAME         "PoePoem" 内容来自dedecms 
        IDS_CAPTION         """Annabel Lee"" by Edgar Allan Poe" 内容来自dedecms 
    IDS_ERRMSG              "This program requires Windows NT!" 

织梦内容管理系统

END 
织梦内容管理系统
 RESOURCE.H (摘录) 织梦好,好织梦 
// Microsoft Developer Studio generated include file. dedecms.com 
// Used by PoePoem.rc 织梦好,好织梦 
  
织梦好,好织梦
#define IDS_APPNAME   1 织梦好,好织梦 
#define IDS_CAPTION   2 

copyright dedecms

#define IDS_ERRMSG    3 
copyright dedecms
 POEPOEM.TXT 内容来自dedecms 
It was many and many a year ago, 

织梦内容管理系统

   In a kingdom by the sea, 织梦内容管理系统 
That a maiden there lived whom you may know 

内容来自dedecms

By the name of Annabel Lee; 
织梦内容管理系统
And this maiden she lived with no other thought 内容来自dedecms 
   Than to love and be loved by me. 
copyright dedecms
I was a child and she was a child 

dedecms.com

   In this kingdom by the sea, copyright dedecms 
But we loved with a love that was more than love -- 织梦好,好织梦 
   I and my Annabel Lee -- 

织梦好,好织梦

With a love that the winged seraphs of Heaven 
本文来自织梦
   Coveted her and me. dedecms.com 
And this was the reason that, long ago, 

织梦内容管理系统

   In this kingdom by the sea, 
本文来自织梦
A wind blew out of a cloud, chilling copyright dedecms 
   My beautiful Annabel Lee; 
织梦好,好织梦
So that her highborn kinsmen came 织梦内容管理系统 
   And bore her away from me, 

织梦内容管理系统

To shut her up in a sepulchre 
copyright dedecms
   In this kingdom by the sea. 

copyright dedecms

The angels, not half so happy in Heaven, 织梦好,好织梦 
   Went envying her and me -- 

内容来自dedecms

Yes! that was the reason (as all men know, 
本文来自织梦
   In this kingdom by the sea) 
织梦好,好织梦
That the wind came out of the cloud by night, 内容来自dedecms 
   Chilling and killing my Annabel Lee. 
copyright dedecms
But our love it was stronger by far than the love Of those who were older than we -- Of many far wiser than we -- 织梦内容管理系统 
And neither the angels in Heaven above dedecms.com 
   Nor the demons down under the sea 

本文来自织梦

Can ever dissever my soul from the soul copyright dedecms 
   Of the beautiful Annabel Lee: 本文来自织梦 
For the moon never beams, without bringing me dreams 

dedecms.com

   Of the beautiful Annabel Lee; 

本文来自织梦

And the stars never rise, but I feel the bright eyes dedecms.com 
   Of the beautiful Annabel Lee: 

织梦内容管理系统

And so, all the night-tide, I lie down by the side dedecms.com 
Of my darling -- my darling -- my life and my bride, copyright dedecms 
   In her sepulchre there by the sea -- 

内容来自dedecms

   In her tomb by the sounding sea. 内容来自dedecms 
 

dedecms.com

   [May, 1849] 

dedecms.com

\ dedecms.com 

 

本文来自织梦

POEPOEM.ICO 织梦好,好织梦

 


 

copyright dedecms

dedecms.com

POEPOEM.RC资源描述档中,使用者定义的资源被定义为TEXT型态,取名为AnnabelLee织梦内容管理系统

ANNABELLEE  TEXT  POEPOEM.TXT 
织梦好,好织梦

WndProc处理WM_CREATE时,使用FindResourceLoadResource取得资源代号。使用LockResource锁定资源,并且使用一个小程式将档案末尾的反斜线(\)换成0,这有利於後面WM_PAINT讯息处理期间使用的DrawText函式。 织梦内容管理系统

注意,这里使用的是子视窗的卷动列,而不是视窗卷动列,这是因为子视窗卷动列有一个自动的键盘介面,因此在POEPOEM中没有处理WM_KEYDOWN本文来自织梦

POEPOEM还使用三个字串,它们的IDRESOURCE.H表头档案中定义。在程式的开始,IDS_APPNAMEIDS_CAPTIONPOEPOEM字串由LoadString载入记忆体: 织梦内容管理系统

LoadString (hInstance, IDS_APPNAME, szAppName,       sizeof (szAppName) /  copyright dedecms 
                                              sizeof (TCHAR)) ; 
织梦好,好织梦
  copyright dedecms 
LoadString (hInstance, IDS_CAPTION, szCaption,       sizeof (szCaption) / dedecms.com 
                                              sizeof (TCHAR)) ; 本文来自织梦 

注意RegisterClass前面的两个呼叫。如果您在Windows 98下执行Unicode版本的POEPOEM,这两个呼叫就都会失败。因此,LoadStringALoadStringW要复杂得多(LoadStringA必须将资源字串由Unicode转化为ANSI,而LoadStringW仅是直接载入它),LoadStringWWindows 98下不被支援。这意味著在Windows 98下,当RegisterClassW函式失败时,MessageBoxW函式(Windows 98支援)就不能使用LoadStringW载入程式的字串。由於这个原因,程式使用LoadStringA载入IDS_APPNAMEIDS_ERRMSG字串,并使用MessageBoxA显示自订的讯息方块:

本文来自织梦

if (!RegisterClass (&wndclass)) 
copyright dedecms
{ 

copyright dedecms

        LoadStringA (hInstance, IDS_APPNAME, (char *) szAppName,  

织梦内容管理系统

                     sizeof (szAppName)) ; copyright dedecms 
        LoadStringA (hInstance, IDS_ERRMSG, (char *) szErrMsg,  
内容来自dedecms
                     sizeof (szErrMsg)) ; copyright dedecms 
        MessageBoxA (NULL, (char *) szErrMsg,  
本文来自织梦
                     (char *) szAppName, MB_ICONERROR) ; 

dedecms.com

        return 0 ; 本文来自织梦 
} 内容来自dedecms 

注意,TCHAR字串变数是指向char的指标。

本文来自织梦

既然我们已经定义了用於POEPOEM的所有字串资源,那么翻译者将程式转换成外语版本就很容易了。当然,它们将不得不翻译「Annabel Lee」这个名字-我想,这会是一项困难得多的工作。 织梦内容管理系统

功能表
 

dedecms.com

您还记得Monty Python有关乳酪店的幽默短剧吗?那故事内容是这样的:一个客人走进乳酪店想买某种乳酪。当然,店里没有这种乳酪。因此他又问有没有另一种乳酪,然後再问另一种,再问另一种,不断的问店家有没有另一种乳酪(最後总共问了40种的乳酪),回答仍然是没有,没有,没有,没有,没有。 copyright dedecms

这个不幸的事件可以通过功能表的使用来避免。一个功能表是一列可用的选项,它告诉饥饿的用餐者,厨房可以提供哪些服务,并且-对於Windows程式来说-还告诉使用者一个应用程式能够执行哪些操作。

本文来自织梦

功能表可能是Windows程式提供的一致使用者介面中最重要的部分,而在您的程式中增加功能表,是Windows程式设计中相对简单的部分。您在Developer Studio中定义功能表。每个可选的功能表项被赋予唯一的ID。您在视窗类别结构中指定功能表名称。当使用者选择一个功能表项时,Windows给您的程式发送包含该IDWM_COMMAND讯息。

copyright dedecms

讨论完功能表後,我还将讨论键盘加速键,它们是一些键的组合,主要用於启动功能表功能。

织梦好,好织梦

功能表概念
  织梦内容管理系统

视窗的功能表列紧接在标题列的下方显示,这个功能表列有时被称为「主功能表」或「顶层功能表」。列在顶层功能表的项目通常是下拉式功能表,也叫做「突现式功能表」或「子功能表」。您也可以定义多重嵌套的突现式功能表,也就是说,在突现式功能表上的项目可以存取另一个突现式功能表。有时突现式功能表上的项目呼叫对话方块以获得更多的资讯(对话方块在下一章介绍)。在标题列的最左端,很多父视窗都显示程式的小图示,这个图示可以启动系统功能表。它实际上是另一个突现式功能表。 本文来自织梦

突现式功能表的各项可以是「被选中的」,这意味著Windows在功能表文字的左端显示一个小的选中标记,选中标记让使用者知道从功能表中选中了哪些选项。这些选项之间可以是互斥的,也可以不互斥。顶层功能表项不能被选中。 内容来自dedecms

顶层功能表或突现式功能表项可以被「启用」、「禁用」或「无效化」。「启动」和「不启动」有时候被当作「启用」和「禁用」的同义词。被启用或禁用的功能表项在使用者看来是一样的,但是无效化的功能表项是使用灰色文字来显示的。 织梦好,好织梦

从使用者的角度来看,启用、禁用和无效化的功能表项都是可以「选择的」(被选择的功能表项目会被加高亮度显示),也就是说,使用者可以使用滑鼠选择被禁用的功能表项,将反相显示游标列移动到禁用的功能表项上,或者使用功能表项的关键字母来选择该功能表项。然而,从程式写作者的角度来看,启用、禁用和无效化功能表项的功能是不同的。Windows只为启用的功能表项向程式发送WM_COMMAND讯息。要让选项变得无效,可以把那些功能表项禁用和无效化。如果您想让使用者知道选择是无效的,那么您可以让一个功能表项无效化。

内容来自dedecms

功能表结构
 

dedecms.com

当您建立或改变程式中的功能表时,把顶层功能表和每一个突现式功能表想像成各自独立的功能表是有用的。顶层功能表有一个功能表代号,在顶层功能表中的每一个突现式功能表也有它自己的功能表代号。系统功能表(也是一个突现式功能表)也有功能表代号。 copyright dedecms

功能表中的每一项都有三个特性。第一个特性是功能表中显示什么,它可以是字串或点阵图。第二个特性是WM_COMMAND讯息中Windows发送给程式的功能表ID,或者是在使用者选择功能表项时Windows显示的突现式功能表的代号。第三个特性是功能表项的属性,包括是否被禁用、无效化或被选中。

dedecms.com

定义功能表
  内容来自dedecms

要使用Developer Studio来给程式资源描述档添加功能表,可以从 Insert 功能表中选择 Resource 并选择 Menu (或者您可能已经知道了)。然後,您可以用交谈式的方式定义功能表。功能表中每一项都有一个相关的 Menu Item Properties 对话方块,指出该项目的字串。如果选中了 Pop-up 核取方块,该项目就会呼叫一个突现式功能表,并且没有ID与此项目相联系。如果没有选中 Pop-up 核取方块,该项目被选中时就会产生带有特定IDWM_COMMAND讯息。这两类功能表项分别出现在资源描述档的POPUPMENUITEM叙述中。

内容来自dedecms

当您为功能表中的项目键入文字时,可以键入一个「&」符号,指出後面一个字元在Windows显示功能表时要加底线。这种底线字元是在您使用Alt键选择功能表项时Windows要寻找的比对字元。如果在文字中不包括「&」符号,就不显示任何底线,Windows会将功能表项文字的第一个字母用於Alt键查找。 织梦内容管理系统

如果在 Menu Items Properties 对话方块中选中 Grayed 选项,则功能表项是不能启动的,它的文字是灰色的,该项不产生WM_COMMAND讯息。如果选中 Inactive 选项,则功能表项也是不能启动的,也不产生WM_COMMAND讯息,但是它的文字显示正常。 Checked 选项在功能表项边上放置一个选中标记。 Separator 选项在突现式功能表上产生一个分栏的横线。 copyright dedecms

在突现式功能表的项目上,可以在字串中使用跳位字元\t。紧接著\t的文字被放置在距离突现式功能表的第一列右边新的一列上。在本章後面,会看到在使用键盘加速键时它起的作用。字串中的\a使跟著它的文字向右对齐。 织梦好,好织梦

您指定的ID值是Windows发送给视窗讯息处理程式中功能表讯息中的数值。在功能表中ID值应该是唯一的。按照惯例,我使用以IDM(「ID for a Menu」)开头的识别字。

织梦内容管理系统

在程式中引用功能表
  织梦内容管理系统

大多数Windows应用程式在资源描述档中只有一个功能表。您可以给功能表起一个与程式名称相同的文字的名称。程式写作者经常将程式名用於功能表名称,以便相同的字串可以用於视窗类别、程式的图示名称和功能表名称。然後,程式在视窗的定义中为功能表引用该名称: 织梦好,好织梦

wndclass.lpszMenuName = szAppName ; 
织梦好,好织梦

虽然存取功能表资源的最常用方法是在视窗类别中指定功能表,您也可以使用其他方法。Windows应用程式可以使用LoadMenu函式将功能表资源载入记忆体中,如同LoadIconLoadCursor函式一样。LoadMenu传回一个功能表代号。如果您在资源描述档中为功能表使用了名称,叙述如下: copyright dedecms

hMenu = LoadMenu (hInstance, TEXT ("MyMenu")) ; 

dedecms.com

如果使用了数值,那么LoadMenu呼叫采用如下的形式:

织梦内容管理系统

hMenu = LoadMenu (hInstance, MAKEINTRESOURCE (ID_MENU)) ; 本文来自织梦 

然後,您可以将这个功能表代号作为CreateWindow的第九个参数: 织梦内容管理系统

hwnd = CreateWindow (  TEXT ("MyClass"), TEXT ("Window Caption"), 本文来自织梦 
    WS_OVERLAPPEDWINDOW, dedecms.com 
    CW_USEDEFAULT, CW_USEDEFAULT, 
织梦好,好织梦
    CW_USEDEFAULT, CW_USEDEFAULT, 
内容来自dedecms
    NULL, hMenu, hInstance, NULL) ; 织梦好,好织梦 

在这种情况下,CreateWindow呼叫中指定的功能表可以覆盖视窗类别中指定的任何功能表。如果CreateWindow的第九个参数是NULL,那么您可以把视窗类别中的功能表看作是这种视窗类别的视窗内定使用的功能表。这样,您可以为依据同一视窗类别建立的几个视窗使用不同的功能表。 织梦好,好织梦

您也可以在视窗类别中指定NULL功能表,并且在CreateWindow呼叫中也指定NULL功能表,然後在视窗被建立後再给视窗指定一个功能表: 内容来自dedecms

SetMenu (hwnd, hMenu) ; 

织梦内容管理系统

这种形式使您可以动态地修改视窗的功能表。在本章後面的NOPOPUPS程式中我们将会看到这方面的例子。

织梦内容管理系统

当视窗被清除时,与视窗相关的所有功能表都将被清除。与视窗不相关的功能表在程式结束前通过呼叫DestroyMenu主动清除。 内容来自dedecms

功能表和讯息
  dedecms.com

当使用者选择一个功能表项时,Windows通常向视窗讯息处理程式发送几个不同的讯息。在大多数情况下,您的程式可以忽略大部分讯息,只需把它们传递给DefWindowProc即可。WM_INITMENU就是这一类的讯息,它具有下列参数:

本文来自织梦

wParam:主功能表代号 dedecms.com

lParam0 织梦好,好织梦

wParam值是您的主功能表代号,即使使用者选择的是系统功能表中的项目。Windows程式通常忽略WM_INITMENU讯息。尽管在选中该项之前的讯息已经给程式提供了修改功能表的机会,但是我们觉得此刻改变顶层功能表是会扰乱使用者的。

织梦好,好织梦

程式也会接收到WM_MENUSELECT讯息。随著使用者在功能表项中移动游标或者滑鼠,程式会收到许多WM_MENUSELECT讯息。这对实作那些包含对功能表项的文字描述的状态列是很有帮助的。WM_MENUSELECT的参数如下所示:

织梦好,好织梦

LOWORD (wParam):被选中项目:功能表ID或者突现式功能表代号

dedecms.com

HIWORD (wParam):选择旗标 织梦内容管理系统

lParam: 包含被选中项目的功能表代号 copyright dedecms

WM_MENUSELECT是一个功能表追踪讯息,wParam的值告诉您目前选择的是功能表中的哪一项(加高亮度显示的那个),wParam的高字组中的「选择旗标」可以是下列这些旗标的组合:MF_GRAYEDMF_DISABLEDMF_CHECKEDMF_BITMAPMF_POPUPMF_HELPMF_SYSMENUMF_MOUSESELECT。如果您需要根据对功能表项的选择来改变视窗显示区域的内容,那么您可以使用WM_MENUSELECT讯息。许多程式把该讯息发送给DefWindowProc

dedecms.com

Windows准备显示一个突现式功能表时,它给视窗讯息处理程式发送一个WM_INITMENUPOPUP讯息,参数如下:

织梦内容管理系统

wParam:突现式功能表代号

织梦好,好织梦

LOWORD (lParam):突现式功能表索引 本文来自织梦

HIWORD (lParam):系统功能表为1,其他为0 本文来自织梦

如果您需要在显示突现式功能表之前启用或者禁用功能表项,那么这个讯息就很重要。例如,假定程式使用突现式功能表上的 Paste 命令从 剪贴簿 复制文字,当您收到突现式功能表中的WM_INITMENUPOPUP讯息时,应确定剪贴簿内是否有文字存在。如果没有,那么应该使 Paste 功能表项无效化。我们将在本章後面修改的POPPAD程式中看到这样的例子。 织梦好,好织梦

最重要的功能表讯息是WM_COMMAND,它表示使用者已经从功能表中选中了一个被启用的功能表项。第八章中的WM_COMMAND讯息也可以由子视窗控制项产生。如果您碰巧为功能表和子视窗控制项使用同一ID码,那么您可以通过lParam的值来区别它们,功能表项的lParam其值为0,请参见表10-1

dedecms.com

 

dedecms.com

10-1

织梦好,好织梦

 

  织梦好,好织梦

功能表

织梦好,好织梦

控制项

copyright dedecms

LOWORD (wParam):

织梦内容管理系统

功能表ID 织梦内容管理系统

控制项ID 织梦内容管理系统

HIWORD (wParam): 织梦内容管理系统

0

织梦内容管理系统

通知码

内容来自dedecms

lParam: 本文来自织梦

0

copyright dedecms

子视窗代号 内容来自dedecms

 

WM_SYSCOMMAND讯息类似於WM_COMMAND讯息,只是WM_SYSCOMMAND表示使用者从系统功能表中选择一个启用的功能表项:

dedecms.com

wParam: 功能表ID 织梦好,好织梦

lParam: 0

dedecms.com

然而,如果WM_SYSCOMMAND讯息是由按滑鼠按键产生的,LOWORDlParam)和HIWORDlParam)将包含滑鼠游标位置的xy萤幕座标。 本文来自织梦

对於WM_SYSCOMMAND,功能表ID指示系统功能表中的哪一项被选中。对於预先定义的系统功能表项,较低的那四个位元应该和0xFFF0进行AND运算来遮罩掉,结果值应该为下列之一:SC_SIZESC_MOVESC_MINIMIZESC_MAXIMIZESC_NEXTWINDOWSC_PREVWINDOWSC_CLOSESC_VSCROLLSC_HSCROLLSC_ARRANGESC_RESTORESC_TASKLIST。此外,wParam可以是SC_MOUSEMENUSC_KEYMENU

copyright dedecms

如果您在系统功能表中添加功能表项,那么wParam的低字组将是您定义的功能表ID。为了避免与预先定义的功能表ID相冲突,应用程式应该使用小於0xF000的值,这对於将一般的WM_SYSCOMMAND讯息发送给DefWindowProc是很重要的。如果您不这样做,那么您实际上就是禁用了正常的系统功能表命令。 copyright dedecms

我们将讨论的最後一个讯息是WM_MENUCHAR。实际上,它根本不是功能表讯息。在下列两种情况之一发生时,Windows会把这个讯息发送到视窗讯息处理程式:如果使用者按下Alt和一个与功能表项不匹配的字元时,或者在显示突现式功能表而使用者按下一个与突现式功能表里的项目不匹配的字元键时。随WM_MENUCHAR讯息一起发送的参数如下所示: 内容来自dedecms

LOWORD (wParam): 字元代码(ASCIIUnicode

织梦好,好织梦

HIWORD (wParam): 选择码

织梦好,好织梦

lParam: 功能表代号

本文来自织梦

选择码是: 织梦内容管理系统

  • 0 不显示突现式功能表
     
  • MF_POPUP 显示突现式功能表
     
  • MF_SYSMENU 显示系统突现式功能表
     

Windows程式通常把该讯息传递给DefWindowProc,它一般给Windows传回0,这会使Windows发出哔声。在第十四章GRAFMENU程式中会看到WM_MENUCHAR讯息的使用。 织梦内容管理系统

范例程式
  copyright dedecms

让我们来看一个简单的例子。程式10-4所示的MENUDEMO程式,在主功能表中有五个选择项-FileEditBackgroundTimerHelp,每一项都与一个突现式功能表相连。MENUDEMO只完成了最简单、最通用的功能表处理操作,包括拦截WM_COMMAND讯息和检查wParam的低字组。 copyright dedecms

 程式10-4  MENUDEMO 

织梦好,好织梦

MENUDEMO.C 内容来自dedecms 
/*--------------------------------------------------------------------- 

织梦好,好织梦

   MENUDEMO.C --       Menu Demonstration 

dedecms.com

                                                             (c) Charles Petzold, 1998 
本文来自织梦
-----------------------------------------------------------------------*/ 内容来自dedecms 
  copyright dedecms 
#include <windows.h> 

内容来自dedecms

#include "resource.h" 织梦内容管理系统 
  
内容来自dedecms
#define ID_TIMER 1 内容来自dedecms 
  

copyright dedecms

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; dedecms.com 
  织梦内容管理系统 
TCHAR szAppName[] = TEXT ("MenuDemo") ; 
织梦好,好织梦
  
织梦内容管理系统
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 

本文来自织梦

                                                             PSTR szCmdLine, int iCmdShow) copyright dedecms 
{ 
织梦好,好织梦
    HWND     hwnd ; 
本文来自织梦
        MSG                            msg ; 织梦好,好织梦 
        WNDCLASS               wndclass ; 

copyright dedecms

      
本文来自织梦
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 
copyright dedecms
        wndclass.lpfnWndProc                          = WndProc ; 

dedecms.com

        wndclass.cbClsExtra                           = 0 ; copyright dedecms 
        wndclass.cbWndExtra                           = 0 ; 

织梦内容管理系统

        wndclass.hInstance                            = hInstance ; 

copyright dedecms

        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 本文来自织梦 
        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 织梦内容管理系统 
        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
织梦好,好织梦
        wndclass.lpszMenuName          = szAppName ; 

内容来自dedecms

        wndclass.lpszClassName                = szAppName ; 
织梦好,好织梦
        if (!RegisterClass (&wndclass)) 

织梦内容管理系统

        { 内容来自dedecms 
               MessageBox (   NULL, TEXT ("This program requires Windows NT!"), copyright dedecms 
                                                     szAppName, MB_ICONERROR) ; dedecms.com 
               return 0 ; 内容来自dedecms 
     } 本文来自织梦 
      
内容来自dedecms
        hwnd = CreateWindow (  szAppName, TEXT ("Menu Demonstration"), 内容来自dedecms 
                      WS_OVERLAPPEDWINDOW, 织梦好,好织梦 
                      CW_USEDEFAULT, CW_USEDEFAULT, 织梦好,好织梦 
                      CW_USEDEFAULT, CW_USEDEFAULT, 
copyright dedecms
                      NULL, NULL, hInstance, NULL) ; 

copyright dedecms

      内容来自dedecms 
        ShowWindow (hwnd, iCmdShow) ; 织梦内容管理系统 
        UpdateWindow (hwnd) ; 

本文来自织梦

      

织梦好,好织梦

        while (GetMessage (&msg, NULL, 0, 0)) 
copyright dedecms
        { 织梦内容管理系统 
                       TranslateMessage (&msg) ; dedecms.com 
                       DispatchMessage (&msg) ; 
copyright dedecms
        } 

本文来自织梦

        return msg.wParam ; 

织梦好,好织梦

} copyright dedecms 
  copyright dedecms 
LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) 

织梦内容管理系统

{ 
copyright dedecms
        static int idColor [5] = {     WHITE_BRUSH,  LTGRAY_BRUSH, GRAY_BRUSH, 
copyright dedecms
                                      DKGRAY_BRUSH, BLACK_BRUSH } ; copyright dedecms 
        static int iSelection = IDM_BKGND_WHITE ; dedecms.com 
        HMENU                          hMenu ; 本文来自织梦 
      
dedecms.com
        switch (message) copyright dedecms 
        { 
内容来自dedecms
        case    WM_COMMAND: 

copyright dedecms

                       hMenu = GetMenu (hwnd) ; dedecms.com 
           

织梦好,好织梦

                       switch (LOWORD (wParam)) 
dedecms.com
                               { copyright dedecms 
                       case    IDM_FILE_NEW: 

copyright dedecms

                       case    IDM_FILE_OPEN: 

织梦内容管理系统

                       case    IDM_FILE_SAVE: 本文来自织梦 
                       case    IDM_FILE_SAVE_AS: 
内容来自dedecms
                                      MessageBeep (0) ; 织梦内容管理系统 
                                      return 0 ; 

织梦好,好织梦

  

织梦内容管理系统

                       case    IDM_APP_EXIT: 

本文来自织梦

                                      SendMessage (hwnd, WM_CLOSE, 0, 0) ; copyright dedecms 
                                      return 0 ; copyright dedecms 
                
本文来自织梦
                       case IDM_EDIT_UNDO: copyright dedecms 
                       case IDM_EDIT_CUT: 内容来自dedecms 
                       case IDM_EDIT_COPY: 内容来自dedecms 
                       case IDM_EDIT_PASTE: dedecms.com 
                       case IDM_EDIT_CLEAR: 织梦内容管理系统 
                                      MessageBeep (0) ; dedecms.com 
                                      return 0 ; 

内容来自dedecms

                

内容来自dedecms

                       case    IDM_BKGND_WHITE:               // Note: Logic below 
本文来自织梦
                       case    IDM_BKGND_LTGRAY:              // assumes that IDM_WHITE 
本文来自织梦
                       case    IDM_BKGND_GRAY:                // through IDM_BLACK are 

本文来自织梦

                       case    IDM_BKGND_DKGRAY:              // consecutive numbers in 织梦好,好织梦 
                       case    IDM_BKGND_BLACK:               // the order shown here. 

织梦内容管理系统

                

copyright dedecms

                       CheckMenuItem (hMenu, iSelection, MF_UNCHECKED) ; 

织梦内容管理系统

                       iSelection = LOWORD (wParam) ; 
内容来自dedecms
                       CheckMenuItem (hMenu, iSelection, MF_CHECKED) ; 织梦好,好织梦 
                

dedecms.com

                       SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG)  dedecms.com 
                                                                     GetStockObject  

内容来自dedecms

                    (idColor [LOWORD (wParam) - IDM_BKGND_WHITE])) ; 

内容来自dedecms

                
织梦内容管理系统
                       InvalidateRect (hwnd, NULL, TRUE) ; 本文来自织梦 
                       return 0 ; 

copyright dedecms

                
copyright dedecms
                       case    IDM_TIMER_START: 
dedecms.com
                                      if (SetTimer (hwnd, ID_TIMER, 1000, NULL)) 

dedecms.com

                                      { 织梦内容管理系统 
                       EnableMenuItem (hMenu, IDM_TIMER_START, MF_GRAYED) ; 
织梦好,好织梦
                       EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_ENABLED) ; 

织梦好,好织梦

                                      } 织梦内容管理系统 
                               return 0 ; 本文来自织梦 
                copyright dedecms 
                       case    IDM_TIMER_STOP: 织梦好,好织梦 
                                      KillTimer (hwnd, ID_TIMER) ; 

dedecms.com

                                      EnableMenuItem (hMenu, IDM_TIMER_START, MF_ENABLED) ; 

内容来自dedecms

                                      EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_GRAYED) ; 

本文来自织梦

                                      return 0 ; 织梦好,好织梦 
                       case    IDM_APP_HELP: 
本文来自织梦
                                      MessageBox (hwnd, TEXT ("Help not yet  copyright dedecms 
implemented!"), 

内容来自dedecms

                            szAppName, MB_ICONEXCLAMATION | MB_OK) ; 本文来自织梦 
                                      return 0 ; copyright dedecms 
                织梦内容管理系统 
                       case    IDM_APP_ABOUT: 内容来自dedecms 
                                      MessageBox (hwnd,TEXT ("Menu Demonstration  内容来自dedecms 
Program\n") 
织梦内容管理系统
                           TEXT ("(c) Charles Petzold, 1998"), 
织梦内容管理系统
                        szAppName, MB_ICONINFORMATION | MB_OK) ; 
本文来自织梦
                                      return 0 ; 内容来自dedecms 
                       } 织梦好,好织梦 
                       break ; 本文来自织梦 
           
dedecms.com
                       case    WM_TIMER: 
织梦好,好织梦
                                      MessageBeep (0) ; 本文来自织梦 
                                      return 0 ; 
本文来自织梦
                

copyright dedecms

                       case    WM_DESTROY: 
本文来自织梦
                                      PostQuitMessage (0) ; 织梦好,好织梦 
                                      return 0 ; 
内容来自dedecms
        } 本文来自织梦 
        return DefWindowProc (hwnd, message, wParam, lParam) ; 

织梦好,好织梦

} 

织梦好,好织梦

 MENUDEMO.RC (摘录) dedecms.com 
//Microsoft Developer Studio generated resource script. 

dedecms.com

#include "resource.h" copyright dedecms 
#include "afxres.h" 
织梦好,好织梦
  

织梦内容管理系统

///////////////////////////////////////////////////////////////////////////// 

本文来自织梦

// Menu 织梦好,好织梦 
MENUDEMO MENU DISCARDABLE  

本文来自织梦

BEGIN 织梦内容管理系统 
        POPUP "&File" 织梦内容管理系统 
        BEGIN copyright dedecms 
                       MENUITEM "&New",                              IDM_FILE_NEW 

本文来自织梦

                       MENUITEM "&Open",                             IDM_FILE_OPEN 织梦内容管理系统 
                       MENUITEM "&Save",                             IDM_FILE_SAVE 本文来自织梦 
                       MENUITEM "Save &As...",               IDM_FILE_SAVE_AS 织梦内容管理系统 
                       MENUITEM SEPARATOR 内容来自dedecms 
                       MENUITEM "E&xit",                             IDM_APP_EXIT 
本文来自织梦
        END 织梦好,好织梦 
        POPUP "&Edit" 

织梦好,好织梦

        BEGIN 内容来自dedecms 
                       MENUITEM "&Undo",                             IDM_EDIT_UNDO 

dedecms.com

                       MENUITEM SEPARATOR                                     

dedecms.com

                       MENUITEM "C&ut",                                      IDM_EDIT_CUT 

织梦内容管理系统

                       MENUITEM "&Copy",                             IDM_EDIT_COPY 织梦内容管理系统 
                       MENUITEM "&Paste",                            IDM_EDIT_PASTE 

dedecms.com

                       MENUITEM "De&lete",                   IDM_EDIT_CLEAR 
本文来自织梦
        END 

copyright dedecms

        POPUP "&Background" 

copyright dedecms

        BEGIN 织梦内容管理系统 
                       MENUITEM "&White",      IDM_BKGND_WHITE, CHECKED 内容来自dedecms 
                       MENUITEM "&Light Gray", IDM_BKGND_LTGRAY 
织梦好,好织梦
                       MENUITEM "&Gray",        IDM_BKGND_GRAY 本文来自织梦 
                       MENUITEM "&Dark Gray",  IDM_BKGND_DKGRAY 本文来自织梦 
                       MENUITEM "&Black",      IDM_BKGND_BLACK 织梦内容管理系统 
        END 
本文来自织梦
        POPUP "&Timer" 

织梦好,好织梦

        BEGIN 
织梦好,好织梦
                       MENUITEM "&Start",      IDM_TIMER_START 织梦内容管理系统 
                       MENUITEM "S&top",        IDM_TIMER_STOP, GRAYED 
织梦好,好织梦
        END 

本文来自织梦

        POPUP "&Help" copyright dedecms 
        BEGIN 

内容来自dedecms

                       MENUITEM "&Help...",                  IDM_APP_HELP 
copyright dedecms
                   MENUITEM "&About MenuDemo...",    IDM_APP_ABOUT dedecms.com 
        END 
织梦好,好织梦
END 本文来自织梦 
 RESOURCE.H (摘录) 
织梦内容管理系统
// Microsoft Developer Studio generated include file. 

内容来自dedecms

// Used by MenuDemo.rc 内容来自dedecms 
  

本文来自织梦

#define IDM_FILE_NEW               40001 本文来自织梦 
#define IDM_FILE_OPEN              40002 本文来自织梦 
#define IDM_FILE_SAVE              40003 

内容来自dedecms

#define IDM_FILE_SAVE_AS           40004 织梦内容管理系统 
#define IDM_APP_EXIT               40005 本文来自织梦 
#define IDM_EDIT_UNDO              40006 本文来自织梦 
#define IDM_EDIT_CUT               40007 织梦内容管理系统 
#define IDM_EDIT_COPY              40008 内容来自dedecms 
#define IDM_EDIT_PASTE             40009 
本文来自织梦
#define IDM_EDIT_CLEAR             40010 

织梦好,好织梦

#define IDM_BKGND_WHITE            40011 
copyright dedecms
#define IDM_BKGND_LTGRAY           40012 copyright dedecms 
#define IDM_BKGND_GRAY             40013 copyright dedecms 
#define IDM_BKGND_DKGRAY           40014 织梦内容管理系统 
#define IDM_BKGND_BLACK            40015 dedecms.com 
#define IDM_TIMER_START            40016 本文来自织梦 
#define IDM_TIMER_STOP             40017 

本文来自织梦

#define IDM_APP_HELP               40018 dedecms.com 
#define IDM_APP_ABOUT              40019 
本文来自织梦

MENUDEMO.RC资源描述档给了您定义功能表的提示。功能表的名称为「MenuDemo」。大多数项目有底线字母,这就是说您必须在字母前键入『&』。MENUITEM SEPARATOR叙述是在「 Menu Item Properties 」对话方块中选中「 Separator 」框产生的。注意功能表中有一个项目具有「 Checked 」选项,另一个具有「 Grayed 」选项。还有,「 Background 」突现式功能表中的五个项目应该按顺序输入,确保识别字是以数值的顺序,本程式需要这样。所有功能表项的识别字定义在RESOURCE.H中。 copyright dedecms

当收到突现式功能表「 File 」和「 Edit 」各项有关的WM_COMMAND讯息时,MENUDEMO程式只使系统发出哔声。「 Background 」突现式功能表列出MENUDEMO用来给背景著色的五种现有画刷。在MENUDEMO.RC资源描述档中,「 White 」功能表项(功能表IDIDM_BKGND_WHITE)被标以「 CHECKED 」,它在功能表项旁边设定选中标记。在MENUDEMO.C中,iSelection的值被初始化为IDM_BKGND_WHITE内容来自dedecms

 Background 」突现式功能表上的五种画刷相互排斥。当MENUDEMO.C收到一个WM_COMMAND讯息,而该讯息中的wParam是「 Background 」突现式功能表上的五项之一时,它必须从先前选中的背景颜色中除掉选中标记,并把标记加到新的背景颜色上。为此,首先要得到功能表代号: copyright dedecms

hMenu = GetMenu (hwnd) ; 

织梦好,好织梦

CheckMenuItem函式用来取消目前被选中的项目:

内容来自dedecms

CheckMenuItem (hMenu, iSelection, MF_UNCHECKED) ; 

本文来自织梦

iSelection的值被设定为wParam的值,新的背景颜色被选中: 织梦好,好织梦

iSelection = wParam ; dedecms.com 
CheckMenuItem (hMenu, iSelection, MF_CHECKED) ; 内容来自dedecms 

视窗类别中的背景颜色於是被替换为新的背景颜色,视窗显示区域变为无效状态,Windows使用新的背景颜色清除视窗。 本文来自织梦

Timer突现式功能表列出了两个选项-「Start」和「Stop」。开始时,「Stop」选项变为灰色的(就像在资源描述档中的功能表定义一样)。当您选择「Start」选项时,MENUDEMO试图启动一个计时器,如果成功,则无效化「Start」选项,并启用「Stop」选项:

内容来自dedecms

EnableMenuItem (hMenu, IDM_TIMER_START, MF_GRAYED) ; 
本文来自织梦
EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_ENABLED) ; 织梦内容管理系统 

当收到一条WM_COMMAND讯息,并且wParam等於IDM_TIMER_STOP时,MENUDEMO程式会停止计数,启用「 Start 」项,然後无效化「 Stop 」选项: 织梦内容管理系统

EnableMenuItem (hMenu, IDM_TIMER_START, MF_ENABLED) ; 

织梦内容管理系统

EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_GRAYED) ; 
内容来自dedecms

请注意,在计时器执行时,MENUDEMO程式不可能收到wParam等於IDM_TIMER_STARTWM_COMMAND讯息。同样地,在计时器关闭时,MENUDEMO程式也不可能收到wParam等於IDM_TIMER_STOPWM_COMMAND讯息。

dedecms.com

MENUDEMO收到一个WM_COMMAND讯息,而该讯息的参数wParam等於IDM_APP_ABOUTIDM_APP_HELP时,MENUDEMO程式显示一个讯息方块(在下一章中,我们将把讯息方块变为对话方块)。 织梦内容管理系统

MENUDEMO程式收到一个WM_COMMAND讯息,其参数wParam等於IDM_APP_EXIT时,它给自己发送一个WM_CLOSE讯息。这个讯息与DefWindowProc收到WM_SYSCOMMAND讯息且wParam等於SC_CLOSE时发送给视窗讯息处理程式的讯息相同。我们将在本章後面介绍POPPAD2时再仔细研究这个问题。

织梦内容管理系统

功能表设计规范
 

织梦好,好织梦

MENUDEMO中的「 File 」和「 Edit 」突现式功能表的格式与其他Windows程式中的格式非常类似。Windows的目的之一是为使用者提供一种易懂的介面,而不要求使用者为每个程式重新学习基本操作方式。如果「 File 」和「 Edit 」功能表在每个Windows程式中看起来都一样,并且都使用同样的字母和Alt键来进行选择,那么当然有助於减轻使用者的学习负担。

内容来自dedecms

除了「 File 」和「 Edit 」突现式功能表外,大多数Windows程式的功能表都是不同的。当设计一个功能表时,您应该看一看现有的Windows程式以尽量保持一致。当然,如果您认为别的程式是不对的,而您知道正确的方法,那么没有人能够阻止您。同时记住,修改一个功能表,通常只需要修改资源描述档而不必修改您的程式码。即使以後要改变功能表项的位置,也不会有多大的问题。

本文来自织梦

虽然您的程式功能表在顶层可以有MENUITEM叙述,但这是不合规范的,因为这样会很容易导致错误的选择。如果您要这样做,那么请在字串後面加一个惊叹号,表示功能表项不会启动突现式功能表。 本文来自织梦

较难的一种功能表定义方法
  内容来自dedecms

在程式的资源描述档中定义功能表,通常是在您的视窗中添加功能表的最简单方法,但不是唯一的方法。如果您没有使用资源描述档,那么可以使用CreateMenuAppendMenu两个函式在程式中建立功能表。在您定义完功能表後,您可以将功能表代号发送给CreateWindow,或者使用SetMenu来设定视窗的功能表。 织梦内容管理系统

以下是具体的做法。CreateMenu简单地把一个代号传回给新功能表:

织梦好,好织梦

hMenu = CreateMenu () ; 

dedecms.com

功能表一开始为空。AppendMenu将功能表项插入功能表中。您必须为顶层功能表项和每一个突现式功能表提供不同的功能表代号。突现式功能表是单独构成的,然後将突现式功能表代号插入顶层功能表。程式10-5中所示的程式码就是用这种方法建立功能表的,实际上,这个功能表与MENUDEMO程式中的功能表相同。为了简化说明,代码使用ASCII字串。 内容来自dedecms

 程式10-5  不使用资源描述档建立与MENUDEMO程式相同功能表的C程式码 
copyright dedecms
hMenu = CreateMenu () ; 
本文来自织梦
hMenuPopup = CreateMenu () ; 
内容来自dedecms
AppendMenu             (hMenuPopup,   MF_STRING, IDM_FILE_NEW, "&New"); 

内容来自dedecms

AppendMenu             (hMenuPopup,   MF_STRING, IDM_FILE_OPEN, "&Open..."); 

copyright dedecms

AppendMenu             (hMenuPopup,   MF_STRING, IDM_FILE_SAVE, "&Save"); 织梦好,好织梦 
AppendMenu             (hMenuPopup,   MF_STRING, IDM_FILE_SAVE_AS, "Save &As..."); 本文来自织梦 
AppendMenu             (hMenuPopup,   MF_SEPARATOR, 0, NULL) ; 

内容来自dedecms

AppendMenu             (hMenuPopup,   MF_STRING, IDM_APP_EXIT, "E&xit") ; 织梦内容管理系统 
  

copyright dedecms

AppendMenu             (hMenu, MF_POPUP, hMenuPopup, "&File") ; 本文来自织梦 
  
内容来自dedecms
hMenuPopup = CreateMenu () ; 
织梦好,好织梦
AppendMenu             (hMenuPopup,   MF_STRING, IDM_EDIT_UNDO,"&Undo") ; 内容来自dedecms 
AppendMenu             (hMenuPopup,   MF_SEPARATOR, 0, NULL) ; 
copyright dedecms
AppendMenu             (hMenuPopup,   MF_STRING,IDM_EDIT_CUT, "Cu&t") ; 本文来自织梦 
AppendMenu             (hMenuPopup,   MF_STRING,IDM_EDIT_COPY,"&Copy") ; 
织梦内容管理系统
AppendMenu             (hMenuPopup,  MF_STRING,IDM_EDIT_PASTE,"&Paste") ; 内容来自dedecms 
AppendMenu             (hMenuPopup, MF_STRING,IDM_EDIT_CLEAR,"De&lete") ; 
织梦内容管理系统
AppendMenu             (hMenu,        MF_POPUP,      hMenuPopup, "&Edit") ; 
dedecms.com
  

内容来自dedecms

hMenuPopup = CreateMenu () ; 
织梦内容管理系统
AppendMenu     (hMenuPopup,   MF_STRING| MF_CHECKED,         IDM_BKGND_WHITE, "&White"); 织梦内容管理系统 
AppendMenu     (hMenuPopup,   MF_STRING,          IDM_BKGND_LTGRAY, "&Light Gray"); 
内容来自dedecms
AppendMenu     (hMenuPopup,   MF_STRING,                     IDM_BKGND_GRAY,   "&Gray") ; 
copyright dedecms
AppendMenu     (hMenuPopup,   MF_STRING,          IDM_BKGND_DKGRAY, "&Dark Gray"); 本文来自织梦 
AppendMenu (hMenuPopup,        MF_STRING,          IDM_BKGND_BLACK,  "&Black") ; 
织梦内容管理系统
  dedecms.com 
AppendMenu (hMenu, MF_POPUP, hMenuPopup, "&Background") ; 内容来自dedecms 
hMenuPopup = CreateMenu () ; 
织梦好,好织梦
AppendMenu     (hMenuPopup,   MF_STRING,          IDM_TIMER_START, "&Start") ; 

织梦内容管理系统

AppendMenu     (hMenuPopup,   MF_STRING | MF_GRAYED, IDM_TIMER_STOP, "S&top") ; 织梦好,好织梦 
  dedecms.com 
AppendMenu     (hMenu,        MF_POPUP, hMenuPopup, "&Timer") ; 内容来自dedecms 
  内容来自dedecms 
hMenuPopup     =       CreateMenu () ; 本文来自织梦 
  织梦好,好织梦 
AppendMenu     (hMenuPopup,   MF_STRING,     IDM_HELP_HELP,         "&Help") ; 织梦好,好织梦 
AppendMenu     (hMenuPopup,   MF_STRING,     IDM_APP_ABOUT,         "&About MenuDemo...") ; 内容来自dedecms 
  copyright dedecms 
AppendMenu (hMenu, MF_POPUP, hMenuPopup, "&Help") ; 
织梦内容管理系统

我认为您会同意底下这个观点:使用资源描述档功能表模板来制作功能表,会更容易而且更清楚。我并不鼓励您使用这里的方法定义功能表,而只是提供了一种实作功能表的方法。当然,您可以使用包含所有功能表项字串、ID和旗标等的结构阵列来压缩程式码大小。不过,如果您这么做了,那么您还可以利用Windows定义功能表的第三种方法。LoadMenuIndirect函式接受一个指向MENUITEMTEMPLATE型态的结构指标,并传回功能表的代号,该函式在载入资源描述档中的常规功能表模板後,在Windows中构造功能表,读者不妨自己尝试一下。 本文来自织梦

浮动突现式功能表
  dedecms.com

您还可以在没有顶层功能表列的情况下使用功能表,也就是说,您可以使突现式功能表出现在萤幕顶层的任何位置。一种方法是使用滑鼠右键来启动突现式功能表。程式10-6所示的POPMENU说明了这种方法。 本文来自织梦

 程式10-6   POPMENU 内容来自dedecms 
POPMENU.C 织梦好,好织梦 
/*---------------------------------------------------------------------- 内容来自dedecms 
   POPMENU.C -- Popup Menu Demonstration dedecms.com 
                                                      (c) Charles Petzold, 1998 本文来自织梦 
-------------------------------------------------------------------------*/ 
内容来自dedecms
  copyright dedecms 
#include <windows.h> 
织梦好,好织梦
#include "resource.h" 
织梦好,好织梦
  

本文来自织梦

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 织梦内容管理系统 
HINSTANCE hInst ; 
copyright dedecms
TCHAR                  szAppName[] = TEXT ("PopMenu") ; 本文来自织梦 
  织梦内容管理系统 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 内容来自dedecms 
                                                             PSTR szCmdLine, int iCmdShow) dedecms.com 
{ dedecms.com 
        HWND                           hwnd ; 
织梦好,好织梦
        MSG                            msg ; 

dedecms.com

        WNDCLASS               wndclass ; 本文来自织梦 
      

内容来自dedecms

        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 
dedecms.com
        wndclass.lpfnWndProc                          = WndProc ; 

本文来自织梦

        wndclass.cbClsExtra                           = 0 ; 
织梦内容管理系统
        wndclass.cbWndExtra                           = 0 ; 本文来自织梦 
        wndclass.hInstance                            = hInstance ; 

dedecms.com

        wndclass.hIcon                                = LoadIcon (NULL, szAppName) ; 织梦内容管理系统 
       wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 

内容来自dedecms

        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 内容来自dedecms 
        wndclass.lpszMenuName                 = NULL ; 织梦内容管理系统 
        wndclass.lpszClassName                = szAppName ; copyright dedecms 
      

本文来自织梦

        if (!RegisterClass (&wndclass)) 本文来自织梦 
        { 

本文来自织梦

               MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 

内容来自dedecms

                                                                     szAppName, MB_ICONERROR) ; 

本文来自织梦

                       return 0 ; dedecms.com 
     } 织梦好,好织梦 
      

dedecms.com

        hInst = hInstance ; 

织梦好,好织梦

        hwnd = CreateWindow (  szAppName, TEXT ("Popup Menu Demonstration"), copyright dedecms 
                     WS_OVERLAPPEDWINDOW, 织梦好,好织梦 
                     CW_USEDEFAULT, CW_USEDEFAULT, 

织梦好,好织梦

                     CW_USEDEFAULT, CW_USEDEFAULT, dedecms.com 
                     NULL, NULL, hInstance, NULL) ; 本文来自织梦 
        ShowWindow (hwnd, iCmdShow) ; 内容来自dedecms 
        UpdateWindow (hwnd) ; 

dedecms.com

      织梦好,好织梦 
        while (GetMessage (&msg, NULL, 0, 0)) 本文来自织梦 
        { 本文来自织梦 
                               TranslateMessage (&msg) ; 

织梦好,好织梦

                               DispatchMessage (&msg) ; 
dedecms.com
        } 

本文来自织梦

        return msg.wParam ; 
织梦好,好织梦
} 织梦内容管理系统 
  内容来自dedecms 
LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) 
内容来自dedecms
{ dedecms.com 
        static HMENU   hMenu ; 

内容来自dedecms

        static int             idColor [5] = {WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH, 

dedecms.com

                                              DKGRAY_BRUSH, BLACK_BRUSH } ; copyright dedecms 
        static int             iSelection     = IDM_BKGND_WHITE ; 
内容来自dedecms
        POINT                                 point ; dedecms.com 
      
dedecms.com
        switch (message) 内容来自dedecms 
     { copyright dedecms 
        case    WM_CREATE: dedecms.com 
                       hMenu = LoadMenu (hInst, szAppName) ; copyright dedecms 
                       hMenu = GetSubMenu (hMenu, 0) ; 
本文来自织梦
                       return 0 ; 本文来自织梦 
  

dedecms.com

        case    WM_RBUTTONUP: dedecms.com 
                       point.x = LOWORD (lParam) ; copyright dedecms 
                       point.y = HIWORD (lParam) ; 织梦好,好织梦 
                       ClientToScreen (hwnd, &point) ; 

copyright dedecms

           

内容来自dedecms

                       TrackPopupMenu (hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL) ; 
织梦内容管理系统
                       return 0 ; copyright dedecms 
           
织梦内容管理系统
        case    WM_COMMAND: 
内容来自dedecms
                       switch (LOWORD (wParam)) 
copyright dedecms
                       { 内容来自dedecms 
                       case    IDM_FILE_NEW: 

copyright dedecms

                       case    IDM_FILE_OPEN: 
织梦内容管理系统
                       case    IDM_FILE_SAVE: 
织梦内容管理系统
                       case    IDM_FILE_SAVE_AS: 
dedecms.com
                       case    IDM_EDIT_UNDO: 织梦好,好织梦 
                       case    IDM_EDIT_CUT: copyright dedecms 
                       case    IDM_EDIT_COPY: copyright dedecms 
                       case    IDM_EDIT_PASTE: 
织梦好,好织梦
                       case    IDM_EDIT_CLEAR: 织梦好,好织梦 
                                      MessageBeep (0) ; copyright dedecms 
                                      return 0 ; 
织梦内容管理系统
                本文来自织梦 
                       case    IDM_BKGND_WHITE:               // Note: Logic below 织梦好,好织梦 
                       case    IDM_BKGND_LTGRAY:              //   assumes that IDM_WHITE 

织梦好,好织梦

                       case    IDM_BKGND_GRAY:                //   through IDM_BLACK are 

织梦好,好织梦

                       case    IDM_BKGND_DKGRAY:              //   consecutive numbers in 

copyright dedecms

                       case    IDM_BKGND_BLACK:               //   the order shown here. 织梦内容管理系统 
                

dedecms.com

                                      CheckMenuItem (hMenu, iSelection, MF_UNCHECKED) ; 
dedecms.com
                                      iSelection = LOWORD (wParam) ; copyright dedecms 
                                      CheckMenuItem (hMenu, iSelection, MF_CHECKED) ; 

本文来自织梦

                

织梦好,好织梦

                                      SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG)  本文来自织梦 
                                                                     GetStockObject  dedecms.com 
                            (idColor [LOWORD (wParam) - IDM_BKGND_WHITE])) ; 

dedecms.com

                

织梦好,好织梦

                                      InvalidateRect (hwnd, NULL, TRUE) ; 
dedecms.com
                                      return 0 ; 内容来自dedecms 
                dedecms.com 
                       case    IDM_APP_ABOUT: 

织梦内容管理系统

                                      MessageBox (hwnd, TEXT ("Popup Menu Demonstration Program\n") 内容来自dedecms 
                           TEXT ("(c) Charles Petzold, 1998"), 织梦好,好织梦 
                                      szAppName, MB_ICONINFORMATION | MB_OK) ; 

织梦好,好织梦

                               return 0 ; 
内容来自dedecms
                

本文来自织梦

                       case    IDM_APP_EXIT: 织梦内容管理系统 
                                      SendMessage (hwnd, WM_CLOSE, 0, 0) ; 
copyright dedecms
                                      return 0 ; 本文来自织梦 
                

本文来自织梦

                       case    IDM_APP_HELP: 本文来自织梦 
                                      MessageBox (hwnd, TEXT ("Help not yet implemented!"), 

copyright dedecms

                            szAppName, MB_ICONEXCLAMATION | MB_OK) ; 
copyright dedecms
                                      return 0 ; 

dedecms.com

                       } copyright dedecms 
                       break ; 

dedecms.com

           织梦好,好织梦 
        case    WM_DESTROY: 内容来自dedecms 
                       PostQuitMessage (0) ; 本文来自织梦 
                       return 0 ; 织梦好,好织梦 
        } 

copyright dedecms

        return DefWindowProc (hwnd, message, wParam, lParam) ; 织梦内容管理系统 
} 

dedecms.com

 POPMENU.RC (摘录) 
本文来自织梦
//Microsoft Developer Studio generated resource script. 

dedecms.com

#include "resource.h" 内容来自dedecms 
#include "afxres.h" dedecms.com 
  织梦好,好织梦 
///////////////////////////////////////////////////////////////////////////// 
内容来自dedecms
// Menu 织梦内容管理系统 
POPMENU MENU DISCARDABLE  dedecms.com 
BEGIN 织梦好,好织梦 
        POPUP "MyMenu" 
织梦内容管理系统
        BEGIN 

copyright dedecms

                       POPUP "&File" 

内容来自dedecms

                       BEGIN 织梦好,好织梦 
                       MENUITEM "&New",                              IDM_FILE_NEW 织梦好,好织梦 
                       MENUITEM "&Open",                     IDM_FILE_OPEN copyright dedecms 
                    MENUITEM "&Save",                        IDM_FILE_SAVE copyright dedecms 
                       MENUITEM "Save &As",      IDM_FILE_SAVE_AS 
内容来自dedecms
                       MENUITEM SEPARATOR dedecms.com 
                       MENUITEM "E&xit",                     IDM_APP_EXIT 
本文来自织梦
                       END 内容来自dedecms 
                       POPUP "&Edit" 
本文来自织梦
                       BEGIN 
织梦内容管理系统
                               MENUITEM "&Undo",              IDM_EDIT_UNDO 织梦好,好织梦 
                               MENUITEM SEPARATOR 
dedecms.com
                               MENUITEM "Cu&t",               IDM_EDIT_CUT 

本文来自织梦

                               MENUITEM "&Copy",              IDM_EDIT_COPY 
dedecms.com
                               MENUITEM "&Paste",             IDM_EDIT_PASTE 内容来自dedecms 
                               MENUITEM "De&lete",            IDM_EDIT_CLEAR dedecms.com 
END 
dedecms.com
        POPUP "&Background" 

copyright dedecms

BEGIN 织梦好,好织梦 
    MENUITEM "&White",                        IDM_BKGND_WHITE, CHECKED dedecms.com 
MENUITEM "&Light Gray",            IDM_BKGND_LTGRAY 织梦好,好织梦 
MENUITEM "&Gray",                             IDM_BKGND_GRAY 
copyright dedecms
MENUITEM "&Dark Gray",         IDM_BKGND_DKGRAY 
copyright dedecms
MENUITEM "&Black",                    IDM_BKGND_BLACK 
织梦内容管理系统
END 
本文来自织梦
        POPUP "&Help" 

织梦内容管理系统

BEGIN 织梦好,好织梦 
MENUITEM "&Help...",                  IDM_APP_HELP dedecms.com 
        MENUITEM "&About PopMenu...", IDM_APP_ABOUT 织梦好,好织梦 
END 内容来自dedecms 
        END 织梦内容管理系统 
END 
内容来自dedecms
 RESOURCE.H (摘录) 

内容来自dedecms

// Microsoft Developer Studio generated include file. 内容来自dedecms 
// Used by PopMenu.rc 织梦好,好织梦 
  

织梦内容管理系统

#define IDM_FILE_NEW                  40001 织梦内容管理系统 
#define IDM_FILE_OPEN                 40002 

织梦好,好织梦

#define IDM_FILE_SAVE                 40003 
dedecms.com
#define IDM_FILE_SAVE_AS              40004 

织梦好,好织梦

#define IDM_APP_EXIT                  40005 织梦好,好织梦 
#define IDM_EDIT_UNDO                 40006 
织梦好,好织梦
#define IDM_EDIT_CUT                  40007 

织梦内容管理系统

#define IDM_EDIT_COPY                 40008 织梦内容管理系统 
#define IDM_EDIT_PASTE                40009 
本文来自织梦
#define IDM_EDIT_CLEAR                40010 

本文来自织梦

#define IDM_BKGND_WHITE               40011 织梦内容管理系统 
#define IDM_BKGND_LTGRAY              40012 
织梦内容管理系统
#define IDM_BKGND_GRAY                40013 
本文来自织梦
#define IDM_BKGND_DKGRAY              40014 dedecms.com 
#define IDM_BKGND_BLACK               40015 

本文来自织梦

#define IDM_APP_HELP                  40016 内容来自dedecms 
#define IDM_APP_ABOUT                 40017 本文来自织梦 

资源描述档POPMENU.RC定义的功能表与MENUDEMO.RC中的功能表非常相似。不同的是,在顶层功能表中只包含一项-一个突现式功能表「MyMenu」,它呼叫「File」、「Edit」、「Background」和「Help」选项。这四个选项垂直一行地出现在突现式功能表上,而不是水平一列地出现在主功能表上。 织梦好,好织梦

WndProc中的WM_CREATE处理期间,POPMENU取得此突现式功能表的代号,就是带有文字「MyMenu」的那个突现式功能表:

copyright dedecms

hMenu = LoadMenu (hInst, szAppName) ; copyright dedecms 
hMenu = GetSubMenu (hMenu, 0) ; 内容来自dedecms 

WM_RBUTTONUP讯息处理期间,POPMENU提供了滑鼠指标的位置,将此位置转换为萤幕座标,再将座标值传递给TrackPopupMenu内容来自dedecms

point.x = LOWORD (lParam) ; 织梦内容管理系统 
point.y = HIWORD (lParam) ; 

copyright dedecms

ClientToScreen (hwnd, &point) ; 
织梦好,好织梦
  

copyright dedecms

TrackPopupMenu (hMenu, TPM_RIGHTBUTTON, point.x, point.y,  
内容来自dedecms
                                                     0, hwnd, NULL) ; 
copyright dedecms

然後,Windows显示出具有「File」、「Edit」、「Background」和「Help」项的突现式功能表。选择其中任何一项都可以使嵌套的突现式功能表显示在右边,功能表函式与一般的功能表一样。

织梦好,好织梦

如果要使用与该程式的主功能表相同的功能表并带有TrackPopupMenu,您会遇到一些问题,因为函式需要突现式功能表代号。在「Microsoft Knowledge Base」文章ID Q99806有提供一些资讯。

dedecms.com

使用系统功能表
  dedecms.com

使用WS_SYSMENU样式建立的父视窗,在其标题列的左侧有一个系统功能表按钮。如果您愿意,可以修改这个功能表。在Windows程式设计的早期,程式写作者一般把「About」功能表项放入系统功能表。虽然这种方法不常见,但是修改系统功能表往往是一种在短程式中添加功能表的快速偷懒方法。这里唯一的限制是:在系统功能表中增加的命令其ID值必须小於0xF000;否则它们将会与Windows系统功能表命令所使用的ID值相冲突。还要记住,当您为这些新功能表项在视窗讯息处理程式中处理WM_SYSCOMMAND讯息时,您必须把其他的WM_SYSCOMMAND讯息发送给DefWindowProc。如果您不这样做,那么实际上是禁用了系统功能表上的所有正常选项。 copyright dedecms

程式10-7中所示的POORMENU(「设计不当的个人功能表」)在系统功能表中加入了一个分隔条和三个命令,最後一个命令将删除这些附加的功能表项。

dedecms.com

 程式10-7  POORMENU 内容来自dedecms 
POORMENU.C 

本文来自织梦

/*------------------------------------------------------------------------- 

织梦内容管理系统

        POORMENU.C --          The Poor Person's Menu 

dedecms.com

                                                             (c) Charles Petzold, 1998 

内容来自dedecms

--------------------------------------------------------------------------*/ 织梦好,好织梦 
  

织梦好,好织梦

#include <windows.h> 
dedecms.com
#define IDM_SYS_ABOUT                                1 
copyright dedecms
#define IDM_SYS_HELP                                 2 织梦好,好织梦 
#define IDM_SYS_REMOVE                            3 本文来自织梦 
  copyright dedecms 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; copyright dedecms 
static TCHAR szAppName[] = TEXT ("PoorMenu") ; 
内容来自dedecms
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, copyright dedecms 
                                                             PSTR szCmdLine, int iCmdShow) 

dedecms.com

{ copyright dedecms 
        HMENU                                 hMenu ; 

本文来自织梦

        HWND                                  hwnd ; 

copyright dedecms

        MSG                                   msg ; 织梦内容管理系统 
        WNDCLASS                       wndclass ; copyright dedecms 
      
dedecms.com
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; copyright dedecms 
        wndclass.lpfnWndProc                          = WndProc ; 织梦内容管理系统 
        wndclass.cbClsExtra                           = 0 ; 

织梦内容管理系统

        wndclass.cbWndExtra                           = 0 ; 
织梦好,好织梦
        wndclass.hInstance                            = hInstance ; 
dedecms.com
        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 本文来自织梦 
        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 
本文来自织梦
        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
织梦内容管理系统
        wndclass.lpszMenuName                 = NULL ; 内容来自dedecms 
        wndclass.lpszClassName                = szAppName ; 织梦好,好织梦 
      

内容来自dedecms

        if (!RegisterClass (&wndclass)) 

内容来自dedecms

        { 内容来自dedecms 
                       MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 本文来自织梦 
                                                                     szAppName, MB_ICONERROR) ; 
内容来自dedecms
                       return 0 ; 
内容来自dedecms
     } 
dedecms.com
      
本文来自织梦
        hwnd = CreateWindow (  szAppName, TEXT ("The Poor-Person's Menu"), 
织梦好,好织梦
                         WS_OVERLAPPEDWINDOW, copyright dedecms 
                         CW_USEDEFAULT, CW_USEDEFAULT, 

本文来自织梦

                         CW_USEDEFAULT, CW_USEDEFAULT, 内容来自dedecms 
                         NULL, NULL, hInstance, NULL) ; 
copyright dedecms
      
内容来自dedecms
        hMenu = GetSystemMenu (hwnd, FALSE) ; 

织梦内容管理系统

        AppendMenu     (hMenu, MF_SEPARATOR, 0,                                     NULL) ; 内容来自dedecms 
        AppendMenu     (hMenu, MF_STRING, IDM_SYS_ABOUT,     TEXT ("About...")) ; 织梦好,好织梦 
        AppendMenu     (hMenu, MF_STRING, IDM_SYS_HELP,      TEXT ("Help...")) ; 本文来自织梦 
        AppendMenu     (hMenu, MF_STRING, IDM_SYS_REMOVE,    TEXT ("Remove Additions")) ; 织梦内容管理系统 
      

织梦好,好织梦

        ShowWindow (hwnd, iCmdShow) ; 本文来自织梦 
        UpdateWindow (hwnd) ; 内容来自dedecms 
      织梦内容管理系统 
        while (GetMessage (&msg, NULL, 0, 0)) 织梦好,好织梦 
        { 织梦内容管理系统 
                       TranslateMessage (&msg) ; 

dedecms.com

                       DispatchMessage (&msg) ; 
织梦好,好织梦
        } 
copyright dedecms
        return msg.wParam ; 织梦好,好织梦 
} 织梦好,好织梦 
  

织梦好,好织梦

LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) 

织梦内容管理系统

{ copyright dedecms 
        switch (message) 内容来自dedecms 
        { copyright dedecms 
        case    WM_SYSCOMMAND: 本文来自织梦 
                       switch (LOWORD (wParam)) 

本文来自织梦

                       { 内容来自dedecms 
                       case    IDM_SYS_ABOUT: copyright dedecms 
                                      MessageBox (   hwnd,   TEXT ("A Poor-Person's Menu Program\n") 
dedecms.com
                      TEXT ("(c) Charles Petzold, 1998"), 织梦内容管理系统 
                      szAppName, MB_OK | MB_ICONINFORMATION) ; 

copyright dedecms

                                      return 0 ; 

织梦好,好织梦

                织梦内容管理系统 
                       case    IDM_SYS_HELP: 

织梦好,好织梦

                                      MessageBox (   hwnd, TEXT ("Help not yet implemented!"), 织梦好,好织梦 
                      szAppName, MB_OK | MB_ICONEXCLAMATION) ; dedecms.com 
                                      return 0 ; 本文来自织梦 
                

dedecms.com

                       case    IDM_SYS_REMOVE: 
织梦内容管理系统
                                      GetSystemMenu (hwnd, TRUE) ; 

copyright dedecms

                                      return 0 ; 织梦内容管理系统 
                       } 织梦好,好织梦 
                       break ; 

织梦内容管理系统

           
织梦内容管理系统
               case    WM_DESTROY: 

本文来自织梦

                                      PostQuitMessage (0) ; 织梦内容管理系统 
                                      return 0 ; 内容来自dedecms 
        } 
织梦内容管理系统
        return DefWindowProc (hwnd, message, wParam, lParam) ; 织梦内容管理系统 
} 内容来自dedecms 

三个功能表IDPOORMENU.C的开始部分定义: 本文来自织梦

#define IDM_ABOUT              1 织梦好,好织梦 
#define IDM_HELP               2 

dedecms.com

#define IDM_REMOVE             3 织梦好,好织梦 

在程式视窗建立之後,POORMENU得到一个系统功能表的代号: 本文来自织梦

hMenu = GetSystemMenu (hwnd, FALSE) ; 
内容来自dedecms

第一次呼叫GetSystemMenu时,您应该为修改功能表作准备,将第二个参数设定为FALSE

内容来自dedecms

使用四个AppendMenu呼叫来实作对功能表的修改:

织梦内容管理系统

AppendMenu     (hMenu,        MF_SEPARATOR, 0,                                                     NULL) ; 
本文来自织梦
AppendMenu     (hMenu,        MF_STRING, IDM_SYS_ABOUT,      TEXT ("About...")) ; 
内容来自dedecms
AppendMenu     (hMenu,        MF_STRING, IDM_SYS_HELP,              TEXT ("Help...")) ; 
内容来自dedecms
AppendMenu     (hMenu,        MF_STRING, IDM_SYS_REMOVE,     TEXT ("Remove Additions")); dedecms.com 

第一个AppendMenu呼叫是添加分隔条。选择「Remove Additions」功能表项将使POORMENU删除这些附加的功能表项,这只要把第二个参数设定为TRUE,再次呼叫GetSystemMenu即可: 本文来自织梦

GetSystemMenu (hwnd, TRUE) ; 织梦内容管理系统 

标准系统功能表有下列选项:RestoreMoveSizeMinimizeMaximizeClose。它们产生wParam分别等於SC_RESTORESC_MOVESC_SIZESC_MINIMUMSC_MAXIMUMSC_CLOSEWM_SYSCOMMAND讯息。尽管Windows程式一般不这样做,但是您可以自己处理这些讯息,而不把它们留给DefWindowProc。您也可以使用下面所述的方法来禁止或者除掉系统功能表的标准选项。Windows文件中还介绍了一些系统功能表的标准附加项目,这些附加项目使用识别字SC_NEXTWINDOWSC_PREVWINDOWSC_VSCROLLSC_HSCROLLSC_ARRANGE。您也许会发现,在一些应用程式中将这些命令加入系统功能表是合适的。 织梦内容管理系统

改变功能表
  本文来自织梦

我们已经看到了如何使用AppendMenu函式为程式定义功能表以及将功能表项加入到系统功能表中。在Windows 3.0之前,您不得不被迫使用ChangeMenu函式来完成这种工作。ChangeMenu函式有很多功能,至少在当时,整个Windows中它是最复杂的函式之一。现在,许多函式都比ChangeMenu函式还要复杂,并且ChangeMenu的功能被分解为五个新的函式:

内容来自dedecms

  •  AppendMenu 在功能表尾部添加一个新的功能表项目
     
  •  DeleteMenu 删除功能表中一个现有的功能表项并清除该项目
     
  •  InsertMenu 在功能表中插入一个新项目
     
  •  ModifyMenu 修改一个现有的功能表项目
     
  •  RemoveMenu 从功能表中移走某一项目
     

如果功能表项是一个突现式功能表,那么DeleteMenuRemoveMenu之间的区别就很重要。DeleteMenu清除突现式功能表,但RemoveMenu不清除它。

copyright dedecms

其他功能表命令
 

织梦内容管理系统

下面是在使用功能表时一些有用的函式。

dedecms.com

当您改变顶层功能表项时,直到Windows重画功能表列时才显示所做的改变。您可以通过下列呼叫来强迫执行功能表更新: dedecms.com

DrawMenuBar (hwnd) ; 织梦好,好织梦 

注意,DrawMenuBar的参数是视窗代号而不是功能表代号。 内容来自dedecms

您可以使用下列命令来获得突现式功能表的代号:

dedecms.com

hMenuPopup = GetSubMenu (hMenu, iPosition) ; 

织梦好,好织梦

其中iPositionhMenu指示的顶层功能表中突现式功能表项的索引(开始为0)。然後您可以在其他函式中使用突现式功能表代号(例如在AppendMenu函式中)。

内容来自dedecms

您可以使用下列命令获得顶层功能表或者突现式功能表中目前的项数:

织梦好,好织梦

iCount = GetMenuItemCount (hMenu) ; 

织梦内容管理系统

您可以取得突现式功能表项的功能表ID织梦内容管理系统

id = GetMenuItemID (hMenuPopup, iPosition) ; 

内容来自dedecms

其中iPosition是功能表项在突现式功能表中的位置(以0开始)。 dedecms.com

MENUDEMO中您已经看到如何选中、或者取消选中突现式功能表中的某一项:

copyright dedecms

CheckMenuItem (hMenu, id, iCheck) ; 
dedecms.com

MENUDEMO中,hMenu是顶层功能表的代号,id是功能表ID,而iCheck的值是MF_CHECKEDMF_UNCHECKED。如果hMenu是突现式功能表代号,那么参数id是位置索引而不是功能表ID。如果使用索引会更方便的话,那么您可以在第三个参数中包含MF_BYPOSITION,例如:

dedecms.com

CheckMenuItem (hMenu, iPosition, MF_CHECKED | MF_BYPOSITION) ; 

内容来自dedecms

除了第三个参数是MF_ENABLEDMF_DISABLEDMF_GRAYED外,EnableMenuItem函式与CheckMenuItem函式所完成的工作类似。如果您在具有突现式功能表的顶层功能表项上使用EnableMenuItem,那么必须在第三个参数中使用MF_BYPOSITION识别字,因为功能表项没有功能表ID。我们将在本章後面所示的POPPAD2程式中看到EnableMenuItem的一个例子。HiliteMenuItem也类似於CheckMenuItemEnableMenuItem,但是它使用的是MF_HILITEMF_UNHILITE。当您在功能表项之间移动时,Windows使用反白显示方式加亮显示功能表项。您通常不需要使用HiliteMenuItem

织梦好,好织梦

您还需要对您的功能表做些什么呢?还记得我们在功能表中使用了哪些字串吗?您可以透过下面的呼叫来回顾一下: 内容来自dedecms

iCharCount = GetMenuString (hMenu, id, pString, iMaxCount, iFlag) ; 
织梦内容管理系统

iFlag可以是MF_BYCOMMAND(其中id是功能表ID),也可以是MF_BYPOSITION(其中的id是位置索引)。函式将字串的iMaxCount个位元组复制到pString中,并传回复制的位元组数。 织梦好,好织梦

或许您也想知道功能表项目前的属性是什么:

dedecms.com

iFlags = GetMenuState (hMenu, id, iFlag) ; 内容来自dedecms 

同样地,iFlag可以是MF_BYCOMMANDMF_BYPOSITION。传回值iFlags是目前所有属性的组合,您可以通过对MF_DISABLEDMF_GRAYEDMF_CHECKEDMF_MENUBREAKMF_MENUBARBREAKMF_SEPARATOR识别字的检测来决定目前的属性。

copyright dedecms

也许现在您对功能表有了一些了解。这时您可能想知道,如果您不再需要功能表时又应该如何处理。您可以使用下面的命令来清除功能表: 织梦好,好织梦

DestroyMenu (hMenu) ; 

copyright dedecms

从而使功能表代号无效。

内容来自dedecms

建立功能表的非正统方法
 

copyright dedecms

现在让我们稍微偏离我们所讨论的主题。如果在您的程式中没有下拉式功能表,而是建立了多个没有突现式功能表的顶层功能表,并呼叫SetMenu在顶层功能表之间切换,那会是什么样的情形呢?就像Lotus 1-2-3中老式的文字模式功能表那样。程式10-8中的NOPOPUPS程式展示了处理这种情况。在这个程式中,「File」和「Edit」项与MENUDEMO程式中的类似,但是却以另一种顶层功能表显示出来。 内容来自dedecms

 程式10-8  NOPOPUPS 

织梦内容管理系统

NOPOPUPS.C 

织梦好,好织梦

/*------------------------------------------------------------------------- copyright dedecms 
        NOPOPUPS.C --          Demonstrates No-Popup Nested Menu 
dedecms.com
                                                             (c) Charles Petzold, 1998 dedecms.com 
-------------------------------------------------------------------------*/ 

dedecms.com

  
本文来自织梦
#include <windows.h> 
织梦好,好织梦
#include "resource.h" 
copyright dedecms
  
dedecms.com
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 

织梦好,好织梦

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
内容来自dedecms
                                                             PSTR szCmdLine, int iCmdShow) 本文来自织梦 
{ 
dedecms.com
        static TCHAR   szAppName[] = TEXT ("NoPopUps") ; copyright dedecms 
        HWND                                  hwnd ; 
织梦好,好织梦
        MSG                                   msg ; 内容来自dedecms 
        WNDCLASS                       wndclass ; copyright dedecms 
      
copyright dedecms
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 
copyright dedecms
        wndclass.lpfnWndProc                          = WndProc ; 

copyright dedecms

        wndclass.cbClsExtra                           = 0 ; 

内容来自dedecms

        wndclass.cbWndExtra                           = 0 ; 

本文来自织梦

        wndclass.hInstance                            = hInstance ; 织梦好,好织梦 
        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 

本文来自织梦

        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 

本文来自织梦

        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 本文来自织梦 
        wndclass.lpszMenuName                 = NULL ; 

织梦好,好织梦

        wndclass.lpszClassName = szAppName ; 

dedecms.com

        if (!RegisterClass (&wndclass)) copyright dedecms 
        { 织梦内容管理系统 
               MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 内容来自dedecms 
                                                     szAppName, MB_ICONERROR) ; 织梦好,好织梦 
               return 0 ; 

内容来自dedecms

     } 

织梦好,好织梦

      dedecms.com 
        hwnd = CreateWindow (  szAppName,  本文来自织梦 
                 TEXT ("No-Popup Nested Menu Demonstration"), dedecms.com 
                 WS_OVERLAPPEDWINDOW, 
copyright dedecms
                 CW_USEDEFAULT, CW_USEDEFAULT, 织梦好,好织梦 
                 CW_USEDEFAULT, CW_USEDEFAULT, 内容来自dedecms 
                 NULL, NULL, hInstance, NULL) ; 

copyright dedecms

      dedecms.com 
        ShowWindow (hwnd, iCmdShow) ; 内容来自dedecms 
        UpdateWindow (hwnd) ; 
织梦好,好织梦
      copyright dedecms 
        while (GetMessage (&msg, NULL, 0, 0)) 织梦好,好织梦 
        { dedecms.com 
                       TranslateMessage (&msg) ; 织梦内容管理系统 
                       DispatchMessage (&msg) ; 织梦好,好织梦 
        } 织梦内容管理系统 
        return msg.wParam ; 
内容来自dedecms
} 本文来自织梦 
  本文来自织梦 
LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) 内容来自dedecms 
{ 织梦内容管理系统 
        static HMENU   hMenuMain, hMenuEdit, hMenuFile ; 

本文来自织梦

        HINSTANCE              hInstance ; 
本文来自织梦
        switch (message) 

内容来自dedecms

     { 本文来自织梦 
        case    WM_CREATE: 本文来自织梦 
                       hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ; dedecms.com 
           本文来自织梦 
                       hMenuMain = LoadMenu (hInstance, TEXT ("MenuMain")) ; 织梦内容管理系统 
                       hMenuFile = LoadMenu (hInstance, TEXT ("MenuFile")) ; copyright dedecms 
                       hMenuEdit = LoadMenu (hInstance, TEXT ("MenuEdit")) ; 

内容来自dedecms

           
dedecms.com
                       SetMenu (hwnd, hMenuMain) ; 

织梦内容管理系统

                       return 0 ; 内容来自dedecms 
           本文来自织梦 
        case    WM_COMMAND: copyright dedecms 
                       switch (LOWORD (wParam)) copyright dedecms 
                       { 
dedecms.com
                       case    IDM_MAIN: 

本文来自织梦

                                      SetMenu (hwnd, hMenuMain) ; copyright dedecms 
                                      return 0 ; 

内容来自dedecms

                织梦内容管理系统 
                       case    IDM_FILE: 织梦内容管理系统 
                                      SetMenu (hwnd, hMenuFile) ; copyright dedecms 
                                      return 0 ; copyright dedecms 
                dedecms.com 
                       case    IDM_EDIT: 

本文来自织梦

                                     SetMenu (hwnd, hMenuEdit) ; 
织梦内容管理系统
                                      return 0 ; 

内容来自dedecms

                织梦内容管理系统 
                       case    IDM_FILE_NEW: 本文来自织梦 
                       case    IDM_FILE_OPEN: 

内容来自dedecms

                       case    IDM_FILE_SAVE: 

织梦内容管理系统

                       case    IDM_FILE_SAVE_AS: 

内容来自dedecms

                       case    IDM_EDIT_UNDO: 

copyright dedecms

                       case    IDM_EDIT_CUT: 内容来自dedecms 
                       case    IDM_EDIT_COPY: 
内容来自dedecms
                       case    IDM_EDIT_PASTE: 织梦好,好织梦 
                       case    IDM_EDIT_CLEAR: copyright dedecms 
                                      MessageBeep (0) ; 

dedecms.com

                                      return 0 ; copyright dedecms 
                       } copyright dedecms 
                       break ; 

织梦内容管理系统

           织梦好,好织梦 
        case    WM_DESTROY: 织梦内容管理系统 
                       SetMenu (hwnd, hMenuMain) ; 织梦好,好织梦 
                       DestroyMenu (hMenuFile) ; copyright dedecms 
                       DestroyMenu (hMenuEdit) ; 
内容来自dedecms
  

织梦内容管理系统

                       PostQuitMessage (0) ; 
dedecms.com
                       return 0 ; dedecms.com 
     } 织梦好,好织梦 
        return DefWindowProc (hwnd, message, wParam, lParam) ; 本文来自织梦 
} copyright dedecms 
 NOPOPUPS.RC (摘录) 

本文来自织梦

//Microsoft Developer Studio generated resource script. dedecms.com 
#include "resource.h" dedecms.com 
#include "afxres.h" copyright dedecms 
  dedecms.com 
///////////////////////////////////////////////////////////////////////////// 织梦好,好织梦 
// Menu dedecms.com 
MENUMAIN MENU DISCARDABLE  dedecms.com 
BEGIN 

本文来自织梦

        MENUITEM "MAIN:",         0, INACTIVE 
本文来自织梦
        MENUITEM "&File...",  IDM_FILE dedecms.com 
        MENUITEM "&Edit...",   IDM_EDIT dedecms.com 
END 

织梦内容管理系统

MENUFILE MENU DISCARDABLE                                                    内容来自dedecms 
BEGIN dedecms.com 
        MENUITEM "FILE:",              0, INACTIVE 

本文来自织梦

        MENUITEM "&New",                                                                    IDM_FILE_NEW 本文来自织梦 
        MENUITEM "&Open...",                                                IDM_FILE_OPEN copyright dedecms 
        MENUITEM "&Save",                                                            IDM_FILE_SAVE 

织梦好,好织梦

        MENUITEM "Save &As",                                                 IDM_FILE_SAVE_AS 
织梦内容管理系统
        MENUITEM "(&Main)",                                                                 IDM_MAIN 本文来自织梦 
END 本文来自织梦 
MENUEDIT MENU DISCARDABLE                                                    

copyright dedecms

BEGIN 

dedecms.com

    MENUITEM "EDIT:",                         0, INACTIVE 
本文来自织梦
    MENUITEM "&Undo",                                                       IDM_EDIT_UNDO copyright dedecms 
    MENUITEM "Cu&t",                  IDM_EDIT_CUT copyright dedecms 
    MENUITEM "&Copy",                 IDM_EDIT_COPY 

本文来自织梦

    MENUITEM "&Paste",                        IDM_EDIT_PASTE 

dedecms.com

    MENUITEM "De&lete",                       IDM_EDIT_CLEAR 
织梦好,好织梦
    MENUITEM "(&Main)",                       IDM_MAIN dedecms.com 
END 织梦内容管理系统 
 RESOURCE.H (摘录) 

本文来自织梦

// Microsoft Developer Studio generated include file. 
织梦内容管理系统
// Used by NoPopups.rc 织梦好,好织梦 
  dedecms.com 
#define IDM_FILE                   40001 
内容来自dedecms
#define IDM_EDIT                   40002 织梦内容管理系统 
#define IDM_FILE_NEW               40003 织梦内容管理系统 
#define IDM_FILE_OPEN              40004 

本文来自织梦

#define IDM_FILE_SAVE              40005 copyright dedecms 
#define IDM_FILE_SAVE_AS           40006 

本文来自织梦

#define IDM_MAIN                   40007 
copyright dedecms
#define IDM_EDIT_UNDO              40008 copyright dedecms 
#define IDM_EDIT_CUT               40009 内容来自dedecms 
#define IDM_EDIT_COPY              40010 copyright dedecms 
#define IDM_EDIT_PASTE             40011 

copyright dedecms

#define IDM_EDIT_CLEAR             40012 
内容来自dedecms

Microsoft Developer Studio中,您建立了三个功能表,而不是一个。从「Insert」中选择「Resource」三次,每个功能表有一个不同的名称。当视窗讯息处理程式处理WM_CREATE讯息时,Windows将每个功能表资源载入记忆体:

本文来自织梦

hMenuMain = LoadMenu (hInstance, TEXT ("MenuMain")) ; 
织梦好,好织梦
hMenuFile = LoadMenu (hInstance, TEXT ("MenuFile")) ; 织梦内容管理系统 
hMenuEdit = LoadMenu (hInstance, TEXT ("MenuEdit")) ; 
织梦好,好织梦

开始时,程式只显示主功能表:

织梦好,好织梦

SetMenu (hwnd, hMenuMain) ; 本文来自织梦 

主功能表使用字串「MAIN:」、「File...」和「Edit...」列出这三个选项。然而,「MAIN:」是禁用的,因此它不能使WM_COMMAND讯息被发送到视窗讯息处理程式。「File」和「Edit」功能表项以「FILE:」和「EDIT:」开始,表示它们是子功能表。每个功能表的最後一项都是字串「(Main)」,表示传回到主功能表。在这三个功能表之间进行切换是很简单的: dedecms.com

case    WM_COMMAND : 内容来自dedecms 
        switch (wParam) 本文来自织梦 
        { 内容来自dedecms 
        case    IDM_MAIN : 
织梦内容管理系统
               SetMenu (hwnd, hMenuMain) ; 

dedecms.com

                       return 0 ; 

dedecms.com

  
dedecms.com
        case    IDM_FILE : 

copyright dedecms

                       SetMenu (hwnd, hMenuFile) ; 织梦好,好织梦 
                       return 0 ; 

本文来自织梦

  
dedecms.com
        case    IDM_EDIT : 织梦内容管理系统 
                       SetMenu (hwnd, hMenuEdit) ; 织梦内容管理系统 
                       return 0 ; 
copyright dedecms
  本文来自织梦 
       其他行程式 
dedecms.com
        } 

织梦好,好织梦

        break ; 

本文来自织梦

WM_DESTROY讯息处理期间,NOPOPUPS将程式的功能表设定为主功能表,并呼叫DestroyMenu来清除「File」和「Edit」功能表。当视窗被清除时,主功能表将被自动清除。

内容来自dedecms

键盘加速键
 

copyright dedecms

加速键是产生WM_COMMAND讯息(有些情况下是WM_SYSCOMMAND)的键组合。许多时候,程式使用加速键来重复常用功能表项的动作(然而,加速键还可以用於执行非功能表功能)。例如,许多Windows程式都有一个包含「Delete」或「Clear」选项的「Edit」功能表,这些程式习惯上都将Del键指定为该选项的加速键。使用者可以通过「 Alt 键」从功能表中选择「 Delete 」选项,或者只需按下加速键 Del 。当视窗讯息处理程式收到一个WM_COMMAND讯息时,它不必确定使用的是功能表还是加速键。

copyright dedecms

为什么要使用加速键
  织梦内容管理系统

您也许会问:为什么我应该使用加速键?为什么不能直接拦截WM_KEYDOWNWM_CHAR讯息而自己实作同样的功能表功能呢?好处又在哪里呢?对於一个单视窗应用程式,您当然可以拦截键盘讯息,但是使用加速键可以得到一些好处:您不需要把功能表和加速键的处理方式重写一遍。 织梦内容管理系统

对於有多个视窗和多个视窗讯息处理程式的应用程式来说,加速键是非常重要的。正如我们所看到的,Windows将键盘讯息发送给目前活动视窗的视窗讯息处理程式。然而对於加速键,WindowsWM_COMMAND讯息发送给视窗讯息处理程式,该视窗讯息处理程式的代号在Windows函式TranslateAccelerator中给出。通常这是主视窗,也是拥有功能表的视窗,这意味著无须每个视窗讯息处理程式都把加速键的操作处理程式重写一遍。 织梦内容管理系统

如果您在主视窗的显示区域中,使用了非系统模态对话方块(在下一章中会讨论)或者子视窗,那么这种好处就变得非常重要。如果定义一个特定的加速键以便在不同的视窗之间移动,那么,只需要一个视窗讯息处理程式有这个处理程式。子视窗就不会收到加速键引发的WM_COMMAND讯息。 dedecms.com

安排加速键的几条规则
  copyright dedecms

理论上,您可以使用任何虚拟键或者字元键连同Shift键、Ctrl键或Alt键来定义加速键。然而,您应该尽力使应用程式之间协调一致,并且尽量避免干扰Windows的键盘使用。在加速键中,应该避免使用TabEnterEscSpacebar键,因为这些键常常用於完成系统功能。 织梦好,好织梦

加速键最经常的用途是操作程式的「Edit」功能表中的各项。为这些功能表项推荐的加速键在Windows 3.0Windows 3.1之间已有不同,因此通常都要支援如下所列的新旧两套加速键: copyright dedecms

 

copyright dedecms

10-2 dedecms.com

 

功能

copyright dedecms

旧加速键

copyright dedecms

新加速键 织梦内容管理系统

Undo 织梦好,好织梦

Alt+Backspace

织梦内容管理系统

Ctrl+Z 内容来自dedecms

Cut 本文来自织梦

Shift+Del

织梦好,好织梦

Ctrl+X 织梦内容管理系统

Copy

本文来自织梦

Ctrl+Ins 内容来自dedecms

Ctrl+C 织梦内容管理系统

Paste

copyright dedecms

Shift+Ins

织梦好,好织梦

Ctrl+V

dedecms.com

Delete或Clear 本文来自织梦

Del

dedecms.com

Del

织梦好,好织梦

 

另一种常用的虚拟键是启动辅助资讯的功能键F1。应该避免使用F4F5F6键,因为这些键常用在多重文件介面(MDI)程式中来完成特殊的功能(将在第十九章中讨论)。

内容来自dedecms

加速键表
 

dedecms.com

您可以在Developer Studio中定义加速键表。为了让程式中载入加速键表更为容易,给它和程式名相同的名称(与功能表和图示名也相同)。

内容来自dedecms

每个加速键都有在 Accel Properties 对话方块中定义的ID和按键组合。如果您已经定义了功能表,则功能表ID会出现在下拉式清单方块中,因此不需要键入它们。 织梦好,好织梦

加速键可以是虚拟键或ASCII字元与ShiftCtrlAlt键的组合。可以通过在字母前键入『^』来指定带有Ctrl键的ASCII字元。也可以从下拉式清单方块中选取虚拟键。 copyright dedecms

当您为功能表项定义加速键时,应该将键的组合包含到功能表项的文字中。跳位字元(\t)将文字与加速键分割开,将加速键列在第二列。为了在功能表中为加速键做上标记,可以在文字「Ctrl」、「Shift」或「Alt」之後跟上一个「+」号和一个键名(例如,「Shift+F6」或「Ctrl+F6」)。 本文来自织梦

加速键表的载入
  dedecms.com

在您的程式中,您使用LoadAccelerators函式把加速键表载入记忆体,并获得该表的代号。LoadAccelerators叙述非常类似於LoadIconLoadCursorLoadMenu叙述。

内容来自dedecms

首先,把加速键表的代号定义为型态HANDLE织梦内容管理系统

HANDLE hAccel ; 

内容来自dedecms

然後载入加速键表: 内容来自dedecms

hAccel = LoadAccelerators (hInstance, TEXT ("MyAccelerators")) ; 
内容来自dedecms

正如图示、游标和功能表一样,您可以使用一个数值代替加速键表的名称,然後在LoadAccelerators叙述中和MAKEINTRESOURCE巨集一起使用该数值,或者把它放在双引号内,前面冠以字元「#」。 织梦内容管理系统

键盘代码转换
  织梦内容管理系统

现在我们将讨论底下这三行程式码,在本书中,截至目前为止建立的所有Windows程式中都使用过它们。这些程式码是标准的讯息回圈: dedecms.com

while   (GetMessage (&msg, NULL, 0, 0)) dedecms.com 
{ 本文来自织梦 
        TranslateMessage (&msg) ; 织梦内容管理系统 
        DispatchMessage (&msg) ; 

织梦好,好织梦

} 
本文来自织梦

下面把上头那段程式码加以修改,以便使用加速键:

织梦好,好织梦

while   (GetMessage (&msg, NULL, 0, 0)) 
内容来自dedecms
{ 内容来自dedecms 
        if (!TranslateAccelerator (hwnd, hAccel, &msg)) 织梦内容管理系统 
     { 内容来自dedecms 
                       TranslateMessage (&msg) ; 

织梦内容管理系统

                       DispatchMessage (&msg) ; 织梦好,好织梦 
        } 
织梦内容管理系统
} copyright dedecms 

TranslateAccelerator函式确认存放在msg讯息结构中的讯息是否为键盘讯息。如果是,该函式将找寻代号为hAccel的加速键表。如果找到了一个符合的,则呼叫代号为hwnd的视窗讯息处理程式。如果加速键ID与系统功能表的功能表项一致,则讯息就是WM_SYSCOMMAND;否则,讯息为WM_COMMANDcopyright dedecms

TranslateAccelerator传回时,如果讯息已经被转换(并且已经被发送给视窗讯息处理程式),那么传回值为非零;否则,传回值为0。如果TranslateAccelerator传回一个非零值,则不呼叫TranslateMessageDispatchMessage,而是经过回圈回到GetMessage呼叫中。

dedecms.com

TranslateMessage中的参数hwnd看起来有点累赘,因为讯息回圈中的其他三个函式都没有要求这个参数。此外,讯息结构本身(结构变数msg)有一个叫做hwnd的成员,它是视窗代号。 织梦内容管理系统

该函式有些不同的原因在於:msg结构的栏位由GetMessage呼叫填入。当GetMessage的第二个参数为NULL时,函式会找寻应用程式所有视窗的讯息。当GetMessage传回时,msg结构的hwnd是将要获得讯息之视窗的视窗代号。然而,当TranslateAccelerator把键盘讯息转换为WM_COMMANDWM_SYSCOMMAND讯息时,它使用函式的第一个参数指定的视窗代号hwnd来代替视窗代号msg.hwndWindows就是这样把所有加速键讯息发送给同一视窗讯息处理程式的,即使另一个应用视窗目前拥有输入焦点。当系统模态对话方块或者讯息方块拥有输入焦点时,TranslateAccelerator不会转换键盘讯息,因为这些视窗的讯息是不经过程式的讯息回圈的。

copyright dedecms

在某些情况下,当您程式的另一个视窗(比如一个非系统模态对话方块)拥有输入焦点时,您也许不想转换加速键。您将在下一章中看到如何处理这种情况。

本文来自织梦

接收加速键讯息
  copyright dedecms

当加速键与系统功能表中的功能表项相对应时,TranslateAccelerator给视窗讯息处理程式发送一个WM_SYSCOMMAND讯息,否则,TranslateAccelerator给视窗讯息处理程式发送一个WM_COMMAND讯息。下表所示为几种可能接收到的WM_COMMAND讯息,这些讯息用於加速键、功能表命令以及子视窗控制项:

内容来自dedecms

 

织梦好,好织梦

10-3 copyright dedecms

 

 

织梦内容管理系统

加速键 copyright dedecms

功能表 copyright dedecms

控制项 dedecms.com

LOWORD (wParam)

本文来自织梦

加速键ID

dedecms.com

功能表ID

dedecms.com

控制项ID 本文来自织梦

HIWORD (wParam)

内容来自dedecms

1

本文来自织梦

0 本文来自织梦

通知码 织梦内容管理系统

lParam dedecms.com

0 本文来自织梦

0 dedecms.com

子视窗代号 copyright dedecms

 

如果加速键与一个功能表项对应,那么视窗讯息处理程式还会收到WM_INITMENUWM_INITMENUPOPUPWM_MENUSELECT讯息,就好像选中了功能表选项一样。在处理WM_INITMENUPOPUP时,程式往往启用和禁用突现式功能表中的功能表项,因此,在使用加速键时,您仍然能够实作这类功能。如果加速键与一个禁用或者无效化的功能表项相对应,那么,TranslateAccelerator函式就不会向视窗讯息处理程式发送WM_COMMANDWM_SYSCOMMAND讯息。

copyright dedecms

如果活动视窗已经被最小化,那么TranslateAccelerator将为与启用的系统功能表项相对应的加速键向视窗讯息处理程式发送WM_SYSCOMMAND讯息,而不是WM_COMMAND讯息。TranslateAccelerator也会为没有任何功能表项与之对应的加速键,来向视窗讯息处理程式发送WM_COMMAND讯息。

织梦内容管理系统

功能表与加速键应用程式POPPAD
  织梦内容管理系统

在第九章,我们建立了一个叫做POPPAD1的程式,它使用了子视窗编辑控制项来实作基本的笔记本功能。在这一章中,我们将加入「File」和「Edit」功能表,并称此程式为POPPAD2。「Edit」功能表的功能表项的功能全部可用;我们将在第十一章中完成「File」功能,在第十三章中完成「Print」功能。POPPAD2如程式10-9所示。

织梦内容管理系统

 程式10-9  POPPAD2 织梦好,好织梦 
POPPAD2.C 织梦好,好织梦 
/*--------------------------------------------------------------------------- 
织梦内容管理系统
        POPPAD2.C --           Popup Editor Version 2 (includes menu) 
织梦好,好织梦
                                                             (c) Charles Petzold, 1998 

内容来自dedecms

---------------------------------------------------------------------------*/ copyright dedecms 
  

织梦好,好织梦

#include <windows.h> 内容来自dedecms 
#include "resource.h" 本文来自织梦 
  织梦好,好织梦 
#define ID_EDIT                       1 

织梦好,好织梦

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); 

织梦内容管理系统

TCHAR szAppName[] = TEXT ("PopPad2") ; 本文来自织梦 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 

dedecms.com

                                                             PSTR szCmdLine, int iCmdShow) 
内容来自dedecms
{ 内容来自dedecms 
        HACCEL                 hAccel ; 内容来自dedecms 
        HWND                           hwnd ; 

织梦内容管理系统

        MSG                            msg ; 织梦内容管理系统 
        WNDCLASS               wndclass ; 
内容来自dedecms
        wndclass.style                                        = CS_HREDRAW | CS_VREDRAW ; 本文来自织梦 
        wndclass.lpfnWndProc                                  = WndProc ; copyright dedecms 
        wndclass.cbClsExtra                                   = 0 ; copyright dedecms 
        wndclass.cbWndExtra                                   = 0 ; 

本文来自织梦

        wndclass.hInstance                                    = hInstance ; 织梦内容管理系统 
        wndclass.hIcon                                        = LoadIcon (hInstance, szAppName) ; copyright dedecms 
        wndclass.hCursor                                      = LoadCursor (NULL, IDC_ARROW) ; copyright dedecms 
        wndclass.hbrBackground                        = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 织梦好,好织梦 
        wndclass.lpszMenuName                         = szAppName ; 本文来自织梦 
        wndclass.lpszClassName                        = szAppName ; copyright dedecms 
      
织梦内容管理系统
        if (!RegisterClass (&wndclass)) dedecms.com 
        { 
内容来自dedecms
                       MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 织梦内容管理系统 
                    szAppName, MB_ICONERROR) ; 
织梦内容管理系统
                       return 0 ; 
内容来自dedecms
        } dedecms.com 
      本文来自织梦 
        hwnd = CreateWindow (  szAppName, szAppName, 织梦好,好织梦 
                       WS_OVERLAPPEDWINDOW, 织梦内容管理系统 
                     GetSystemMetrics (SM_CXSCREEN) / 4, 

dedecms.com

                     GetSystemMetrics (SM_CYSCREEN) / 4, 

织梦内容管理系统

                     GetSystemMetrics (SM_CXSCREEN) / 2, 

dedecms.com

                     GetSystemMetrics (SM_CYSCREEN) / 2, 本文来自织梦 
                     NULL, NULL, hInstance, NULL) ; copyright dedecms 
      织梦内容管理系统 
        ShowWindow (hwnd, iCmdShow) ; 

copyright dedecms

        UpdateWindow (hwnd) ;  dedecms.com 
      织梦好,好织梦 
        hAccel = LoadAccelerators (hInstance, szAppName) ; 内容来自dedecms 
        while (GetMessage (&msg, NULL, 0, 0)) copyright dedecms 
        { 

dedecms.com

                       if (!TranslateAccelerator (hwnd, hAccel, &msg)) 

dedecms.com

                               { 
本文来自织梦
                                      TranslateMessage (&msg) ; 
织梦内容管理系统
                                      DispatchMessage (&msg) ; 

copyright dedecms

                       } 

内容来自dedecms

        } 

织梦内容管理系统

        return msg.wParam ; 

本文来自织梦

} 
内容来自dedecms
  

织梦内容管理系统

AskConfirmation (HWND hwnd) copyright dedecms 
{ 织梦内容管理系统 
        return MessageBox (    hwnd, TEXT ("Really want to close PopPad2?"), 
织梦好,好织梦
                               szAppName, MB_YESNO | MB_ICONQUESTION) ; 织梦好,好织梦 
} 本文来自织梦 
  
dedecms.com
LRESULT CALLBACK WndProc (     HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) copyright dedecms 
{ 
内容来自dedecms
       static HWND    hwndEdit ; 
本文来自织梦
        int                                   iSelect, iEnable ; 

内容来自dedecms

      本文来自织梦 
        switch (message) 
本文来自织梦
        { 内容来自dedecms 
        case    WM_CREATE: 内容来自dedecms 
                       hwndEdit = CreateWindow (TEXT ("edit"), NULL, 内容来自dedecms 
                   WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | 
copyright dedecms
                   WS_BORDER | ES_LEFT | ES_MULTILINE | 内容来自dedecms 
                   ES_AUTOHSCROLL | ES_AUTOVSCROLL, 内容来自dedecms 
                   0, 0, 0, 0, hwnd, (HMENU) ID_EDIT, 

织梦好,好织梦

                   ((LPCREATESTRUCT) lParam)->hInstance, NULL) ; 

织梦内容管理系统

                       return 0 ; copyright dedecms 
           

内容来自dedecms

        case    WM_SETFOCUS: 内容来自dedecms 
                       SetFocus (hwndEdit) ; 本文来自织梦 
                       return 0 ; 织梦好,好织梦 
           内容来自dedecms 
        case    WM_SIZE:  dedecms.com 
                       MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ; 织梦内容管理系统 
                       return 0 ; 

copyright dedecms

           copyright dedecms 
        case    WM_INITMENUPOPUP: copyright dedecms 
                       if (lParam == 1) 
本文来自织梦
                       { 

内容来自dedecms

                                      EnableMenuItem ((HMENU) wParam, IDM_EDIT_UNDO, 
内容来自dedecms
                               SendMessage (hwndEdit, EM_CANUNDO, 0, 0) ? 
织梦好,好织梦
                            MF_ENABLED : MF_GRAYED) ; 

copyright dedecms

                内容来自dedecms 
                                      EnableMenuItem ((HMENU) wParam, IDM_EDIT_PASTE, 
本文来自织梦
                               IsClipboardFormatAvailable (CF_TEXT) ? 

内容来自dedecms

                            MF_ENABLED : MF_GRAYED) ; 织梦好,好织梦 
                

copyright dedecms

                                      iSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0) ; 
本文来自织梦
                
内容来自dedecms
                                      if (HIWORD (iSelect) == LOWORD (iSelect)) 织梦好,好织梦 
                                                             iEnable = MF_GRAYED ; 

内容来自dedecms

                                      else copyright dedecms 
                                                             iEnable = MF_ENABLED ; 
copyright dedecms
                
内容来自dedecms
               EnableMenuItem ((HMENU) wParam, IDM_EDIT_CUT,  iEnable) ; 
内容来自dedecms
               EnableMenuItem ((HMENU) wParam, IDM_EDIT_COPY,  iEnable) ; 

织梦内容管理系统

               EnableMenuItem ((HMENU) wParam, IDM_EDIT_CLEAR, iEnable) ; 织梦好,好织梦 
                                      return 0 ; 

dedecms.com

                       } 内容来自dedecms 
                       break ; 

dedecms.com

        case    WM_COMMAND: 内容来自dedecms 
                       if (lParam) 本文来自织梦 
                       { 

dedecms.com

                               if (LOWORD (lParam) == ID_EDIT && 
织梦内容管理系统
                        (HIWORD (wParam) == EN_ERRSPACE || 

copyright dedecms

                        HIWORD (wParam) == EN_MAXTEXT)) 

内容来自dedecms

                       MessageBox (hwnd, TEXT ("Edit control out of space."), 

copyright dedecms

                        szAppName, MB_OK | MB_ICONSTOP) ; copyright dedecms 
                               return 0 ; dedecms.com 
          } 

copyright dedecms

                       else    switch (LOWORD (wParam)) 

本文来自织梦

                       { 

copyright dedecms

                       case    IDM_FILE_NEW: 织梦好,好织梦 
                       case    IDM_FILE_OPEN: 

本文来自织梦

                       case    IDM_FILE_SAVE: 内容来自dedecms 
                       case    IDM_FILE_SAVE_AS: 织梦好,好织梦 
                       case    IDM_FILE_PRINT: 

织梦内容管理系统

                                      MessageBeep (0) ; 
内容来自dedecms
                                      return 0 ; 

织梦好,好织梦

           
dedecms.com
                       case    IDM_APP_EXIT: 内容来自dedecms 
                                      SendMessage (hwnd, WM_CLOSE, 0, 0) ; 
织梦内容管理系统
                                      return 0 ; 

织梦内容管理系统

  copyright dedecms 
                       case    IDM_EDIT_UNDO: 

织梦好,好织梦

                                      SendMessage (hwndEdit, WM_UNDO, 0, 0) ; 
织梦内容管理系统
                                      return 0 ; 内容来自dedecms 
           copyright dedecms 
                       case    IDM_EDIT_CUT: 内容来自dedecms 
                                      SendMessage (hwndEdit, WM_CUT, 0, 0) ; 本文来自织梦 
                                      return 0 ; 织梦好,好织梦 
           

织梦内容管理系统

                       case    IDM_EDIT_COPY: 
copyright dedecms
                                      SendMessage (hwndEdit, WM_COPY, 0, 0) ; dedecms.com 
                                      return 0 ; 

内容来自dedecms

           

织梦内容管理系统

                       case    IDM_EDIT_PASTE: dedecms.com 
                                      SendMessage (hwndEdit, WM_PASTE, 0, 0) ; 

本文来自织梦

                                      return 0 ; 

织梦好,好织梦

           
内容来自dedecms
                       case    IDM_EDIT_CLEAR: copyright dedecms 
                                      SendMessage (hwndEdit, WM_CLEAR, 0, 0) ; 内容来自dedecms 
                                      return 0 ; 内容来自dedecms 
  本文来自织梦 
               case    IDM_EDIT_SELECT_ALL: 织梦好,好织梦 
                                       SendMessage (hwndEdit, EM_SETSEL, 0, -1) ; 内容来自dedecms 
                                      return 0 ; 本文来自织梦 
           
织梦内容管理系统
                       case    IDM_HELP_HELP: copyright dedecms 
                                      MessageBox (hwnd, TEXT ("Help not yet implemented!"), 本文来自织梦 
                            szAppName, MB_OK | MB_ICONEXCLAMATION) ; 
内容来自dedecms
                                      return 0 ; copyright dedecms 
           

织梦好,好织梦

                       case    IDM_APP_ABOUT: 
织梦内容管理系统
                                      MessageBox (hwnd, TEXT ("POPPAD2 (c) Charles Petzold, 1998"), 本文来自织梦 
                               szAppName, MB_OK | MB_ICONINFORMATION) ; 织梦好,好织梦 
                                      return 0 ; 

本文来自织梦

                       } dedecms.com 
                       break ; 织梦内容管理系统 
           

copyright dedecms

        case    WM_CLOSE: dedecms.com 
                       if (IDYES == AskConfirmation (hwnd)) 

dedecms.com

                                      DestroyWindow (hwnd) ; 本文来自织梦 
                       return 0 ; 
织梦内容管理系统
           织梦好,好织梦 
        case    WM_QUERYENDSESSION: 织梦好,好织梦 
                       if (IDYES == AskConfirmation (hwnd)) 内容来自dedecms 
                                      return 1 ; 

内容来自dedecms

                       else 织梦内容管理系统 
                                      return 0 ; 

dedecms.com

           
dedecms.com
        case    WM_DESTROY: 
dedecms.com
                       PostQuitMessage (0) ; 

copyright dedecms

                       return 0 ; 织梦好,好织梦 
     } 

织梦内容管理系统

        return DefWindowProc (hwnd, message, wParam, lParam) ; 织梦内容管理系统 
} 
copyright dedecms
 POPPAD2.RC (摘录) copyright dedecms 
//Microsoft Developer Studio generated resource script. 

织梦好,好织梦

#include "resource.h" 

内容来自dedecms

#include "afxres.h" copyright dedecms 
  copyright dedecms 
///////////////////////////////////////////////////////////////////////////// dedecms.com 
// Icon 本文来自织梦 
POPPAD2                ICON    DISCARDABLE     "poppad2.ico" 织梦好,好织梦 
///////////////////////////////////////////////////////////////////////////// copyright dedecms 
// Menu 

织梦内容管理系统

POPPAD2 MENU DISCARDABLE  copyright dedecms 
BEGIN 织梦好,好织梦 
        POPUP "&File"                                          本文来自织梦 
        BEGIN dedecms.com 
               MENUITEM "&New",                                             IDM_FILE_NEW 织梦好,好织梦 
                       MENUITEM "&Open...",                          IDM_FILE_OPEN 
织梦好,好织梦
                       MENUITEM "&Save",                                     IDM_FILE_SAVE 
dedecms.com
                       MENUITEM "Save &As...",                       IDM_FILE_SAVE_AS 本文来自织梦 
                       MENUITEM SEPARATOR 本文来自织梦 
                       MENUITEM "&Print",                                    IDM_FILE_PRINT 

织梦好,好织梦

                       MENUITEM SEPARATOR      

copyright dedecms

                       MENUITEM "E&xit",                             IDM_APP_EXIT 
织梦内容管理系统
        END 
dedecms.com
        POPUP "&Edit" 织梦好,好织梦 
        BEGIN 本文来自织梦 
                       MENUITEM "&Undo\tCtrl+Z",                     IDM_EDIT_UNDO 织梦内容管理系统 
                       MENUITEM SEPARATOR 

织梦内容管理系统

                       MENUITEM "Cu&t\tCtrl+X",                              IDM_EDIT_CUT 

本文来自织梦

                       MENUITEM "&Copy\tCtrl+C",                     IDM_EDIT_COPY 织梦内容管理系统 
                       MENUITEM "&Paste\tCtrl+V",                    IDM_EDIT_PASTE 

本文来自织梦

                       MENUITEM "De&lete\tDel",                              IDM_EDIT_CLEAR 本文来自织梦 
                       MENUITEM SEPARATOR 

dedecms.com

                       MENUITEM "&Select All",                               IDM_EDIT_SELECT_ALL copyright dedecms 
        END 

织梦内容管理系统

        POPUP "&Help" 

本文来自织梦

        BEGIN 

copyright dedecms

                       MENUITEM "&Help...",                                          IDM_HELP_HELP 
内容来自dedecms
                       MENUITEM "&About PopPad2...",         IDM_APP_ABOUT dedecms.com 
        END 

织梦内容管理系统

END 本文来自织梦 
  

本文来自织梦

///////////////////////////////////////////////////////////////////////////// 

织梦好,好织梦

// Accelerator copyright dedecms 
POPPAD2 ACCELERATORS DISCARDABLE  

本文来自织梦

BEGIN dedecms.com 
        VK_BACK,                       IDM_EDIT_UNDO,          VIRTKEY, ALT, NOINVERT 
本文来自织梦
        VK_DELETE,                     IDM_EDIT_CLEAR,                VIRTKEY, NOINVERT 内容来自dedecms 
        VK_DELETE,                     IDM_EDIT_CUT,           VIRTKEY, SHIFT, NOINVERT 内容来自dedecms 
        VK_F1,                         IDM_HELP_HELP,          VIRTKEY, NOINVERT 
dedecms.com
        VK_INSERT,                     IDM_EDIT_COPY,          VIRTKEY, CONTROL, NOINVERT 

内容来自dedecms

        VK_INSERT,                     IDM_EDIT_PASTE,         VIRTKEY, SHIFT, NOINVERT 本文来自织梦 
        "^C",         IDM_EDIT_COPY,          ASCII,  NOINVERT 

dedecms.com

        "^V",         IDM_EDIT_PASTE,         ASCII,  NOINVERT 本文来自织梦 
       "^X",         IDM_EDIT_CUT,           ASCII,  NOINVERT 织梦内容管理系统 
        "^Z",         IDM_EDIT_UNDO,          ASCII,  NOINVERT 

dedecms.com

END copyright dedecms 
 RESOURCE.H (摘录) 

dedecms.com

// Microsoft Developer Studio generated include file. 本文来自织梦 
// Used by POPPAD2.RC dedecms.com 
  本文来自织梦 
#define IDM_FILE_NEW                 40001 织梦内容管理系统 
#define IDM_FILE_OPEN                40002 
织梦好,好织梦
#define IDM_FILE_SAVE                40003 

内容来自dedecms

#define IDM_FILE_SAVE_AS             40004 织梦好,好织梦 
#define IDM_FILE_PRINT               40005 
织梦内容管理系统
#define IDM_APP_EXIT                 40006 内容来自dedecms 
#define IDM_EDIT_UNDO                40007 
dedecms.com
#define IDM_EDIT_CUT                 40008 
织梦好,好织梦
#define IDM_EDIT_COPY                40009 本文来自织梦 
#define IDM_EDIT_PASTE               40010 

内容来自dedecms

#define IDM_EDIT_CLEAR               40011 内容来自dedecms 
#define IDM_EDIT_SELECT_ALL          40012 织梦好,好织梦 
#define IDM_HELP_HELP                40013 

织梦好,好织梦

#define IDM_APP_ABOUT                40014 
dedecms.com

  dedecms.com

POPPAD2.ICO 内容来自dedecms

 

 

内容来自dedecms

 

织梦好,好织梦


  本文来自织梦

织梦好,好织梦


  本文来自织梦

织梦内容管理系统

 

POPPAD2.RC资源描述档包含功能表和加速键。您将注意到,所有加速键都表示在跳位字元(\t)後的「Edit」突现式功能表的字串中。 织梦内容管理系统

启用功能表项
  本文来自织梦

视窗讯息处理程式的工作包括启用和无效化「Edit」功能表中的选项,这项工作在处理WM_INITMENUPOPUP时完成。首先,程式检查是否要显示「Edit」突现式功能表。因为功能表里「Edit」的位置索引(「File」从0开始)是1,因此如果即将显示「Edit」突现式功能表,那么lParam应该等於1

本文来自织梦

为了确定是否启用「Undo」选项,POPPAD2给编辑控制项发送一条EM_CANUNDO讯息。如果编辑控制项能够执行「Undo」动作,那么SendMessage呼叫传回非零值。在这种情况下,选项被启用;否则,选项无效化:

dedecms.com

EnableMenuItem (wParam, IDM_UNDO, 内容来自dedecms 
        SendMessage (hwndEdit, EM_CANUNDO, 0, 0) ? 织梦内容管理系统 
                                                      MF_ENABLED : MF_GRAYED) ; 
内容来自dedecms

只有当剪贴簿中包含文字时,「Paste」选项才能够被启用。我们可以使用CF_TEXT识别字通过IsClipboardFormatAvailable呼叫来确定这一点:

copyright dedecms

EnableMenuItem (wParam, IDM_PASTE, 
copyright dedecms
        IsClipboardFormatAvailable (CF_TEXT) ? MF_ENABLED : MF_GRAYED) ; 
本文来自织梦

只有选择了编辑控制项中的文字,「Cut」、「Copy」和「Delete」选项才能够被启用。给编辑控制项发送一条EM_GETSEL讯息,并传回包含此资讯的整数:

织梦内容管理系统

iSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0) ; copyright dedecms 

iSelect的低位元字是第一个被选中字元的位置,iSelect的高字组是下一个被选中字元的位置。如果这两个字相等,则表示没有选中文字:

copyright dedecms

if (HIWORD (iSelect) == LOWORD (iSelect)) 

内容来自dedecms

        iEnable = MF_GRAYED ; copyright dedecms 
else copyright dedecms 
        iEnable = MF_ENABLED ; 

织梦内容管理系统

然後可以将iEnable的值用於「Cut」、「Copy」和「Delete」选项: copyright dedecms

EnableMenuItem (wParam, IDM_CUT,  iEnable) ; 

内容来自dedecms

EnableMenuItem (wParam, IDM_COPY, iEnable) ; 
内容来自dedecms
EnableMenuItem (wParam, IDM_DEL,  iEnable) ; dedecms.com 

处理功能表项
 

本文来自织梦

当然,如果POPPAD2程式不使用子视窗编辑控制项,那么我们将面临一些问题,这涉及如何完成「Edit」功能表中的「Undo」、「Cut」、「Copy」、「Paste」、「Clear」和「Select All」选项。正是编辑控制项使得这种处理变得容易,因为对於每一个选项我们只需向编辑控制项发送一个讯息即可:

copyright dedecms

case    IDM_UNDO : 

dedecms.com

        SendMessage (hwndEdit, WM_UNDO, 0, 0) ; 

内容来自dedecms

        return 0 ; 内容来自dedecms 
  dedecms.com 
case    IDM_CUT : 内容来自dedecms 
        SendMessage (hwndEdit, WM_CUT, 0, 0) ; 
copyright dedecms
        return 0 ; 织梦好,好织梦 
  内容来自dedecms 
case    IDM_COPY : 织梦内容管理系统 
        SendMessage (hwndEdit, WM_COPY, 0, 0) ; 内容来自dedecms 
        return 0 ; 

织梦内容管理系统

 
copyright dedecms
case    IDM_PASTE : dedecms.com 
        SendMessage (hwndEdit, WM_PASTE, 0, 0) ; 

织梦内容管理系统

        return 0 ; 本文来自织梦 
  
内容来自dedecms
case    IDM_DEL : 内容来自dedecms 
        SendMessage (hwndEdit, WM_DEL, 0, 0) ; 本文来自织梦 
        return 0 ; copyright dedecms 
case    IDM_SELALL : dedecms.com 
        SendMessage (hwndEdit, EM_SETSEL, 0, -1) ; 

本文来自织梦

        return 0 ; 

内容来自dedecms

注意,我们可以更进一步简化这些处理-只要使IDM_UNDOIDM_CUT等等的值等於相对应的视窗讯息WM_UNDOWM_CUT的值。 copyright dedecms

File」突现式功能表上的「About」选项启动一个简单的讯息方块:

织梦好,好织梦

case    IDM_ABOUT : 

织梦内容管理系统

        MessageBox (hwnd, TEXT ("POPPAD2 (c) Charles Petzold, 1998"), 内容来自dedecms 
                                                     szAppName, MB_OK | MB_ICONINFORMATION) ; dedecms.com 
        return 0 ; 

dedecms.com

在下一章中,我们将把它变成一个对话方块。当您从功能表中选择「Help」选项或者按下F1加速键时,同样可以启动一个讯息方块。

内容来自dedecms

Exit」选项向视窗讯息处理程式发送一个WM_CLOSE讯息:

内容来自dedecms

case    IDM_EXIT : 织梦内容管理系统 
        SendMessage (hwnd, WM_CLOSE, 0, 0) ; dedecms.com 
        return 0 ; 

copyright dedecms

这正是DefWindowProc收到一个wParam等於SC_CLOSEWM_SYSCOMMAND讯息时所完成的工作。

copyright dedecms

在前面的那些程式中,我们没有在视窗讯息处理程式中处理WM_CLOSE讯息,而只是简单地把它送给DefWindowProcDefWindowProcWM_CLOSE的处理非常简单:呼叫DestroyWindow函式。可以不把WM_CLOSE讯息送给DefWindowProc,而让POPPAD2来处理它。这个事实到目前为止并不重要,但是在第十一章中当POPPAD可以真正编辑文字时,它就变得非常重要了。 内容来自dedecms

case WM_CLOSE : 织梦内容管理系统 
        if (IDYES == AskConfirmation (hwnd)) 
内容来自dedecms
                       DestroyWindow (hwnd) ; 
copyright dedecms
        return 0 ; 
织梦内容管理系统

AskConfirmationPOPPAD2中的一个函式,它显示一个请求确认关闭程式的讯息方块: dedecms.com

AskConfirmation (HWND hwnd) 
织梦好,好织梦
{ 本文来自织梦 
        return MessageBox (hwnd, TEXT ("Really want to close Poppad2?"), copyright dedecms 
                               szAppName, MB_YESNO | MB_ICONQUESTION) ; 

内容来自dedecms

} copyright dedecms 

如果选择了Yes按钮的话,讯息方块(以及AskConfirmation函式)将传回IDYES。只有这样,程式才会呼叫DestroyWindow,否则,程式不会结束。 dedecms.com

如果要在程式结束之前确认使用者真的要结束程式,那么您还必须处理WM_QUERYENDSESSION讯息。当使用者要关闭Windows时,Windows开始向每个视窗讯息处理程式发送一个WM_QUERYENDSESSION讯息。如果有任何一个视窗讯息处理程式处理这个讯息後传回0,那么Windows将不会结束。我们如下处理了WM_QUERYENDSESSION织梦内容管理系统

case    WM_QUERYENDSESSION : 本文来自织梦 
        if (IDYES == AskConfirmation (hwnd)) 织梦内容管理系统 
                       return 1 ; 

copyright dedecms

        else 
本文来自织梦
                       return 0 ; 
本文来自织梦

如果要在程式结束之前要求使用者的确认,必须处理WM_CLOSEWM_QUERYENDSESSION这两个讯息,这就是为什么我们使POPPAD2中的「Exit」功能表选项只向视窗讯息处理程式发送一个WM_CLOSE讯息的原因。这样做,我们避免了在别处进行请求确认的动作。 织梦内容管理系统

如果要处理WM_QUERYENDSESSION讯息,那么您也许还会对WM_ENDSESSION讯息感兴趣。Windows把这个讯息发送给先前收到WM_QUERYENDSESSION讯息的每个视窗讯息处理程式。如果由於另一个程式从WM_QUERYENDSESSION传回了0而不能结束Windows的执行,那么WM_ENDSESSIONwParam参数为0WM_ENDSESSION讯息实际上回答了这个问题:我告诉过Windows可以把我结束掉,但是我真的被结束掉了吗? 织梦内容管理系统

尽管在POPPAD2的「File」功能表中我加上了常见的「New」、「Open」、「Save」和「Save As」选项,但是它们现在并不起作用。要处理这些命令,我们需要使用对话方块。现在是讨论对话方块的时机,也是您准备学习它们的时候了。 本文来自织梦