按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
都有自已独立的地址空间,因此,它们之间互相独立,互不
干涉。但是,对于一些应用程序,只需要而且只应该有一个
实例在运行。什么情况下会是这样呢?假设我们编写了一个
应用程序,在默认情况下,该应用程序将在后台运行,通过
按下程序所定义的某一个热键,应用程序将被激活。对于这
样的应用程序,在同一时该只应该有一个实例在运行。另
外,像Windows NT下在任务管理器,在同一时刻也只可以有
一个实例在运行。
使用下面的技巧可以保证在同一时刻只有应用程序的一个实
例:
l #include 〃windows。h〃
l
l #define VK_X 0x58
l
l int WINAPI WinMain (HINSTANCE hInstance;
…………………………………………………………Page 126……………………………………………………………
l HINSTANCE hPrevInstance;
l LPSTR lpCmdLine;
l int nCmdShow)
l {
l if (!CreateMutex(NULL;TRUE;〃No Previous Instance!〃))
l {
l MessageBox(NULL;〃创建Mutex失败!〃;〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
l return FALSE;
l }
l if (GetLastError()==ERROR_ALREADY_EXISTS)
l {
l MessageBox(NULL;〃已有NoPrev的一个实例在运行; 当前实例将被终止!〃;
l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
l return FALSE;
l }
l if(!RegisterHotKey(NULL;0x0001;MOD_CONTROL|MOD_SHIFT;VK_X))
l {
l MessageBox(NULL;〃注册热键Ctrl+Shift+X失败!〃;
l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
l return FALSE;
l }
l MessageBox(NULL;〃NoPrev已启动!nn按下热键Ctrl+Shift+X将终止NoPrev。〃;
l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
…………………………………………………………Page 127……………………………………………………………
l MSG msg;
l while (GetMessage(&msg;NULL;0;0))
l {
l switch (msg。message)
l {
l case WM_HOTKEY:
l if (int(msg。wParam)==0x0001)
l if (MessageBox(NULL;〃终止NoPrev?〃;
l 〃NoPrev〃;MB_YESNO|MB_SYSTEMMODAL)==IDYES)
l return TRUE;
l }
l }
l return TRUE;
l }
上面的代码是一个功能完整的Windows应用程序,其中用到了
一些到目前为止我们还未讲述到的内容。程序定义了热键
Ctrl+Shift+X,当按下该热键时将终止该程序。由于程序中
没有包括任何窗口,因此这是唯一的一种正常终止应用程序
的方法。当程序NoPrev正在后台运行时,如果用户按下了组
合键Ctrl+Shift+X,Windows将向程序主线程的消息队列中发
送一条称为WM_HOTKEY的消息,当程序收到这条消息时,即弹
出了消息框询问是否终止NoPrev。上面的说明将有助于你理
解以上代码,但是我们 目前对止并不做要求。这里,只需要
注意下面的代码 :
l if (!CreateMutex(NULL;TRUE;〃No Previous Instance!〃))
l {
…………………………………………………………Page 128……………………………………………………………
l MessageBox(NULL;〃创建Mutex失败!〃;〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
l return FALSE;
l }
l if (GetLastError()==ERROR_ALREADY_EXISTS)
l {
l MessageBox(NULL;〃已有NoPrev的一个实例在运行; 当前实例将被终止!〃;
l 〃NoPrev〃;MB_OK|MB_SYSTEMMODAL);
l return FALSE;
l }
在上面的代码 中,我们先调用CreateMutex创建一个名为 “
No
Previous Instance”的命名互斥对象(named mutex
object),如果该对象名已存在(注意这时函数CreateMutex仍
返回真值TRUE),则随后调用的GetLastError函数将返回
ERROR_ALREADY_EXISTS,由此得知已有一个应用程序的实例
正在运行。从而弹出消息框提醒用户,然后终止应用程序的
当前实例。
在上面的WinMain函数原型中的另一个奇怪的标识符为WINAPI,这是
一个在windef。h头文件中定义的宏,在当前版本Win32 SDK中,
WINAPI被定义为FAR PASCAL,因此,使用FAR PASCAL同使用WINAPI具
有同样的效果,但是,我们强烈建议你使用WINAPI来代替以前常用的
FAR PASCAL,因为Microsoft不保证FAR PASCAL能够在将来的Windows
版本中正常工作。在目前情况下,和FAR PASCAL等价的标识符还有
CALLBACK (用在如窗口过程或对话框过程之类的回调函数前)和
APIENTRY等。它们对编译器而言都是一回事,最终将被解释为
__stdcall。在Windows环境下编程,会遇到很多这样的情况,注意不
要混淆它们。
一般情况下,我们应该在WinMain函数中完成下面的操作:
1。 注册窗口类;
2。 创建应用程序主窗口;
…………………………………………………………Page 129……………………………………………………………
3。 进入应用程序消息循环。
接下来我们将依次讨论这些内容。
在Windows应用程序中,每一个窗口都必须从属于一个窗口类,窗口
类定义了窗口所具有的属性,如它的样式、图标、鼠标指针、菜单名
称及窗口过程名等。在注册窗口类前,我们先创建一个类型为
WNDCLASS的结构,然后在该结构对象中填入窗口类的信息,最后将它
传递给函数RegisterClass,整个过程如下面的代码所示:
WNDCLASS wc;
// 填充窗口类信息
wc。style=CS_HREDRAW|CS_VREDRAW;
wc。lpfnWndProc=WndProc;
wc。cbClsExtra=0;
wc。cbWndExtra=0;
wc。hInstance=hInstance;
wc。hIcon=LoadIcon(NULL;IDI_APPLICATION);
wc。hCursor=LoadCursor(NULL;IDC_ARROW);
wc。hbrBackground=GetStockObject(WHITE_BRUSH);
wc。lpszMenuName=NULL;
wc。lpszClassName=〃SdkDemo1〃;
// 注册窗口类
RegisterClass(&wc);
下面解释一下结构WNDCLASS 中各成员的含义:
style: 指定窗口样式。该样式可以为一系列屏
蔽位的按位或,在前面的例子中,CS_HREDRAW表
示当窗口用户区宽度改变时重绘整个窗口,而
CS_VREDRAW则表则表示当窗口用户区高度改变时
重绘整个窗口。对于其它的窗口样式,请参阅
SDK中关于WNDCLASS的联机文档。(顺便说一句,
请注意该成员的大小写,它是小写的style,而
…………………………………………………………Page 130……………………………………………………………
不是Style。)
lpfnWndProc: 指向窗口过程的指针。关于窗口
过程我们将以后面的内容中讲述。在前面的例子
中,我们使用名为WndProc的窗口过程。
cbClsExtra: 指定在窗口类结构之后分配的附加
字节数。操作系统将这些字节初始化为0。
cbWndExtra: 指定在窗口实例之后分配的附加字
节数。操作系统将这些字节初始化为0。如果应
用程序使用WNDCLASS结构注册一个�