Convert const wchar_t* to LPWSTR - c++

I'm trying to convert a const wchar_t* to LPWSTR but I'm getting the error E0513.
I'm using Visual Studio with C++17.
Here is my code:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
LPWSTR* argv;
int argCount;
argv = CommandLineToArgvW(GetCommandLineW(), &argCount);
if (argv[1] == nullptr) argv[1] = L"2048"; <-- conversion error
}
How to fix this?

To answer your question:
You can use const_cast:
argv[1] = const_cast<LPWSTR>(L"2048");
Or a local wchar_t[] array:
wchar_t arg[] = L"2048";
argv[1] = arg;
However, CommandLineToArgvW() will never return any array elements set to nullptr to begin with. All array elements are null-terminated string pointers, so empty parameters would have to be specified as quoted strings ("") on the command-line in order to be parsed, and as such will be returned as 0-length string pointers in the array. So, you would need to check for that condition instead, eg:
if (argCount > 1 && *(argv[1]) == L'\0')

For Visual Studio:
C/C++ => Language => Compatibility Mode => Set to NO.
This will allow to do such casting.

Related

Cannot start process from different directory

I'm trying to write a program in C++ that launches an executable. When I try to run the program, nothing happens. But when I try to run the program on the same directory and drive the exe is in, it does work.
Here's the code:
else if (result1 == 0) {
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
CreateProcess(L"D:\\Games\\Origin Games\\Command and Conquer Red Alert\\RA95Launcher.exe", NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
When I do it like this:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
CreateProcess(L"D:\\Games\\Origin Games\\Command and Conquer Red Alert\\RA95Launcher.exe", NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, "D:\\Games\\Origin Games\\Command and Conquer Red Alert\\", &si, &pi);
I get the error:
argument of type "const char *" is incompatible with parameter of type "LPCWSTR"
Any help would be appreciated.
Most likely you should set the lpCurrentDirectory parameter to the directory the exe is in.
See: CreateProcess
It's often that executables like RA95Launcher.exe are depending on other files. Usually these are reffered to by a relative path from perspective of the Current Working Directory.
If you launch the process from within the directory the exe is in, your automatically in the correct Current Working Directory. If you have the launcher running at a different location, you'll need to specify it.
I get the error: argument of type "const char *" is incompatible with
parameter of type "LPCWSTR"
This means that you're trying to pass incompatible type to function. LPCWSTR is Windows.h typedef for const wchar_t*(a UTF-16 string), but CreateProcess requires ANSI string(LPCSTR). You can either call the appropriate function, in this case - CreateProcessW(W at the end of the function name means it takes UTF-16 strings as parameters) or make your string ANSI by removing L before it.

Command Line Argument Truncated by CreateprocessW

VS10, MBCS, Unicode preprocessor defs.
Having gone through Dr Google's casebook, the best help was here, but it doesn't quite address this particular problem. Consider this code where thisexePath is the path to the executable:
cmdLineArg = (wchar_t *)calloc(BIGGERTHANMAXPATH, sizeof(wchar_t));
wcscpy_s (cmdLineArg, maxPathFolder, L"\\\\??\\C:\\My directory\\My directory\\");
CreateProcessW (thisexePath, cmdLineArg, NULL, NULL, FALSE, NULL, NULL, NULL, &lpStartupInfo, &lpProcessInfo)
When the program is called
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
wchar_t hrtext[256];
swprintf_s(hrtext, sizeof(hrtext), L"%ls", lpCmdLine);
//deal with possible buffer overflow later
MessageBoxW(NULL, hrtext, L"Display", MB_ICONINFORMATION);
}
hrtext only displays "My directory\My directory\" Something obvious missed here?
This is not correct:
wchar_t hrtext[256];
swprintf_s(hrtext, sizeof(hrtext), L"%ls", lpCmdLine);
The second parameter should denote the number of characters, not bytes.
MSDN link to swprintf_s
It should be this:
wchar_t hrtext[256];
swprintf_s(hrtext, sizeof(hrtext) / sizeof(wchar_t), L"%ls", lpCmdLine);
or simply:
wchar_t hrtext[256];
swprintf_s(hrtext, 256, L"%ls", lpCmdLine);

Appending Strings to lpCmdLine WinMain

Trying to create a loader for an executable, it fails to execute when the length of string supplied in the Parameters is more than some length. But the Parameters are completely read from the initialization file. It also crashes when the Parameters=Null.
typedef int (__cdecl *ExecMain_t)(HINSTANCE, HINSTANCE, LPSTR, int);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HMODULE Loader = LoadLibraryExA(".\\library.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
char* Parameters;
CIniFile iniReader(".\\Configure.ini");
Parameters = iniReader.IniReadValue("App", "Parameters");
char xCommand[MAX_PATH] = {0};
_snprintf_s(xCommand, _TRUNCATE, "-verify "); //parameter from exe
strcat_s(xCommand, _TRUNCATE, Parameters);
strcpy_s(lpCmdLine, _TRUNCATE, xCommand);
delete[] Parameters;
Parameters = NULL;
ExecMain_t procExecMain = (ExecMain_t)GetProcAddress(Loader,"ExecMain");
procExecMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
return 1;
}
Crash description:
Problem Event Name: APPCRASH
Application Name: exec.exe
Application Version: 0.0.0.0
Application Timestamp: 530df50a
Fault Module Name: KERNELBASE.dll
Fault Module Version: 6.2.9200.16384
EDIT: Trying to figure out why it crashes when the Parameter string length is increases.
Even crashes if I pass more characters along with "-verify " (passing parameter from exe)
EDIT2: Modified the code by replacing MAX_PATH by _TRUNCATE. Seems to work for some characters in the parameters but when exceeded, crashes.
Here are several problems:
char xCommand[MAX_PATH] = {0};
_snprintf_s(xCommand, _TRUNCATE, "-verify "); //parameter from exe
strcat_s(xCommand, _TRUNCATE, Parameters);
strcpy_s(lpCmdLine, _TRUNCATE, xCommand);
I think you should use strcpy_s instead of _snprintf_s, after all I don't see you printing any format in xCommand.
Then, the second parameter, _TRUNCATE should actually be MAX_PATH since the second parameter of this functions is the number of elements of the destination buffer.
But most important, the third line is completely wrong, because you're trying to write into the input buffer lpCmdLine and that will overwrite the memory beyond the buffer bounds. What you need is to copy the content of the original buffer into your new command buffer. Something like this (notice I wrote this code in the browser so it may contain errors):
char xCommand[MAX_PATH] = {0};
strcpy_s(xCommand, MAX_PATH, lpCmdLine); // copy the original command line
strcat_s(xCommand, MAX_PATH, " -verify "); // append
strcat_s(xCommand, MAX_PATH, Parameters); // append
and then pass this buffer to your ExecMain function:
procExecMain(hInstance, hPrevInstance, xCommand, nCmdShow);

C++ MessageBox character array

I am having difficulties using MessageBox function with variables
I have
int main(int argc, char* argv[])
{
char* filename = argv[0];
DWORD length = strlen(filename);
MessageBox(0, TEXT("filename text"), TEXT("length text"), 0); // Works
}
But I want to output variables filename and length as:
MessageBox(0, filename, length, 0); -- compiler error
Function MessageBox has syntax:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
I tried using
MessageBox(0, (LPCWSTR)filename, (LPCWSTR)length, 0);
but the output is in some kind of hieroglyphs.
The variable length is not a string, and only strings can be used. It doesn't help that you try to cast it to a char* as then the value of length will be taken as a pointer to the string which will cause undefined behavior.
For C++, you can use e.g. std::to_string to convert non-string values to strings, like
MessageBox(0, filename, std::to_string(length).c_str(), 0);
Note that you must use the c_str function to get a char*.
If you don't have std::to_string then you can use e.g. std::istringstream instead:
std::istringstream is;
is << length;
MessageBox(0, filename, is.str().c_str(), 0);
If you want a more old-style C solution, then there's snprintf (or _snprintf in Visual Studio):
char length_string[20];
_snprintf(length_string, sizeof(length_string), "%ld", length);
MessageBox(0, filename, length_string, 0);
With a C++ win32 project in VS2015 a char array displays in a MessageBox with this code. Include header atlstr.h
// open a file in read mode.
ifstream myInfile;
myInfile.open("C:\\Users\\Desktop\\CodeOnDesktop\\myTrialMessageBox.txt");
if (myInfile.fail())
{
MessageBox(NULL,
L"We have an error trying to open the file myTrialMessageBox.txt",
L"Opening a file.",
MB_ICONERROR);
}
char data[200];
// Read the data from the file and display it.
//infile >> data; // Only gets the first word.
myInfile.getline(data, 100);
//To use CString, include the atlstr.h header.
// Cast array called data to a CString to enable use as MessageBox parameter.
CString cdata = (CString)data;
// or CString cdata = CString(_T("A string"));
MessageBox(NULL,
cdata,
L"Opening a file.",
MB_ICONERROR);
// close the opened file.
myInfile.close();

C++: convert LPTSTR to char array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Convert lptstr to char*
I need to convert an LPTSTR p to CHAR ch[]. I am new to C++.
#include "stdafx.h"
#define _WIN32_IE 0x500
#include <shlobj.h>
#include <atlstr.h>
#include <iostream>
#include <Strsafe.h>
using namespace std;
int main(){
int a;
string res;
CString path;
char ch[MAX_PATH];
LPTSTR p = path.GetBuffer(MAX_PATH);
HRESULT hr = SHGetFolderPath(NULL,CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, p);
/* some operation with P and CH */
if(SUCCEEDED(hr))
{ /* succeeded */
cout << ch;
} /* succeeded */
else
{ /* failed */
cout << "error";
} /* failed */
cin >> a;
return 0;
}
Thanks in advance.
LPTSTR is a (non-const) TCHAR string. Depends if it is Unicode or not it appears. LPTSTR is char* if not Unicode, or w_char* if so.
If you are using non-Unicode strings LPTSTR is just a char*, otherwise do:
size_t size = wcstombs(NULL, p, 0);
char* CharStr = new char[size + 1];
wcstombs( CharStr, p, size + 1 );
Also, this link can help:
Convert lptstr to char*
LPTSTR means TCHAR* (expanding those Win32 acronyms typedefs can make it easier to understand them). TCHAR expands to char in ANSI/MBCS builds, and to wchar_t in Unicode builds (which should be the default in these days for better internationalization support).
This table summarizes the TCHAR expansions in ANSI/MBCS and Unicode builds:
| ANSI/MBCS | Unicode
--------+----------------+-----------------
TCHAR | char | wchar_t
LPTSTR | char* | wchar_t*
LPCTSTR | const char* | const wchar_t*
So, in ANSI/MBCS builds, LPTSTR expands to char*; in Unicode builds it expands to wchar_t*.
char ch[MAX_PATH] is an array of char's in both ANSI and Unicode builds.
If you want to convert from a TCHAR string (LPTSTR) to an ANSI/MBCS string (char-based), you can use ATL string conversion helpers, e.g.:
LPTSTR psz; // TCHAR* pointing to something valid
CT2A ch(psz); // convert from TCHAR string to char string
(Note also that in your original code you should call CString::ReleaseBuffer() which is the symmetric of CString::GetBuffer().)
Sample code follows:
// Include ATL headers to use string conversion helpers
#include <atlbase.h>
#include <atlconv.h>
...
LPTSTR psz = path.GetBuffer(MAX_PATH);
HRESULT hr = SHGetFolderPath(NULL,CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, psz);
path.ReleaseBuffer();
if (FAILED(hr))
{
// handle error
...
}
// Convert from TCHAR string (CString path) to char string.
CT2A ch(path);
// Use ch...
cout << static_cast<const char*>(ch) << endl;
Note also that the conversion from Unicode to ANSI can be lossy.
First, you defined char* ch[MAX_PATH] instead of char ch[MAX_PATH].
Regarding your question, LPTSTR (Long Pointer to TCHAR String) is equivalent to LPWSTR (which is w_char*) if it's unicode, or just LPSTR (char*) if it is not. You can use this link for reference about conversion in each case.
EDIT: To cut to the chase, here's some code:
if (sizeof(TCHAR) == sizeof(char)) // String is non-unicode
strcpy(ch, (char*)(p));
else // String is unicode
wcstombs(ch, p, MAX_PATH);
EDIT 2: In windows I would recommend using TCHAR instead of char. It will save you some headache.
EDIT 3: As a side note, if you want to prevent Visual Studio from flooding you with warnings about unsafe functions, you can add something like the following to the very beginning of your code:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif