《Windows核心编程》1对程序的错误处理读书笔记

1.函数返回值:

2.获得错误消息

从系统内部来讲,当一个 Windows函数检测到一个错误时,它会使用一个称为线程本地存储器(thread-local storage)的机制,将相应的错误代码号码与调用的线程关联起来。这将使线程能够互相独立地运行,而不会影响各自的错误代码。当函数返回时,它的返回值就能指明一个错误已经发生。使用GetlastError()获得错误代码(当Windows函数运行失败时,应该立即调用GetLastError函数。如果调用另一个Windows函数,它的值很可能被改写)。

WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(
    VOID);

对应的错误消息在WinError.h可以查看。每个错误都有3种表示法:一个消息ID(这是你可以在源代码中使用的一个宏,以便与GetLastError的返回值进行比较),消息文本(对错误的英文描述)和一个号码(应该避免使用这个号码,可使用消息ID)。如:

//
// MessageId: ERROR_PROFILING_NOT_STOPPED
//
// MessageText:
//
// Profiling not stopped.
//
#define ERROR_PROFILING_NOT_STOPPED      551L

//
// MessageId: ERROR_COULD_NOT_INTERPRET
//
// MessageText:
//
// The passed ACL did not contain the minimum required information.
//
#define ERROR_COULD_NOT_INTERPRET        552L

注意 GetLastError能返回线程产生的最后一个错误。如果该线程调用的 Windows函数运行成功,那么最后一个错误代码就不被改写,并且不指明运行成功。有少数Windows函数并不遵循这一规则,它会更改最后的错误代码;但是 Platform SDK文档通常指明,当函数运行成功时,该函数会更改最后的错误代码。

3.定义自己的错误代码

//设置线程错误代码
WINBASEAPI VOID WINAPI SetLastError(
    _In_ DWORD dwErrCode);      //   32位的错误代码

自定义错误代码29位必须设置为1.

3.1编写错误信息文本

 

自定义错误代码:点击打开链接

4.错误查看小工具:

vs查看错误:

通过选定 Watch窗口(快速监视窗口)中的一行,并键入“@ e r r, h r”,能显示线程的最后错误代码的号码和该错误的英文描述。

在vs目录下VSSystem\Common7\Tools\errlook.exe可以用来查看错误信息代码所代表的意思。

5.FormatMessage函数:

DWORD WINAPI FormatMessage (
                            DWORD dwFlags, // source and processing options
                            LPCVOID lpSource, // message source
                            DWORD dwMessageId, // message identifier
                            DWORD dwLanguageId, // language identifier
                            LPTSTR lpBuffer, // message buffer
                            DWORD nSize, // maximum size of message buffer
                            va_list *Arguments // array of message inserts
                            );

dwFlags

标志位,决定如何说明lpSource参数,dwFlags的低位制定如何处理换行功能在输出缓冲区,也决定最大宽度的格式化输出行。可选参数:

标志标志说明

FORMAT_MESSAGE_ALLOCATE_BUFFER

函数会分配一个足够大的缓冲区保存格式化消息,并且通过lpBuffer指向该

地址。当不再使用lpBuffer数据时,需调用LocalFree释放内存。

FORMAT_MESSAGE_ARGUMENT_ARRAY

Arguments参数不是指向va_list结构体,是一个指向保存参数的数组指针。

FORMAT_MESSAGE_FROM_HMODULE

指定lpSource参数是要去搜索的一个包含消息表的模块句柄。如果 lpSource 是NULL,会搜索当前进程的主模块,这个标志不能与FORMAT_MESSAGE_FROM_STRING 同时使用。

FORMAT_MESSAGE_FROM_STRING

lpSource参数是一个指向以NULL结尾的字符串,字符串包含一个消息定义,

这个消息定义可以包含插入序列。此标志不能与FORMAT_MESSAGE_FROM_HMODULE 、

FORMAT_MESSAGE_FROM_SYSTEM同时使用

FORMAT_MESSAGE_FROM_SYSTEM

0x00001000

函数会从系统信息列表中搜索所请求的信息。如果使用

FORMAT_MESSAGE_FROM_HMODULE,函数会先在lpSource指定

的模块中搜索请求的消息,如果搜索不到再去搜索系统消息表资源。此

标志不能与FORMAT_MESSAGE_FROM_STRING同时使用。

FORMAT_MESSAGE_IGNORE_INSERTS

指定消息定义中的插入序列将被忽略,并将其直接传递给输出缓冲区。 此标志对于获取稍后格式化的消息很有用。 如果设置了此标志,则忽略Arguments参数。

lpSource

根据dwFlags标志而定。[1] 

dwMessageId

请求的消息的标识符。当dwFlags标志为FORMAT_MESSAGE_FROM_STRING时会被忽略。[1] 

dwLanguageId

请求的消息的语言标识符。

LPTSTR lpBuffer

接收错误信息描述的缓冲区指针。

nSize

如果FORMAT_MESSAGE_ALLOCATE_BUFFER标志没有被指定,这个参数必须指定为输出缓冲区的大小,如果指定,这个参数指定为分配给输出缓冲区的最小数。[1] 

Arguments

保存格式化信息中的插入值的一个数组。

返回值

如果函数调用成功,返回输出缓冲区的大小,除最后一个空字符。如果失败则返回0。

FormatMessage失败处理

如果 FormatMessage函数运行失败,设法查看N e t M s g . d l l模块中的消息代码,以了解该错误是否与网络有关。使用 N e t M s g . d l l 模块的句柄,再次调用FormatMessage函数。

      // Get the error code's textual description
      BOOL fOk = FormatMessage(
         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
         FORMAT_MESSAGE_ALLOCATE_BUFFER, 
         NULL, dwError, systemLocale, 
         (PTSTR) &hlocal, 0, NULL);

      if (!fOk) {
         // Is it a network-related error?
         HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, 
            DONT_RESOLVE_DLL_REFERENCES);

         if (hDll != NULL) {
            fOk = FormatMessage(
               FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |
               FORMAT_MESSAGE_ALLOCATE_BUFFER,
               hDll, dwError, systemLocale,
               (PTSTR) &hlocal, 0, NULL);
            FreeLibrary(hDll);
         }
      }

6.消息分流器:

对于系统带有的消息分流器HANDLE_MESSAGENAME,如HANDLE_WM_COMMAND、HANDLE_WM_HSCROLL等。本质上是使用函数指针实现。

#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
    ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
    ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
    ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)

使用:

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate);    //Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lParam)
case WM_PAINT:
return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);
case WM_DESTROY:
return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

在《Windows核心编程》中作者使用如下宏

// The normal HANDLE_MSG macro in WindowsX.h does not work properly for dialog
// boxes because DlgProc return a BOOL instead of an LRESULT (like
// WndProcs). This chHANDLE_DLGMSG macro corrects the problem:
#define chHANDLE_DLGMSG(hwnd, message, fn)                 \
   case (message): return (SetDlgMsgResult(hwnd, uMsg,     \
      HANDLE_##message((hwnd), (wParam), (lParam), (fn))))

而在<windowsx.h>中有宏HANDLE_MSG

#define HANDLE_MSG(hwnd, message, fn)        \
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

在chHANDLE_DLGMSG中实际上是调用SetDlgMsgResult实现:

#define     SetDlgMsgResult(hwnd, msg, result) (( \
        (msg) == WM_CTLCOLORMSGBOX      || \
        (msg) == WM_CTLCOLOREDIT        || \
        (msg) == WM_CTLCOLORLISTBOX     || \
        (msg) == WM_CTLCOLORBTN         || \
        (msg) == WM_CTLCOLORDLG         || \
        (msg) == WM_CTLCOLORSCROLLBAR   || \
        (msg) == WM_CTLCOLORSTATIC      || \
        (msg) == WM_COMPAREITEM         || \
        (msg) == WM_VKEYTOITEM          || \
        (msg) == WM_CHARTOITEM          || \
        (msg) == WM_QUERYDRAGICON       || \
        (msg) == WM_INITDIALOG             \
    ) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))

SetWindowLongPtr函数功能:

该函数改变指定窗口的属性。函数也将指定的一个值设置在窗口的额外存储空间的指定偏移位置。

该函数用于取代SetWindowLong函数。如果您想要您编写的代码兼容32位和64位版本的Windows系统,请使用SetWindowLongPtr函数。

对于SetWindowLongPtr在ASCII下:

#define SetWindowLongPtr  SetWindowLongPtrA
#define SetWindowLongPtrA   SetWindowLongA
WINUSERAPI LONG WINAPI SetWindowLongA(
    _In_ HWND hWnd,            //窗口句柄,间接给出窗口所属的类。
    _In_ int nIndex,          //指定将设定的大于等于0的偏移值。有效值的范围从0到额外类的存储空间的字节数减去一个整型的大小(-sizeof(int))。
要设置其他任何值,可以指定下面值之一:
    _In_ LONG dwNewLong);    //指定的替换值。
nlndex说明
GWL_EXSTYLE

设定一个新的扩展风格。更多信息,请见CreateWindowEx

GWL_STYLE设定一个新的窗口风格。
GWL_WNDPROC为窗口过程设置一个新的地址。
GWL_HINSTANCE设置一个新的应用程序实例句柄。
GWL_ID设置一个新的窗口标识符。
GWL_USERDATA

设置与该窗口相关的用户数据。这些用户数据可以在程序创建该窗口时被使用。用户数据的初始值为0。

当hWnd参数标识了一个对话框时,也可使用下列值:
DWL_DLGPROC设置对话框过程的新地址。
DWL_MSGRESULT设置对话框中的消息处理程序的返回值。
DWL_USER设置的应用程序所私有的新的额外信息,例如句柄或指针。

参考:

消息分流器:点击打开链接

SetWindowLongPtr:点击打开链接

DialogProc与WndProc的区别:

DialogProc與WndProc不同,前者要返回True或者False,後者成功時返回0。如果返回False,對話框管理器將處理消息。如果消息需要一個特定的返回值,必須在返回True之前調用SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult)。

参考:点击打开链接

7.实现程序唯一

使用IsWindows实现程序唯一

 HWND hwnd = FindWindow(TEXT("#32770"), TEXT("Error Show"));
   if (IsWindow(hwnd)) {
      // An instance is already running, activate it and send it the new #
      SendMessage(hwnd, ESM_POKECODEANDLOOKUP, _ttoi(pszCmdLine), 0);
   } else {
      DialogBoxParam(hinstExe, MAKEINTRESOURCE(IDD_ERRORSHOW), 
         NULL, Dlg_Proc, _ttoi(pszCmdLine));
   }
   return(0);

8.SetDlgItemInt

该函数将uValue的值设为对话框控件的文本。

BOOL SetDlgItemInt(HWND hDlg,//指向对话框窗口的句柄。
int nIDDlgItem,//要改变其文本的控件ID。
UINT uValue,//要设置的值
BOOL bSigned);//指定uValue是否为一个有符号的值。

9.EnableWindow

允许/禁止指定的窗口或控件接受鼠标和键盘的输入,当输入被禁止时,窗口不响应鼠标和按键的输入,输入允许时,窗口接受所有的输入。

WINUSERAPI
BOOL
WINAPI
EnableWindow(
_In_HWNDhWnd,//被允许/禁止的窗口句柄
_In_BOOLbEnable);//允许/禁止指定的窗口或控件接受鼠标和键盘的输入 若该参数为TRUE,则窗口被允许。若该参数为FALSE,则窗口被禁止。

10.Edit_GetTextLength

该函数返回指定窗口的标题文本(如果存在)的字符长度。如果指定窗口是一个控件,函数将返回控制内文本的长度。

备注:如果目标窗口属于当前进程,GetWindowTextLength函数给指定的窗口或控制发送WM_GETTEXT消息。

头文件WindowsX.h

#define Edit_GetTextLength(hwndCtl)             GetWindowTextLength(hwndCtl)
uint GetWindowTextLength(HWND hWnd);//窗口或控制的句柄。

11.GetDlgItemInt

GetDlgItemInt函数通过发送控件WM_GETTEXT消息来检索指定控件的文本。 该函数通过剥离文本开头的任何额外的空格,然后转换十进制数字来翻译检索到的文本。 该功能在到达文本末尾或遇到非数字字符时停止转换。

返回值:

  1. 如果函数成功,则由lpTranslated指向的变量设置为TRUE,返回值为转换的控件文本。

  2. 如果函数失败,则由lpTranslated指向的变量设置为FALSE,返回值为零。 请注意,由于零是可能的转换值,返回值零并不表示失败。

  3. 如果lpTranslated为NULL,则该函数不会返回有关成功或失败的信息。

  4. 如果bSigned参数为TRUE,则指定要检索的值为有符号整数值,则将返回值转换为int类型。 要获取扩展错误信息,请调用GetLastError。

备注:  如果转换的值大于INT_MAX(对于带符号)或UINT_MAX(对于无符号数字),GetDlgItemInt函数将返回零。

UINT GetDlgItemInt(
HWNDhDlg, // 窗口句柄
int nIDDlgItem, // 控件标识符(名称)
BOOL *lpTranslated, //[out]指向接收成功或失败值的变量的指针 (TRUE表示成功,FALSE表示失败)。
如果此参数为NULL,则该函数不会返回有关成功或失败的信息。
BOOL bSigned // 有符号或无符号值 [in] 指定函数是否应该在开始时检查减号的文本,并返回一个有符号的整数值,如果它找到一个(TRUE指定应该检查,FALSE指定不应该检查)。
);

12.设置地区语言

//获取默认的区域语言
if (GetUserDefaultUILanguage() == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)) // [中文(简体)]
{		
}
 
	//设置当前的进程区域语言
	SetThreadUILanguage(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA));  // [阿拉伯语(沙特阿拉伯)]		
	SetThreadUILanguage(MAKELANGID(LANG_POLISH, SUBLANG_POLISH_POLAND));        // [波兰语(波兰)]
	SetThreadUILanguage(MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN));               // [朝鲜语(韩国)]
	SetThreadUILanguage(MAKELANGID(LANG_DANISH, SUBLANG_DANISH_DENMARK));       // [丹麦语(丹麦)]
	SetThreadUILanguage(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN));               // [德语(德国)]
	SetThreadUILanguage(MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA));      // [俄语(俄罗斯)]
	SetThreadUILanguage(MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH));               // [法语(法国)]
	SetThreadUILanguage(MAKELANGID(LANG_FINNISH, SUBLANG_FINNISH_FINLAND));     // [芬兰语(芬兰)]
	SetThreadUILanguage(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH));                 // [荷兰语(荷兰)]
	SetThreadUILanguage(MAKELANGID(LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC));  // [捷克语(捷克共和国)]
	SetThreadUILanguage(MAKELANGID(LANG_CROATIAN, SUBLANG_CROATIAN_CROATIA));   // [克罗地亚语(克罗地亚)]
	SetThreadUILanguage(MAKELANGID(LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA));   // [罗马尼亚语(罗马尼亚)]
	SetThreadUILanguage(MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL));  // [挪威语、博客马尔语(挪威)]		
	SetThreadUILanguage(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN));// [葡萄牙语(巴西)]
	SetThreadUILanguage(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE));          // [葡萄牙语(葡萄牙)]
	SetThreadUILanguage(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN));        // [日语(日本)]
	SetThreadUILanguage(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH));                // [瑞典语(瑞典)]
	SetThreadUILanguage(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN));   // [塞尔维亚语(拉丁语,塞尔维亚)]
	SetThreadUILanguage(MAKELANGID(LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA));         // [斯洛伐克语(斯洛伐克)]
	SetThreadUILanguage(MAKELANGID(LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA));   // [斯洛文尼亚语(斯洛文尼亚)]
	SetThreadUILanguage(MAKELANGID(LANG_TURKISH, SUBLANG_TURKISH_TURKEY));         // [土耳其语(土耳其)]
	SetThreadUILanguage(MAKELANGID(LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE));    // [乌克兰语(乌克兰)]
	SetThreadUILanguage(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN));         // [西班牙语(西班牙,国际风格)]
	SetThreadUILanguage(MAKELANGID(LANG_HEBREW, SUBLANG_HEBREW_ISRAEL));           // [希伯来语(以色列)]
 	SetThreadUILanguage(MAKELANGID(LANG_GREEK, SUBLANG_GREEK_GREECE));             // [希腊语(希腊)]
 	SetThreadUILanguage(MAKELANGID(LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY));    // [匈牙利语(匈牙利)]
 	SetThreadUILanguage(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN));                // [意大利语(意大利)]
	SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));             // [英语(美国)]
	SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL));    // [中文(繁体,台湾)]

https://blog.csdn.net/leez0301/article/details/50440394

13.LocalLock

局部内存

局部内存对象在局部堆中分配,局部堆是应用程序独享的自由内存,它只能由应用程序的特定实例访问。局部堆建立在应用程序的数据段中,因此,用户可分配的局部内存对象的最大内存空间不能超过64K。局部堆由Windows应用程序在模块定义文件中用HEAPSIZE语句申请,HEAPSIZE指定以字节为单位的局部堆初始空间尺寸。Windows提供了一系列函数来操作局部内存对象。

分配局部内存对象

LocalAlloc函数用来分配局部内存,它在应用程序局部堆中分配一个内存块,并返回内存块的句柄。LocalAlloc函数可以指定内存对象的大小和特性,其中主要特性有固定的(LMEM_FIXED),可移动的(LMEM_MOVEABLE)和可删除的(LMEM_DISCARDABLE)。如果局部堆中无法分配申请的内存,则LocalAlloc函数返回NULL。下面的代码用来分配一个固定内存对象,因为局部固定内存对象的对象句柄其本身就是16位内存近地址,因此它可以被应用程序直接存取。

加锁与解锁

上面程序段分配的固定局部内存对象可以由应用程序直接存取,但是,Windows并不鼓励使用固定内存对象。因此,在使用可移动和可删除内存对象时,就要经常用到对内存对象的加锁与解锁。

不管是可移动对象还是可删除对象,在它分配后其内存句柄是不变的,它是内存对象的恒定引用。但是,应用程序无法通过内存句柄直接存取内存对象,应用程序要存取内存对象还必须获得它的近地址,这通过调用LocalLock函数实现。LocalLock函数将局部内存对象暂时固定在局部堆的某一位置,并返回该地址的近地址值,此地址可供应用程序存取内存对象使用,它在应用程序调用 LocalUnlock函数解锁此内存对象之前有效。

应用程序在使用完内存对象后,要尽可能早地为它解锁,这是因为Windows无法移动被锁住了的内存对象。当应用程序要分配其它内存时,Windows不能利用被锁住对象的区域,只能在它周围寻找,这会降低Windows内存管理的效率。

改变局部内存对象

局部内存对象分配之后,还可以调用LocalReAlloc函数进行修改。LocalReAlloc函数可以改变局部内存对象的大小而不破坏其内容:如果比原来的空间小,则Windows将对象截断;如果比原来大,则Windows将增加区域填0(使用LMEM_ZEROINIT选项),或者不定义该区域内容。另外,LocalReAlloc函数还可以改变对象的属性,如将属性从LMEM_MOVEABLE改为LMEM_DISCARDABLE,或反过来,此时必须同时指定LMEM_MODIFY选项。但是,LocalReAlloc函数不能同时改变内存对象的大小和属性,也不能改变具有LMEM_FIXED属性的内存对象和把其它属性的内存对象改为LMEM_FIXED属性。

释放与删除

分配了的局部内存对象可以使用LocalDiscard和LocalFree函数来删除和释放,删除和释放只有在内存对象未锁住时才有效。

LocalFree函数用来释放局部内存对象,当一个局部内存对象被释放时,其内容从局部堆移走,并且其句柄也从有效的局部内存表中移走,原来的内存句柄变为不可用。LocalDiscard 函数用来删除局部内存对象,它只移走对象的内容,而保持其句柄有效,用户在需要时,还可以使用此内存句柄用LocalReAlloc函数重新分配一块内存。

另外,Windows还提供了函数LocalSize用于检测对象所占空间;函数LocalFlags用于检测内存对象是否可删除,是否已删除,及其锁计数值;函数LocalCompact用于确定局部堆的可用内存。

返回值:

如果函数成功,返回值是指向内存块的第一个字节的指针。

如果函数失败,返回值为NULL。

LPVOID LocalLock(
  HLOCAL hMem//本地内存对象的句柄。此句柄由LocalAlloc或LoalRealLoc函数返回。 
);

eg:
//获取错误标识
DWORD dwError = GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE);

HLOCAL hlocal = NULL;   // Buffer that gets the error message string

// Use the default system locale since we look for Windows messages.
// Note: this MAKELANGID combination has 0 as value
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);

// Get the error code's textual description
BOOL fOk = FormatMessage(
         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
         FORMAT_MESSAGE_ALLOCATE_BUFFER, 
         NULL, dwError, systemLocale, 
         (PTSTR) &hlocal, 0, NULL);
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);

http://blog.sina.com.cn/s/blog_472226a60100l4oi.html

https://baike.baidu.com/item/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/5633616

14.SetWindowPos

SetWindowPos函数改变一个子窗口,弹出式窗口或顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。

hwnd
在z序中的位于被置位的窗口前的窗口句柄。该参数必须为一个窗口句柄
hWndlnsertAfter
用于标识在z-顺序的此 CWnd 对象之前的 CWnd 对象。如果uFlags参数中设置了SWP_NOZORDER标记则本参数将被忽略。可为下列值之一:

    HWND_BOTTOM:值为1,将窗口置于Z序的底部。如果参数hWnd标识了一个顶层窗口,则窗口失去顶级位置,并且被置在其他窗口的底部。
    HWND_NOTOPMOST:值为-2,将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口已经是非顶层窗口则该标志不起作用。
    HWND_TOP:值为0,将窗口置于Z序的顶部。
    HWND_TOPMOST:值为-1,将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持顶级位置。

查看该参数的使用方法,请看说明部分。
x
以客户坐标指定窗口新位置的左边界。
Y
以客户坐标指定窗口新位置的顶边界。
cx
以像素指定窗口的新的宽度。
cy
以像素指定窗口的新的高度。
uFlags
窗口尺寸和定位的标志。该参数可以是下列值的组合:

    SWP_ASYNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。
    SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。
    SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。
    SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。
    SWP_HIDEWINDOW;隐藏窗口。
    SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。
    SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。
    SWP_NOMOVE:维持当前位置(忽略X和Y参数)。
    SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。
    SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。
    SWP_NOREPOSITION:与SWP_NOOWNERZORDER标志相同。
    SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。
    SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。
    SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。
    SWP_SHOWWINDOW:显示窗口。

返回值:

如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误消息,请调用GetLastError函数。

备注:

如果设置了SWP_SHOWWINDOW和SWP_HIDEWINDOW标志,则窗口不能被移动和改变大小。如果使用SetWindowLong改变了窗口的某些数据,则必须调用函数SetWindowPos来作真正的改变。使用下列的组合标志:SWP_NOMOVEISWP_NOSIZEISWP_FRAMECHANGED。

有两种方法将窗口设为最顶层窗口:一种是将参数hWndlnsertAfter设置为HWND_TOPMOST并确保没有设置SWP_NOZORDER标志;另一种是设置窗口在Z序中的位置以使其在其他存在的窗口之上。当一个窗口被置为最顶层窗口时,属于它的所有窗口均为最顶层窗口,而它的所有者的z序并不改变。

如果HWND_TOPMOST和HWND_NOTOPMOST标志均未指定,即应用程序要求窗口在激活的同时改变其在Z序中的位置时,在参数hWndinsertAfter中指定的值只有在下列条件中才使用:

在hWndlnsertAfter参数中没有设定HWND_NOTOPMOST和HWND_TOPMOST标志。

由hWnd参数标识的窗口不是激活窗口。

如果未将一个非激活窗口设定到z序的顶端,应用程序不能激活该窗口。应用程序可以无任何限制地改变被激活窗口在Z序中的位置,或激活一个窗口并将其移到最高级窗口的顶部或非最高级窗口的顶部。

如果一个顶层窗口被重定位到z序的底部(HWND_BOTTOM)或在任何非最高序的窗口之后,该窗口就不再是最顶层窗口。当一个最顶层窗口被置为非最顶级,则它的所有者窗口和所属者窗口均为非最顶层窗口。

一个非最顶端窗口可以拥有一个最顶端窗口,但反之则不可以。任何属于顶层窗口的窗口(例如一个对话框)本身就被置为顶层窗口,以确保所有被属窗口都在它们的所有者之上。

如果应用程序不在前台,但应该位于前台,就应调用SetForegroundWindow函数来设置。

Windows CE:如果这是一个可见的顶层窗口,并且未指定SWP_NOACTIVATE标志,则这个函数将激活窗口、如果这是当前的激活窗口,并且指定了SWP_NOACTIVATE或SWP_HIDEWINDOW标志,则激活另外一个可见的顶层窗口。

当在这个函数中的nFlags参数里指定了SWP_FRAMECHANGED标志时,WindowsCE重画窗口的整个非客户区,这可能会改变客户区的大小。这也是重新计算客户区的唯一途径,也是通过调用SetwindowLong函数改变窗口风格后通常使用的方法。

SetWindowPos将使WM_WINDOWPOSCHANGED消息向窗口发送,在这个消息中传递的标志与传递给函数的相同。这个函数不传递其他消息。

Windows CE 1.0不支持在hWndlnsertAber参数中的HWND_TOPMOST和HWND_NOTOPMOST常量

Windows CE1.0不支持在fuFags参数中的SWP_DRAWFRAME和SWP_NOCOPYBITS标志。

速查:Windows NT:3.1以上版本;Windows:95以上版本;Windows CE:1.0以上版本;头文件:winuser.h库文件:eser32lib。

https://baike.baidu.com/item/SetWindowPos/6376849?fr=aladdin

15.IsDlgButtonChecked

可以确定某个按钮控件是否有选中标志,或者三态按钮控制是否为灰色的、选中的、或两者都不是。

返回值:

使用BS_AUTOCHECKBOX、BS_AUTORADIOBUTTON、BS_AUTO3STATE、BS_CHECKBOX、BS_RADIOBUTION或BS_3STATE样式创建的按钮的返回值可以是如下值之一:

BST_CHECKED:表示按钮被选中。

BST_INDETERMINATE:表示按钮是灰色的,即为不确定状态(只有具有BS_3STATE或BS_AUTO3STATE样式的按钮才使用该值)。

BST_UNCHECKED:表示该按钮未选中(unckecked)。如果该按钮用其他任何样式,那么返回值为零。

UINT IsDlgButtonChecked(
HWND hDlg,//指向包含按钮控制的对话框。
Int nlDBUtton);//指定按钮控制的整型标识符。

16.EndDialog/DestroyWindow

关闭模态对话框,使系统中止对对话框的任何处理的函数,并且将参数作为父对话框调用的返回值。

返回值:

如果函数调用成功,则返回值为非零值;如果函数调用失败则返回值为零。若想获得错误信息请调用GetLastError函数。

备注:

由DialogBox,DialogBoxParam、DialogBoxlndirect和DialogBoxlndirectParam函数创建的对话框一定要用EndDialog函数来清除。应用程序从对话框应用程序内部调用EndDialog函数,该函数不能为其他目的而供使用。对话框应用程序可以在任何时间调用EndDialog函数;甚至在WM_INITDIALOG消息处理过程中。如果应用程序在WM_INITDIALOG消息处理过程中调用该函数,则对话框在显示和输入焦点被设置之前对话框被清除。EndDialog函数并不立即清除对话框。而是设置一个标志,并且允许对话框应用程序把控制权返回系统。系统在试图从应用程序队列检索下一个消息之前检测标志。如果已经设置了标志则系统中止消息循环,清除对话框,且用nResUlt中的值作为从创建对话框的函数中返回的值。

DestroyWindow 关闭非模态对话框。 退出消息循环,真正结束进程。有不少程序窗口关闭,但是不等于退出运行。

BOOL EndDialog(HWND hDlg,//表示要被清除的对话框窗口。
int nResult);//指定从创建对话框函数返回到应用程序的值。

https://baike.baidu.com/item/EndDialog/6370746?fr=aladdin

https://blog.csdn.net/hfhhxh/article/details/40982715

17.SetForegroundWindow

将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。

返回值:

如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。

备注:

前台窗口是z序顶部的窗口,是用户的工作窗口。在一个多任务优先抢占环境中,应让用户控制前台窗口。

Windows NT 5.0:当用户在另一个窗口中工作时,应用程序不能强行设置一个窗口到前台。相反,SetForeground函数将会激活窗口并且调用FlashWindowEx函数通知用户。

Windows CE:拥有窗口的线程不具有优先启动权。

BOOL SetForegroundWindow(HWND hWnd)//将要设置前台的窗口句柄

EX:

//显示错误代码对应文本 需要使用时(PCTSTR) LocalLock(hlocal) 需要释放LocalFree(hlocal)
//dwError错误代码
//fOK==TRUE&&hlocal!=NULL时找到错误文本
BOOL HXShowErrorLocal(DWORD dwError, HLOCAL &hlocal)
{
	hlocal = nullptr;
	DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);

	BOOL fOK = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dwError, systemLocale, (PTSTR)&hlocal, 0, NULL);


	if (!fOK) {
		// Is it a network-related error?
		HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);

		if (hDll != NULL) 
		{
			fOK = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |
				FORMAT_MESSAGE_ALLOCATE_BUFFER,	hDll, dwError, systemLocale,
				(PTSTR)&hlocal, 0, NULL);
			FreeLibrary(hDll);
		}
	}
	return fOK;
}

eg:
      HLOCAL hlocal = NULL;   // Buffer that gets the error message string
	  BOOL fOk = HXShowErrorLocal(dwError, hlocal);
      if (fOk && (hlocal != NULL)) {
         SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
         LocalFree(hlocal);
      } else {
         SetDlgItemText(hwnd, IDC_ERRORTEXT, 
            TEXT("No text found for this error number."));
      }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值