1

Okay, I'm not really a C++ person, and this will probably be downvoted to damnation as I am just reading the code and making guesses based of the other languages I know (bad I know, but I just want to compile one solution with a small change)

...

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

... many lines later ...

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

So, as you can see, the program is reading an ini file, writing the API key to szAPI, and then I need to use it in the ostringstream (buf). When I look at the POST variables in PHP, it gives me an 8 digit hex "0019EEE0" when I'd like it to be giving a 32 character long alphanumeric string in the ini file. I looked in how to convert tchar to string, but nothing really worked for me. When i put

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

in the header file, nothing happens, and when i put it right when the variable should convert to string, it errors (symbol cannot be overloaded with a typedef)

I would use TCHAR to make the headers, but I wouldn't know how to make work with the code to put the image in the headers right below the api header.

So I'm sort of at a loss with making this work. I need the API key to be in the ini file so I can build a zip in php with a generated ini file and an exe, then send it out so I can track who is uploading what to my server.

If you've got any ideas, thanks.

Alice
  • 422
  • 1
  • 9
  • 28
  • The purpose of `TCHAR` was to make it possible to build a program for Windows 9x, so that it would work in Windows 9x for a limited local character set. This ugly macro based device was obsoleted in the year 2000 by the introduction of Layer for Unicode. Then some years later, Windows 9x was no more. Are you **sure** that you're targeting Windows 9x, and that you have a good reason to not use the Layer for Unicode? If not, why on Earth are you using `TCHAR`? – Cheers and hth. - Alf Oct 26 '16 at 01:09
  • In modern Windows just use wide chars (`wchar_t` based strings and functions) and be done with it. – Cheers and hth. - Alf Oct 26 '16 at 01:12
  • Don't use TCHAR with anything but Windows API wrappers. It's designed to transition between ANSI character encoding and wide-characters. As far as the C stdlib is concerned, TCHAR doesn't exist. Decide which character encoding your software uses and use the appropriate standard library functions. – Andon M. Coleman Oct 26 '16 at 01:27
  • In this case, I almost think everything would be simpler if you used `wchar_t` everywhere and then used `HttpSendRequestW`. It will handle any conversion to ANSI character encoding necessary. – Andon M. Coleman Oct 26 '16 at 01:43
  • 1
    @Cheersandhth.-Alf I kind of wish they'd transition back to 8-bit chars, only UTF-8 this time. – Mark Ransom Oct 26 '16 at 01:54
  • @MarkRansom You know they actually have done that now - the catch being that you have to use old-style CHARs again! https://learn.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page – fabspro Aug 20 '20 at 07:45
  • @fabspro there used to be problems with that approach. I suppose they had to fix it in order to get WSL fully working. It's still more work than it should be. – Mark Ransom Aug 20 '20 at 15:37
  • @MarkRansom Yeah it isn't exactly /smooth/... but I guess it's something better than nothing at this point – fabspro Aug 21 '20 at 00:29

3 Answers3

1

As you have noted, Windows use UTF16, but internet functions expect UTF8.

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

This conversion will not always work.

In general, you have to use WideCharToMultiByte to convert UTF16 to UTF8.

Since you are using Visual Studio, you can use ATL classes for convenience.

#include <AtlStr.h>

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

sA now contains UTF8 data. Use as follows:

my_ostringstream << sA.GetString();

or

HttpSendRequest(hRequest, szHeader, lstrlen(szHeader),
    (LPVOID)sA.GetString(), (DWORD)sA.GetLength());
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • Thank you for this. The utf16 seemed to work fine in all situations, but I switched to this and it works too. I did need to give the imagedata a filename in the headers for php file upload to work. – Alice Oct 26 '16 at 06:01
0

Okay, this probably isn't the best way to do things, but I've been trying for hours and it started working with

...

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

...
Alice
  • 422
  • 1
  • 9
  • 28
0

Since you intend to use your code with Win32, the cleanest way would be to use std::wostringstream instead of std::ostringstream to make string manipulations work on UCS-16 space.

Another workaround is to use Win32 ANSI functions to work on multibyte space (e.g., GetPrivateProfileStringA()), if those pesky i18n problems in ANSI functions are non-issue in your application.

nedsociety
  • 88
  • 8