何以关闭Windows程序特别退出时的提醒新闻对话框

  刚开始学习Windows程序设计,磕磕碰碰,先做个小笔记缓缓神经,主要是将MessageBox这个Windows
API函数的。

下载地址

  • 下载地址1
  • 下载地址2

windows程序设计之对话框
在windows程序设计十一章ABOUT2中。要在对话框上绘图,实现过程是:程序在处理WM-COMMAND消息时调用painttheblock函数来绘图,painttheblock函数使子窗口控件无效并向控件窗口过程发送WM-PAINT消息,然后调用paintwindow函数。然而WM-PAINT处理过程也是调用painttheblock函数。当执行了painttheblock函数就会触发WM-PAINT,WM-PAINT消息代码又会调用painttheblock函数,painttheblock函数又会触发WM-PAINT,WM-PAINT消息代码又会调用painttheblock函数他们不是进入了无限循环么。但是程勋运行是并没有无限循环,想不通,求大神解惑?

1.   
当Windows程序异常出错时Windows会弹出异常提示对话框,导致程序不能完全退出,影响监控程序自动重启该程序,可以通过

[文章导读]Windows Sockets 是从 Berkeley Sockets
扩展而来的,其在继承 Berkeley Sockets 的基础上,又进行了新的扩充

  MessageBox函数是许多人刚开始学习Windows程序设计或者是Windows
API遇到的第一个内置函数,这个函数使用的方式是:

书籍介绍

作为Windows开发人员的必备参考,涵盖基础知识和中高级主题,全面地介绍了Windows程序设计所涉及的细枝末节,旨在帮助读者从高屋建瓴的角度,建立完整的知识体系,为以后的职业生涯奠定良好的基础。全书共3部分23章。第1~12章着重介绍基础知识,第13~18章的主题为图形,第19~23章涉及更多高级主题。

《Windows程序设计(第5版
珍藏版)》适合任何层次的Windows程序员阅读和参考,是帮助他们梳理和建立Windows知识体系的理想读物。

serverWerOptin
/disable  

一、简介

  MessageBox(NULL, TEXT(“弹出框内容”),
TEXT(“标题”), MB_OK);

命令禁用显示提示信息。

Windows Sockets 是从 Berkeley Sockets 扩展而来的,其在继承 Berkeley
Sockets
的基础上,又进行了新的扩充。这些扩充主要是提供了一些异步函数,并增加了符合WINDOWS消息驱动特性的网络事件异步选择机制。

  初次之外,它还有几个姐妹:

但是要将该窗口完全禁用,则需要将如下注册表项修改为1。

Windows Sockets由两部分组成:开发组件和运行组件。

  MessageBoxA(NULL, “弹出框内容”,
“标题”, MB_OK);   // TEXT可有可无

HKEY_CURRENT_USER\Software\Microsoft\Windows\WindowsErrorReporting\DontShowUI

开发组件:Windows Sockets
实现文档、应用程序接口(API)引入库和一些头文件。

  MessageBoxW(NULL, L””, L””, MB_OK);  
                    // 这个L用来表示Unicode,不可以省略

2.   
程序挂起导致未能正常退出时,要想通过系统函数获取程序当前是否处于挂起状态非常困难,还是按照常规的通过两个进程之间通过管道、文件、网络等通讯定时监测比较可靠。

运行组件:Windows Sockets 应用程序接口的动态链接库(WINSOCK.DLL)。

  其实之所以有这两个是因为微软需要满足Windows
98之后对汉字等其他语言编码的需求,这种需求通过Unicode实现,但是微软本意不是要我们使用Unicode来编程,而是通过使用“通用”形式,也就是MessageBox();函数,实现不同的编码主要还是通过IDE集成开发环境下改变不同的编码形式。回到MessageBox();,今天比较头疼的是,怎么在MessageBox();中实现变量的打印呢?

二、主要扩充说明

  就像C语言中经常使用printf函数,这个函数挺有趣的,应为函数输入的参数是没有限定个数的,相当于是随机改变的。例如:

1、异步选择机制:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int main(){
 5
 6     int x=100, y=200, z=300;    
 7     
 8     printf("%d %d %d.\n", x, y, z);
 9     system("pause");
10     return 0;
11 }

Windows Sockets
的异步选择函数提供了消息机制的网络事件选择,当使用它登记网络事件发生时,应用程序相应窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。

 

Windows Sockets 提供了一个异步选择函数
WSAAsyncSelect(),用它来注册应用程序感兴趣的网络事件,当这些事件发生时,应用程序相应的窗口函数将收到一个消息。

  这个printf函数不仅可以使用多个参数打印,还可以用来直接打印变量,但是MessageBox却不能直接打印,这个引起我的直接思考。我先想到的是建立一个缓冲区,利用这个缓冲区取打印字符数据。当然打印的函数得使用sprintf了

函数结构如下:

  

int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long
lEvent);

 1 int main(){
 2     
 3     int a = 12;
 4     char szBuffer[100];             // 使用一个字符数组来做缓冲区
 5 
 6     sprintf(szBuffer, "helloworld %d.\n", a);
 7     _snprintf(szBuffer, 100, "helloworld %d.\n", a);
 8         // 使用_snprintf函数比较安全,因为可以输入限定字符的个数  
 9 
10     printf("%s.\n", szBuffer);
11     puts(szBuffer);                            // 可以使用printf中的%s将szBuffer打印出来,或者用puts直接输出
12     //printf("helloworld.\n");
13 
14     system("pause");
15     return 0;
16 }

参数说明:

 

hWnd:窗口句柄

  这个缓冲区的方法如果用在MessageBox函数里面,就可以实现打印变量的方式,比如以下代码:

wMsg:需要发送的消息

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){
    int a = 12;

    TCHAR szBuffer[100];                  // 通用版本
    _stprintf(szBuffer, TEXT("hello 通用 %d"), a);
    MessageBox(NULL, szBuffer, TEXT("通用"), MB_OK  | MB_ICONINFORMATION);

    return 0;
}

lEvent:事件(以下为事件的内容)

 

值: 含义:
FD_READ 期望在套接字上收到数据(即读准备好)时接到通知
FD_WRITE 期望在套接字上可发送数据(即写准备好)时接到通知
FD_OOB 期望在套接字上有带外数据到达时接到通知
FD_ACCEPT 期望在套接字上有外来连接时接到通知
FD_CONNECT 期望在套接字连接建立完成时接到通知
FD_CLOSE 期望在套接字关闭时接到通知

  但是每次都写个缓冲区来存放,并且一不下心忘记使用_snprintf函数,那就GG了,很可能发生缓冲区溢出的危险。因此,这里利用printf原先函数设计的原理,我们也来设计一个MessageBoxPrintf();函数,用这个函数来实现格式化输出的作用,要实现这个函数,首先得参照printf();函数的实现原理。

例如:我们要在套接字读准备好或写准备好时接到通知,语句如下:

int my_printf(const char * szFormat, ...){

    int iReturn;
    va_list pArgs;

    va_start(pArgs, szFormat);
    iReturn = vprintf(szFormat, pArgs);
    va_end(pArgs);

    return iReturn;
}


int main(){

    int x=100, y=200, z=300;

    printf("hello %d, %d, %d.\n", x, y, z);        
    my_printf("test_my_printf,哈哈%d %d.\n", x, y);

    system("pause");
    return 0;
}

rc=WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE);

 

如果我们需要注销对套接字网络事件的消息发送,只要将 lEvent 设置为0

  …表示的意思是传入的参数是可变参数个数的,va_start(pArgs,
szFormat);表示指向szFormat之后的一个参数,这个函数的许多东西我现在也还没理解过来,之后再来补充,不过现在仿照这个函数我们可以自己写个MessageBoxPrintf();函数,具体代码如下:

2、异步请求函数

// 自己做一个格式化的messageboxprintf对话框
int CDECL MessageBoxPrintf(TCHAR * szCaption, TCHAR * szFormat, ...){

    TCHAR szBuffer[1024];
    va_list pArglist;

    va_start(pArglist, szFormat);
    _vsnprintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), szFormat, pArglist);
    va_end(pArglist);

    return MessageBox(NULL, szBuffer, szCaption, MB_OK | MB_ICONINFORMATION);
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){

    int x=100, y=200, z=300;
    int cxScreen, cyScreen;

    cxScreen = GetSystemMetrics(SM_CXSCREEN);
    cyScreen = GetSystemMetrics(SM_CYSCREEN);

    // MessageBoxW(NULL, L"helloworld", L"biaoti", MB_OK);
    // MessageBoxA(NULL, TEXT("helloworld"), TEXT("biaoti"), MB_OK);
    MessageBoxPrintf(TEXT("我的标题"), TEXT("hello %d %d %d"), x, y, z);    // 把这个函数做好后,直接就可以输出
    MessageBoxPrintf(TEXT("我的屏幕大小"), TEXT("我的屏幕宽度是:%d.\n高度是:%d.\n"), cxScreen, cyScreen);


    return 0;
}

在 Berkeley Sockets 中请求服务是阻塞的,WINDOWS SICKETS
除了支持这一类函数外,还增加了相应的异步请求函数(WSAAsyncGetXByY();)。

  相当于自己设计出来一个类似printf的小工具,因为微软确实没有设计MessageBox中进行格式化输出的函数。

3、阻塞处理方法

Windows Sockets
为了实现当一个应用程序的套接字调用处于阻塞时,能够放弃CPU让其它应用程序运行,它在调用处于阻塞时便进入一个叫“HOOK”的例程,此例程负责接收和分配WINDOWS消息,使得其它应用程序仍然能够接收到自己的消息并取得控制权。

WINDOWS
是非抢先的多任务环境,即若一个程序不主动放弃其控制权,别的程序就不能执行。因此在设计Windows
Sockets 程序时,尽管系统支持阻塞操作,但还是反对程序员使用该操作。但由于
SUN 公司下的 Berkeley Sockets 的套接字默认操作是阻塞的,WINDOWS
作为移植的 SOCKETS 也不可避免对这个操作支持。

在Windows Sockets
实现中,对于不能立即完成的阻塞操作做如下处理:DLL初始化→循环操作。在循环中,它发送任何
WINDOWS 消息,并检查这个 Windows Sockets
调用是否完成,在必要时,它可以放弃CPU让其它应用程序执行(当然使用超线程的CPU就不会有这个麻烦了^_^)。我们可以调用
WSACancelBlockingCall() 函数取消此阻塞操作。

在 Windows Sockets 中,有一个默认的阻塞处理例程 BlockingHook()
简单地获取并发送 WINDOWS 消息。如果要对复杂程序进行处理,Windows Sockets
中还有 WSASetBlockingHook()
提供用户安装自己的阻塞处理例程能力;与该函数相对应的则是
SWAUnhookBlockingHook(),它用于删除先前安装的任何阻塞处理例程,并重新安装默认的处理例程。请注意,设计自己的阻塞处理例程时,除了函数
WSACancelBlockingHook() 之外,它不能使用其它的 Windows Sockets API
函数。在处理例程中调用
WSACancelBlockingHook()函数将取消处于阻塞的操作,它将结束阻塞循环。

4、出错处理

Windows Sockets
为了和以后多线程环境(WINDOWS/UNIX)兼容,它提供了两个出错处理函数来获取和设置当前线程的最近错误号。(WSAGetLastEror()和WSASetLastError())

5、启动与终止

使用函数 WSAStartup() 和 WSACleanup() 启动和终止套接字。
三、Windows Sockets网络程序设计核心

  我们终于可以开始真正的 Windows Sockets
网络程序设计了。不过我们还是先看一看每个 Windows Sockets
网络程序都要涉及的内容。让我们一步步慢慢走。

  1、启动与终止

   在所有 Windows Sockets 函数中,只有启动函数 WSAStartup() 和终止函数
WSACleanup() 是必须使用的。

   启动函数必须是第一个使用的函数,而且它允许指定 Windows Sockets API
的版本,并获得 SOCKETS的特定的一些技术细节。本结构如下:

int PASCAL FAR WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

  其中 wVersionRequested 保证 SOCKETS 可正常运行的 DLL
版本,如果不支持,则返回错误信息。
我们看一下下面这段代码,看一下如何进行 WSAStartup() 的调用

WORD wVersionRequested;// 定义版本信息变量WSADATA wsaData;//定义数据信息变量int err;//定义错误号变量wVersionRequested = MAKEWORD(1,1);//给版本信息赋值err = WSAStartup(wVersionRequested, &wsaData);//给错误信息赋值if(err!=0){return;//告诉用户找不到合适的版本}//确认 Windows Sockets DLL 支持 1.1 版本//DLL 版本可以高于 1.1//系统返回的版本号始终是最低要求的 1.1,即应用程序与DLL 中可支持的最低版本号if(LOBYTE(wsaData.wVersion)!= 1|| HIBYTE(wsaData.wVersion)!=1){WSACleanup();//告诉用户找不到合适的版本return;}//Windows Sockets DLL 被进程接受,可以进入下一步操作

  关闭函数使用时,任何打开并已连接的 SOCK_STREAM
套接字被复位,但那些已由 closesocket()
函数关闭的但仍有未发送数据的套接字不受影响,未发送的数据仍将被发送。程序运行时可能会多次调用
WSAStartuo() 函数,但必须保证每次调用时的 wVersionRequested
的值是相同的。

  2、异步请求服务

   Windows Sockets 除支持 Berkeley Sockets
中同步请求,还增加了了一类异步请求服务函数
WSAAsyncGerXByY()。该函数是阻塞请求函数的异步版本。应用程序调用它时,由
Windows Sockets DLL
初始化这一操作并返回调用者,此函数返回一个异步句柄,用来标识这个操作。当结果存储在调用者提供的缓冲区,并且发送一个消息到应用程序相应窗口。常用结构如下:

HANDLE taskHnd;char hostname="rs6000";taskHnd = WSAAsyncBetHostByName(hWnd,wMsg,hostname,buf,buflen);

  需要注意的是,由于 Windows
的内存对像可以设置为可移动和可丢弃,因此在操作内存对象是,必须保证
WIindows Sockets DLL 对象是可用的。

   3、异步数据传输

   使用 send() 或 sendto() 函数来发送数据,使用 recv() 或recvfrom()
来接收数据。Windows Sockets
不鼓励用户使用阻塞方式传输数据,因为那样可能会阻塞整个 Windows
环境。下面我们看一个异步数据传输实例:

   假设套接字 s 在连接建立后,已经使用了函数 WSAAsyncSelect()
在其上注册了网络事件 FD_READ 和 FD_WRITE,并且 wMsg 值为
UM_SOCK,那么我们可以在 Windows 消息循环中增加如下的分支语句:

case UM_SOCK:switch(lParam){case FD_READ:len = recv(wParam,lpBuffer,length,0);break;case FD_WRITE:while(send(wParam,lpBuffer,len,0)!=SOCKET_ERROR)break;}break;

  4、出错处理

] Windows Sockets 是从 Berkeley
Sockets 扩展而来的,其在继承 Berkeley Sockets 的基础上,又进行了新的扩充
一、简介 Windows Sockets 是从 B…

相关文章