How to use FindResourceW() Properly? - c++

A simple example here I want to load some embedded text file to my application but when I use FindResourceW I get compile-time error:
HGLOBAL res_handle = NULL;
HRSRC res;
wchar_t* res_data;
DWORD res_size;
// NOTE: providing g_hInstance is important, NULL might not work
res = FindResourceW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(MY_RESOURCE), RT_RCDATA);
if (!res)
return 1;
In my .rc file I defined the resource like this:
MY_RESOURCE RCDATA L"Help topics.txt"
The error:
Severity Code Description Project File Line Error C2664 'HRSRC
FindResourceW(HMODULE,LPCWSTR,LPCWSTR)': cannot convert argument 3
from 'LPSTR' to
'LPCWSTR' FindFilesProj C:\Users\WongFei\Desktop\FindFilesProj
UNICODE\WinMain.cpp 674

You are using RT_RCDATA, which is defined as:
#define RT_RCDATA MAKEINTRESOURCE(10)
And MAKEINTRESOURCE() is defined as:
#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
#ifdef UNICODE
#define MAKEINTRESOURCE MAKEINTRESOURCEW
#else
#define MAKEINTRESOURCE MAKEINTRESOURCEA
#endif // !UNICODE
You have a project were UNICODE isn't defined. So MAKEINTRESOURCE() returns a char* but FindeResourceW() wants a wchar_t* instead. Thus the compiler error. You can't use RT_RCDATA as-is in combination with FindResourceW() when UNICODE isn't defined.
Use FindResource() instead of FindResourceW(). This makes sure that MAKEINTRESOURCE() returns a pointer of the same type (UNICODE or non-UNICODE) that FindResource() expects:
res = FindResource(GetModuleHandle(NULL), MAKEINTRESOURCE(MY_RESOURCE), RT_RCDATA);
Otherwise, you have to type-cast RT_RCDATA to wchar_t* to match what FindResourceW() expects:
res = FindResourceW(GetModuleHandleW(NULL), MAKEINTRESOURCEW(MY_RESOURCE), (LPWSTR)RT_RCDATA);
The type-cast is safe.
Remember that your resource is stored in the way you created it. There may be need to convert it into the proper character mode you need.

Related

converting between const wchar_t* and const char* and the reverse using macros

I'm trying to make my win32 program interchangeable between character sets (Unicode and Multi-Byte) the macros such as CreateWindowEx() use wchar_t* and char* depending on the set and for my class name I have it stored in a variable in a windowClass Class.
static constexpr const wchar_t* wndClassName = L"windowclass";
at the moment for other functions I've been using macros I have created defined in a header file
#pragma once
#include <sstream>
#ifdef _UNICODE
#define ConstString(constStringIn) (std::wstringstream() << constStringIn).str().c_str() //used as arguments in functions
#define STRINGALIASMACRO wchar_t* //Used as function return tpyes and wndClassName
#endif // _UNICODE
#ifdef _MBCS
#define ConstString(constStringIn) (std::stringstream() << constStringIn).str().c_str()
#define STRINGALIASMACRO char*
#endif // _MBCS
when trying to replace the wchar_t* with STRINGALIASMACRO and ConstString("windowclass") for the wndClassName variable value the error expression must have a constant value
What could I do to fix this and is it good practice to use macros as type definitions and return types instead of e.g typedef wchar_t* STRINGALIAS I did try this and I got a whole bunch of other errors.
The Win32 API (and the C runtime library) already provide their own sets of preprocessor macros for this exact purpose. Look at:
TCHAR/_TCHAR = char or wchar_t
LP(C)TSTR = (const) char* or (const) wchar_t*
TEXT("literal")/_T("literal") = "literal" or L"literal"
TEXT('literal')/_T('literal') = 'literal' or L'literal'
For example:
#pragma once
#include <windows.h>
#define ConstString(constStringIn) TEXT(constStringIn) //used as arguments in functions
typedef LPTSTR STRINGALIASMACRO; //Used as function return tpyes and wndClassName
typedef LPCTSTR CONSTSTRINGALIASMACRO; //Used as function return tpyes and wndClassName
static constexpr CONSTSTRINGALIASMACRO wndClassName = ConstString("windowclass");
Or simply:
static constexpr LPCTSTR wndClassName = TEXT("windowclass");
See the following for more details:
Win32 Data Types
Working With Strings
Generic-Text Mappings in tchar.h
What are TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR (etc.)?

'HMODULE LoadLibraryA(LPCSTR)': cannot convert argument 1 from 'const _Elem *' to 'LPCSTR'

in the vc++ I have a solution with two projects. project A has a dllLoader.h and dllLoader.cpp which loads a dll with LoadLibrary and I need to call its functions in Project B. So I did Copy and Paste the header and cpp file to Project B.
Project A Main.cpp
------------------
#include "../Plugin/DllLoader.h"
#include "../Plugin/Types.h"
int main(){
std::string str("plugin.dll");
bool scuccessfulLoad = LoadDll(str);}
and here is the dllLoader in Project A (the mirror/copy in Project B get changed with changes here)
bool LoadDll(std::string FileName)
{
std::wstring wFileName = std::wstring(FileName.begin(), FileName.end());
HMODULE dllHandle1 = LoadLibrary(wFileName.c_str());
if (dllHandle1 != NULL)
{ ****
return TRUE;
}
Building the project itself does not show any error and get successfully done, but when I build the Solution (which contains other projects) I get the error
C2664 'HMODULE LoadLibraryA(LPCSTR)': cannot convert argument 1 from
'const _Elem *' to 'LPCSTR'
Your LoadDll() function takes a std::string as input, converts it (the wrong way 1) to std::wstring, and then passes that to LoadLibrary(). However, LoadLibrary() is not a real function, it is a preprocessor macro that expands to either LoadLibraryA() or LoadLibraryW() depending on whether your project is configured to map TCHAR to char for ANSI or wchar_t for UNICODE:
WINBASEAPI
__out_opt
HMODULE
WINAPI
LoadLibraryA(
__in LPCSTR lpLibFileName
);
WINBASEAPI
__out_opt
HMODULE
WINAPI
LoadLibraryW(
__in LPCWSTR lpLibFileName
);
#ifdef UNICODE
#define LoadLibrary LoadLibraryW
#else
#define LoadLibrary LoadLibraryA
#endif // !UNICODE
In your situation, the project that is failing to compile is configured for ANSI, thus the compiler error because you are passing a const wchar_t* to LoadLibraryA() where a const char* is expected instead.
The simplest solution is to just get rid of the conversion altogether and call LoadLibraryA() directly:
bool LoadDll(std::string FileName)
{
HMODULE dllHandle1 = LoadLibraryA(FileName.c_str());
...
}
If you still want to convert the std::string to std::wstring 1, then you should call LoadLibraryW() directly instead:
bool LoadDll(std::string FileName)
{
std::wstring wFileName = ...;
HMODULE dllHandle1 = LoadLibraryW(wFileName.c_str());
...
}
This way, your code always matches your data and is not dependent on any particular project configuration.
1: the correct way to convert a std::string to a std::wstring is to use a proper data conversion method, such as the Win32 MultiByteToWideChar() function, C++11's std::wstring_convert class, a 3rd party Unicode library, etc. Passing std::string iterators to std::wstring's constructor DOES NOT perform any conversions, it simply expands the char values as-is to wchar_t, thus any non-ASCII char values > 0x7F will NOT be converted to Unicode correctly (UTF-16 is Windows's native encoding for wchar_t strings). Only the 7-bit ASCII characters (0x00 - 0x7F) are the same values in ASCII, ANSI codepages, Unicode UTF encodings, etc. Higher-valued characters require conversion.
You pass a wide string to the function. So the code is clearly intended to be compiled targeting UNICODE, so that the LoadLibrary macro expands to LoadLibraryW. But the project in which the code fails does not target UNICODE. Hence the macro here expands to LoadLibraryA. And hence the compiler error because you are passing a wide string.
The problem therefore is that you have inconsistent compiler settings across different projects. Review the project configuration for the failing project to make sure that consistent conditionals are defined. That is, make sure that the required conditionals (presumably to enable UNICODE) are defined in all of the projects that contain this code.

error C2664: 'wsprintfW' : cannot convert parameter 1 from 'char *' to 'LPWSTR'

I copied some code from a VC6 project to a vc++2010 project, but the code cannot be compiled.
the error is 'wsprintfW' : cannot convert parameter 1 from 'char *' to 'LPWSTR', problem code is:
inline bool RingCtrl::BuildPathAndName(char* pBuf, int bufSize, int8 priority, int idxNumber) const
{
wsprintf(pBuf, "%s\\R%u%06x.DAT", _directory, (int)priority, idxNumber);
return true;
}
the wsprintf is defined in wmcommn.h like below:
WINUSERAPI
int
WINAPIV
wsprintfA(
__out LPSTR,
__in __format_string LPCSTR,
...);
WINUSERAPI
int
WINAPIV
wsprintfW(
__out LPWSTR,
__in __format_string LPCWSTR,
...);
#ifdef UNICODE
#define wsprintf wsprintfW
#else
#define wsprintf wsprintfA
#endif
You are building your program with UNICODE defined (default in VC++2010), while it was not defined in VC6. When UNICODE is defined wsprintf takes wchar_t* instead of char* as a first parameter (and const wchar_t* instead of const char* as a second one).
Easy solution would be to explicitly call wsprintfA instead of wsprintf in RingCtrl::BuildPathAndName, but in this case you'll have a problems with Unicode file names. You'll probably have a lot of other similar errors connected to UNICODE and _UNICODE, so you may want to change your project settings in VC++2012: Project Properties->General->Character Set->Use Multi-Byte Character Set.
Correct solution would be to move from char* to wchar_t* (or even better to TCHAR*), but that would probably require a lot of effort.

Converting from const char * to LPTSTR without USES_CONVERSTION

I am trying to convert const char * to LPTSTR. But i do not want to use USES_CONVERSION to perform that.
The following is the code i used to convert using USES_CONVERSION. Is there a way to convert using sprintf or tcscpy, etc..?
USES_CONVERSION;
jstring JavaStringVal = (some value passed from other function);
const char *constCharStr = env->GetStringUTFChars(JavaStringVal, 0);
LPTSTR lpwstrVal = CA2T(constCharStr); //I do not want to use the function CA2T..
LPTSTR has two modes:
An LPWSTR if UNICODE is defined, an LPSTR otherwise.
#ifdef UNICODE
typedef LPWSTR LPTSTR;
#else
typedef LPSTR LPTSTR;
#endif
or by the other way:
LPTSTR is wchar_t* or char* depending on _UNICODE
if your LPTSTR is non-unicode:
according to MSDN Full MS-DTYP IDL documentation, LPSTR is a typedef of char *:
typedef char* PSTR, *LPSTR;
so you can try this:
const char *ch = "some chars ...";
LPSTR lpstr = const_cast<LPSTR>(ch);
USES_CONVERSION and related macros are the easiest way to do it. Why not use them? But you can always just check whether the UNICODE or _UNICODE macros are defined. If neither of them is defined, no conversion is necessary. If one of them is defined, you can use MultiByteToWideChar to perform the conversion.
Actually that's a silly thing to do. JNIEnv alreay has a method to get the characters as Unicode: JNIEnv::GetStringChars. So just check for the UNICODE and _UNICODE macros to find out which method to use:
#if defined(UNICODE) || defined(_UNICODE)
LPTSTR lpszVal = env->GetStringChars(JavaStringVal, 0);
#else
LPTSTR lpszVal = env->GetStringUTFChars(JavaStringVal, 0);
#endif
In fact, unless you want to pass the string to a method that expects a LPTSTR, you should just use the Unicode version only. Java strings are stored as Unicode internally, so you won't get the overhead of the conversion, plus Unicode strings are just better in general.

error C2664: 'CComboBox::InsertString' : cannot convert parameter 2 from 'const char [4]' to 'LPCTSTR'

I am trying to do the following:
class sig
{
CComboBox objList;
void SetDefault();
}
void sig :: SetDefault()
{
objList.InsertString(0, METHOD_ONE);
}
I have defined METHOD_ONE in a different class as
#define METHOD_ONE "OFF"
And I get the above error.
Can somebody please help me?
Cheers,
Chintan
The most important part is to understand the error; know what is a const char [4], is the easy part but, what about the LPCTSTR?
According to the Microsoft documentation:
An LPCWSTR if UNICODE is defined, an LPCSTR otherwise. For more
information, see Windows Data Types for Strings.
And the LPCWSTR is:
A pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.
First, you must check out what type of encoding are using your program; it seems that you're using UNICODE, so in the end you're trying to convert a const pointer to chars (the "OFF" constant) to a const pointer to wchar_t, and (logically) the conversion isn't allowed.
Then, you can choose the correct string type; if UNICODE is defined, your #define must be wide string:
// Note the L
#define METHOD_ONE L"OFF"
You can also define it this way:
#ifdef UNICODE
#define METHOD_ONE L"OFF"
#else
#define METHOD_ONE "OFF"
#endif
Or use the _T macro suggested by Roman R. The only that this macro does is to append L prefix to the text:
#ifdef UNICODE
#define _T(x) L ##x
#else
#define _T(x) x
#endif
In the end, you must be aware of what kind of string are using; but Microsoft is hidding it by using an obscure chain of #defines and typedefs.