Win7 中的 SendMessageA 和 SendMessageW 从 WinXP 迁移
编辑:工作代码发布在下面,非工作代码被注释掉。您必须使用与在 Win7 中创建数据相同的 CHAR_T 从 Windows 中检索数据。
我有一个用 C 编写的对话框,它在 WinXP 中完美运行,但无法从 Win7 中的 unicode 编辑控件收集用户输入。问题发生在第一次调用 SendMessageW 时,如下所示:
/* handles to controls */
HWND hDomainEdit;
HWND hOtherEdit;
HWND hTextOut;
HWND hButton;
/* buffers to receive input */
WCHAR wszDomain[256];
CHAR szOtherInput[512];
CHAR szBuffer[512]; //added to hold temporary value of wszDomain
/* a test string */
const CHAR szTest[] = "This is a test of SendMessageA."
BOOL dialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_INIT) {
/* get all the handles shown above, then... */
SendMessageA(hTextOut, WM_SETTEXT, 0, (LPARAM) szTest);
/* worked fine */
/* do a few other things */
} else if (message == WM_COMMAND) {
/* are some other conditions are true? they sure are */
/* time to collect a bunch of input from controls */
int cchResultLen = (int) SendMessageA(hOtherEdit, WM_GETTEXT, 512, (LPARAM) szOtherInput);
/* cchResultLen is correctly the length of the user input */
/* cchResultLen = (int) SendMessageW(hDomainEdit, WM_GETTEXT, 256, (LPARAM) wszDomain); */
/* begin new code */
cchResultLen = (int) SendMessageA(hDomainEdit, WM_GETTEXT, 512, (LPARAM) szBuffer);
cchResultLen = MultiByteToWideChar(CP_UTF8, 0, szBuffer, cchResultLen, wszDomain, 256);
wszDomain[cchResultLen] = 0; /* above doesn't terminate string */
/* after SendMessageW(), cchResultLen was 0, no string transferred, no error
message. using SendMessageA, all is well. */
}
}
看起来 SendMessageA 在 message = WM_GETTEXT 或 WM_SETTEXT 时多次工作,突然间,当需要宽字符串时,SendMessageW 失败。现在,我知道每个人都认为您应该选择 CHAR_T 并始终使用 SendMessage 来坚持使用它,但事实并非如此; Win32.hlp 明确指出,可以通过手动调用各个函数在同一程序中使用这两个函数。我确信其他人已经准备好说控件本身已经或将致力于某个特定的 CHAR_T,但在 WinXP 中情况并非如此,在 WinXP 中这可以完美地工作。该特定的编辑控件也从未明确设置为 ASCII 字符串。
该程序与 WinHttp 交互,需要所有 WCHAR 字符串,这就是 SendMessageW 的用武之地。其余输入仅在内部使用,主要是带有单位标签的解析整数,如果没有的话,在 ASCII 中更方便和高效除了程序最初是这样编写的之外,还有其他原因。
那么怎么办呢?他们真的把像 SendMessage 这样不可或缺的东西变成了不兼容吗?如果是这样,这是否是一个已知的错误并有解决方法,或者随意切换 CHAR_T 的功能是否已被弃用?使用 SendMessageA 获取输入后,是否有比手动将输入扩展为 WCHAR 更简单的方法?
EDIT: Working code posted below, nonworking code commented out. You must use the same CHAR_T for retrieving data from windows as you used to create them in Win7.
I have a dialog written in C that works perfectly in WinXP but fails to collect user input from an edit control in unicode in Win7. The problem occurs on the first call to SendMessageW as shown below:
/* handles to controls */
HWND hDomainEdit;
HWND hOtherEdit;
HWND hTextOut;
HWND hButton;
/* buffers to receive input */
WCHAR wszDomain[256];
CHAR szOtherInput[512];
CHAR szBuffer[512]; //added to hold temporary value of wszDomain
/* a test string */
const CHAR szTest[] = "This is a test of SendMessageA."
BOOL dialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_INIT) {
/* get all the handles shown above, then... */
SendMessageA(hTextOut, WM_SETTEXT, 0, (LPARAM) szTest);
/* worked fine */
/* do a few other things */
} else if (message == WM_COMMAND) {
/* are some other conditions are true? they sure are */
/* time to collect a bunch of input from controls */
int cchResultLen = (int) SendMessageA(hOtherEdit, WM_GETTEXT, 512, (LPARAM) szOtherInput);
/* cchResultLen is correctly the length of the user input */
/* cchResultLen = (int) SendMessageW(hDomainEdit, WM_GETTEXT, 256, (LPARAM) wszDomain); */
/* begin new code */
cchResultLen = (int) SendMessageA(hDomainEdit, WM_GETTEXT, 512, (LPARAM) szBuffer);
cchResultLen = MultiByteToWideChar(CP_UTF8, 0, szBuffer, cchResultLen, wszDomain, 256);
wszDomain[cchResultLen] = 0; /* above doesn't terminate string */
/* after SendMessageW(), cchResultLen was 0, no string transferred, no error
message. using SendMessageA, all is well. */
}
}
It appears SendMessageA works multiple times with message = WM_GETTEXT or WM_SETTEXT, and suddenly, when a wide string is required, SendMessageW fails. Now, I know everyone is thinking that you should pick a CHAR_T and stick with it by always using SendMessage, but it's not so; Win32.hlp explicitly notes that it's possible to use both in the same program by calling the individual functions manually. I'm sure someone else is ready to say that the control itself is or becomes committed to one particular CHAR_T, but that's not the case in WinXP, where this worked perfectly. That particular edit control is also never set to an ASCII string explicitly.
The program interacts with WinHttp, which requires all WCHAR strings, and that's where the SendMessageW comes in. The rest of the inputs are only used internally and are primarily parsed integers with unit labels, which are more convenient and efficient in ASCII, if for no other reason than because the program was originally written that way.
So what do? Have they really changed something as integral as SendMessage to be incompatible? If so, is it a known bug with a work around, or is the ability to switch CHAR_T at will a deprecated feature? Is there some other easier way than expanding the input to WCHAR manually after getting it with SendMessageA?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我的理解是,如果您使用调试器单步执行代码 - 您就会看到原因。
首先,您相继拥有两个 SendMessage,它们使用不同的窗口句柄,因此它们不会给您相同的结果。让我们谈谈给您带来问题的那个:
站在这一行上的调试器,检查您的 hDomainEdit 变量。也许它无效,例如 NULL 或被其他代码损坏。这可以解释无效句柄和零结果。
My understanding is that if you step through your code with debugger - you will see the reason.
First of all, the two SendMessages you have one after another, they are using different window handles, so they are not of the kind to give you the same result. Let's talk about the one that gives you the problem:
Standing with debugger on this line, check your hDomainEdit variable. Perhaps it's not valid, like NULL or damaged by some other code. This would explain invalid handle and zero result.
所有的窗把手都很好。 MSDN 的人员告诉我,任何使用“A”函数创建的窗口(在本例中为 DialogBoxParamA())都必须通过“A”函数访问。至于它在 XP 中运行的事实,他们说“仅仅因为它运行并不意味着它是正确的”。我想该功能已被弃用 - 在它停止工作之前听到这个消息就好了!
All window handles were fine. The folks at MSDN informed me that any window created with an 'A' function - in this case DialogBoxParamA() - must be accessed via the 'A' functions. As for the fact that it worked in XP, they said "Just because it works doesn't mean it's right". I suppose that functionality was deprecated - would have been nice to hear about that before it stopped working!