CFileImageLoader(LPCTSTR lpszFileName); - c++

I have a class which expects a LPCTSTR.
When i call :
new CFileImageLoader(_T("Splash02.png"))
OR
new CFileImageLoader("Splash02.png")
both don't work.
Why ?
I'm new to cpp...
Thanks
Jonathan d.

This issue is a combination of C++ issues and Windows specific issues.
C++ defines two types of strings, regular and wide. A regular string looks like:
const char *str = "regular string";
while a wide string looks like:
const wchar_t *wstr = L"wide string";
With just standard C++, you have to decide when you write your library whether to use regular or wide strings.
Windows has defined a pseudo type called tchar. With tchar you write something like:
LPCTSTR tstr = _T("regular or wide string");
Whether this is actually a regular (char *) or a wide (wchar_t *) string depends on whether you compile your code for Unicode or not.
Since the function is specified as taking an LPCTSTR, it needs to be called with the appropriate type for how you are compiling.
If you know you are only going to be building with or without Unicode support, you can skip all the TCHAR stuff and directly use either wchar_t or char respectively.
Since CFileImageLoader("Splash02.png") is not working, you must be compiling with Unicode support enabled. You can change that to CFileImageLoader(L"Splash02.png") and commit to always using Unicode or you can change it to CFileImageLoader(_T("Splash02.png")) and let the macro magic do the work.

"both don't work" - could you maybe be a tiny, tiny little bit more specific?
If you compile with _UNICODE defined, then the second shouldn't even compile.
You're also just passing a filename, not a full path. Maybe your image loader class can't find the file because it uses a differen CWD path as you expect. Try passing the full path instead.

Maybe your image library can't support to open PNG format file.
Try passing the full path instead.
Maybe you need to call some initialization functions which provide by your image library

Related

Qt5.9.9+Vs2017 encountered a character set problem [duplicate]

I'm learning to write and use DLLs and this is my first attempt at exporting a function from my dll. It works, but this line is what gave me trouble and what I've been able to find regarding the TEXT cast for UNICODE and ANSI I think I need some guidance. As far as I can find this question has not been asked elsewhere on the site so I apologize if anyone finds what I couldn't.
HINSTANCE hInstLibrary = LoadLibrary("MyDLL.dll");
My initial usage, from a short tutorial on explicit linking gives E0167 and C2664 errors regarding LPCWSTR type
HINSTANCE hInstLibrary = LoadLibrary(TEXT("MyDLL.dll"));
Casting the string to TEXT solves the problem, though I'm not sure why and would like to know
HINSTANCE hInstLibrary = LoadLibraryA("MyDLL.dll");
The line I decided to use in the working example. LoadLibraryA() expands LoadLibrary to accept ANSI rather than Wide, which may be the root of my misunderstanding. Why is this necessary when most examples I find show LoadLibrary("NameOfDLL.dll")?
Why does the string not satisfy the standard LoadLibrary() call?
LoadLibrary() is a preprocessor macro. It maps to either LoadLibraryW() or LoadLibraryA() depending on whether UNICODE is defined or not, respectively. LoadLibraryW() takes a const wchar_t* string as input, while LoadLibraryA() takes a const char * string instead.
The string literal "MyDLL.dll" is a const char[10], which decays into a const char *. If UNICODE is defined, LoadLibrary("MyDLL.dll") will fail to compile, as you cannot pass a const char * where a const wchar_t * is expected.
TEXT() is also a preprocessor macro. If UNICODE is defined, it appends an L prefix to the specified literal making the literal use wchar_t, otherwise no prefix is added and the literal uses char instead.
Thus, if UNICODE is defined, then LoadLibrary(TEXT("MyDLL.dll")) is compiled as LoadLibraryW(L"MyDLL.dll"), otherwise it is compiled as LoadLibraryA("MyDLL.dll") instead.
A majority of Win32 APIs that deal with textual data have similar A and W versions, and corresponding UNICODE-aware preprocessor macros. So, when using character/string literals with these APIs, you should always use the TEXT() macro. Otherwise, just use the A and W APIs directly as needed, depending on the type of textual data you are working with.

Exporting functions from DLLs, LoadLibrary() needs the string cast with TEXT to compile without error

I'm learning to write and use DLLs and this is my first attempt at exporting a function from my dll. It works, but this line is what gave me trouble and what I've been able to find regarding the TEXT cast for UNICODE and ANSI I think I need some guidance. As far as I can find this question has not been asked elsewhere on the site so I apologize if anyone finds what I couldn't.
HINSTANCE hInstLibrary = LoadLibrary("MyDLL.dll");
My initial usage, from a short tutorial on explicit linking gives E0167 and C2664 errors regarding LPCWSTR type
HINSTANCE hInstLibrary = LoadLibrary(TEXT("MyDLL.dll"));
Casting the string to TEXT solves the problem, though I'm not sure why and would like to know
HINSTANCE hInstLibrary = LoadLibraryA("MyDLL.dll");
The line I decided to use in the working example. LoadLibraryA() expands LoadLibrary to accept ANSI rather than Wide, which may be the root of my misunderstanding. Why is this necessary when most examples I find show LoadLibrary("NameOfDLL.dll")?
Why does the string not satisfy the standard LoadLibrary() call?
LoadLibrary() is a preprocessor macro. It maps to either LoadLibraryW() or LoadLibraryA() depending on whether UNICODE is defined or not, respectively. LoadLibraryW() takes a const wchar_t* string as input, while LoadLibraryA() takes a const char * string instead.
The string literal "MyDLL.dll" is a const char[10], which decays into a const char *. If UNICODE is defined, LoadLibrary("MyDLL.dll") will fail to compile, as you cannot pass a const char * where a const wchar_t * is expected.
TEXT() is also a preprocessor macro. If UNICODE is defined, it appends an L prefix to the specified literal making the literal use wchar_t, otherwise no prefix is added and the literal uses char instead.
Thus, if UNICODE is defined, then LoadLibrary(TEXT("MyDLL.dll")) is compiled as LoadLibraryW(L"MyDLL.dll"), otherwise it is compiled as LoadLibraryA("MyDLL.dll") instead.
A majority of Win32 APIs that deal with textual data have similar A and W versions, and corresponding UNICODE-aware preprocessor macros. So, when using character/string literals with these APIs, you should always use the TEXT() macro. Otherwise, just use the A and W APIs directly as needed, depending on the type of textual data you are working with.

Differences using std::string in C++ Builder and VC++

since I can get hands on the new RAD Studio Xe4 I thought I'd give it a try.
Unfortunatly, I am not so experienced with C++ and therefore I was wondering why the Code that works perfectly fine in VC++ doesn't work at all in C++ Builder.
Most of the problems are converting different var-types.
For example :
std::string Test = " ";
GetFileAttributes(Test.c_str());
works in VC++ but in C++ Builder it won't compile, telling me "E2034 Cannot convert 'const char *' to 'wchar_t *'.
Am I missing something? What is the reason that doesn't work the same on all compilers the same?
Thanks
Welcome to Windows Unicode/ASCII hell.
The function
GetFileAttributes
is actually a macro defined to either GetFileAttributesA or GetFileAttributesW depending on if you have _UNICODE (or was it UNICODE, or both?) defined when you include the Windows headers. The *A variants take char* and related arguments, the *W functions take wchar_t* and related arguments.
I suggest calling only the wide *W variants directly in new code. This would mean switching to std::wstring for Windows only code and some well-thought out design choices for a cross-platform application.
Your C++ Builder config is set to use UNICODE character set, which means that Win32 APIs are resolved to their wide character versions. Therefore you need to use wide char strings in your C++ code. If you would set your VS config to use UNICODE, you would get the same error.
You can try this:
// wstring = basic_string<wchar_t>
// _T macro ensures that the specified literal is a wide char literal
std::wstring Test = _T(" ");
GetFileAttributes(Test.c_str()); // c_str now returns const wchar_t*, not const char*
See more details about _T/_TEXT macros here: http://docwiki.embarcadero.com/RADStudio/XE3/en/TCHAR_Mapping
You have defined _UNICODE and/or UNICODE in Builder and not defined it in VC.
Most Windows APIs come in 2 flavours the ANSI flavour and the UNICODE flavour.
For, when you call SetWindowText, there really is no SetWindowText functions. Instead there are 2 different functions
- SetWindowTextA which takes an ANSI string
and
- SetWindowTextW which takes a UNICODE string.
If your program is compiled with /DUNICODE /D_UNICODE, SetWindowText maps to SetWindowTextWwhich expects aconst wchar_t *`.
If your program is compiled without these macros defined, it maps to SetWindowTextA which takes a const char *.
The windows headers typically do something like this to make this happen.
#ifdef UNICODE
#define SetWindowText SetWindowTextW
#else
#define SetWindowText SetWindowTextA
#endif
Likewise, there are 2 GetFileAttributes.
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName);
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName);
In VC, you haven't defined UNICODE/_UNICODE & hence you are able to pass string::c_str() which returns a char *.
In Builder, you probably have defined UNICODE/_UNICODE & it expects a wchar_t *.
You may not have done this UNICODE/_UNICODE thing explicitly - may be the IDE is doing it for you - so check the options in the IDE.
You have many ways of fixing this
find the UNICODE/_UNICODE option in the IDE and disable it.
or
use std::w_string - then c_str() will return a wchar_t *
or
Call GetFileAttributesA directly instead of GetFileAttributes - you will need to do this for every other Windows API which comes with these 2 variants.

C++ TCHAR[] to string

I have this method which receives a path through a TCHAR szFileName[] variable, which contains something like C:\app\...\Failed\
I'd like to sort through it so I can verify if the name of the last folder on that path is in fact, "Failed"
I thought that using something like this would work:
std::wstring Path = szFileName;
string dirpath2;
dirpath2 = Path.substr(0,5);
But I get the following error:
Error 6 error C2679: binary '=' : no
operator found which takes a
right-hand operand of type
'std::basic_string<_Elem,_Traits,_Ax>'
(or there is no acceptable
conversion)
Needless to say, I'm very new to C++, and I've been looking for an answer for a while now, but I haven't had any luck, so any help would be appreciated :)
Either you’re consistently using wstring (the wide character variant) or string (the “normal” variant).
Since you’re getting a TCHAR (which can be either wchar_t or char, depending on compiler flags), the appropriate type to use would be a tstring, but that doesn’t exist. However, you can define a typedef for it:
typedef std::basic_string<TCHAR> tstring;
Now you can consistently use the same string type, tstring, for all your operations.
dirpath2 has to be a std::wstring as well. There are ways to convert between the two, but they involve changing the character encoding and that seems like more than you're asking for.
I like to simply not use TCHAR. Today, there is rarely is there a need to enable or disable the UNICODE macros and create both an ASCII and a Unicode version of a program. Just always use wstring, wchar_t, and the Windows API functions that end in 'W'.
If you're working on something where you don't have control over the above, Konrad's typedef answer is more practical than mine.

How to declate a wide char constant in an IDL

We are migrating our C++ COM application to be unicode, and as part of this migration we want to migrate the constant strings in our IDL to unicode as well.
The problem is that at the moment, we still compile it both in ANSI and in UNICODE, which means that we can't use the L"String" construct to declare wide charts.
At the moment, our string constant defined like this:
const LPSTR STRING_CONST_NAME = "STRING VALUE";
And we want to define it like this:
const LPTSTR STRING_CONST_NAME = "STRING VALUE";
If it were regular code we would just add the _T("STRING VALUE") macro which would have converted it to L"STRING VALUE" when compiling in unicode
But from what I can see we can't use it in the IDL because _T is a pure C++ construct.
Is our approach even correct ? May be we should define it like this no matter what:
const LPTSTR STRING_CONST_NAME = L"STRING VALUE";
I wonder why you need to have string constants in the IDL file, anyway. Wouldn't it be sufficient to have them in a header file? I see that Microsoft has wide string literals only in sapiaut.idl (looking at all platform SDK IDL files); as those few constants are never used, this might have been a mistake, as well. Also notice that those constants are defined as BSTR.
If you want them in the IDL file, it might be sufficient to cpp_quote them.
If you absolutely want them in the IDL literally, you could use an #ifdef to have two different definitions. In that case, you should also have two different type libraries, with seperate sets of interfaces, with different UUIDs, and so on.
If it's supposed to always be Unicode, there's no use using the "T" constructs -- just do;
const LPCWSTR STRING_CONST_NAME = L"STRING VALUE";
"W" is for "wide"-
Not sure how the Windows-defined LPC*STR typedefs interplay with IDL, but if LPSTR worked, the wide variety should work, too.