I need to create a variable to use in the CreateProcess:
CreateProcess(z7Cmdline, z7Arg, NULL, NULL, FALSE, NULL, NULL, NULL, &startInfo, &processInfo);
The variable z7Arg is a argument list for 7 -zip which contains a file name based on the current date ie: 2017-12-13.zip.
string buArg = "-o""c:\\moshe"" a " + buDir + buFileName + "c:\\moshe\\*.pdf";
I want to copy buArg into z7Arg as a LPTSTR to use in the CreateProcess routine
How do I go about it?
I am new at coding in C++, 30 years ago I programed in IBM Fortran & Assembly language for Grumman Aerospace, but have done little coding since then.
You have to do 2 things:
Convert const char* to const TCHAR*, where TCHAR may be either char or wchar_t depending on whether Unicode is enabled for your project.
Remove const because CreateProcess requires TCHAR*, not const TCHAR*. You can't just use const_cast, you need a writable buffer that you'll pass to CreateProcess.
For that you may use convenient string conversion macros from ATL or MFC. Use it the following way:
CA2T param(buArg.c_str());
CreateProcess(..., param, ...);
or just
CreateProcess(..., CA2T(buArg.c_str()), ...);
Read more about string conversion macros here.
If you don't have access to ATL or MFC in your project and you have Unicode enabled, you'll need to manually convert char* to wchar_t* using MultibyteToWideChar.
When compiling for Unicode, TCHAR-based APIs map to wchar_t-based functions, and when compiling for ANSI/MCBS, they map to char-based functions instead.
So, in your case, the TCHAR-based CreateProcess() macro maps to either CreateProcessA() taking char* strings, or CreateProcessW() taking wchar_t* strings.
std::string operates with char only, and std::wstring operates with wchar_t only.
So, the simplest solution to your issue is to just call CreateProcessA() directly, eg:
std::string z7Cmdline = ...;
std::string z7Arg = ...;
STARTUPINFOA si = {};
...
CreateProcessA(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);
If you want to call CreateProcessW(), use std::wstring instead:
std::wstring z7Cmdline = ;
std::wstring z7Arg = ...;
STARTUPINFOW si = {};
...
CreateProcessW(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);
In this latter case, if your input must be std:string, then you have to use a runtime conversion, via MultiByteToWideChar(), std::wstring_convert, etc.
Or, you could use std::basic_string<TCHAR> instead:
std::basic_string<TCHAR> z7Cmdline = ;
std::basic_string<TCHAR> z7Arg = ...;
STARTUPINFO si = {};
...
CreateProcess(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);
string buArg = "-o""c:\\moshe"" a " + buDir + buFileName + "c:\\moshe\\*.pdf";
LPTSTR lpt = new TCHAR[31];
lpt = (LPTSTR) buArg.c_str();
tested by MinGW 6.3.0
Related
I'm trying to combine 2 tchar.
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
But I get error error at appdatapath line. How can I combine 2 tchar? Thanks
Have a look at strcat and wcscat. You can't add char pointer with char array.
If you are on a windows machine, you can use _tcscat which will redirect to the right function to use depending on _UNICODE and _MBCS defines.
Might want to use the safe versions as well by appending _s to the function name.
As pointed in the comments, you can also use snprintf like so:
const size_t concatenated_size = 256;
char concatenated[concatenated_size];
snprintf(concatenated, concatenated_size, "C:\\Users\\%s\\AppData", username);
Since you have string literals before and after the runtime string, it is probably a better approach.
To answer the question in the title: you concatenate two TCHAR strings using the _tcscat function.
However, there are other issues in your code related to this: GetUserName expects a LPTSTR, i.e. a pointer to a buffer TCHAR characters. Furthermore, there's another TCHAR usage in
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
The issue with this is that the type to which TCHAR expands changes depending on whether _UNICODE is defined. In particular, if you set it, TCHAR (eventually) expands to wchar and hence GetUserName expects a wchar_t* but you pass a char*. Another issue is that you cannot concatenate C arrays using the + operator.
I suggest to stop worrying about TCHAR in the first place and always just compile with _UNICODE defined - and use wchar throughout your code. Also, since you're using C++, just use std::wstring:
wchar username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserNameW(username, &username_len);
std::wstring appdatapath = L"C:\\Users\\";
appdatapath += username;
appdatapath += L"\\AppData";
Last but not least: your entire code can probably be replaced with a call to the SHGetSpecialFolderPath function - pass CSIDL_APPDATA to it to get the "AppData" path.
#include <tchar.h>
const size_t stringSize= 20;
TCHAR value[stringSize] = { 0 };
_tcscat_s(value, stringSize, TEXT("appendMe"));
MSDN: _tcscat_s
Dealing with these insane strings and arrays is giving me a headache...
Here's my code so far
wchar_t mypath[MAX_PATH];
wchar_t temppath[MAX_PATH];
GetModuleFileName(0, mypath, MAX_PATH);
GetTempPath(MAX_PATH, temppath);
CreateDirectory(???, NULL);
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference? After I get the path for the TEMP directory, I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable. Can someone give me some tips on how to use these arrays. This is what makes C++ a pain. Why couldn't everyone just settle on one data type for strings. How is wchar_t even useful? It's so hard to use and manipulate.
Thanks guys!
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference?
LPCWSTR is a const version of LPWSTR:
From LPCWSTR:
typedef const wchar_t* LPCWSTR;
From LPWSTR:
typedef wchar_t* LPWSTR, *PWSTR;
I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable.
Use a std::wostringstream:
std::wostringstream wos;
wos << temppath << L"\\test";
std::wstring fullpath(wos.str());
or just a std::wstring (as suggested by chris in the comments):
std::wstring fullpath(std::wstring(temppath) + L"\\test");
to produce a concatenated version. Then use c_str() as the argument to CreateDirectory():
if (CreateDirectory(fullpath.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// Directory created or already existed.
}
else
{
// Failed to create directory.
}
Use PathCombine(), eg:
wchar_t temppath[MAX_PATH+1] = {0};
GetTempPath(MAX_PATH, temppath);
wchar_t mypath[MAX_PATH+8] = {0};
PathCombineW(mypath, temppath, L"test");
CreateDirectoryW(mypath, NULL);
I am trying to convert a program for multibyte character to Unicode.
I have gone through the program and preceded the string literals with L so they look like L"string".
This has worked but I am now left with a C style string that won't conform. I have tried the L and putting it in TEXT() but the L gets added to the variable name -- not the string -- if I use TEXT().
I have tried making it a TCHAR but then it complains that it cannot convert a TCHAR to a char *.
What options am I left with?
I know C and C++ are different. It is an old in-house C library that has been used in C++ projects for several years now.
The std::mbstowcs function is what you are looking for:
char text[] = "something";
wchar_t wtext[20];
mbstowcs(wtext, text, strlen(text)+1);//Plus null
LPWSTR ptr = wtext;
for strings,
string text = "something";
wchar_t wtext[20];
mbstowcs(wtext, text.c_str(), text.length());//includes null
LPWSTR ptr = wtext;
--> ED: The "L" prefix only works on string literals, not variables. <--
The clean way to use mbstowcs is to call it twice to find the length of the result:
const char * cs = <your input char*>
size_t wn = mbsrtowcs(NULL, &cs, 0, NULL);
// error if wn == size_t(-1)
wchar_t * buf = new wchar_t[wn + 1](); // value-initialize to 0 (see below)
wn = mbsrtowcs(buf, &cs, wn + 1, NULL);
// error if wn == size_t(-1)
assert(cs == NULL); // successful conversion
// result now in buf, return e.g. as std::wstring
delete[] buf;
Don't forget to call setlocale(LC_CTYPE, ""); at the beginning of your program!
The advantage over the Windows MultiByteToWideChar is that this is entirely standard C, although on Windows you might prefer the Windows API function anyway.
I usually wrap this method, along with the opposite one, in two conversion functions string->wstring and wstring->string. If you also add trivial overloads string->string and wstring->wstring, you can easily write code that compiles with the Winapi TCHAR typedef in any setting.
[Edit:] I added zero-initialization to buf, in case you plan to use the C array directly. I would usually return the result as std::wstring(buf, wn), though, but do beware if you plan on using C-style null-terminated arrays.[/]
In a multithreaded environment you should pass a thread-local conversion state to the function as its final (currently invisible) parameter.
Here is a small rant of mine on this topic.
I'm using the following in VC++ and it works like a charm for me.
CA2CT(charText)
This version, using the Windows API function MultiByteToWideChar(), handles the memory allocation for arbitrarily long input strings.
int lenA = lstrlenA(input);
int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
if (lenW>0)
{
output = new wchar_t[lenW];
::MultiByteToWideChar(CP_ACP, 0, input, lenA, output, lenW);
}
You may use CString, CStringA, CStringW to do automatic conversions and convert between these types. Further, you may also use CStrBuf, CStrBufA, CStrBufW to get RAII pattern modifiable strings
Can anyone help in converting string to LPWSTR
string command=obj.getInstallationPath()+"<some string appended>"
Now i wat to pass it as parameter for CreateProcessW(xx,command,x...)
But createProcessW() accepts only LPWSTR so i need to cast string to LPWSTR
Thanks in Advance
If you have an ANSI string, then have you considered calling CreateProcessA instead? If there is a specific reason you need to call CreateProcessW then you will need to convert the string. Try the MultiByteToWideChar function.
Another way:
mbstowcs_s
use with string.c_str(), you can find example here or here
OR
USES_CONVERSION_EX;
std::string text = "text";
LPWSTR lp = A2W_EX(text.c_str(), text.length());
OR
{
std::string str = "String to LPWSTR";
BSTR b = _com_util::ConvertStringToBSTR(str.c_str());
LPWSTR lp = b;
Use lp before SysFreeString...
SysFreeString(b);
}
The easiest way to convert an ansi string to a wide (unicode) string is to use the string conversion macros.
To use these, put USES_CONVERSION at the top of your function, then you can use macros like A2W() to perform the conversion very easily.
eg.
char* sz = "tadaaa";
CreateProcessW(A2W(sz), ...);
The macros allocate space on the stack, perform the conversion and return the converted string.
Also, you might want to consider using TCHAR throughout... If I'm correct, the idea would be something like this:
typedef std::basic_string<TCHAR> tstring
// Make any methods you control return tstring values. Thus, you could write:
tstring command = obj.getInstallationPath();
CreateProcess(x, command.c_str(), ...);
Note that we use CreateProcess instead of CreateProcessW or CreateProcessA. The idea is that if UNICODE is defined, then TCHAR is typedefed to WCHAR and CreateProcess is #defined to be CreateProcessW, which accepts a LPWSTR; but if UNICODE is not defined, then TCHAR becomes char, and CreateProcess becomes CreateProcessA, which accepts a LPSTR. But I might not have the details right here... this stuff seems somewhat needlessly complicated :(.
Here is another option. I've been using this function to do the conversion.
//C++ string to WINDOWS UNICODE string
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
And wrap your string like this.
s2ws( volume.c_str())
This is my procedure:
bool Open(std::string filename)
{
...
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
...
}
Error:'CreateFileW' : cannot convert parameter 1 from 'const char *' to 'LPCWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Where is the problem?
A std::string consists of an array of char's, and so the c_str function returns a const char*.
A LPCWSTR is a Long Pointer to a Constant Wide String, or in other words, const wchar_t*.
So you have a couple of options. Either get the filename as a wide string (std::wstring), or specify that you want the non-wide version of CreateFile instead. That can be done either by calling CreateFileA or disabling UNICODE in your project settings.
CreateFile is a macro which either resolves to CreateFileA (the char version) or CreateFileW (the wide char version) depending on whether or not unicode is enabled.
You have specified std::string, whose character type is char. And the code you're using CreateFile() in must be being compiled under the definition of the pre-processor symbol UNICODE, since that selects the actual underlying function CreateFileW().
Either get rid of the UNICODE definition, or explicitly use CreateFileA().
It looks like you are compiling with Unicode support turned on. You may want to turn it off, or if not use std::wstring instead of std::string.
As others have suggested, you could call CreateFileA directly, but I'd strongly suggest you not do this - you will end up with an unmaintanable collection of Unicode and non-Unicode function calls.
The problem is you are trying to pass char* to a function requiring wchar_t*
You could write a function to convert string into wstring:
wstring Widen( const string& str );
Then you could call CreateFile like this:
HANDLE hFile = CreateFile( Widen(filename).c_str(), etc. );
Another technique I've seen used is to conditionally define tstring to be either string or wstring depending on the Unicode setting, and use tstring everywhere in your code.
bool Open(tstring filename)
{
...
HANDLE hFile = CreateFile( filename.c_str(), etc. );
...
}
It's a bit of a thorny issue I'm afraid and the best solution for you is something only you can decide. However, I'd agree with Neil and steer clear of directly calling CreateFileA as that will leave you in a mess eventually.