How concatenate a char with TCHAR array? - c++

I want concatenate a random string with a directory name and the final result must be something like this:
C:\Program Files (x86)\AAAFFF1334
On following code this part: "AAAFFF1334" comes strange characters see:
What must be made to fix this?
TCHAR mydir[MAX_PATH];
void gen_random(char *s, const int len) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum)-1)];
}
s[len] = 0;
}
// main
TCHAR szProgramFiles[MAX_PATH];
HRESULT hProgramFiles = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szProgramFiles);
char str;
gen_random(&str, 10);
wsprintf(mydir, TEXT("%s\\%s"), szProgramFiles, str);

gen_random should get char array with at least 11 characters (10 for size + 1 for terminating null).
So it should be:
char str[10+1]; //or char str[11];
gen_random(str, 10);
in addition, the format string should be: "%s\\%hs", the first is TCHAR* type (if UNICODE defined wchar_t* if not char*) the second is always char* type.
hs, hS
String. This value is always interpreted as type LPSTR, even
when the calling application defines Unicode.
look here
Note: in Microsoft documentation:
LPSTR = always char*
LPWSTR = always wchar_t*
LPTSTR = TCHAR* (if UNICODE defined: wchar_t*, else: char*)

Related

Converting SQLWCHAR * to char*

Working for the first time in the area of unicode and widechars,
I am trying to convert WCHAR* to char*.
(WCHAR typedefed to SQLWCHAR, and eventually to unsigned short)
And I need to support all platforms(windows, mac, linux).
What I have as input is a WCHAR* and its length.
I figured, if I convert the input to wstring, I will have a chance to then strcpy/ strdup it to the output variable.
But looks like I am not constructing my wstring correctly because wprintf doesn't print its value.
Any hints what I am missing?
#include <iostream>
#include <codecvt>
#include <locale>
SQLRETURN SQL_API SQLExecDirectW(SQLHSTMT phstmt, SQLWCHAR* pwCmd, SQLINTEGER len)
{
char *output;
wchar_to_utf8(pwCmd, len, output);
// further processing
SQLRETURN rc;
return rc;
}
int wchar_to_utf8(WCHAR *wStr, int size, char *output)
{
std::wstring ws((const wchar_t*)wStr, size - 1);
wprintf(L"wstring:%s\n", ws);
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::string t = conv.to_bytes(ws);
/*allocate output or use strdup*/
strncpy(output, t.c_str(), size); // todo:take care of the last null char
return strlen(output);
}
"%s" in a wprintf format string requires a wchar_t* argument, so
wprintf(L"wstring%s\n", ws);
should be
wprintf(L"wstring%s\n", ws.c_str());
To convert wchar* to char*
const std::wstring wStr = /*your WCHAR* */;
const char* str = std::filesystem::path(wStr).string().c_str();

C++ TCHAR array to wstring not working in VS2010

I would like to convert a TCHAR array to a wstring.
TCHAR szFileName[MAX_PATH+1];
#ifdef _DEBUG
std::string str="m:\\compiled\\data.dat";
TCHAR *param=new TCHAR[str.size()+1];
szFileName[str.size()]=0;
std::copy(str.begin(),str.end(),szFileName);
#else
//Retrieve the path to the data.dat in the same dir as our data.dll is located
GetModuleFileName(_Module.m_hInst, szFileName, MAX_PATH+1);
StrCpy(PathFindFileName(szFileName), _T("data.dat"));
#endif
wstring sPath(T2W(szFileName));
I need to pass szFileName to a function that expects
const WCHAR *
For completeness I am stating the void that I need to pass szFileName to:
HRESULT CEngObj::MapFile( const WCHAR * pszTokenVal, // Value that contains file path
HANDLE * phMapping, // Pointer to file mapping handle
void ** ppvData ) // Pointer to the data
However, T2W does not work for me. The compiler says that "_lpa" is not defined, and I don't know where to go on from here. I have tried other conversion methods that I found stated on the net, but they did not work either.
There are functions like
mbstowcs_s()
that convert from char* to wchar_t*.
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
char *orig = "Hello, World!";
cout << orig << " (char *)" << endl;
// Convert to a wchar_t*
size_t origsize = strlen(orig) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, orig, _TRUNCATE);
wcscat_s(wcstring, L" (wchar_t *)");
wcout << wcstring << endl;
Look here for an article and here for MSDN.
The definition of TCHAR differs depending on if certain preprocessor macros are defined or not. See e.g. this article for the possible combinations.
This means that TCHAR may already be a wchar_t.
You can use the _UNICODE macro to check if you need to convert the string. If you do, then you can use mbstowcs to do the conversion:
std::wstring str;
#ifdef _UNICODE
// No need to convert the string
str = your_tchar_string;
#else
// Need to convert the string
// First get the length needed
int length = mbstowcs(nullptr, your_tchar_string, 0);
// Allocate a temporary string
wchar_t* tmpstr = new wchar_t[length + 1];
// Do the actual conversion
mbstowcs(tmpstr, your_tchar_str, length + 1);
str = tmpstr;
// Free the temporary string
delete[] tmpstr;
#endif

Can I use a crypted hash as a filename or do I have to convert it first?

I am trying to hash a string then use that hash as the name of a file.
My problem: is that all the C++ hashers/crypters I have come across hash a std::string or char* & return the hashed string as an unsigned char*?
How do I convert that unsigned char* to a char* or std::string so I can then write it to a file or filename? Or do I not need to convert it to a normal string to use it?
tstring hashString( tstring str )
{
// Post:
unsigned char hashStr[SHA256_DIGEST_SIZE];
std::string messageStr = str;
SHA256::getInstance()->digest( messageStr, hashStr );
//TCHAR *hashStrSigned = reinterpret_cast <TCHAR*>(hashStr);
// can I just use this hashStr to create a file? Or do I have to convert it to char* to use?
Handle newF = CreateFile( (LPTSTR)hashStr, GENERIC_ALL, 0, NULL, CREATE_ALWAYS,
0, NULL );
return tstring(hashStrSigned);
}
The result of the hash likely contain bytes that map to chars that are not allowed in a filename (e.g. null-char, '+', '?', etc....). So "hashStr" in your code isn't likely to be a string, but just an array of bytes that aren't null terminated.
Try this little function to convert from "binary hash to string suitable for file name"
void HashToString(unsigned char* shaHash, std::string* pStr)
{
char szHash[SHA256_DIGEST_SIZE*2+1];
char* pszOut = szHash;
for (int x = 0; x < SHA256_DIGEST_SIZE; x++)
{
sprintf(pszOut, "%.2X", shaHash[x]); // write out as hex chars
pszOut += 2; // advance 2 chars
}
*pszOut = '\0'; // null terminate
*pStr = std::string(szHash);
}
In your above code example, you'd call it as follows:
std::string str;
HashToString(hashStr, &str);
HANDLE newF = CreateFileA(str.c_str(), ...);

How to convert a TCHAR array to std::string?

How do I convert a TCHAR array to std::string (not to std::basic_string)?
TCHAR is just a typedef that, depending on your compilation configuration, either defaults to char or wchar_t.
Standard Template Library supports both ASCII (with std::string) and wide character sets (with std::wstring). All you need to do is to typedef String as either std::string or std::wstring depending on your compilation configuration. To maintain flexibility you can use the following code:
#ifndef UNICODE
typedef std::string String;
#else
typedef std::wstring String;
#endif
Now you may use String in your code and let the compiler handle the nasty parts. String will now have constructors that lets you convert TCHAR to std::string or std::wstring.
My answer is late, I'll admit that, but with the answers of 'Alok Save' and some research I've found a good way! (Note: I didn't test this version a lot, so it might not work in every case, but from what I tested it should):
TCHAR t = SomeFunctionReturningTCHAR();
std::string str;
#ifndef UNICODE
str = t;
#else
std::wstring wStr = t;
str = std::string(wStr.begin(), wStr.end());
#endif
std::cout << str << std::endl; //<-- should work!
TCHAR is either char or wchar_t, so a
typedef basic_string<TCHAR> tstring;
is one way of doing it.
The other is to skip char altogether and just use std::wstring.
TCHAR type is char or wchar_t, depending on your project settings.
#ifdef UNICODE
// TCHAR type is wchar_t
#else
// TCHAR type is char
#endif
So if you must use std::string instead of std::wstring, you should use a converter function. I may use wcstombs or WideCharToMultiByte.
TCHAR * text;
#ifdef UNICODE
/*/
// Simple C
const size_t size = ( wcslen(text) + 1 ) * sizeof(wchar_t);
wcstombs(&buffer[0], text, size);
std::vector<char> buffer(size);
/*/
// Windows API (I would use this)
std::vector<char> buffer;
int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
if (size > 0) {
buffer.resize(size);
WideCharToMultiByte(CP_UTF8, 0, text, -1, static_cast<BYTE*>(&buffer[0]), buffer.size(), NULL, NULL);
}
else {
// Error handling
}
//*/
std::string string(&buffer[0]);
#else
std::string string(text);
#endif
Quick and dirty solution :
TCHAR str[256] = {};
// put something in str...
// convert to string
std::string strtmp(&str[0], &str[255]);
std::cout << strtmp << std::endl;
Simple!
std::string tcharToChar(TCHAR* buffer)
{
char *charBuffer = NULL;
std::string returnValue;
int lengthOfbuffer = lstrlenW(buffer);
if(buffer!=NULL)
{
charBuffer = (char*)calloc(lengthOfbuffer+1,sizeof(char));
}
else
{
return NULL;
}
for (int index = 0;
index < lengthOfbuffer;
index++)
{
char *singleCharacter = (char*)calloc(2,sizeof(char));
singleCharacter[0] = (char)buffer[index];
singleCharacter[1] = '\0';
strcat(charBuffer, singleCharacter);
free(singleCharacter );
}
strcat(charBuffer, "\0");
returnValue.append(charBuffer);
free(charBuffer);
return returnValue;
}

How do I convert from _TCHAR * to char * when using C++ variable-length args?

We need to pass a format _TCHAR * string, and a number of char * strings into a function with variable-length args:
inline void FooBar(const _TCHAR *szFmt, const char *cArgs, ...) {
//...
}
So it can be called like so:
char *foo = "foo";
char *bar = "bar";
LogToFileA(_T("Test %s %s"), foo, bar);
Obviously a simple fix would be to use _TCHAR instead of char, but we don't have that luxury unfortunately.
We need to use this with va_start, etc so we can format a string:
va_list args;
_TCHAR szBuf[BUFFER_MED_SIZE];
va_start(args, cArgs);
_vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args);
va_end(args);
Unfortunately we cannot use this because it give us this error:
Unhandled exception at 0x6a0d7f4f (msvcr90d.dll) in foobar.exe:
0xC0000005: Access violation reading location 0x2d86fead.
I'm thinking we need to convert our char * to _TCHAR * - but how?
Use %hs or %hS instead of %s. That will force the parameters to be interpretted as char* in both Ansi and Unicode versions of printf()-style functions, ie:
inline void LogToFile(const _TCHAR *szFmt, ...)
{
va_list args;
TCHAR szBuf[BUFFER_MED_SIZE];
va_start(args, szFmt);
_vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args);
va_end(args);
}
{
char *foo = "foo";
char *bar = "bar";
LogToFile(_T("Test %hs %hs"), foo, bar);
}
Usually it looks like the following:
char *foo = "foo";
char *bar = "bar";
#ifdef UNICODE
LogToFileW( L"Test %S %S", foo, bar); // big S
#else
LogToFileA( "Test %s %s", foo, bar);
#endif
Your question is not completely clear. How your function is implemented and how do you use it?
Here was my solution - I welcome suggestions for improvement!
inline void FooBar(const _TCHAR *szFmt, const char *cArgs, ...) {
va_list args;
_TCHAR szBuf[BUFFER_MED_SIZE];
// Count the number of arguments in the format string.
const _TCHAR *at = _tcschr(szFmt, '%');
int argCount = 0;
while(at) {
argCount++;
at = _tcschr(at + 1, '%');
}
CA2W *ca2wArr[100];
LPWSTR szArgs[100];
va_start(args, cArgs);
for (int i = 1; i < argCount + 1; i++) {
CA2W *ca2w = new CA2W(cArgs);
szArgs[i] = ca2w->m_psz;
ca2wArr[i] = ca2w;
cArgs = va_arg(args, const char *);
}
va_end(args);
// Use the new array we just created (skips over first element).
va_start(args, szArgs[0]);
_vstprintf_s(szBuf, BUFFER_MED_SIZE, szFmt, args);
va_end(args);
// Free up memory used by CA2W objects.
for (int i = 1; i < argCount + 1; i++) {
delete ca2wArr[i];
}
// ... snip ... - code that uses szBuf
}
this is something I have used before to convert a TCHAR to char, hope it helps, although I wasn't really looking for optimization, so it's not the fastest way.. but it worked!
TCHAR tmp[255];
::GetWindowText(hwnd, tmp, 255);
std::wstring s = tmp;
//convert from wchar to char
const wchar_t* wstr = s.c_str();
size_t wlen = wcslen(wstr) + 1;
char newchar[100];
size_t convertedChars = 0;
wcstombs_s(&convertedChars, newchar, wlen, wstr, _TRUNCATE);