std::wstring Is converting first character randomly - c++

I've got this piece of code:
const char * c = &(4:); //This pointer contains "JPG" string
//Wide char conversion
wchar_t *cc = new wchar_t[128];
MultiByteToWideChar(CP_ACP, 0, c, -1, cc, wcslen(cc));
Then I declare a wstring variable:
wstring sFilter;
sFilter.append(L"Format: ");
sFilter.append(cc);
sFilter.push_back('\0');
sFilter.append(L"*.");
sFilter.append(cc);
sFilter.push_back('\0');
sFilter.push_back('\0');
const wchar_t * extensionFilter = sFilter.c_str();
I'm forming this wchar_t to apply a filter to GetOpenFileName function from WinApi: ofn.lpstrFilter = extensionString; which is a member of a structure.
Extension filter randomly contains: "3ormat: JPG" or ":ormat: JPG"...
I cannot change project to Unicode just because the IDE I'm working on doesn't allow it. So I need to work with this.

wchar_t *cc = new wchar_t[128];
MultiByteToWideChar(CP_ACP, 0, c, -1, cc, wcslen(cc));
new[] does not fill the memory that it allocates. You are calling wcslen() on a buffer that is not guaranteed to be null-terminated. And even if it were, the null would be at the front of the buffer so wcslen() would return 0. You need to pass the actual length of the allocated buffer:
MultiByteToWideChar(CP_ACP, 0, c, -1, cc, 128);
I cannot change project to Unicode just because the IDE I'm working on doesn't allow it.
You don't need to change the whole project. That only affects TCHAR-based declarations anyway. Since your input data is Ansi, you could simply call GetOpenFileNameA() directly and not worry about converting your input data to Unicode first:
const char * c = ...; //This pointer contains "JPG" string
string sFilter;
sFilter.append("Format: ");
sFilter.append(c);
sFilter.push_back('\0');
sFilter.append("*.");
sFilter.append(c);
sFilter.push_back('\0');
sFilter.push_back('\0');
const char * extensionFilter = sFilter.c_str();
OPENFILENAMEA ofn;
...
ofn.lpstrFilter = extensionFilter;
...
GetOpenFileNameA(&ofn);

Related

How do I assign a value to TCHAR* without using a string literal with TEXT()?

I need to assign a value to a TCHAR* variable in C++ and I have been told that this is accomplished using the TEXT() macro. However, I have found that I am only able to do this when using string literals.
//This assignment uses a string literal and works
TCHAR* name = TEXT("example");
//This assignment uses a local variable and causes an error
char* example = "example";
TCHAR* otherName = TEXT(example);
This wouldn't be a problem if it wasn't for the fact that the value of the TEXT() quote parameter will be determined by the user at runtime. Therefore, I need to store the value in some kind of local variable and pass it to the TEXT() macro. How am I able to use a local variable with TEXT() instead of a string literal? Or is there another way that I can assign the value to the TCHAR* varible?
The TEXT() macro only works for literals at compile-time. For non-literal data, you have to perform a runtime conversion instead.
If UNICODE is defined for the project, TCHAR will map to wchar_t, and you will have to use MultiByteToWideChar() (or equivalent) to convert your char* value to a wchar_t buffer:
char* example = "example";
int example_len = strlen(example);
int otherName_len = MultiByteToWideChar(CP_ACP, 0, example, example_len, NULL, 0);
TCHAR* otherName = new TCHAR[otherName_len+1];
MultiByteToWideChar(CP_ACP, 0, example, example_len, otherName, otherName_len);
otherName[otherName_len] = 0;
// use otherName as needed ...
delete[] otherName;
If UNICODE is not defined, TCHAR will map to char instead, and you can just assign your char* directly:
char* example = "example";
TCHAR* otherName = example;
I would suggest using C++ strings to help you:
std::basic_string<TCHAR> toTCHAR(const std::string &s)
{
#ifdef UNICODE
std::basic_string<TCHAR> result;
int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s.length(), NULL, 0);
if (len > 0)
{
result.resize(len);
MultiByteToWideChar(CP_ACP, 0, s.c_str(), s.length(), &result[0], len);
}
return result;
#else
return s;
#endif
}
char* example = "example";
std::basic_string<TCHAR> otherName = toTCHAR(example);

Concatenating strings of different types in C++

How can I concatenate the following char and TCHAR variables in C++?
TCHAR fileName[50];
TCHAR prefix[5] = "file_";
TCHAR ext[4] = ".csv";
char *id[10];
generateId(*id);
The generateId(char *s) function simply generates a random string.
I need to end up with fileName being something like file_randomIdGoesHere.csv
I have tried strncat(fileName, prefix, 5); which works fine with all TCHAR variables but not with char * as it requires a const char * instead, so maybe there's a better way of doing it, not sure how to convert char * or char ** to const char *.
Any ideas?
The error I get with strncat(fileName, id, 10) is error: cannot convert 'char**' to 'const char*'
The error you are seeing is because your id array is declared wrong. You declared an array of pointers instead of an array of characters. It should be more like this:
char id[10];
generateId(id);
That being said, you are also assigning char-based string literals to your TCHAR arrays, which means you are not compiling your project for Unicode, otherwise such assignments would fail to compile. So you may as well replace TCHAR with char:
char fileName[50] = {0};
char prefix[] = "file_";
char ext[] = ".csv";
char id[10] = {0};
generateId(id);
And then, you should change strncat() to _snprintf():
_snprintf(filename, 49, "%s%s.cvs", prefix, id);
If you really want to use TCHAR then you need to change everything to TCHAR, and use the TEXT() macro for literals:
TCHAR fileName[50] = {0};
TCHAR prefix[] = TEXT("file_");
TCHAR ext[] = TEXT(".csv");
TCHAR id[10] = {0};
generateId(id);
__sntprintf(filename, 49, TEXT("%s%s.cvs"), prefix, id);
If you cannot change id to TCHAR then you will have to perform a runtime conversion:
TCHAR fileName[50] = {0};
TCHAR prefix[] = TEXT("file_");
TCHAR ext[] = TEXT(".csv");
char id[10] = {0};
generateId(id);
#ifdef UNICODE
wchar_t id2[10] = {0};
MultiByteToWideChar(CP_ACP, 0, id, -1, id2, 10);
#else
char *id2 = id;
#endif
__sntprintf(filename, 49, TEXT("%s%s.cvs"), prefix, id2);
The first thing you should do is, since you are using C++ and not pure C, just use a string class to represent your strings and to manage them in a way much more convenient than raw C-style character arrays.
In the context of Windows C++ programming, CString is a very convenient string class.
You can use its overloaded operator+ (or +=) to concatenate strings in a convenient, robust and easy way.
If you have an id stored in a char string (as an ASCII string), as you showed in your question's code:
char id[10];
generateId(id);
you can first create a CString around it (this will also convert from char-string to TCHAR-string, in particular to wchar_t-string if you are using Unicode builds, which have been the default since VS2005):
const CString strId(id);
Then, you can build the whole file name string:
//
// Build file name using this format:
//
// file_<generatedIdGoesHere>.csv
//
CString filename(_T("file_"));
filename += strId;
filename += _T(".csv");
As an alternative, you could also use the CString::Format method, e.g.:
CString filename;
filename.Format(_T("file_%s.csv"), strId.GetString());
You can simply pass instances of CString to LPCTSTR parameters in Win32 APIs, since CString offers an implicit conversion to LPCTSTR (i.e. const TCHAR*).
To use CString, you can simply #include <atlstr.h>.
First, convert char to TCHAR (see How to convert char* to TCHAR[ ]? )
Then, concatenate two TCHAR strings using _tcscat().
If you are not using UNICODE character table. Than your TCHAR is equivalent to char.
TCHAR prefix[6] = "file_"; //don't forget to allocate space for null terminator '\0'
TCHAR ext[5] = ".csv"; // size is not 4, remember null terminator
char id[10] = "random"; // no need to use char* here
std::ostringstream oss;
oss << prefix << id << ext << std::endl;
std::cout << oss.str() << std::endl; // gives you file_random.csv as output

WNetUseConnection SystemErrorCode 1113 No Mapping Exist

I am trying to convert a string into a wchar_t string to use it in a WNetUseConnection function.
Basicly its an unc name looking like this "\\remoteserver".
I get a return code 1113, which is described as:
No mapping for the Unicode character
exists in the target multi-byte code
page.
My code looks like this:
std::string serverName = "\\uncDrive";
wchar_t *remoteName = new wchar_t[ serverName.size() ];
MultiByteToWideChar(CP_ACP, 0, serverName.c_str(), serverName.size(), remoteName, serverName.size()); //also doesn't work if CP_UTF8
NETRESOURCE nr;
memset( &nr, 0, sizeof( nr ));
nr.dwType = RESOURCETYPE_DISK;
nr.lpRemoteName = remoteName;
wchar_t pswd[] = L"user"; //would have the same problem if converted and not set
wchar_t usrnm[] = L"pwd"; //would have the same problem if converted and not set
int ret = WNetUseConnection(NULL, &nr, pswd, usrnm, 0, NULL, NULL, NULL);
std::cerr << ret << std::endl;
The intersting thing is, that if remoteName is hard codede like this:
char_t remoteName[] = L"\\\\uncName";
Everything works fine. But since later on the server, user and pwd will be parameters which i get as strings, i need a way to convert them (also tried mbstowcs function with the same result).
MultiByteToWideChar will not 0-terminate the converted string with your current code, and therefore you get garbage characters following the converted "\uncDrive"
Use this:
std::string serverName = "\\uncDrive";
int CharsNeeded = MultiByteToWideChar(CP_ACP, 0, serverName.c_str(), serverName.size() + 1, 0, 0);
wchar_t *remoteName = new wchar_t[ CharsNeeded ];
MultiByteToWideChar(CP_ACP, 0, serverName.c_str(), serverName.size() + 1, remoteName, CharsNeeded);
This first checks with MultiByteToWideChar how many chars are needed to store the specified string and the 0-termination, then allocates the string and converts it. Note that I didn't compile/test this code, beware of typos.

Why is the following C++ code printing only the first character?

I am trying to convert a char string to a wchar string.
In more detail: I am trying to convert a char[] to a wchar[] first and then append " 1" to that string and the print it.
char src[256] = "c:\\user";
wchar_t temp_src[256];
mbtowc(temp_src, src, 256);
wchar_t path[256];
StringCbPrintf(path, 256, _T("%s 1"), temp_src);
wcout << path;
But it prints just c
Is this the right way to convert from char to wchar? I have come to know of another way since. But I'd like to know why the above code works the way it does?
mbtowc converts only a single character. Did you mean to use mbstowcs?
Typically you call this function twice; the first to obtain the required buffer size, and the second to actually convert it:
#include <cstdlib> // for mbstowcs
const char* mbs = "c:\\user";
size_t requiredSize = ::mbstowcs(NULL, mbs, 0);
wchar_t* wcs = new wchar_t[requiredSize + 1];
if(::mbstowcs(wcs, mbs, requiredSize + 1) != (size_t)(-1))
{
// Do what's needed with the wcs string
}
delete[] wcs;
If you rather use mbstowcs_s (because of deprecation warnings), then do this:
#include <cstdlib> // also for mbstowcs_s
const char* mbs = "c:\\user";
size_t requiredSize = 0;
::mbstowcs_s(&requiredSize, NULL, 0, mbs, 0);
wchar_t* wcs = new wchar_t[requiredSize + 1];
::mbstowcs_s(&requiredSize, wcs, requiredSize + 1, mbs, requiredSize);
if(requiredSize != 0)
{
// Do what's needed with the wcs string
}
delete[] wcs;
Make sure you take care of locale issues via setlocale() or using the versions of mbstowcs() (such as mbstowcs_l() or mbstowcs_s_l()) that takes a locale argument.
why are you using C code, and why not write it in a more portable way, for example what I would do here is use the STL!
std::string src = std::string("C:\\user") +
std::string(" 1");
std::wstring dne = std::wstring(src.begin(), src.end());
wcout << dne;
it's so simple it's easy :D
L"Hello World"
the prefix L in front of the string makes it a wide char string.

How do you convert from a nsACString to a LPCWSTR?

I'm making a firefox extension (nsACString is from mozilla) but LoadLibrary expects a LPCWSTR. I googled a few options but nothing worked. Sort of out of my depth with strings so any references would also be appreciated.
It depends whether your nsACString (which I'll call str) holds ASCII or UTF-8 data:
ASCII
std::vector<WCHAR> wide(str.Length()+1);
std::copy(str.beginReading(), str.endReading(), wide.begin());
// I don't know whether nsACString has a terminating NUL, best to be sure
wide[str.Length()] = 0;
LPCWSTR newstr = &wide[0];
UTF-8
// get length, including nul terminator
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
str.BeginReading(), str.Length(), 0, 0);
if (len == 0) panic(); // happens if input data is invalid UTF-8
// allocate enough space
std::vector<WCHAR> wide(len);
// convert string
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
str.BeginReading(), str.Length(), &wide[0], len)
LPCWSTR newstr = &wide[0];
This allocates only as much space as is needed - if you want faster code that potentially uses more memory than necessary, you can replace the first two lines with:
int len = str.Length() + 1;
This works because a conversion from UTF-8 to WCHAR never results in more characters than there were bytes of input.
Firstly note: LoadLibrary need not accept a LPWSTR. Only LoadLibraryW does. You may call LoadLibraryA directly (passing a narrow LPCSTR) and it will perform the translation for you.
If you choose to do it yourself however, below is one possible example.
nsACString sFoo = ...; // Some string.
size_t len = sFoo.Length() + 1;
WCHAR *swFoo = new WCHAR[len];
MultiByteToWideChar(CP_ACP, 0, sFoo.BeginReading(), len - 1, swFoo, len);
swFoo[len - 1] = 0; // Null-terminate it.
...
delete [] swFoo;
nsACString a;
const char* pData;
PRUint32 iLen = NS_CStringGetData(a, &pData);