MultiByteToWideChar doesn't work properly - c++

I'm trying to use MultiByteToWideChar api. for lpWideCharStr, when I use a pointer with dynamic memory allocation, it works properly. but now I should use a pointer with static memory allocation as you see in the code. and it doesn't work properly, return 0.
what's wrong with it?
how should I use a static memory allocated pointer for lpWideCharStr in MultiByteToWideChar?
thank's for your solutions.
#include <windows.h>
#include <iostream>
#include "Shlwapi.h"
#pragma comment(lib,"shlwapi.lib")
void main(int argc, char *argv[]){
int iToSizeB = 0;
iToSizeB = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1 , NULL, 0);
LPWSTR lpFileAddress[260] = {0};
int nResult = 0;
//MultiByteToWideChar function reurns 0 !!!
nResult = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, lpFileAddress[0], iToSizeB);
}

Probably you mean this:
WCHAR lpFileAddress[260] = {0};
nResult = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, lpFileAddress, iToSizeB);
In your code, you define array of WCHAR pointers: LPWSTR lpFileAddress[260] instead of WCHAR array, as required: WCHAR lpFileAddress[260] = {0};

Related

Is it necessary to avoid memory leak when returning pointer by using shared_ptr?

I have two functions for converting char array from gb2321 to utf-8 like,
#include <windows.h>
#include "memory.h"
#include <wchar.h>
#include <iostream>
using namespace std;
//GB2312 to UTF-8
char* G2U(const char* gb2312)
{
int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
//what about using shared_ptr to release resource but how to modify following code?
//shared_ptr<char> str(new char[len + 1], default_delete<char[]>());
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
if (wstr) delete[] wstr;
return str;
}
I read this code part in website and I was wondering if I should replace char* str = new char[len + 1]; with shared_ptr. If so, how to modify the following code, memset and WideCharToMultiByte? P.S, is there some method used by C not CPP ?
Instead of managing a raw pointer, or even a shared_ptr to manage a char pointer, you can simply use std::vector.
It has a constructor that accepts a size and a value (thus you don't need memset). You can use std::vector::data to access the underlying data buffer.
Below you can see an example for str. A similar solution can be applied to wstr.
#include <vector>
std::vector<char> str(len + 1, 0); // allocate size and set all elements to 0
//----------------------------------------vvvvvvvvvv
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str.data(), len, NULL, NULL);
Note:
In general it could be more straightforward using std::string. But until C++17 std::string::data returns a const char* which is incompatible with the Win32 API pointer which is used to write data into.
You can still return std::string from your G2U function, by using:
return std::string(str.begin(), str.end());
If you can use C++17 you can use std::string instead of std::vector<char> and then you will be able to return str directly.
Update:
Regarding the "P.S." at the end of your question - as far as I know the c language has no mechanism for automatic heap memory management.

Windows System Programming OpenFile function

The documentation for OpenFile function in Windows is located here. And I am trying to do this:
#include "Tchar.h"
#include <windows.h>
int main(int argc, TCHAR *argv[]){
LPOFSTRUCT _buffer;
HFILE _hfile_ = OpenFile("E:\\mozunit.txt", _buffer, OF_READ);
LPVOID _buffer_read;
LPDWORD _bytes_read;
bool flag = ReadFile(_buffer, _buffer_read, 5, _bytes_read, NULL);
CloseHandle(_buffer);
return 0;
}
Now, when I run this I get an error that I have not initialized the _buffer. So to counter that I initialized _buffer like this:
LPOFSTRUCT _buffer = NULL;
Which gives me an access violation error. Why is that?
According to the documentation, the second argument is...
A pointer to the OFSTRUCT structure that receives information about a file when it is first opened.
By setting it to NULL you're attempting to write to memory with the address of zero.
Try this instead:
OFSTRUCT buffer;
HFILE hfile = OpenFile("E:\\mozunit.txt", &buffer, OF_READ);
char buffer_read[6];
DWORD bytes_read = 0;
bool flag = ReadFile(hfile, &buffer_read, 5, &bytes_read, NULL);
CloseHandle(hfile);
You need to pass a pointer to an allocated LPOFSTRUCT object to OpenFile. You are passing NULL to a function that expects a valid memory, not NULL. You declare an OFSTRUCT object and pass a pointer to it to OpenFile
You have the same issue for the parameters that you pass in ReadFile. And you need to call CloseFile on the _hFile_ file handle, not on the _buffer. The same goes for ReadFile Finally you shouldn't be using OpenFile anyway - you should be using CreateFile as the documentation states.
Your code should be something more like:
#include "Tchar.h"
#include <windows.h>
int main(int argc, TCHAR *argv[]){
OFSTRUCT _buffer = {0}; // Create an OFSTRUCT structure local variable and initialize it to zero.
HFILE _hfile_ = OpenFile("E:\\mozunit.txt", &_buffer, OF_READ);
char _buffer_read[5];
DWORD _bytes_read;
bool flag = ReadFile(_hfile_ , _buffer_read, 5, &_bytes_read, NULL);
CloseHandle(_hfile_ );
return 0;
}

RegSetValueEx and CHAR

consider the following code
addHash("hash");
bool addHash(char* hash) {
HKEY hKey = 0;
int code = RegOpenKey(HKEY_CURRENT_USER, subkey, &hKey);
const int length = strlen(hash)+1;
WCHAR whash[100];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hash, strlen(hash), whash, 100);
LONG setRes = RegSetValueEx(hKey, L"hash", 0, REG_SZ, (LPBYTE)whash, strlen(hash)+1);
return true;
}
After code is compiled and executed "ha" is puted into registry. Can somebody tell me where the problem is?
Thank you in advance!
The last argument is the number of bytes, not the number of characters, that the second last argument points to.
So the first five bytes (strlen(hash) + 1) of whash will be stored in the registry. Change to:
LONG setRes = RegSetValueEx(hKey,
L"hash",
0,
REG_SZ,
(LPBYTE)whash,
(wcslen(whash) + 1) * sizeof(WCHAR));
You may also need to initialise whash (I don't think MultiByteToWideChar() adds a null terminator for you):
WCHAR whash[100] = { 0 };
I think this is what you are trying to do:
#include <tchar.h>
#include <Windows.h>
using namespace std;
bool addHash(wstring hash) {
const wchar_t* wHash = hash.c_str();
LONG ret = RegSetKeyValue(HKEY_CURRENT_USER, _T("Software\\aa\\test"), _T("hash"), REG_SZ, wHash, hash.length() * sizeof(wchar_t));
return (ret == ERROR_SUCCESS);
}
int main()
{
addHash(_T("A42B2094EDC43"));
return 0;
}
Hope this helps ;)

How to convert from wchar_t to LPSTR?

How can I convert a string from wchar_t to LPSTR.
A wchar_t string is made of 16-bit units, a LPSTR is a pointer to a string of octets, defined like this:
typedef char* PSTR, *LPSTR;
What's important is that the LPSTR may be null-terminated.
When translating from wchar_t to LPSTR, you have to decide on an encoding to use. Once you did that, you can use the WideCharToMultiByte function to perform the conversion.
For instance, here's how to translate a wide-character string into UTF8, using STL strings to simplify memory management:
#include <windows.h>
#include <string>
#include <vector>
static string utf16ToUTF8( const wstring &s )
{
const int size = ::WideCharToMultiByte( CP_UTF8, 0, s.c_str(), -1, NULL, 0, 0, NULL );
vector<char> buf( size );
::WideCharToMultiByte( CP_UTF8, 0, s.c_str(), -1, &buf[0], size, 0, NULL );
return string( &buf[0] );
}
You could use this function to translate a wchar_t* to LPSTR like this:
const wchar_t *str = L"Hello, World!";
std::string utf8String = utf16ToUTF8( str );
LPSTR lpStr = utf8String.c_str();
I use this
wstring mywstr( somewstring );
string mycstr( mywstr.begin(), mywstr.end() );
then use it as mycstr.c_str()
(edit, since i cannot comment) this is how i used this, and it works fine:
#include <string>
std::wstring mywstr(ffd.cFileName);
std::string mycstr(mywstr.begin(), mywstr.end());
pRequest->Write(mycstr.c_str());

How do I use MultiByteToWideChar?

I want to convert a normal string to a wstring. For this, I am trying to use the Windows API function MultiByteToWideChar.
But it does not work for me.
Here is what I have done:
string x = "This is c++ not java";
wstring Wstring;
MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring , 0 );
The last line produces the compiler error:
'MultiByteToWideChar' : cannot convert parameter 5 from 'std::wstring *' to 'LPWSTR'
How do I fix this error?
Also, what should be the value of the argument cchWideChar? Is 0 okay?
You must call MultiByteToWideChar twice:
The first call to MultiByteToWideChar is used to find the buffer size you need for the wide string. Look at Microsoft's documentation; it states:
If the function succeeds and cchWideChar is 0, the return value is the required size, in characters, for the buffer indicated by lpWideCharStr.
Thus, to make MultiByteToWideChar give you the required size, pass 0 as the value of the last parameter, cchWideChar. You should also pass NULL as the one before it, lpWideCharStr.
Obtain a non-const buffer large enough to accommodate the wide string, using the buffer size from the previous step. Pass this buffer to another call to MultiByteToWideChar. And this time, the last argument should be the actual size of the buffer, not 0.
A sketchy example:
int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, NULL , 0 );
wchar_t* wstr = new wchar_t[wchars_num];
MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, wstr , wchars_num );
// do whatever with wstr
delete[] wstr;
Also, note the use of -1 as the cbMultiByte argument. This will make the resulting string null-terminated, saving you from dealing with them.
Few common conversions:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <string>
std::string ConvertWideToANSI(const std::wstring& wstr)
{
int count = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
std::string str(count, 0);
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
return str;
}
std::wstring ConvertAnsiToWide(const std::string& str)
{
int count = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), NULL, 0);
std::wstring wstr(count, 0);
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), &wstr[0], count);
return wstr;
}
std::string ConvertWideToUtf8(const std::wstring& wstr)
{
int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
std::string str(count, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
return str;
}
std::wstring ConvertUtf8ToWide(const std::string& str)
{
int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
std::wstring wstr(count, 0);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], count);
return wstr;
}
You can try this solution below. I tested, it works, detect special characters (example: º ä ç á ) and works on Windows XP, Windows 2000 with SP4 and later, Windows 7, 8, 8.1 and 10.
Using std::wstring instead new wchar_t / delete, we reduce problems with leak resources, overflow buffer and corrupt heap.
dwFlags was set to MB_ERR_INVALID_CHARS to works on Windows 2000 with SP4 and later, Windows XP. If this flag is not set, the function silently drops illegal code points.
std::wstring ConvertStringToWstring(const std::string &str)
{
if (str.empty())
{
return std::wstring();
}
int num_chars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), NULL, 0);
std::wstring wstrTo;
if (num_chars)
{
wstrTo.resize(num_chars);
if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), &wstrTo[0], num_chars))
{
return wstrTo;
}
}
return std::wstring();
}
Second question about this, this morning!
WideCharToMultiByte() and MultiByteToWideChar() 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.
Here's the other question this morning
The function cannot take a pointer to a C++ string. It will expect a pointer to a buffer of wide characters of sufficient size- you must allocate this buffer yourself.
string x = "This is c++ not java";
wstring Wstring;
Wstring.resize(x.size());
int c = MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring[0], 0 );