anastaciu
anastaciu

Reputation: 23802

Using std::copy with LPTSTR type argument

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)

Upvotes: 0

Views: 306

Answers (1)

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29985

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

Upvotes: 2

Related Questions