How to convert TCHAR to const char? - c++

The most similar thing I found is conversion to char. I'm trying to convert TCHAR "path" to const char. Btw I use character set: "Not Set".
#include <stdlib.h>
// ... your defines
#define MAX_LEN 100
TCHAR *systemDrive = getenv("systemDrive");
TCHAR path[_MAX_PATH];
_tcscpy(path, systemDrive);
TCHAR c_wPath[MAX_LEN] = _T("Hello world!");//this is original
//TCHAR c_wPath[MAX_LEN] = path; "path" shows error
char c_szPath[MAX_LEN];
wcstombs(c_szPath, c_wPath, wcslen(c_wPath) + 1);

TCHAR is alias for different types depending of platform, defined macros, etc.
so, TCHAR can be alias for char(1 byte) or WCHAR(2 bytes).
further, WCHAR can be alias for wchar_t or unsigned short.
But, you made conversion using wcstombs which has signature like
size_t wcstombs(char *, const wchar_t *, size_t),
so you have
char* c_szPath
pointing to converted array of char,
now, if you need const char*, it is probably enough to write simply
const char * myPath = c_szPath, it is legal, and use myPath.
But maybe, you even don't need this, because char* can bind on argument of type
const char * if you need to pass it to function as argument.
When you say,
"path" shows error
that is because array type is not assignable.
I really hope this helps.

Related

Am I converting properly from "const char *" to "TCHAR*"?

I'm trying to pass a process name as a TCHAR to the following void:
void GetBaseAddressByName(DWORD pID, TCHAR *pN)
By doing it like this:
GetBaseAddressByName(aProcs[i], (TCHAR*)"Process.exe");
So my question is: is what I am doing correct? Because I have tried both TEXT("Process.exe") and _T("Process.exe") with my project's Character Set both on Multi-Bite and Unicode and it just tells me that
argument of type "const char*" is incompatible with parameter of type "TCHAR*"
The short answer is no. TCHAR maps to either char or wchar_t depending on your project's Unicode/Multi-byte setting. So, in general, a cast like that is either unnecessary or incorrect. The correct way, as you said, is to use either the TEXT or _T macro. The reason you're getting an error is that you're trying to pass a const character string to a function that expects a mutable character string. The safeset way to get around the error is to copy your constant string into a local TCHAR buffer and then pass that to GetBaseAddressByName.
It is better to have a TCHAR array first, then copy into it.
#include "atlstr.h"
char const * procName = "processName.exe";
TCHAR szName [128];
_tcscpy(szName, A2T(procName));
GetBaseAddressByName(aProcs[i], szName);
As suggested by #Remy Lebeau in the comments, procName can be defined as TCHAR const * procName = TEXT("processName.exe");.
(TCHAR*)"Process.exe" is not a valid type-cast. It will "work" when the project charset is set to ANSI/MBCS, but it will produce garbage if the charset is set to Unicode.
Using TEXT("Process.exe") is the correct way to make a string literal use TCHAR characters.
GetBaseAddressByName(aProcs[i], TEXT("Process.exe"));
However, you need to change your pN parameter to const TCHAR * (or LPCTSTR) instead:
void GetBaseAddressByName(DWORD pID, const TCHAR *pN);
void GetBaseAddressByName(DWORD pID, LPCTSTR pN);
A string literal is const data, and you cannot pass a pointer-to-const-data where a pointer-to-non-const-data is expected (without casting the const away with const_cast). That is why you were still getting errors when trying to use the TEXT()/_T() macros.
You need a L, like L"Process.exe". Unicode strings are specified with L"".
That said, there is no reason to use TCHAR. Use unicode all the time, if doing Windows work only.

start_info.lpDesktop is LPWSTR entity, but it says this is const wchat_t*?

I am a complete noob using C++, i just want to re-compile an exploit.
I got the error:
you can not assign a value of type "const wchar_t *" to an entity of type "LPWSTR"
The lpDesktop field is a LPWSTR (wchar_t*), not a LPCWSTR (const wchar_t *). A wide string literal is a const wchar_t[N] (where N is 16 in your example), which decays to const wchar_t *. You cannot assign a pointer-to-const-data to a pointer-to-non-const-data. That is what the compiler is complaining about.
To assign a string literal to lpDesktop, you need to cast it:
start_info.lpDesktop = (LPWSTR) L"WinSta0\\Default";
Or better:
start_info.lpDesktop = const_cast<LPWSTR>(L"WinSta0\\Default");
Otherwise, copy the data to a local non-const wchar_t[] buffer and use that instead:
WCHAR szDesktop[] = L"WinSta0\\Default";
start_info.lpDesktop = szDesktop;

argument of type "char *" is incompatible with parameter of type "STRSAFE_LPCWSTR

I have the following:
DYNAMIC_TIME_ZONE_INFORMATION dtzRecorder;
GetDynamicTimeZoneInformation(&dtzRecorder);
I normally do the following to copy a new name:
StringCchCopy(dtzRecorder.TimeZoneKeyName, 128, L"GMT Standard Time");
But now I need to do the following:
char tzKey[51];
std::string timezone("someTimeZOneName");
strncpy_s(MyStruct.tzKey, timezone.c_str(), _TRUNCATE);
StringCchCopy(dtzRecorder.TimeZoneKeyName, 128, MyStruct.tzKey); <--Error
But I get the error:
argument of type "char *" is incompatible with parameter of type "STRSAFE_LPCWSTR"
How can I copy this to dtzRecorder.TimeZoneKeyName??
The basic problem is that dtzRecorder.TimeZoneKeyName is a wide string (wchar_t[]), but tzKey is a narrow string (char[]).
The easiest way to solve it would be to use wchar_t for tzKey, too:
wchar_t tzKey[51];
std::wstring timezone(L"someTimeZOneName");
wcsncpy_s(MyStruct.tzKey, timezone.c_str(), _TRUNCATE);
StringCchCopy(dtzRecorder.TimeZoneKeyName, 128, MyStruct.tzKey);
LPSTR is Microsoft for "Long Pointer to STRing" or char *, LPWSTR is Microsoft for "Long Pointer to Wide-c STring" or wchar_t *. Additionally LPCSTR and LPCWSTR refer to const variants.
The error you see comes from passing an LPCSTR (const character pointer) to a function expecting an LPWSTR (non-const unicode/wide character pointer).
Wide string constants are denoted with an L prefix (L"wide"), generally have the type wchar_t* and require a variant of std::string called std::wstring.
Which is the default for most Windows system calls is handled by a general project setting "Character Set", if it is "Unicode" then wide strings are required. Support for this is provided by <tchar.h> see https://msdn.microsoft.com/en-us/library/dybsewaf.aspx
#include <tchar.h>
// tchar doesn't help with std::string/std::wstring, so use this helper.
#ifdef _UNICODE
#define TSTRING std::wstring
#else
#define TSTRING std::string
#endif
// or as Matt points out
typedef std::basic_string<_TCHAR> TSTRING;
// Usage
TCHAR tzKey[51]; // will be char or wchar_t accordingly
TSTRING timezone(_T("timezonename")); // string or wstring accordingly
_tscncpy_s(tzKey, timezone.c_str(), _TRUNCATE);
Alternatively you can just be explicit about using wides
wchar_t tzKey[51]; // note: this is not 51 bytes
std::wstring timezone(L"timezonename");
wscncpy_s(tzKey, timezone.c_str(), _TRUNCATE);
As an aside, why not simply do this:
std::wstring timezone(L"tzname");
timezone.erase(50); // limit length
Why waste time copying the value when you could just insert a null-terminator at the limit?

How to convert char* to LPCWSTR?

I know this has already been discussed in several questions on SO, but none of those solutions have worked for me.
I start with a char* because this is for a DLL that will be called from VBA, and char* is necessary for VBA to pass a string to the DLL.
I need to return a LPCWSTR because that's the input parameter for the API function I'm trying to call, and I can't enable casting by switching from Unicode to multi-byte character set in the Properties window, because the API has this code:
#if !defined(UNICODE) && !defined(NOUNICODE)
#error UNICODE is not defined. UNICODE must be defined for correct API arguments.
#endif
I tried this:
LPCWSTR convertCharArrayToLPCWSTR(char* charArray)
{
const char* cs=charArray;
wchar_t filename[4096] = {0};
MultiByteToWideChar(0, 0, cs[1], strlen(cs[1]), filename, strlen(cs[1]));
}
which gave these errors:
error C2664: 'strlen' : cannot convert parameter 1 from 'const char' to 'const char *'
error C2664: 'MultiByteToWideChar' : cannot convert parameter 3 from 'const char' to 'LPCCH'
I tried this (same function header), loosely adapted from this post:
size_t retVal;
const char * cs = charArray;
size_t length=strlen(cs);
wchar_t * buf = new wchar_t[length](); // value-initialize to 0 (see below)
size_t wn = mbsrtowcs_s(&retVal,buf,20, &cs, length + 1, NULL);
return buf;
This compiled ok, but when I passed it an example string of "xyz.xlsx", mbsrtowcs_s() set buf to an empty string: L""
So, how do I make this conversion?
Following Hans Passant's advice regarding pointers to local variables, I worked out this approach, which seems to work well:
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t* wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
I'm aware that the use of new requires memory management, which I perform in the function that calls this one.
Since cs is a const char*, cs[1] is a const char. C++ won't convert it to a pointer for you, because in most cases that doesn't make sense.
You could instead say &cs[1] or cs+1 if the intent is to skip the first char. (That's what you're doing when you pass a pointer to the 1th element; in C++, indexes start at 0.) If the intent is to pass the whole string, then just pass cs.

How to convert tchar pointer to char pointer

I want to conver a tchar* to char * is this possible . if yes how to do it. I use unicode setting
A TCHAR is either a plain char or a wchar_t depending on your project's settings. If it's the latter, you would need to use WideCharToMultiByte with appropriate code page parameter.
You can't convert the pointer, you need to allocate a new string that is "char" instead of "wchar_t"
the most elegant way to do this is with the ATL conversion macros because it will hide all the allocation and called to the functions mentioned in the other comments
example
#include <atlbase.h>
#include <atlconv.h>
void YourFunction()
{
TCHAR wszHelloTchar = _T("Hello!\n");
USES_CONVERSION; // a macro required once before using T2A() and other ATL macros
// printf require a char*
// T2A converts (if necessary) the TCHAR string to char
printf( T2A( wszHelloTchar ) );
}
I find wcstombs works great for doing this sort of thing,