How to convert char* to LPCWSTR? - c++

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.

Related

Error C2440 when compiling a library with meson

I have code C++ that I want to compile as a library using meson where I get 2 kinds of errors
error C2440: 'initializing': cannot convert from 'const wchar_t [19]'
to 'const PWCHAR'
-note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)
error C2664: '... cannot convert argument 2 from 'const wchar_t [6]'
to 'PWSTR note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)
winnt.h uses typedef for wchar_t:
typedef wchar_t WCHAR;
typedef WCHAR *PWCHAR;
If I do this in my code I get Error C2440:
const PWCHAR Tokens[] = { L"A", L"B", L"C", L"D" };
If I change my code that error disappears:
const wchar_t * Tokens[] = { L"A", L"B", L"C", L"D" };
I know in C, the type of a string literal is array of char, but in C++, it's array of const char which causes this error.
I also know it is possible to change Zc:strictStrings in VStudio. But since I compile my code with meson how would I get rid of that error using meson?
With the definition
const PWCHAR Tokens[] = { ... };
you declare that Tokens is an array of constant pointers. The data that those pointers are pointing to are not constant.
And as literal strings are constant you can't use them to initialize the array.
The working definition:
const wchar_t * Tokens[] = { ... };
Or the alternative
wchar_t const * Tokens[] = { ... };
Here you declare that Tokens is an array of (non-constant) pointers to constant wchar_t data. Which is correct for literal strings.
If you want to be portable and follow the C++ standard, using PWCHAR is simply not possible.
If you want the pointers themselves to be constant, you need to add another const qualifier for them:
wchar_t const * const Tokens[] = { ... };
// ^^^^^
// makes the pointers constant
// ^^^^^
// makes the data constant
Or as mentioned in a comment: Use std::wstring (and other standard C++ containers):
// Or std::array if the size if known and fixed at compile-time
std::vector<std::wstring> Tokens = { ... };

error: cannot convert 'const CHAR**' {aka 'const char**'} to 'LPCSTR' {aka 'const char*'} in C++

I have a big chunk of code that I am debugging, and I am stuck trying to figure out why I get the following error when I try to build the project:
"error: cannot convert 'const CHAR**' {aka 'const char**'} to 'LPCSTR'
{aka 'const char*'}"
The issue is with the wsKey parameter. SHRegGetValue is a function defined in the Shlwapi.h header, but I don't know how to fix this and I am inexperienced with the Windows API. Please let me know if there is a solution.
LPCSTR wsKey[MAX_PATH] = {"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"};
WCHAR wsValue[MAX_PATH] = L"ProxyEnable";
DWORD dwValue = (DWORD)FALSE;
DWORD dwSize = sizeof(dwValue);
LONG nStatus = SHRegGetValue(HKEY_CURRENT_USER, wsKey, wsValue, SRRF_RT_DWORD, NULL, &dwValue, &dwSize);
The line:
LPCSTR wsKey[MAX_PATH] = {"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"};
declares wsKey to be an array of MAX_PATH character pointers, the first of which points to the given string literal. If this is really what you want, then the second argument to your SHRegGetValue call should be that first element: wsKey[0].
However, what is more likely, is that you need wsKey to be an array of MAX_PATH characters – not pointers. Like this:
const CHAR wsKey[MAX_PATH] = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; // Note the removal of the enclosing {...} braces!
You also have an error with the third parameter to SHRegGetValue: this should be a char (or CHAR) string, not a WCHAR string (you are mixing up the ANSI and Unicode versions of the call). Declare wsValue like this, to use the ANSI version:
CHAR wsValue[MAX_PATH] = "ProxyEnable";
Alternatively, if you intend to use the wide-character (Unicode) version, then you need to change your wsKey to a wide-character string. (This seems more likely, given the variable names.)
const WCHAR wsKey[MAX_PATH] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
WCHAR wsValue[MAX_PATH] = L"ProxyEnable";
Isn't your question answered in your title: const char** is not const char*. Why you expect that it should work?
I assume it's a copy & paste error. You should write:
LPCSTR wsKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
LPCSTR is an alias to const char *

How to convert TCHAR to const char?

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.

const WCHAR * myVar vs const char * myVar

I've developed a small bmp to jpg conveter.
Following code is working and providing exact results as I need
BOOLEAN convertBMPtoJPG(const WCHAR *src_bmp_path,const WCHAR *dest_jpeg_path);
then calling function as,
const WCHAR *src_bmp_path = L"test.bmp";
const WCHAR *dest_jpeg_path= L"test.jpg";
convertBMPtoJPG(src_bmp_path,dest_jpeg_path);
However I need the function to be changed as following (as per requirements I've been given), but doing so results as a compilation error.
BOOLEAN convertBMPtoJPG(char *src_bmp_path,char *dest_jpeg_path);
then function would be called as, (though I need to follow just the prototype as above),
char *src_bmp_path = "test.bmp";
char *dest_jpeg_path= "test.jpg";
convertBMPtoJPG(src_bmp_path,dest_jpeg_path);
Another question on stackover provided too much information about Win32 types, however I yet couldn't resolve the issue.
I'm not that great in Win32 API, please guide me what's going wrong in later approach.
Edit:
Error Message:
error C2664: 'Gdiplus::Status Gdiplus::Image::Save(const WCHAR *,const CLSID *,const Gdiplus::EncoderParameters *)' : cannot convert parameter 1 from 'char *' to 'const WCHAR *'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Image::Save() only accepts WCHAR* values, so your char* wrapper will have to convert to WCHAR*, such as with MultiByteToWideChar() (just like Win32 API Ansi functions do when they call Win32 API Unicode functions internally), eg:
std::wstring towstring(const char *src)
{
std::wstring output;
int src_len = strlen(src);
if (src_len > 0)
{
int out_len = MultiByteToWideChar(CP_ACP, 0, src, src_len, NULL, 0);
if (out_len > 0)
{
output.resize(out_len);
MultiByteToWideChar(CP_ACP, 0, src, src_len, &output[0], out_len);
}
}
return output;
}
BOOLEAN convertBMPtoJPG(char *src_bmp_path,char *dest_jpeg_path)
{
return convertBMPtoJPG(towstring(src_bmp_path).c_str(), towstring(dest_jpeg_path).c_str());
}
BOOLEAN convertBMPtoJPG(const WCHAR *src_bmp_path, const WCHAR *dest_jpeg_path)
{
// your existing conversion logic here...
}
Well, looks like your are compiling for Unicode support. The list of Win32 data types can be found here
WCHAR is defined as -
A 16-bit Unicode character. For more information, see Character Sets Used By Fonts.
This type is declared in WinNT.h as follows:
typedef wchar_t WCHAR;
Here is a link showing how to convert between various string types String Conversion Samples.

converting narrow string to wide string

How can i convert a narrow string to a wide string ?
I have tried this method :
string myName;
getline( cin , myName );
wstring printerName( L(myName) ); // error C3861: 'L': identifier not found
wchar_t* WprinterName = printerName.c_str(); // error C2440: 'initializing' : cannot convert from 'const wchar_t *' to 'wchar_t *'
But i get errors as listed above.
Why do i get these errors ? How can i fix them ?
Is there any other method of directly converting a narrow string to a wide string ?
If the source is ASCII encoded, you can just do this:
wstring printerName;
printerName.assign( myName.begin(), myName.end() );
You should do this :
inline std::wstring convert( const std::string& as )
{
// deal with trivial case of empty string
if( as.empty() ) return std::wstring();
// determine required length of new string
size_t reqLength = ::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), 0, 0 );
// construct new string of required length
std::wstring ret( reqLength, L'\0' );
// convert old string to new string
::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), &ret[0], (int)ret.length() );
// return new string ( compiler should optimize this away )
return ret;
}
This expects the std::string to be UTF-8 (CP_UTF8), when you have another encoding replace the codepage.
Another way could be :
inline std::wstring convert( const std::string& as )
{
wchar_t* buf = new wchar_t[as.size() * 2 + 2];
swprintf( buf, L"%S", as.c_str() );
std::wstring rval = buf;
delete[] buf;
return rval;
}
I found this while googling the problem. I have pasted the code for reference. Author of this post is Paul McKenzie.
std::string str = "Hello";
std::wstring str2(str.length(), L' '); // Make room for characters
// Copy string to wstring.
std::copy(str.begin(), str.end(), str2.begin());
ATL (non-express editions of Visual Studio) has a couple useful class types which can convert the strings plainly. You can use the constructor directly, if you do not need to hold onto the string.
#include <atlbase.h>
std::wstring wideString(L"My wide string");
std::string narrowString("My not-so-wide string");
ATL::CW2A narrow(wideString.c_str()); // narrow is a narrow string
ATL::CA2W wide(asciiString.c_str()); // wide is a wide string
Here are two functions that can be used: mbstowcs_s and wcstombs_s.
mbstowcs_s: Converts a sequence of multibyte characters to a corresponding sequence of wide characters.
wcstombs_s: Converts a sequence of wide characters to a corresponding sequence of multibyte characters.
errno_t wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes,
const wchar_t *wcstr,
size_t count
);
errno_t mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count
);
See http://msdn.microsoft.com/en-us/library/eyktyxsx.aspx and http://msdn.microsoft.com/en-us/library/s7wzt4be.aspx.
The Windows API provides routines for doing this: WideCharToMultiByte() and MultiByteToWideChar(). However, they are a pain to use. Each conversion requires two calls to the routines and you have to look after allocating/freeing memory and making sure the strings are correctly terminated. You need a wrapper!
I have a convenient C++ wrapper on my blog, here, which you are welcome to use.
The original question of this thread was: "How can i convert a narrow string to a wide string?"
However, from the example code given in the question, there seems to be no conversion necessary. Rather, there is a compiler error due to the newer compilers deprecating something that used to be okay. Here is what I think is going on:
// wchar_t* wstr = L"A wide string"; // Error: cannot convert from 'const wchar_t *' to 'wchar_t *'
wchar_t const* wstr = L"A wide string"; // okay
const wchar_t* wstr_equivalent = L"A wide string"; // also okay
The c_str() seems to be treated the same as a literal, and is considered a constant (const). You could use a cast. But preferable is to add const.
The best answer I have seen for converting between wide and narrow strings is to use std::wstringstream. And this is one of the answers given to C++ Convert string (or char*) to wstring (or wchar_t*)
You can convert most anything to and from strings and wide strings using stringstream and wstringstream.
This article published on the MSDN Magazine 2016 September issue discusses the conversion in details using Win32 APIs.
Note that using MultiByteToWideChar() is much faster than using the std:: stuff on Windows.
Use mbtowc():
string myName;
wchar_t wstr[BUFFER_SIZE];
getline( cin , myName );
mbtowc(wstr, myName, BUFFER_SIZE);