Unicode вызывает закрытие окна сообщения для завершения программы - PullRequest
0 голосов
/ 01 декабря 2011

Я разрабатываю 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"));

всякий раз, когда пользователь щелкает левой кнопкой мыши по окну.Проблема заключается в том, что независимо от того, сколько сообщений создано, после того, как 4 или 5 из этих сообщений будут закрыты, когда я #define UNICODE, будет показано следующее окно сообщения, будь то новое или то, которое находится под последним закрытым, вызываетпрограмма для возврата 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 и юникодом не должна вызывать многократный сбой программы.При необходимости я могу также загрузить заголовки и тест.

Редактировать: Я только что обнаружил, что создание одного сообщения, а затем закрытие фактического окна приведет к тому же самому сбою. SOURCE CODE Вот ссылка на источник.Пожалуйста, имейте в виду: а) Я когда-либо проходил только один курс программирования первого года обучения (C ++).б) Цель моей обертки - сделать написание приложений win32 как можно проще.c) Мне нравится создавать свои собственные вещи (класс строк и т. д.).

Тоже забыл об этом (дух), я использую Code :: Blocks (MinGW).

Редактировать: Iраньше не понимал, но программа пытается получить доступ к памяти по адресу 0x00000000.Это то, что вызывает проблему, но я понятия не имею, почему он пытается это сделать.Я полагаю, что инструкция, пытающаяся получить к нему доступ, находится где-то в winnt.dll, но так и не научившись отлаживать, я все еще пытаюсь выяснить, как найти нужную мне информацию.

Редактировать: Теперь,не изменяя его, но выполняя его на другом компьютере, он ссылается на 0x7a797877 вместо 0.

Редактировать: изменение оконной процедуры для включения WM_LBUTTONDOWN и вызова msg() внутри вместо вызова добавленной процедуры приводит кпрограмма работает отлично.Что-то с кодированием addmsg() и оконной процедурой приводит к тому, что _lpWindowName и _lpClassName через некоторое время повредили данные, но элементы без указателя все еще сохраняются.

РЕДАКТИРОВАТЬ: После всего этогохаос Я наконец узнал, что мне не хватает одного символа во всем моем исходном коде.Когда я определил msgparams как Window, UINT, WPARAM, LPARAM и аналогично с msgfillparams (кроме имен), я забыл передать ссылку.Я передавал Окно по значению!Я все еще хотел бы поблагодарить всех, кто написал, так как я получил удар по заднице в отладчике и закончил тем, что узнал намного больше о Юникоде.

Ответы [ 2 ]

2 голосов
/ 01 декабря 2011

Вы должны сделать свою домашнюю работу, прежде чем задавать вопросы по SO. У меня сложилось впечатление, что вы почти не представляете, как работает Unicode в Windows, и для объяснения потребуется много страниц.

Перенос приложения из ANSI в Unicode - большая проблема для Windows. Может показаться разумным заплатить кому-то с опытом сделать это.

В основном все, что работало с char, должно работать с wchar_t.

Весь API имеет другие функции, но вы должны начать с использования поддержки Windows для этого, а не писать свой собственный macros, и первым шагом является использование _T, а не W, чтобы вы могли начать изменять код и при этом иметь компилировать как в Юникоде, так и в ANSI.

1 голос
/ 01 декабря 2011

Почему вы вообще беспокоитесь о ANSI? Вся поддержка TCHAR восходит к тому времени, когда Win95 был обычным явлением, поэтому разработчикам приходилось писать код, который можно компилировать как ANSI (для Win95) или UNICODE (для Windows на базе NT). Теперь, когда Win95 давно устарел, вам не нужно беспокоиться о TCHAR: просто используйте all-UNICODE, используя L "Unicode strings" вместо TEXT () и wcs-версии CRT, а не _t-версии.

Сказав это, вот несколько распространенных источников ошибок с кодом ANSI / 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, размер в символах.

В окнах используйте 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);
...