Как преобразовать std::wstring в LPCTSTR на С++?

У меня есть значение ключа реестра Windows в формате wstring. Теперь я хочу передать его этому коду (первый аргумент — путь к javaw.exe):

std::wstring somePath(L"....\\bin\\javaw.exe");

    if (!CreateProcess("C:\\Program Files\\Java\\jre7\\bin\\javaw.exe", <--- here should be LPCTSTR, but I have a somePath in wstring format..
            cmdline, // Command line.
            NULL, // Process handle not inheritable.
            NULL, // Thread handle not inheritable.
            0, // Set handle inheritance to FALSE.
            CREATE_NO_WINDOW, // ON VISTA/WIN7, THIS CREATES NO WINDOW
            NULL, // Use parent's environment block.
            NULL, // Use parent's starting directory.
            &si, // Pointer to STARTUPINFO structure.
            &pi)) // Pointer to PROCESS_INFORMATION structure.
    {
        printf("CreateProcess failed\n");
        return 0;
    }

Как я могу это сделать?


person Ernestas Gruodis    schedule 23.03.2014    source источник


Ответы (4)


Просто используйте функцию c_str std::w/string.

Глянь сюда:

http://www.cplusplus.com/reference/string/string/c_str/

std::wstring somePath(L"....\\bin\\javaw.exe");

    if (!CreateProcess(somePath.c_str(),
            cmdline, // Command line.
            NULL, // Process handle not inheritable.
            NULL, // Thread handle not inheritable.
            0, // Set handle inheritance to FALSE.
            CREATE_NO_WINDOW, // ON VISTA/WIN7, THIS CREATES NO WINDOW
            NULL, // Use parent's environment block.
            NULL, // Use parent's starting directory.
            &si, // Pointer to STARTUPINFO structure.
            &pi)) // Pointer to PROCESS_INFORMATION structure.
    {
        printf("CreateProcess failed\n");
        return 0;
    }
person paulm    schedule 23.03.2014
comment
Это не работает: невозможно преобразовать «const wchar_t *» в «LPCSTR {он же const char *}» для аргумента «1» в «BOOL CreateProcessA (LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, PVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION)' - person Ernestas Gruodis; 23.03.2014
comment
Затем используйте std::string или вызовите CreateProcessW вместо CreateProcessA. - person paulm; 23.03.2014
comment
Если LPCTSTR равно const char*, то нет причин использовать std::wstring. И наоборот, если вы считаете, что должны использовать std::wstring, установите флаг UNICODE в настройках проекта. - person Mooing Duck; 23.03.2014

LPCTSTR — старая реликвия. Это гибридный typedef, который либо определяет char*, если вы используете многобайтовые строки, либо wchar_t*, если вы используете Unicode. В Visual Studio это можно изменить в общих настройках проекта в разделе «Набор символов».

Если вы используете Юникод, то:

std::wstring somePath(L"....\\bin\\javaw.exe");
LPCTSTR str = somePath.c_str();                 // i.e. std::wstring to wchar_t*

Если вы используете мультибайт, используйте этот помощник:

// wide char to multi byte:
std::string ws2s(const std::wstring& wstr)
{
    int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), 0, 0, 0, 0); 
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), int(wstr.length() + 1), &strTo[0], size_needed, 0, 0); 
    return strTo;
}

то есть от std::wstring до std::string, которые будут содержать многобайтовую строку, а затем до char*:

LPCTSTR str = ws2s(somePath).c_str();
person LihO    schedule 23.03.2014
comment
@ErnestasGruodis: Пожалуйста. Если вы работаете с Unicode, ››ЗДЕСЬ‹‹ вы найдете помощника для преобразования многобайтового обратно в std::wstring слишком. - person LihO; 23.03.2014
comment
Беспорядок TCHAR — это пережиток перехода WinNT, но нет гарантии, что std::string будет содержать многобайтовые строки, а std::wstring не использует кодировку фиксированной длины. Было бы неплохо, если бы Microsoft полностью поддержала использование UTF-8 (многобайтовая кодировка), но вместо этого они намерены использовать UTF-16 (многобайтовую кодировку). - person Deduplicator; 23.03.2014

В конце концов решил использовать CreateProcessW, как упомянул Паулм, с небольшими исправлениями - значения должны быть приведены (иначе я получаю ошибку):

STARTUPINFOW si;
    memset(&si, 0, sizeof (STARTUPINFOW));
    si.cb = sizeof (STARTUPINFOW);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = FALSE;

    PROCESS_INFORMATION pi;
    memset(&pi, 0, sizeof (PROCESS_INFORMATION));

    std::wstring cmdline(L" -jar install.jar");

    if (!CreateProcessW((LPCWSTR)strKeyValue.c_str(),
            (LPWSTR)cmdline.c_str(), // Command line.
            NULL, // Process handle not inheritable.
            NULL, // Thread handle not inheritable.
            0, // Set handle inheritance to FALSE.
            CREATE_NO_WINDOW, // ON VISTA/WIN7, THIS CREATES NO WINDOW
            NULL, // Use parent's environment block.
            NULL, // Use parent's starting directory.
            &si, // Pointer to STARTUPINFO structure.
            &pi)) // Pointer to PROCESS_INFORMATION structure.
    {
        printf("CreateProcess failed\n");
        return 0;
    }
person Ernestas Gruodis    schedule 23.03.2014
comment
Я считаю, что CreateProcess() может писать в командную строку, так что это фактически вызывает UB. - person paulm; 17.09.2014

Самый безопасный способ взаимодействия из классов stdlib с TCHARs — использовать std::basic_string<TCHAR> и окружать необработанные строки макросом TEXT() (поскольку TCHAR может быть узким и широким в зависимости от настроек проекта).

std::basic_string<TCHAR> somePath(TEXT("....\\bin\\javaw.exe"));

Поскольку вы не выиграете соревнования по стилю, делая это ... другой правильный метод - явно использовать узкую или широкую версию функции WinAPI. Например. в этом конкретном случае:

  • с std::string используйте CreateProcessA (который использует LPCSTR, который является определением типа char*)
  • с std::u16string или std::wstring используйте CreateProcessW (который использует LPCWSTR, который является typedef wchar_t*, который является 16-битным в Windows)

В С++ 17 вы можете сделать:

std::filesystem::path app = "my/path/myprogram.exe";
std::string commandcall = app.filename.string() + " -myAwesomeParams";
// define si, pi
CreateProcessA(
    const_cast<LPCSTR>(app.string().c_str()),
    const_cast<LPSTR>(commandcall.c_str()),
    nullptr, nullptr, false, CREATE_DEFAULT_ERROR_MODE, nullptr, nullptr,
    &si, &pi)
person Roi Danton    schedule 25.01.2018