Unicode会导致关闭messagebox以终止程序

时间:2011-11-30 22:03:29

标签: c++ winapi unicode crash wrapper

我正在开发一个Win32 API Wrapper。为了使其符合Unicode,我执行以下操作:

#ifndef UNICODE
#define gchar char
#define gstrcpy strcpy
#define gstrncpy strncpy
#define gstrlen strlen
#define gstrcat strcat
#define gstrncat strncat
#define gstrcmp strcmp
#define gstrtok strtok
#else
#define gchar wchar_t
#define gstrcpy lstrcpy
#define gstrncpy lstrncpy
#define gstrlen lstrlen
#define gstrcat lstrcat
#define gstrncat lstrncat
#define gstrcmp lstrcmp
#define gstrtok lstrtok
#endif

我也提供

#define uni(s) TEXT(s)

我的测试包括一个通过

创建消息框的窗口
msg (uni("Left-click"));

每当用户左键单击窗口时。问题在于,无论创建了多少消息,当我#define UNICODE关闭4或5个消息后,显示的下一个消息框,无论是新消息还是最后一个消息都会导致程序返回0xC0000005。不定义UNICODE将使这项工作完美。我的msg功能如下:

dword msg (cstr = uni(""), cstr = uni(""), hwin = null, dword = 0);
...
dword msg (cstr lpText, cstr lpCaption, hwin hWnd, dword uType)
{
    return MessageBox (hWnd, lpText, lpCaption, uType);
}

其中dword是DWORD,cstr是pchar,它是gchar *,可以是char *或wchar_t *,hwin是HWND,null是0。

可能不是消息框这样做,但我没有做任何其他与文本相关的测试,所以我会看到它是否也会崩溃。

有谁知道为什么会这样? MB字符和unicode之间的区别不应该导致程序反复崩溃。如果需要,我也可以上传标题和测试。

编辑: 我刚发现创建了一条消息,然后关闭实际窗口将导致同样的崩溃。 SOURCE CODE以下是来源的链接。铭记于心: a)我只参加过一年级的编程课程(C ++)。 b)我的包装器的目的是使编写win32应用程序尽可能简单。 c)我喜欢自己创作(字符串类等)。

也忘了这个(duh),我正在使用Code :: Blocks(MinGW)。

编辑: 我以前没有意识到,但该程序试图访问0x00000000的内存。这就是导致问题的原因,但我不知道为什么会这样做。我相信试图访问它的指令位于winnt.dll的某个地方,但是从未学过如何调试,我仍在试图弄清楚如何找到我需要的信息。

编辑: 现在,不更改它,而是在另一台计算机上运行它,它引用0x7a797877而不是0。

编辑:更改窗口过程以包含WM_LBUTTONDOWN并在其中调用msg(),而不是调用添加的过程使程序完美运行。 addmsg()和窗口过程的编码方式导致_lpWindowName和_lpClassName在一段时间后出现损坏的数据,但仍然保留非指针成员。

修改: 在所有这些混乱之后,我终于发现我在所有源代码中都缺少一个字符。当我将msgparams定义为Window, UINT, WPARAM, LPARAM并将msgfillparams同样定义时(除了名称)我忘记传递参考。我按价值通过了窗口!我还是要感谢所有发帖的人,因为我确实得到了调试员的支持,最后还学到了很多关于Unicode的知识。

2 个答案:

答案 0 :(得分:2)

在提出SO问题之前,你应该做好功课。我的印象是你几乎不知道Unicode如何在Windows上工作,它需要很多页面来解释。

将应用程序从ANSI移植到Unicode在Windows上是一个大问题。向有经验的人付费似乎是合理的。

主要用于char的所有内容都必须与wchar_t一起使用。

整个API还有其他功能,但你应该首先使用windows支持,而不是编写自己的macros,第一步是使用_T而不是W,这样你就可以开始更改代码了能够以Unicode和ANSI编译。

答案 1 :(得分:1)

为什么你首先要打扰ANSI呢?所有TCHAR支持都可以追溯到Win95常见的时候,因此开发人员必须编写可以编译为ANSI(适用于Win95)或UNICODE(适用于基于NT的Windows)的代码。现在Win95已经过时了,没有必要打扰TCHAR:只需要使用L“Unicode字符串”而不是TEXT()和CRT的wcs版本而不是_t版本来全部UNICODE。

话虽如此,这里有一些常见的ANSI / UNICODE代码错误来源可以解释你所看到的一些错误:

一种可能性是某个地方有一个破坏堆栈的错误 - 未初始化的变量,堆栈溢出等等。在unicode中,与ANSI版本相比,堆栈上的任何字符或字符串可能占用不同的空间量,因此变量将相对于彼此在不同的位置结束。你有可能在ANSI构建中“变得幸运”,任何被破坏的东西都不是重要的数据;但是在UNICODE构建中,堆栈上的一些重要内容正在中获得成功。 (例如,如果溢出堆栈上的缓冲区,最终可能会覆盖堆栈上的返回地址,可能会在下一个函数返回时导致崩溃。)

-

注意混合字符数与字节数的情况:使用ANSI,您可以将'sizeof()'几乎与字符数互换使用(取决于您是否计算终止NUL空间与否;);但是使用UNICODE,你不能:如果你让它们混淆,你可以很容易地获得缓冲区溢出。

例如:

// Incorrectly passing byte count instead of character count
WCHAR szWindowName[32];
GetWindowTextW( hwnd, szWindowName, sizeof(szWindowName) );
  • 这会导致缓冲区溢出(导致崩溃 - 如果你很幸运 - 或者如果你不幸的话,数据会无声地被破坏以及之后会出现不正确的结果),因为它将64位 - 字节大小 - 传递给GetWindowText,而不是32,字符大小。

在Windows上,使用ARRAYSIZE(...)而不是sizeof()来获取数组中元素的数量,而不是数组的字节大小。

-

要注意的另一件事是任何字符串,你使用强制转换将它们“强制”为CHAR或WCHAR以避免编译器错误:例如。

// Incorrectly calling ANSI function with UNICODE strings...
MessageBoxA(hwnd, (LPCSTR)L"Unicode Title", (LPCSTR)"Unicode content", MB_OK);

此类用法通常只会显示字符串的第一个字符。

// Incorrectly calling UNICODE function with ANSI strings...
MessageBoxW(hwnd, (LPCWSTR)"ANSI Title", (LPCWSTR)"ANSI content", MB_OK);

这比较棘手,你可能会得到一堆垃圾,或者可能会出现某种错误。

这些案例很容易发现有演员阵容 - 一般来说,演员阵容应被视为“危险信号”并且不惜一切代价避免。不要使用它们来避免编译器错误,而是修复编译器警告的问题。

还要注意你可以将这些混淆但编译器不会警告你的情况 - 例如printf,scanf和朋友:编译器不检查参数列表:

// Incorrectly calling ANSI function with UNICODE string - compiler won't warn you here...
LPCWSTR pString = L"I'm unicode!";
printf("The result is: %s\n", pString);
相关问题