Консольная программа на C++ с использованием UNICODE

120
08 января 2021, 12:50

Проблема в приведении типов при попытке написать код для WinAPI. Программа простенькая, для вывода таблицы умножения. Минус в том, что программа из учебника 2004 года по C++, возможно с тех пор многое изменилось. Суть проблемы: возникает конфликт типов. Ошибка (активно) E0144 значение типа "const wchar_t *" нельзя использовать для инициализации сущности типа "TCHAR *" также есть такие ошибки типа:

E0167 аргумент типа "const wchar_t *" несовместим с параметром типа "LPWSTR" ,

E0513 значение типа "const wchar_t *" нельзя присвоить сущности типа "TCHAR",

C2440 инициализация: невозможно преобразовать "const wchar_t [20]" в "TCHAR *" Ещё не очень разбираюсь в Венгерской нотации и обозначениях при программировании на Windows, поэтому требуется помощь: "Что исправить, чтобы задумка автора кода работала?". Сам код ниже:

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
#include <conio.h>
#include <iostream>
using namespace std;
BOOL PrintMsg(HANDLE hOut, LPCTSTR pMsg);
BOOL PrintStrings(HANDLE hOut, ...);
int main(char argc, char ** _targv) {
    setlocale(LC_ALL, "");
    int k;
    HANDLE hStdOut;
    hStdOut = CreateFile(_T("CONOUT$"), GENERIC_WRITE, 0, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    SetConsoleMode(hStdOut, ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT);
    TCHAR * pr = _T("Введите множитель: ");
    PrintMsg(hStdOut, pr);
    cin >> k;
    PrintMsg(hStdOut, CharUpper(_T("Таблица умножения:\n")));
    TCHAR str1[3]; _itot(k, str1, 10); str1[2] = 0;
    for (int i = 0; i <= 10; i++) {
        TCHAR str2[3]; _itot(i, str2, 10); str2[2] = 0;
        int d = k * i;
        TCHAR str3[3]; _itot(d, str3, 10); str3[2] = 0;
        TCHAR *st = new TCHAR[25];
        for (int j = 0; j < 25; j++) {
            st[i] = _T("\0");
            st = wcscat(st, str2);
            st = wcscat(st, _T("*"));
            st = wcscat(st, str1);
            st = wcscat(st, _T("="));
            st = wcscat(st, str3);
            st = wcscat(st, _T("\n"));
            PrintMsg(hStdOut, st);
        }
    }
    getch();
    system("pause>nul");
    return 0;
}
Answer 1

На самом деле с того времени поменяло совсем не много. А проблема тут очевидно в использовании T макросов вместо использования wchar_t напрямую. Например

 hStdOut = CreateFile(_T("CONOUT$"),

должно быть

 hStdOut = ::CreateFileW(L"CONOUT$",

и т.д.

Answer 2

Погуглив, исправил код следующим образом: #define _CRT_SECURE_NO_WARNINGS - для совместимости с старыми "небезопасными ф-ями". Для возможности изменения строки нужно писать не TCHAR * pr = _T("Введите множитель: ");, а TCHAR pr[] = _T("Введите множитель: "); (суть в [] - теперь можно инициализировать литералом). Также, вместо st[i] = _T("\0"); st[i] = _T('\0'); (символ всё-таки). Новый код:

#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <tchar.h>
#include <conio.h>
#include <iostream>
using namespace std;
BOOL PrintMsg(HANDLE hOut, LPCTSTR pMsg);
BOOL PrintStrings(HANDLE hOut, ...);
int main(char argc, char ** _targv) {
    setlocale(LC_ALL, "");
    int k;
    HANDLE hStdOut;
    hStdOut = CreateFile(_T("CONOUT$"), GENERIC_WRITE, 0, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    SetConsoleMode(hStdOut, ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT);
    TCHAR pr[] = _T("Введите множитель: ");
    PrintMsg(hStdOut, pr);
    cin >> k;
    TCHAR pr2[] = _T("Таблица умножения:\n");
    PrintMsg(hStdOut, CharUpper(pr2));
    TCHAR str1[3]; _itot(k, str1, 10); str1[2] = 0;
    for (int i = 0; i <= 10; i++) {
        TCHAR str2[3]; _itot(i, str2, 10); str2[2] = 0;
        int d = k * i;
        TCHAR str3[3]; _itot(d, str3, 10); str3[2] = 0;
        TCHAR *st = new TCHAR[25];
        for (int j = 0; j < 25; j++) {
            st[i] = _T('\0');
            st = wcscat(st, str2);
            st = wcscat(st, _T("*"));
            st = wcscat(st, str1);
            st = wcscat(st, _T("="));
            st = wcscat(st, str3);
            st = wcscat(st, _T("\n"));
            PrintMsg(hStdOut, st);
        }
    }
    _getch();
    system("pause>nul");
    return 0;
}

В общем, почти все проблемы решены, осталось лишь решить вопрос с новой ошибкой:

Ошибка LNK2019 ссылка на неразрешенный внешний символ "int __cdecl PrintMsg(void *,wchar_t const *)" (?PrintMsg@@YAHPAXPB_W@Z) в функции _main

Не подскажите, что тут-то не так?

РЕШЕНО

Забыл про следующий листинг, где описание ф-ии PrintMsg:

#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <tchar.h>
#include <conio.h>
#include <iostream>
using namespace std;
BOOL PrintStrings(HANDLE hOut, ...) {
    DWORD MsgLen, Count;
    LPCTSTR pMsg;
    va_list pMsgList;
    va_start(pMsgList, hOut);
    while ((pMsg = va_arg(pMsgList, LPCTSTR)) != NULL) {
        MsgLen = lstrlen(pMsg);
        if (!WriteConsole(hOut, pMsg, MsgLen, &Count, NULL)) return FALSE;
    }
    return TRUE;
}
BOOL PrintMsg(HANDLE hOut, LPCTSTR pMsg) {
    return PrintStrings(hOut, pMsg, NULL);
}
int main(char argc, char ** _targv) {
    setlocale(LC_ALL, "");
    int k;
    HANDLE hStdOut;
    hStdOut = CreateFile(_T("CONOUT$"), GENERIC_WRITE, 0, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    SetConsoleMode(hStdOut, ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT);
    TCHAR pr[] = _T("Введите множитель: ");
    PrintMsg(hStdOut, pr);
    cin >> k;
    TCHAR pr2[] = _T("Таблица умножения:\n");
    PrintMsg(hStdOut, CharUpper(pr2));
    TCHAR str1[3]; _itot(k, str1, 10); str1[2] = 0;
    for (int i = 0; i <= 10; i++) {
        TCHAR str2[3]; _itot(i, str2, 10); str2[2] = 0;
        int d = k * i;
        TCHAR str3[3]; _itot(d, str3, 10); str3[2] = 0;
        TCHAR *st = new TCHAR[25];
        for (int j = 0; j < 25; j++)
            st[j] = _T('\0');
        st = wcscat(st, str2);
        st = wcscat(st, _T("*"));
        st = wcscat(st, str1);
        st = wcscat(st, _T("="));
        st = wcscat(st, str3);
        st = wcscat(st, _T("\n"));
        PrintMsg(hStdOut, st);
    }
    _getch();
    system("pause>nul");
    return 0;
}
READ ALSO
Проверка слов строки на наличие буквы, на которую кончается и начинается

Проверка слов строки на наличие буквы, на которую кончается и начинается

Дана строка, состоящая из символов латинского алфавита, разделенных пробелами (одним или несколькими)Определить количество слов, которые...

102
Label с HyperLink

Label с HyperLink

У меня есть QLabel, его размер 400x400 и в тексте прописано:

110
C++ Вытащить из Char цифры, написанные через пробел

C++ Вытащить из Char цифры, написанные через пробел

есть char b[50] = "11 2 6" или он может быть записан char b[50] = "1 23 6"

119