I'm using Win32 API and I need to copy arguments captured with argv
, the problem is, the code has to be compliant with both ASCII and UNICODE and that's a problem with C/C++ in Windows.
Beyond that I must use, when possible, C++ instead of C, so I'm using std::copy
to copy arguments of type LPTSTR
(or TCHAR*
), I could use _tcscpy_s
but as I said, it must be C++ whenever possible.
Note: I can't use std::wstring
or std::string
because these must be passed to CreateProcess()
and the argument must be of type TCHAR*
so it can convert it to LPTSTR
or LPWSTR
deppending on the encoding.
Here is a console executable minimal reproducible example:
#include <windows.h>
#include <tchar.h>
#include <corecrt_io.h>
#include <fcntl.h>
#include <iostream>
#ifdef UNICODE
#define tcout wcout
#define tcin wcin
#else
#define tcout cout
#define tcin cin
#endif
int _tmain(int argc, LPTSTR argv[])
{
using std::copy;
using std::tcout;
using std::tcin;
constexpr int size = 1024;
TCHAR fileName[size];
#ifdef UNICODE
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
#endif
if (argc > 1)
{
copy(&argv[1][0], &argv[1][1023], fileName); //is this copy ok?
}
else
{
tcout << "Program name: ";
tcin >> fileName;
}
tcout << fileName;
}
My question is:
Is the code safe, and/or is there a better alternative (preferably with C++) to this?
(Not only the copy part, but whole idea)
You should use std::basic_string
:
using tstring = std::basic_string<TCHAR>;
It handles all the copying itself. Whenever you need to talk to some C API, use str.c_str()
for a const pointer and str.data()
(after C++17) or &str[0]
(pre C++17) for a non-const pointer.
#include <windows.h>
#include <tchar.h>
#include <corecrt_io.h>
#include <fcntl.h>
#include <iostream>
#include <string>
using tstring = std::basic_string<TCHAR>;
#ifdef UNICODE
static auto& tcout = std::wcout;
static auto& tcin = std::wcin;
#else
static auto& tcout = std::cout;
static auto& tcin = std::cin;
#endif
int _tmain(int argc, LPTSTR argv[])
{
tstring fileName;
if (argc > 1)
{
fileName = argv[1];
}
else
{
tcout << _T("Program name: ");
tcin >> fileName;
}
tcout << fileName;
return 0;
}