Использовать TCHAR в ostringstream

Хорошо, я на самом деле не человек C++, и это, вероятно, будет отвергнуто до проклятия, поскольку я просто читаю код и делаю предположения, основываясь на других языках, которые я знаю (плохо я знаю, но я просто хочу скомпилировать одно решение с небольшое изменение)

...

BOOL uploadFile(HWND hwnd, LPCTSTR fileName)
{
    const TCHAR* UPLOAD_SERVER  = _T("myhostname.com"); //not my real hostname, just for this question
    const TCHAR* UPLOAD_PATH    = _T("/upload.php"); 
    const TCHAR* CONFIG_FILE    = _T("config.ini");
    const TCHAR* API_KEY = _T("key");

    TCHAR szUploadServer[MAX_PATH];
    TCHAR szUploadPath[MAX_PATH];
    TCHAR szAPI[MAX_PATH];
    TCHAR szWD[MAX_PATH];

    const char*  sBoundary = "----BOUNDARYBOUNDARY----";        // boundary
    const char   sCrLf[]   = { 0xd, 0xa, 0x0 };                 // ‰üs(CR+LF)
    const TCHAR* szHeader  = 
        _T("Content-type: multipart/form-data; boundary=----BOUNDARYBOUNDARY----");

    _tgetcwd(szWD, sizeof(szWD) / sizeof(TCHAR));
    _tcsncat(szWD, _T("\\"), 1);
    _tcsncat(szWD, CONFIG_FILE, _tcslen(CONFIG_FILE));

    GetPrivateProfileString(_T("Configuration"), _T("SERVER"), UPLOAD_SERVER, szUploadServer, sizeof(szUploadServer) / sizeof(TCHAR), szWD);
    GetPrivateProfileString(_T("Configuration"), _T("PATH"), UPLOAD_PATH, szUploadPath, sizeof(szUploadPath) / sizeof(TCHAR), szWD);
    GetPrivateProfileString(_T("Configuration"), _T("API"), API_KEY, szAPI, sizeof(szAPI) / sizeof(TCHAR), szWD);
    std::ostringstream  buf;

    // -- "api" part
    buf << "--";
    buf << sBoundary;
    buf << sCrLf;
    buf << "content-disposition: form-data; name=\"api\"";
    buf << sCrLf;
    buf << sCrLf;
    buf << szAPI;
    buf << sCrLf;
    // -- "imagedata" part
    buf << "--";
    buf << sBoundary;
    buf << sCrLf;
    buf << "content-disposition: form-data; name=\"imagedata\"";
    buf << sCrLf;
    //buf << "Content-type: image/png"; // ˆê‰ž
    //buf << sCrLf;
    buf << sCrLf;

    // –{•¶: PNG ƒtƒ@ƒCƒ‹‚ð“Ç‚Ýž‚Þ
    std::ifstream png;
    png.open(fileName, std::ios::binary);
    if (png.fail()) {
        MessageBox(hwnd, _T("PNG open failed"), szTitle, MB_ICONERROR | MB_OK);
        png.close();
        return FALSE;
    }
    buf << png.rdbuf();     // read all & append to buffer
    png.close();

    // ÅŒã
    buf << sCrLf;
    buf << "--";
    buf << sBoundary;
    buf << "--";
    buf << sCrLf;

    // ƒƒbƒZ[ƒWŠ®¬
    std::string oMsg(buf.str());

...много строк спустя...

HttpSendRequest(hRequest,
                szHeader,
                lstrlen(szHeader),
                (LPVOID)oMsg.c_str(),
                (DWORD) oMsg.length())

Итак, как видите, программа читает ini-файл, записывает API-ключ в szAPI, после чего мне нужно использовать его в ostringstream (buf). Когда я смотрю на переменные POST в PHP, он дает мне 8-значный шестнадцатеричный код «0019EEE0», когда я хочу, чтобы он давал 32-символьную буквенно-цифровую строку в файле ini. Я посмотрел, как преобразовать tchar в строку, но у меня ничего не получилось. когда я положил

#ifndef UNICODE  
  typedef std::string szAPI; 
#else
  typedef std::wstring szAPI; 
#endif

в заголовочном файле ничего не происходит, и когда я делаю это правильно, когда переменная должна преобразовываться в строку, это ошибка (символ не может быть перегружен с помощью typedef)

Я бы использовал TCHAR для создания заголовков, но я бы не знал, как работать с кодом, чтобы поместить изображение в заголовки прямо под заголовком API.

Так что я немного в растерянности, пытаясь сделать эту работу. Мне нужно, чтобы ключ API находился в файле ini, чтобы я мог создать zip-архив на php со сгенерированным файлом ini и exe, а затем отправить его, чтобы я мог отслеживать, кто что загружает на мой сервер.

Если у вас есть идеи, спасибо.


person Alice    schedule 26.10.2016    source источник
comment
Целью TCHAR было сделать возможным создание программы для Windows 9x, чтобы она работала в Windows 9x для ограниченного локального набора символов. Это уродливое устройство, основанное на макросах, устарело в 2000 году с появлением Layer for Unicode. Затем, несколько лет спустя, Windows 9x больше не существовало. Вы уверены, что ориентируетесь на Windows 9x и что у вас есть веская причина не использовать слой для Unicode? Если нет, то с какой стати вы используете TCHAR?   -  person Cheers and hth. - Alf    schedule 26.10.2016
comment
В современной Windows просто используйте широкие символы (строки и функции на основе wchar_t) и покончите с этим.   -  person Cheers and hth. - Alf    schedule 26.10.2016
comment
Не используйте TCHAR ни с чем, кроме оболочек Windows API. Он предназначен для перехода между кодировкой символов ANSI и широкими символами. Что касается C stdlib, TCHAR не существует. Решите, какую кодировку символов использует ваше программное обеспечение, и используйте соответствующие функции стандартной библиотеки.   -  person Andon M. Coleman    schedule 26.10.2016
comment
В этом случае я почти думаю, что все было бы проще, если бы вы везде использовали wchar_t, а затем использовали HttpSendRequestW. Он будет обрабатывать любое необходимое преобразование в кодировку символов ANSI.   -  person Andon M. Coleman    schedule 26.10.2016
comment
@Cheersandhth.-Alf Я бы хотел, чтобы они вернулись к 8-битным символам, на этот раз только UTF-8.   -  person Mark Ransom    schedule 26.10.2016
comment
@MarkRansom Вы знаете, что они действительно сделали это сейчас - загвоздка в том, что вам нужно снова использовать символы старого стиля! docs.microsoft.com/en- мы/windows/uwp/design/globalizing/   -  person fabspro    schedule 20.08.2020
comment
У @fabspro раньше были проблемы с таким подходом. Я предполагаю, что они должны были исправить это, чтобы заставить WSL полностью работать. Это все еще больше работы, чем должно быть.   -  person Mark Ransom    schedule 20.08.2020
comment
@MarkRansom Да, это не совсем /гладко/... но я думаю, что на данный момент это лучше, чем ничего   -  person fabspro    schedule 21.08.2020


Ответы (3)


Как вы заметили, Windows использует UTF16, но интернет-функции ожидают UTF8.

char api[MAX_PATH];
wcstombs(api, szAPI, wcslen(szAPI) + 1);

Это преобразование не всегда будет работать.

В общем, вы должны использовать WideCharToMultiByte для преобразования UTF16 в UTF8.

Поскольку вы используете Visual Studio, для удобства вы можете использовать классы ATL.

#include <AtlStr.h>

...
CStringA sA = CW2A(szAPI, CP_UTF8);

sA теперь содержит данные UTF8. Используйте следующим образом:

my_ostringstream << sA.GetString();

or

HttpSendRequest(hRequest, szHeader, lstrlen(szHeader),
    (LPVOID)sA.GetString(), (DWORD)sA.GetLength());
person Barmak Shemirani    schedule 26.10.2016
comment
Спасибо тебе за это. Utf16, казалось, работал нормально во всех ситуациях, но я переключился на это, и он тоже работает. Мне нужно было указать имя файла изображения в заголовках для загрузки файла php для работы. - person Alice; 26.10.2016

Хорошо, это, вероятно, не лучший способ сделать что-то, но я пытался в течение нескольких часов, и он начал работать с

...

GetPrivateProfileString(_T("Configuration"), _T("SERVER"), UPLOAD_SERVER, szUploadServer, sizeof(szUploadServer) / sizeof(TCHAR), szWD);
GetPrivateProfileString(_T("Configuration"), _T("PATH"), UPLOAD_PATH, szUploadPath, sizeof(szUploadPath) / sizeof(TCHAR), szWD);
GetPrivateProfileString(_T("Configuration"), _T("API"), API_KEY, szAPI, sizeof(szAPI) / sizeof(TCHAR), szWD);
char api[MAX_PATH];
wcstombs(api, szAPI, wcslen(szAPI) + 1);

...
person Alice    schedule 26.10.2016

Поскольку вы собираетесь использовать свой код с Win32, самым чистым способом было бы использовать std::wostringstream вместо std::ostringstream, чтобы манипуляции со строками работали в пространстве UCS-16.

Другим обходным решением является использование функций ANSI Win32 для работы с многобайтовым пространством (например, GetPrivateProfileStringA()), если эти надоедливые проблемы i18n в функциях ANSI не являются проблемой в вашем приложении.

person nedsociety    schedule 26.10.2016