简体   繁体   English

Unicode导致关闭消息框终止程序

[英]Unicode causes closing messagebox to terminate program

I'm developing a Win32 API Wrapper. 我正在开发Win32 API包装器。 To make it Unicode-compliant, I do the following: 为了使其符合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

I also provide 我也提供

#define uni(s) TEXT(s)

My test consisted of a window that creates a message box via 我的测试包含一个通过以下方式创建消息框的窗口

msg (uni("Left-click"));

whenever the user left-clicks the window. 每当用户左键单击窗口时。 The problem is that, no matter how many messages are created, after 4 or 5 of these messages are closed when I #define UNICODE, the next message box shown, whether it be a new one or the one under the last one closed causes the program to return 0xC0000005. 问题是,无论创建多少条消息,在我#define UNICODE时关闭这些消息中的4或5条后,显示的下一个消息框(无论是新消息还是最后一个关闭的消息框)都会导致程序返回0xC0000005。 Not defining UNICODE will make this work perfectly. 不定义UNICODE将使这项工作完美进行。 My msg function is as follows: 我的味精功能如下:

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);
}

where dword is DWORD, cstr is pchar, which is gchar *, which can be char * or wchar_t *, hwin is HWND, and null is 0. 其中dword是DWORD,cstr是pchar,这是gchar *,可以是char *或wchar_t *,hwin是HWND,null是0。

It probably isn't the message box doing this, but I haven't done any other text-related stuff with the testing so I'll see if it crashes some other way too. 可能不是消息框在执行此操作,但是我没有在测试中进行任何其他与文本相关的工作,因此我还将查看它是否也会以其他方式崩溃。

Does anyone know why this would happen? 有谁知道为什么会这样? The difference between MB characters and unicode shouldn't cause the program to repeatedly crash. MB字符和unicode之间的差异不应导致程序反复崩溃。 I can upload the headers and the test too, if needed. 如果需要,我也可以上传标题和测试。

Edit: I just found out creating one message and then closing the actual window will result in the same crash. 编辑:我刚刚发现创建一条消息,然后关闭实际窗口将导致相同的崩溃。 SOURCE CODE Here's the link for the source. 源代码这是源的链接。 Please keep in mind: a) I only took one first-year programming course, ever (C++). 请记住:a)我以前只修过一门一年级的编程课程(C ++)。 b) My wrapper's purpose is to make writing win32 apps as easy as possible. b)我的包装器的目的是使编写Win32应用程序尽可能容易。 c) I like to make things of my own (string class etc). c)我喜欢自己做东西(字符串类等)。

Also forgot this (duh), I'm using Code::Blocks (MinGW). 也忘了这个(duh),我正在使用Code :: Blocks(MinGW)。

Edit: I didn't realize before, but the program is trying to access memory at 0x00000000. 编辑:我以前没有意识到,但是程序正在尝试访问0x00000000的内存。 This is what's causing the problem, but I have no idea why it would be trying to do this. 这就是导致问题的原因,但是我不知道为什么它会尝试这样做。 I believe the instruction trying to access it is located somewhere in winnt.dll, but having never learned how to debug, I'm still trying to figure out how to find the information I need. 我相信尝试访问该指令的指令位于winnt.dll中的某个位置,但是从未学习过调试的知识,但我仍在尝试找出如何找到所需的信息。

Edit: Now, without changing it, but running it on a different computer, it's referencing 0x7a797877 instead of 0. 编辑:现在,不更改它,而是在另一台计算机上运行它,它引用的是0x7a797877而不是0。

Edit: Changing the window procedure to include WM_LBUTTONDOWN and call msg() inside, rather than calling the added procedure makes the program work perfectly. 编辑:更改窗口过程以包括WM_LBUTTONDOWN并在其中调用msg() ,而不是调用添加的过程使该程序完美运行。 Something with the way addmsg() and the window procedure are coded causes the _lpWindowName and _lpClassName to have corrupted data after a while, but non-pointer members are still preserved. 使用addmsg()和窗口过程进行编码的方式会导致_lpWindowName和_lpClassName一段时间后损坏数据,但仍保留非指针成员。

EDIT: After all of this mayhem I finally found out I was missing a single character in all of my source code. 编辑:经过所有这些混乱之后,我终于发现我在所有源代码中都缺少一个字符。 When I defined msgparams as Window, UINT, WPARAM, LPARAM and likewise with msgfillparams (except with names) I forgot to pass a reference. 当我将msgparams定义为Window, UINT, WPARAM, LPARAM以及msgfillparams (名称除外)时,我忘记了传递引用。 I was passing the Window by value! 我正在通过价值传递窗口! I'd still like to thank everyone who posted, as I did get my butt kicked debugger-wise and ended up learning a lot more about Unicode as well. 我仍然要感谢所有发布者,因为我确实在调试器方面受到了极大的鼓舞,并最终也学到了更多有关Unicode的知识。

you should do your homework before asking questions on SO. 您应该先做作业,然后再对SO提出问题。 My impression is that you have almost no idea about how Unicode works on Windows and it will require many pages to explain. 我的印象是,您几乎不了解Unicode在Windows上的工作方式,并且需要很多页面来解释。

Porting an application from ANSI to Unicode is a big deal on Windows. 在Windows上,将应用程序从ANSI移植到Unicode是一件大事。 It may seem reasonable to pay someone with experience do to this. 付钱给有经验的人这样做似乎是合理的。

Mainly everything that worked with char will have to work with wchar_t. 主要与char一起使用的所有内容都必须与wchar_t一起使用。

The entire API has other functions but you should start by using windows support for this, not writing your own macros and first step is to use _T not W so you'll b able to start changing code and still be able to compile in both Unicode and ANSI. 整个API还有其他功能,但是您应该首先使用Windows支持,而不是编写自己的macros ,第一步是使用_T而不是W,这样您就可以开始更改代码,并且仍然可以使用两种Unicode进行编译和ANSI。

Why are you even bothering with ANSI in the first place? 您为什么首先还要担心ANSI? All the TCHAR support dates back to a time when Win95 was commonplace, so developers had to write code that could compile as ANSI (for Win95) or UNICODE (for NT-based Windows). TCHAR的所有支持都可以追溯到Win95普及的时代,因此开发人员必须编写可以编译为ANSI(对于Win95)或UNICODE(对于基于NT的Windows)的代码。 Now that Win95 is long obsolete, there's no need to bother with TCHAR: just go all-UNICODE, using L"Unicode strings" instead of TEXT() and wcs-versions of the CRT rather than the _t-versions. 既然Win95已经过时了,那么就不必理会TCHAR:只需使用L“ Unicode字符串”而不是TEXT()和CRT的wcs版本而不是_t版本,就可以使用UNICODE。

Having said that, here's some common sources of errors with ANSI/UNICODE code that could explain some of what you are seeing: 话虽如此,这是ANSI / UNICODE代码的一些常见错误源,它们可以解释您看到的一些内容:

One possibility is that there's a bug somewhere that's corrupting the stack - uninitialized variable, stack overrun, and the like. 一种可能是某个地方的错误正在破坏堆栈-未初始化的变量,堆栈溢出等。 In unicode, any chars or strings on the stack may take up a different amount of space compared to the ANSI version, so variables will end up in different places relative to one another. 在unicode中,与ANSI版本相比,堆栈中的任何char或字符串可能占用的空间量不同,因此变量相对于彼此将位于不同的位置。 Chances are you are 'getting lucky' in the ANSI build, and whatever is being corrupted isn't important data; 您很有可能在ANSI版本中“很幸运”,而任何损坏的数据都不重要。 but on the UNICODE build, something important on the stack is getting nuked. 但是在UNICODE版本上,堆栈上的一些重要内容被删除。 (For example, if you overflow a buffer on the stack, you could end up overwriting the return address that's also on the stack, likely causing a crash at the next function return.) (例如,如果您在堆栈上溢出了缓冲区,最终可能会覆盖同样在堆栈上的返回地址,很可能在下次函数返回时导致崩溃。)

-- -

Watch out for cases where you are mixing up character counts versus byte counts: with ANSI, you can use 'sizeof()' almost interchangeably with a character count (depending on whether you're counting the terminating NUL space or not); 注意将字符计数与字节计数混淆的情况:使用ANSI,您几乎可以将'sizeof()'与字符计数互换使用(取决于是否要计算终止NUL空间); but with UNICODE, you can't: and if you get them mixed up, you can get a buffer overrun very easily. 但是使用UNICODE,您不能:并且,如果将它们混淆,则可以很容易地使缓冲区溢出。

For example: 例如:

// Incorrectly passing byte count instead of character count
WCHAR szWindowName[32];
GetWindowTextW( hwnd, szWindowName, sizeof(szWindowName) );
  • this can cause a buffer overrun (leading to crash - if you're lucky - or silently corrupted data and incorrect results later on if you're not lucky) since it's passing 64 - the size in bytes - to GetWindowText, instead of 32, the size in characters. 这可能会导致缓冲区溢出(导致崩溃-如果您幸运的话-或崩溃的数据,如果您不幸运的话稍后会导致错误的结果),因为它会将64(以字节为单位)的大小传递给GetWindowText,而不是32,以字符为单位的大小。

On windows, Use the ARRAYSIZE(...) instead of sizeof() to get the number of elements in an array rather than the byte-size of the array. 在Windows上,使用ARRAYSIZE(...)而不是sizeof()来获取数组中元素的数量,而不是数组的字节大小。

-- -

Another thing to watch for is any strings where you have used casts to "force" them into CHAR or WCHAR to avoid compiler errors: eg. 要注意的另一件事是使用强制转换将其“强制”为CHAR或WCHAR以避免编译器错误的任何字符串:

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

This type of usage typically results in just the first character of the string showing. 这种用法通常导致仅显示字符串的第一个字符。

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

This is trickier, you may get a string of garbage, or could get an error of some kind. 这比较棘手,您可能会得到一串垃圾,或者会遇到某种错误。

These cases are easy to spot there there are casts - generally speaking, casts should be viewed as a 'red flags' and avoided at all costs. 这些情况很容易发现有演员表-一般而言,演员表应被视为“危险信号”,不惜一切代价避免。 Don't use them to avoid a compiler error, instead fix the issue that the compiler is warning about. 不要使用它们来避免编译器错误,而要解决编译器警告的问题。

Also watch out for cases where you can get these mixed up but where the compiler won't warn you - eg with printf, scanf and friends: the compiler doesn't check the argument lists: 还要注意可能混在一起但编译器不会警告您的情况-例如,使用printf,scanf和friends:编译器不会检查参数列表:

// 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM