David Knag David Knag - 1 month ago 17
C++ Question

Use TCHAR in ostringstream

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.

Answer

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