《Windows游戏编程大师技巧》2e——我学到了什么? windows游戏编程大师

在游戏开发中,应用正确的物理定律可以逼真地模拟游戏中任何弹跳、飞行、翻滚、滑行或非静止的物体,以建立令人注目且真实的游戏、动画内容。
本书从基础讲起,借助形象的范例程序,介绍了如何在游戏开发中加入物理真实性并丰富游戏内容,使游戏更加灵活生动。全书共分三部分。第一部分是复习基本概念及讨论刚体动力学的机械力学初级课程;第二部分将这些问题应用到现实生活的问题上,例如抛射体、船舰、飞机和汽车;第三部分介绍即时模拟器并示范了如何将其应用到游戏开发中。

人工智能开发是一个程序员能够承担的最有挑战性的任务之一,而这本独一无二的论文集提供给程序员应对这个挑战的非常急需的信息。本书汇集了与智能游戏开发有关的人工智能内容,借助这些内容,程序开发员能够开发出智能角色。本书分为11章,分别是:通用智能,实用技术和专用系统,A*路径搜索,路径搜索与运动,战术问题和智能的群体运动,通用智能游戏架构,决策体系结构,FPS、RTS和RPG游戏中的智能,竞赛与运动智能,脚本语言,学习理论。由于本书是智能游戏专家(高手)亲自编写的,因此读者可以使用本书作为路线图,了解在智能游戏方面什么已经成功使用,什么在将来具有很大潜力。智能游戏专家深入研究了有关智能游戏编程方面的问题,为读者提供了深邃的观点和技术,这些可以很方便地应用在读者自己开发的游戏程序中。本书介绍的虚拟工具箱包括解决一般性人工智能问题的工具,也包括读者可能遇到的一些特定问题的解决思路,无诊费经验丰富的智能游戏专家,还是准备进入游戏工业界的人士,本书都是必备资源。

第3章 高级Windows编程
一、怎么使用资源文件rc,通过手工加载各种资源文件,并且使用他们。
1、rc文件中各种资源的定义:
a.定义ICON资源icon_idICON filename.ico
icon_nameICON filename.ico
b.定义CURSOR资源cursor_idCURSOR filename.cur
cursor_nameCURSOR filename.cur
c.定义STRINGTABLE资源STRINGTABLE{
ID_STRING1,"string1"
ID_STRING2,"string2"


}
d.定义WAVE资源wave_idWAVE filename.wav
wave_name WAVEfilename.wav
e.定义菜单资源menu_nameMENU DISCARDABLE
{


}

2、为什么要用.h文件:在使用id方式创建资源时应定义一个.h文件,用于定义各个id。

3、各种资源的使用方法:
(没有特殊说明以下函数中用的ID都要用MAKEINTRESOURCE()宏转换)
a.使用ICON资源LoadIcon()
它有2个参数分别是:
应用程序实例,字符文件名(或ID)
b.使用CURSOR资源LoadCursor()
它有2个参数分别是:
应用程序实例,字符文件名(或ID)
c.使用STRINGTABLE资源LoadString()
它有4个参数分别是:
应用程序实例,ID,lpBuffer,nBufferMax。
这里的ID不需要使用MAKEINTRESOURCE()宏转换
d.使用WAVE资源PlaySound()
它有3个参数分别是:
字符文件名(或ID),应用程序实例,播放方式。
e.使用菜单资源用一个例子:
MainMenuMENU DISCARDABLE
{
POPUP"File"
{
MENUITEM "Open",MENU_FILE_ID_OPEN
MENUITEM "Close",MENU_FILE_ID_CLOSE
MENUITEM "Save",MENU_FILE_ID_SAVE
MENUITEM "Exit",MENU_FILE_ID_EXIT
}
POPUP"Help"
{
MENUITEM "About",MENU_FILE_ID_ABOUT
}
}
1).在窗口类中定义,有一点不好就是用该类创建的窗口都会有这个菜单。
2).使用LoadMenu()指定菜单给窗口,用法:在CreateWindow()函数中使用LoadMenu()函数指定菜单。
3).还可以用SetMunu()函数将菜单关联到窗口上,有两个参数一个是窗口句柄hWnd,另一个是菜单句柄,可以用LoadMenu()函数得到。
相应菜单事件消息:
msg——WM_COMMAND
lparam——发出消息的窗口句柄
wparam——选中的菜单项的ID,从技术角度上讲,为了安全应用LOWORD()宏从wparam中提取低位的WORD

二、GDI简介
HDCBeginPaint(HWND,PAINTSTRUCT*)/EndPaint(HWND,PAINTSTRACT*)
HDC GetDC(HWND)/int ReleaseDC(HWND,hDC)
1、使用BeginPaint/EndPaint时,它会向系统发出一个窗口区域有效的消息,而GetDC/ReleaseDC不会发送这个消息,以至于系统会不断发送窗口无效的消息要求重画,因此我们要用另外一个函数来完成发送窗口区域有效消息的工作——在ReleaseDC后调用BOOLValidateRect(HWND,CONSTRECT*)。rect中保存着窗口有效区域,可以通过调用GetClientRect(HWND,RECT*)函数得到。
2、另一种方法,在调用BeginPaint/EndPaint之前,调用InvalidateRect(HWND,RECT*,BOOL)第三个参数指定BeginPaint是否会对背景画刷填充。
3、基本文本显示:
TextOut
DrawText
(SetTextColor,SetBkColor,SetBkMode)
4、一些消息的使用

5、绘图函数:
COLORREF SetPixel(HDC,x,y,COLORREF)
BOOL LineTo(HDC,int,int)
BOOL Rectangle(HDC,int,int,int,int)
int FillRect(HDC,CONST RECT*,HBRUSH)
int FrameRect(HDC,CONST RECT *,HBRUSH)
BOOL Ellipse(HDC,int,int,int,int)
BOOL Polygon(HDC,CONST POINT* ,int)

6、定时
SetTimer
KillTimer
GetTickCount

7、使用控件
GreatWindowEx
更多内容参考:《Windows程序设计》


第六章 初次邂逅DirectDraw
第一步:创建DirectDraw对象
方法1:
if(FAILED(DirectDrawCreate(NULL,&lpdd,NULL)))
{
//error
}
if(FAILED(lpdd->QueryInterface(IID_IDirectDraw7,(LPVOID**)&lpdd7,NULL)))
{
//error
}
方法2:
if(FAILED(DirectDrawCreateEx(NULL,(LPVOID**)&lpddh,IID_DirectDraw7,NULL)))
{
//error
}
方法3:
使用底层的COM调用,方法见《Windows游戏编程大师》P197

第二步:设置协作级别
HRESULTlpdd->SetCooperativeLevel(HWND hWnd,DWORDdwFlags)

第三步:设置模式
HRESULTlpdd->SetDisplayMode(width,height,bpp,0,0)

第四部:调色板
(可选条件:当色彩深度设为8时使用)

第五部:创建显示表面

- 作者: 龙七鱼 2005年03月31日, 星期四 20:09  回复(0)|  引用(0)

Windows游戏编程大师技巧

作者:[美]AndréLaMothe
译者:沙鹰
出版社:中国电力出版社
版别版次:2004年2月第1版第1次印刷

出版日期:2004年2月
开本:787*10921/16

字数:1340千字
页数: 807

本书是著名游戏程序设计类书籍作者AndréLaMothe的两卷本《Windows游戏编程大师技巧》中的第一卷的第二版。和作者撰写的其他畅销书一样,在书中随处可见许多有趣但又有一定难度的源程序。作者循循善诱地从程序设计的角度介绍了在Windows环境下进行游戏开发所需的全部知识,包括Win32编程以及DirectX中所有主要组件(包括DirectDraw、DirectSound、DirectInput和DirectMusic)。书中还用单独的章节详细讲授了2D图形学和光栅化技术、游戏算法、多线程编程、文本游戏和解析、人工智能(包括模糊逻辑、神经网络和遗传算法)、物理建模(完全碰撞反应、动量传递和正反向运动学)及实时模拟等游戏程序开发中的关键技术。

感受:一本不错的入门书籍,适合系统的学习2D游戏编程。

- 作者: 龙七鱼 2005年03月31日, 星期四 18:33  回复(0)|  引用(0)

系统托盘编程完全指南

系统托盘编程完全指南(一)


编译/northtibet

下载本文例子源代码

自从Windows95面市以来,系统托盘应用作为一种极具吸引力的UI深受广大用户的喜爱。使用系统托盘UI的Windows应用程序数不胜数,比如"金山词霸"、"Winamp"、"RealPlayer"等等。那么如何编写自己的托盘应用呢?本文是系列文章中的第一篇,这些文章将比较系统地描述托盘应用的编程。并创建自己的C++类来增强系统托盘应用的特性。读完这些文章,再参照例子,相信读者能轻松自如地在自己的程序中应用系统托盘。
大家知道,MFC框架没有提供任何现成的类应用于系统托盘UI,那么如何将表示应用程序的图标添加到任务栏中呢?方法很简单,只用到一个API函数,它就是Shell_NotifyIcon。这个函数本身也相当容易理解和使用。看看它的原型就知道了:

BOOL Shell_NotifyIcon(    DWORD dwMessage,     PNOTIFYICONDATA pnid);      

第一个参数dwMessage类型为DWORD,表示要进行的动作,它可以是下面的值之一:

      NIM_ADD:       添加一个图标到任务栏。      NIM_MODIFY:    修改状态栏区域的图标。      NIM_DELETE:    删除状态栏区域的图标。      NIM_SETFOCUS:  将焦点返回到任务栏通知区域。当完成用户界面操作时,
任务栏图标必须用此消息。例如,如果任务栏图标正 显示上下文菜单,但用户按下"ESCAPE"键取消操作,
这时就必须用此消息将焦点返回到任务栏通知区域。 NIM_SETVERSION:指示任务栏按照相应的动态库版本工作。

第二个参数pnid是NOTIFYICONDATA结构的地址,其内容视dwMessage的值而定。这个结构在SHELLAPI.H文件中定义如下:

typedef struct _NOTIFYICONDATA {  DWORD cbSize;           // 结构大小(sizeof struct),必须设置  HWND hWnd;             // 发送通知消息的窗口句柄  UINT uID;                //  图标ID ( 由回调函数的WPARAM 指定)  UINT uFlags;              UINT uCallbackMessage;    // 消息被发送到此窗口过程  HICON hIcon;             // 图标句柄  CHAR szTip[64];          // 提示文本} NOTIFYICONDATA;uFlags的值:#define NIF_MESSAGE 0x1   // 表示uCallbackMessage 有效#define NIF_ICON    0x2   // 表示hIcon 有效#define NIF_TIP     0x4   // 表示szTip 有效      

有关Shell_NotifyIcon函数的详细使用细节请参考MSDN。
NOTIFYICONDATA结构中的 hWnd 是"拥有"图标的窗口句柄。uID可以是任何标示托盘图标的ID(如果有多个图标),一般使用资源ID。HIcon可以是任何图标的句柄,包括预定义的系统图标,如IDI_HAND、IDI_QUESTION、IDI_EXCLAMATION、或者Windows的徽标IDI_WINLOGO。
图标的显示并不难,关键是事件的处理。当用户将鼠标移到图标上或者在图标上单击鼠标时,为了得到通知消息,你可以将自己的消息ID赋给uCallbackMessage,并设置NIF_MESSAGE标志。当用户在图标上移动或单击鼠标时,Windows将用hWnd指定的窗口句柄调用你建立的窗口过程;消息ID在uCallbackMessage中指定,uID的值即为wParam,lParam为鼠标事件,如WM_LBUTTONDOWN等。
尽管Shell_NotifyIcon函数简单实用。但它毕竟是个Win32API,为此我将它封装在了一个C++类中,这个类叫做CTrayIcon,有了它,托盘编程会更加轻松自如,因为它隐藏了NOTIFYICONDATA、消息代码、标志以及所有那些你必须要看MSDN才能搞掂的繁琐细节。CTrayIcon的定义以及实现细节请下载源代码参考。CTrayIcon为程序员提供了一个更加友好的托盘编程接口,它除了对Shell_NotifyIcon函数进行打包之外,它还是一个迷你框架呢!之所以这么说,是因为按照Windows系统应用软件界面指南所提倡的原则(这个指南可以在MSDN中找到),这个类增强了托盘图标的用户界面行为。以下便是CTrayIcon最终实现的UI特性:

1、 托盘图标应该有信息提示,也就是ToolTips。
2、 单击右键应该弹出上下文菜单,这个菜单中应包含打开属性页的命令或者打开与图标相关的其它窗口的命令。
3、单击左键应该显示进一步的信息或者控制图标所代表的对象,例如,当左键单击声音图标时进行音量控制。如果没有进一步的信息或控制,则不要有任何动作。

CTrayIcon对上面的特性进行了全面的封装。为了示范CTrayIcon的工作原理,本文提供一个例子程序TrayTest1,图一是运行程序后显示的一个对话框:


图一 TrayTest1运行后显示的对话框

当把图标安装到系统托盘之后,如果双击托盘图标,程序会弹出一个消息列表窗口,只要你的鼠标在托盘图标上移动或点击(无论是左右键的单击或双击),产生的消息都会显示在这个窗口里,如图二:


图二 消息显示窗口

当鼠标光标移到托盘图标上时,在图标附近会显示提示信息,如图三:


图三 显示Tooltip

为了正确使用CTrayIcon,首先你必须在程序的某个地方实例化CTrayIcon,例子程序是在主框架中创建CTrayIcon实例的。

Class MainFrame  public CFrameWnd {protected:  CTrayIcon m_trayIcon; // my tray icon…….};      

然后,你必须提供一个ID。这是在图标生命期内的唯一标示,即便以后你修改了要显示的图标。这个ID也是鼠标事件发生时你将获得的ID。它不一定必须是图标的资源ID,例子程序中这个ID为IDR_TRAYICON,由框架的构造函数CMainFrame通过成员初始化列表对m_trayIcon进行初始化:

CMainFrame::CMainFrame() : m_trayIcon(IDR_TRAYICON){……}      

为了添加图标,必须根据具体情况调用下列的 SetIcon 函数之一:

      m_trayIcon.SetIcon(IDI_MYICON);         //资源 ID      m_trayIcon.SetIcon("myicon");           //资源名      m_trayIcon.SetIcon(hicon);              //HICON      m_trayIcon.SetStandardIcon(IDI_WINLOGO);//系统图标      

除了SetIcon(UINT uID)之外,这些函数都有一个LPCSTR类型的可选参数用于指定提示文本。SetIcon(UINTuID)使用ID与uID相同的串资源作为提示文本。例如,TrayTest1有一行代码是这样的:

// (在mainframe.cpp文件中)m_trayIcon.SetIcon(IDI_MYICON);      

这行代码也设置了提示信息,因为TrayTest1有一个串资源,其ID也是IDI_MYICON。这在TRAYTEST.RC文件中可以看到:

STRINGTABLE PRELOAD DISCARDABLE BEGIN      IDI_MYICON "双击图标激活 TRAYTEST." END      

如果你想改变图标,可以用不同的ID或者HICON再次调用SetIcon函数之一。CTrayTest便会用NIM_MODIFY而不是NIM_ADD来改变图标。相同的函数甚至可以用于删除图标,如:

m_trayIcon.SetIcon(0); //删除图标      

CTrayIcon将此代码解释成NIM_DELETE。你已经看到,所有这些表示行为的编码,标志都被一个使用方便的函数所替代:这都归功于C++!现在,我们来看看如何处理通知消息以及前面提到的所有UI特性。通知消息的处理必须要设置图标之前,但是要在创建窗口之后调用CTrayIcon::SetNotificationWnd,做这件事情的最佳场所是在OnCreate处理例程中,TrayTest就是在这里处理的:

// 注册用于托盘的自定义消息#define WM_MY_TRAY_NOTIFICATION WM_USER+0int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){……  // 请通知我  m_trayIcon.SetNotificationWnd(this,                        WM_MY_TRAY_NOTIFICATION);                           m_trayIcon.SetIcon(IDI_MYICON);  return 0;}

消息一旦注册,接下来你便可以用通常的消息映射方式处理托盘通知消息。

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)  ON_MESSAGE(WM_MY_TRAY_NOTIFICATION,             OnTrayNotification)             // (or ON_REGISTERED_MESSAGE)END_MESSAGE_MAP()LRESULT CMainFrame::OnTrayNotification(WPARAM wp, LPARAM lp){                    ……       // 显示消息……return m_trayIcon.OnTrayNotification(wp, lp);}      

当消息处理器得到控制,WPARAM的值是在构造CTrayIcon时指定的ID;LPARAM为鼠标事件(如WM_LBUTTONDOWN)。当你得到通知消息后,可以做任何想做的的事情;例子程序TrayTest此时是显示通知信息,细节请参考源代码。完成消息的处理之后,调用CTrayIcon::OnTrayNotification进行缺省处理。此虚拟函数(所以你可以改写)实现我前面提到过的缺省的UI行为。尤其是处理WM_LBUTTONDBLCLK和WM_RBUTTONUP。CTrayIcon寻找与图标ID相同的某个菜单(如IDR_TRAYICON),如果找到,则当用户右键单击图标时CTrayIcon显示这个菜单;当用户数双击图标时,CTrayIcon执行第一个菜单命令。只有两件事情需要进一步交待:
第一件事情是:在显示菜单之前,CTrayIcon让第一个菜单项为默认,所以它以黑体显示。但如何用黑体来显示某个菜单项呢?我在MSDEVINCLUDE*.H搜索了一番,发现了Get/SetMenuDefaultItem。这个函数没有相关的CMenu打包类,所以我必须直接调用它们。

// 让第一个菜单项为默认(黑体):::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);       

这里0表示第一个菜单项,TRUE说明用位置表示菜单项的ID。为什么MFC没有打包Get/SetMenuDefaultItem函数呢?微软的家伙们解释那是因为这些函数(其它的还有::Get/SetMenuItemInfo,::LoadImage等)还没有在最新的Windows版本中实现。一旦在最新的Windows版本中实现了,便会马上添加到MFC中。
第二件事情是上下文菜单的显示:

      ::SetForegroundWindow(m_nid.hWnd); ::TrackPopupMenu(pSubMenu->m_hMenu, ...);      

为了让TrackPopupMenu在托盘的上下文中正确运行,你必须首先调用SetForegroundWindow,否则,当用户按下ESCAPE键或者在菜单之外单击鼠标时,菜单不会消失。为解决这个问题,我花费了数个小时,最后还是在MSDN上找到了解决方法。为了解详情,请参考MSDN的Q135788。最让我哭笑不得的是我花了那么多时间来关注这个问题,最后微软的这帮家伙在MSDN上给你来了一个问题的结论是:“Thisbehavior is by design.....”真是气刹人也。
正如你所看到的,CTrayIcon使得托盘应用的编程变得易如反掌。TrayTest1要做的事情不外乎调用CTrayIcon::OnTrayNotification实现一个通知消息处理器,提供一个与图标ID相同的菜单。就这么简单。

// (TRAYTEST.RC文件)IDR_TRAYICON MENU DISCARDABLE BEGIN    POPUP "托盘(&T)"    BEGIN        MENUITEM "打开(&O)",                    ID_APP_OPEN        MENUITEM "关于 TrayTest(&A)...",        ID_APP_ABOUT        MENUITEM SEPARATOR        MENUITEM "退出TrayTest 程序(&S)",       ID_APP_SUSPEND    ENDEND      

当用户在托盘图标上单击右键,CTrayIcon显示这个菜单,如图四所示。如果用户双击图标,CTrayIcon执行第一个菜单命令:“打开”,此时激活TrayTest(正常状态下是隐藏的)。为了终止TrayTest1,你必须选择"SuspendTRAYTEST"菜单项。如果你从“文件|退出”退出,或者关闭TrayTest1主窗口,TrayTest1不会真正关闭,它只是将自己隐藏起来。这个行为是TrayTest1改写了CMainframe::OnClose实现的。


图四 TRAYTEST1 托盘图标菜单

最后,我想说明一个很让人担心的问题,每个人在看到这个小图标后都想尽快的在自己的程序中加入托盘图标。作为程序员,这完全是可以理解的。当自己的程序中成功添加了托盘图标,在朋友们中间炫耀一番,那种感觉确实很好。但是要记住:并不是所有的应用都需要用托盘图标,如果不是必须就不要画蛇添足,否则托盘图标太多必然造成屏幕垃圾,看看下面图五吧:


图五 托盘图标程序“噩梦版”

看到这么多的托盘图标对于用户来说简直就是噩梦。

系统托盘编程完全指南(二)


编译/northtibet

下载本文例子源代码


在本文的第一部分,我们讨论并示范了如何在自己的程序中应用系统托盘图标。通过使用自己创建的一个可重用的 C++类——CTrayIcon,我们可以轻松地实现托盘程序。不久以前我用这个类编写了一个程序,开始运行很正常,但是有一次不知什么原因Windows资源管理器死掉了,也就是说非正常关闭,重启资源管理器后,发现托盘程序仍然在运行,但托盘图标显示不出来,在任务栏中看不到托盘图标,只有重新启动机器才能重新显示出托盘图标,让人觉得心里很不舒服,有没有什么办法在这个时候不用重启机器而让Windows自动找回托盘图标并把它添加到任务栏呢?,也就是让它自动恢复托盘图标程序的用户界面,经过一番研究,终于有所收获。
实际上,如果你用的操作系统是Windows98或者你安装了IE4.0的桌面。那么不论什么时候,只要IE4.0启动了任务栏,那么它就会向所有最顶层父窗口广播一个注册消息:TaskbarCreated。有了这个线索,你就可以重新创建图标。如果你用MFC编程,那么只要定义一个全程变量保存这个注册消息并实现ON_REGISTERED_MESSAGE消息处理例程即可:

const UINT WM_TASKBARCREATED =     ::RegisterWindowMessage(_T("TaskbarCreated"));BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)    ON_REGISTERED_MESSAGE(WM_TASKBARCREATED,                           OnTaskBarCreated)END_MESSAGE_MAP(CMainFrame, CFrameWnd)     The handler itself should reinstall whatever icons you need. LRESULT CMainFrame::OnTaskBarCreated(WPARAM wp, LPARAM lp){    VERIFY(InstallIcons());    return 0;}BOOL CMainFrame::InstallIcons(){    NOTIFYICONDATA nid;     //    // 准备 nid 参数    //    return Shell_NotifyIcon(NIM_ADD, &nid);      

难道就这么容易吗?当然不是,你必须单独实现InstallIcons函数,而不是直接从OnTaskBarCreated中调用Shell_NotifyIcon,因为一般来说,在应用程序启动的时候你也会调用它。
当我搞清楚TaskbarCreated的奥秘之后,我便回到本文第一部分中创建的那个CTrayIcon类,对它进行了修改和完善,改动不是很大。这个类管理的是单个的托盘图标(如果你有多个,那么为每个图标创建一个单独的实例吧)。使用CTrayIcon时,你只要在CMainFrame中创建一个实例m_trayIcon并象下面这样安装它即可:

// 在CMainFrame::OnCreate中m_trayIcon.SetNotificationWnd(this,     WM_MY_TRAY_NOTIFICATION);m_trayIcon.SetIcon(IDI_MYICON);      

WM_MY_TRAY_NOTIFICATION是自己的私有消息,只在有事件发生时,托盘图标才发送此消息,如用户单击图标。对于托盘图标来说,你不用对它做什么处理,CTrayIcon全权负责。只是在构造CTrayIcon对象时,你给它一个资源ID就可以了。CTrayIcon用这个ID查找上下文菜单,如果找到的话,它便自动处理右键单击托盘图标事件,这时弹出上下文菜单。如果用户双击图标,CTrayIcon则执行第一个菜单项命令。所以你要做的全部工作只是创建一个菜单资源,将ID传递给构造函数,然后去驱动CTrayIcon就可以了。如果你想要一些非标准的例程,那么只需处理WM_MY_TRAY_NOTIFICATION即可。有关细节请参考源代码。
为了实现图标自动重建特性,我使用了以前很多文章中都用到的一个类CSubclassWnd,这个类在我的编程生涯中几乎无处不在。没有了它,我几乎寸步难行;在我的所有编程诀窍中,它是最有用的一个类。用这个类可以截获Windows消息,并将它发送到另外一个窗口消息处理例程中处理,而不是发送到Windows自己默认的消息处理函数。CTrayIcon用它来截获TaskbarCreated消息,所以你就不必为此编写消息处理器——这个方法非常酷。CSubclassWnd通过安装它自己的窗口过程,从而先于MFC一步对消息进行处理。
当CMainFrame调用CTrayIcon::SetNotificationWnd时,CTrayIcon调用GetTopLevelParent以获取顶层父窗口,然后安装CSubclassWnd窗口过程,这相当于一个钩子,在消息传到任何顶层窗口之前,CSubclassWnd的窗口过程先将它处理掉。这里必须明白一点:Windows只将TaskbarCreated消息发送到顶层父窗口。它有点象WM_QUERYNEWPALETTE、WM_SYSCOLORCHANGE消息以及其它顶层窗口消息。现在当Windows发送TaskbarCreated时,控制将首先被传递到CTrayIcon::CTrayHook::WindowProc。
CTrayIcon::OnTaskBarCreate是CTrayIcon类中新加的一个虚拟函数,其默认实现是在系统托盘中重新安装图标。如果你想做一些其它的事情,可以派生一个新类并改写此默认行为。实际的WindowProc代码比我在本文中描述的要稍微复杂一些,因为它还要处理托盘通知以驱动默认的菜单处理例程,以前,当获得WM_MY_TRAY_NOTIFICATION消息时,你必须自己调用OnTrayNotification。新的CTrayIcon实现请参考本文的源代码。
顺便提及一下,你想知道我是如何测试图标自动重建特性的吗?(如果是你,你用什么办法?),很容易。在Windows98中,按下Ctrl+Alt+Del,弹出任务管理器的任务清单。选择"资源管理器(Explorer)",然后选择"结束任务(EndTask)"。此时会显示关机/重启对话框,此时按下"取消"按钮(不要按"关机"按钮)。然后,等待几秒钟,你得到消息显示"这个任务没有响应",这时你要用"结束任务"来回复。接下来Windows的资源管理器便非正常终止!然后它又会自动起来,这时向所有顶层父窗口广播TaskbarCreated消息。如果你的操作系统是WindowsNT/2000/XP,并安装了IE4.0,如法炮制。当任务栏死掉后,从"开始"菜单的"运行"对话框中敲入"explorer"启动器源管理器。不管是用什么操作系统,在杀掉任务栏之前,如果TrayTest程序处于运行状态,那么当资源管理器自己恢复状态时,TrayTest程序的托盘图标会自动创新安装。不信的话,你用本文第一部分的例子程序和本文提供的范例程序试一下就知道了。你会发现本文的例子程序会处理TaskbarCreated消息,而另一个则完全不会。

系统托盘编程完全指南(三)
——实现气球式提示

编译/NorthTibet

下载源代码

托盘程序的信息提示通常是将鼠标光标移到托盘图标上之后,Windows会发送消息给托盘程序,从而显示提示信息——Tooltip。但在WindowsXP中我们还看到有些系统托盘程序是自动显示ToolTips信息的,也就是说不用将鼠标光标移到托盘图标上便可显示ToolTips,在这是怎么实现的呢?本文将示范一种新奇的ToolTips风格,它叫做气球提示:BalloonTips。
Windows中与托盘图标相关的提示有两类:一类是传统的信息提示方式,当光标移到图标上时显示;另一类是新式的信息提示即气球提示,它是由你的程序来控制显示。气球提示有点像连环漫画中的文字气球。如图一、图二分别为本文例子程序TrayTest3在Windows2000和Windows XP中运行的画面:

在Windows 2000中运行的气球提示,没有关闭按钮。

图一 在Windows 2000运行


在Windows XP中运行。

图二 在 Windows XP中运行的TrayTest3


气球提示为托盘程序提供了一种非打扰式的方法通知用户发生了某件事情。但是如何让气球提示显示出来呢?所有的托盘图标行为都是通过一个单纯的API函数Shell_NotifyIcon来操作的。这个函数的一个参数是NOTIFYICONDATA结构,你可以利用这个结构来告诉Windows你想要做什么。下面是这个结构的定义的最新版本(ForIE5.0+),其中已经加入了新的成员:

typedef struct _NOTIFYICONDATA {     DWORD cbSize;     HWND hWnd;     UINT uID;     UINT uFlags;     UINT uCallbackMessage;     HICON hIcon;     #if (_WIN32_IE < 0x0500)        WCHAR  szTip[64];    #else        WCHAR  szTip[128];    #endif    #if (_WIN32_IE >= 0x0500)        DWORD dwState;        DWORD dwStateMask;        WCHAR  szInfo[256];        union {            UINT  uTimeout;            UINT  uVersion;        } DUMMYUNIONNAME;        WCHAR  szInfoTitle[64];        DWORD dwInfoFlags;    #endif} NOTIFYICONDATA, *PNOTIFYICONDATA;       

有关这个结构的详细信息和用法请参考本文前面的两个部分:

系统托盘编程完全指南(一)

系统托盘编程完全指南(二)

在NOTIFYICONDATA.uFlags中的标志之一是NIF_TIP,用它来设置传统的信息提示,即鼠标要移动到图标上。新的标志NIF_INFO(由于_WIN32_IE>=0x0500条件定义,因此在编译时,请注意包含最新版本的头文件shellapi.h,并保证链接最新版本的库文件shell32.lib,分发程序时用最新版本的运行时动态链接库shell32.dll)便是为显示气球提示所用的。也就是说,要显示气球提示,那么在调用Shell_NotifyIcon函数时必须用NIF_INFO标志。提示文本填入szInfo域,标题文本填入szInfoTitle。你甚至可以在NOTIFYICONDATA.uTimeout中设置一个超时时间,当经过指定的毫秒数之后,气球提示自动隐藏。
为了示范气球提示的实现原理,我对本文前面两个部分的例子以及CTrayIcon类进行了修改。CTrayIcon类中添加了一个新的方法ShowBalloonTip,这个方法有两个重载函数,既可以用文本串来调用,也可以用资源ID来调用。用资源ID时,可以有选择地加载文本串,并调用ShowBalloonTip的文本串版本,原型如下:

BOOL CTrayIcon::ShowBalloonTip(LPCTSTR szMsg,  LPCTSTR szTitle, UINT uTimeout, DWORD dwInfoFlags){  m_nid.cbSize=sizeof(NOTIFYICONDATA);  m_nid.uFlags = NIF_INFO;  m_nid.uTimeout = uTimeout;  m_nid.dwInfoFlags = dwInfoFlags;  strcpy(m_nid.szInfo,szMsg ? szMsg : _T(""));  strcpy(m_nid.szInfoTitle,szTitle ? szTitle : _T(""));  return Shell_NotifyIcon(NIM_MODIFY, &m_nid);}      

这个函数很容易理解,同时也够繁琐的,要把文本串载缓冲里拷来拷去。缺省的dwInfoFlags设置为NIIF_INFO,在文本旁边显示信息图标;其它可能的标志是NIIF_ERROR——表示出错,NIIF_WARNING——表示警告,NIIF_NONE——没有图标。有关修改后的CTrayIcon以及TrayTest3源代码请下载本文的例子。
只有一种方法可以显示气球提示(Shell_NotifyIcon),但终止的方法有多种。用户可以在气球上单击鼠标,也可以单击关闭按钮(在Windows2000里没有关闭按钮,如图一),或者Windows用超时机制来终止气球提示。那么是如何知道所发生的事件是什么呢?每当创建托盘图标时,你可以提供一个HWND和消息ID来接收事件发生的通知。如果用户单击气球提示,Windows发送NIN_BALLOONUSERCLICK;如果超时或者单击关闭按钮,Windows则发送NIN_BALLOONTIMEOUT。就我所知,目前还没有办法区分是超时还是单击了关闭按钮。下表中列出的是所有与气球提示相关的通知消息:

通知消息描述
NIN_BALLOONSHOW显示气球提示时发送
NIN_BALLOONHIDE气球提示消失时发送;例如,当图标被删除,如果因为超时或是用户单击鼠标气球消失,此消息不会被发送
NIN_BALLOONTIMEOUT当由于超时或者用户单击气球上的关闭按钮(X),使气球消失时发送此消息
NIN_BALLOONUSERCLICK当用户在气球提示上或托盘图标上单击鼠标(此时气球处于显示状态)时发送此消息


在测试过程中,我发现一个奇特的现象:在WindowsXP中,只要你的托盘程序拥有焦点,气球提示便不会超时。显然,你只有转到其它应用程序,才能启动计时器。在Windows2000里好像没有这个问题。
你可以用TrayTest3来看通知消息。实际上,TrayTest3的功能就是查看通知消息:当托盘通知消息到达时显示它们。查看的方法是先运行TrayTest3,单击初始对话框的"确认"按钮,然后双击托盘图标调出图一所示的窗口。用"查看|显示气球提示"菜单来让TrayTest3显示它的提示,然后当你关闭提示或等待超时的时候,你查看在主窗口中显示的什么通知消息。
最后时一点忠告:请不要滥用气球提示和托盘图标!很多程序员为了好玩和张扬个性而滥用托盘图标。请在只有真正需要它时才去做。不要让用户觉得你的程序很讨厌,这样他们会毫不犹豫地卸载这些屏幕垃圾。如果你真的必需实现托盘图标,至少要给用户一个选项来关掉它。(完)

- 作者: 龙七鱼 2005年03月29日, 星期二 11:32  回复(0)|  引用(0)

VC技术内幕学习笔记10
##2004-12-23
第十章位图(179-189)
1、GDI
##2004-12-24(190-208)
2、DIB和CDIB类
3、在按钮上添加位图##2004-12-25
第二十九章Microsoft Data Access Objects 数据库管理(699-722)##2004-12-26
Windows消息处理和多线程编成(209-224)
1、Windows消息处理
通过一个进度条的实列讲述了Windows消息处理。
2、使用用户自定义消息进行线程间的通信。
3、使用事件(event)进行线程间的通信。
4、线程阻塞
5、排斥区(CCriticalSection类)
6、互斥体(mutex)和信号(semaphore)
7、用户界面线程(UI线程)##2004-12-28
第十二章 菜单、键盘加速键、复文本编辑控件和属性表(227-257)
1、菜单资源命令的ID必须在0x8000—0xDFFF范围内。
2、菜单项的允许/禁用
3、MFC文本编辑选项,MFC库提供类CEditView和cRichEditView,支持这种功能强大的特性。CRichEidtCtrl类,例题ex12a进行了讲解。
4、属性表,创建属性表的步骤:
一、用资源管理器创建一系列大小差不多的对话框模板,其标题是我们希望显示在选项卡标签上的字符串。
二、用ClassWizard为每个模板产生一个类。选择CPropertyPage作为基类,为控件加入相应的数据成员。
三、用ClassWizard产生一个CPropertySheet的派生类。
四、对属性表类,为其中的每个页类加入一个数据成员。
五、在属性表类的构造函数里,为每一个调用AddPage成员函数,指定嵌入页对象的地址。
六、在应用程序里,构造一个CPropertySheet派生类的对象,然后调用DoModal。我们必须在构造函数调用时指定一个标题,但我们可以在以后通过调用CPropertySheet::SetTitle来改变标题。
七、负责Apply按钮的编程。
5、CMenu类
6、创建浮动的弹出式菜单,创建步骤:
一、用菜单编辑器在工程中的资源文件中插入一个新的空菜单
《Windows游戏编程大师技巧》2e——我学到了什么? windows游戏编程大师
二、在左边的顶层菜单项输入一些字符,然后在所得到的弹出式菜单里加入菜单项
三、用ClassWizard在视图类或其他接收鼠标右键单击的窗口类中加入WM_CONTEXTMENU消息控件函数。如下:
void CMyView::OnContextMenu(CWnd *pWnd,CPoint point)
{
CMenu menu;
menu.LoadMenu(IDR_MYFLOATINGMENU);
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,
point.x,point.y,this);
//////////////////////////////////////////////
// 方法二

}
7、扩展命令处理
ON_COMMAND_EX
ON_COMMAND_RANGE
ON_COMMAND_EX_RANGE
ON_UPDATE_COMMAND_UI_RANGE

- 作者: musen2002 2004年12月28日, 星期二 14:38  回复(0)|  引用(0)

VC6.0添加自定义用户消息的基本过程
VC6.0添加自定义用户消息的基本过程

在学习<vc6.0技术内幕>过程中遇到要添加用户自定义消息的过程.我觉得书上写的比较散,于是就自己总结了这个基本过程,以为日后备查.首先弄清楚两点:(1)谁要发送这个消息(2)谁要接受这个消息。用一个简单的例子来说明。对象A向B(也可以就是A到A)发送消息。1 发送消息首先在A的头文件中定义这个消息:#defineWM_USERMESSAGE WM_USER+30所有自定义消息都是以WM_USER消息为基础加上一个任意的自然数来表示的。A是向外发送消息的对象,因此在A的某个方法(函数)里就会调用用来发消息的函数B::SendMessage()/B::PostMessage(),因为是B接受消息,因此是如上的形式。2 接受消息对象接受一个消息,应该有三部分:在头文件中有该消息的处理函数的原型;在实现文件中有接受消息映射的宏;以及该消息的处理函数的具体实现。2.1 头文件中加上自定义消息的处理函数原型在DECLARE_MESSAGE_MAP()语句之前,一对AFX_MSG之间加上如下形式的函数原型:afx_msg LRESULT OnProcName( WPARAM wParam,LPARAM lParam );对Win32来说,wParam, lParam是传递消息最常用的手段。2.2 在实现文件中加上接受消息映射的宏在cpp文件里,BEGIN_MESSAGE_MAP语句之后,在一对AFX_MSG_MAP之间,增加如下形式的代码:ON_MESSAGE(WM_USERMESSAGE, OnProcName)上面是不用分号结尾的。2.3 在实现文件中给出消息处理函数的具体实现。

- 作者: musen2002 2004年12月27日, 星期一 08:19  回复(0)|  引用(0)

MS OFFICE开发列表
1、How To Create Automation Project Using MFC and aType Libraryhttp://support.microsoft.com/default.aspx?scid=kb;en-us;Q1787492、HowTo Find and Use Office Object ModelDocumentation
http://support.microsoft.com/kb/222101/EN-US/
如何查找和使用 Office 对象模型文档
http://support.microsoft.com/default.aspx?scid=kb;zh-cn;222101#appliesto
3、How To Use MFC to Automate Excel and Fill a Range with an Array
http://support.microsoft.com/kb/186120

- 作者: musen2002 2004年12月23日, 星期四 11:21  回复(0)|  引用(0)

VC技术内幕学习笔记9
##2004-12-17
第八章使用ActiveX控件(142-167)
ActiveX控件(以前经常称为OLE控件,即OCX)第九章Win32内存管理(168-178)
1、VirtualAlloc函数——占用(Reserved)和保留(Committed)内存
使用时用MEM_RESERVE参数进行保留,用MEM_COMMIT参数进行占用;
VirtualFree函数收回占用的内存。
2、Windows堆和GlobalAlloc函数族
HeapAlloc在一个Windows堆里分配内存,HeapFree释放内存。
*GlobalAlloc
3、小内存堆,c++的new和delete操作符,_heapmin
4、内存映射文件

  

爱华网本文地址 » http://www.413yy.cn/a/25101017/338106.html

更多阅读

被凯迪拉克微电影《一触即发》深深的震撼到了 凯迪拉克elr

凯迪拉克 微电影“一触即发”够震撼今天终于知道了什么是微电影,短短的90秒把90分钟的电影精髓都诠释出来!通过此片,才知道,原来微电影可以这么震撼。1、配乐够震撼看凯迪拉克《一触即发》这部微电影的时候,第一印象就是电影中的背景

林宥嘉《说谎》你真的听懂了么? 说谎 林宥嘉下载

前几天在空间里放了一首歌,是林宥嘉的《说谎》,我想,全世界应该没有人会不理解歌词真正的含义吧!真的是没有说谎吗?呵呵,不,其实,歌词的每一句话都在说谎,从一开始就是谎话,一直到最后!虽然歌词写的不是我们,但是有几句话的确是我想说的!既然你

声明:《《Windows游戏编程大师技巧》2e——我学到了什么? windows游戏编程大师》为网友何必等待分享!如侵犯到您的合法权益请联系我们删除