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.
Related
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.
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.
I have to work with an API that is using Microsoft's TCHAR macros and such, so I was wondering if I could use C++ in a way to simplify the task. So i was wondering if there is a way to support implicit conversion and why/why not std::string doesn't support converting from a smaller char size:
#include <Windows.h>
using String = std::basic_string<TCHAR>; // say TCHAR = wchar_t or equivalent
String someLiteralString = "my simple ansi string"; // Error here obviously
// some polymorphic class...
const TCHAR* MyOverriddenFunction() override { return someLiteralString.c_str(); }
// end some polymorphic class
The reason implicit conversion isn't supported is that conversion can be complicated. The simple case is when the string to convert is pure ASCII as in your example, but there's no way to guarantee that. The creators of the standard wisely stayed away from that problem.
If you don't know whether your strings are wide-character or not, you can use Microsoft's _T() macro around each string literal to generate the proper characters. But you say you don't want to do that.
Modern Windows programming always uses wide characters in the API. Chances are your program is too, otherwise the code you've shown would not cause an error. It's very unlikely that once you've used wide characters you'll switch back to narrow ones. A simple one-character change to your literals will make them wide-character to match the string type:
String someLiteralString = L"my simple ansi string";
Use the (ATL/MFC) CStringT class, it will make your life much easier.
http://msdn.microsoft.com/en-us/library/ms174284(v=vs.80).aspx
I have a function which takes two CHAR* as input viz. int _stdcall FileTrans(char* InFile, char* OutFile) in a DLL project.
In the function I'm just calling CopyFile(InFile, OutFile, false); after some process (not related to the files). But it says that it needs both inputs as LPCWSTR. I Googled it but couldn't find anything very interesting.
Like all Windows API functions that accept a string parameter, there are actually two variants of the CopyFile function:
CopyFileA is the ANSI version, which takes narrow (non-Unicode) strings in the system's default character set. Basically, it accepts parameters of type const char*, but the Windows headers use the typedef LPCSTR for this.
CopyFileW is the wide version, which takes Unicode strings. In order to do this, it accepts parameters of type w_char*, but the Windows headers use the typedef LPCWSTR for this (note the additional W in the typedef).
Then, depending on whether the UNICODE preprocessor macro is defined for your project (either in your code before you include the Windows headers, or in your project's properties in Visual Studio), the Windows headers define the unadorned CopyFile as either CopyFileA or CopyFileW. Naturally, if UNICODE is defined, CopyFile will be defined as the Unicode version CopyFileW. Otherwise, it will be defined as CopyFileA. The idea is that the call to the general CopyFile function is automatically resolved at compile time to the correct variant.
Of course, now that you understand all of that, you can mostly forget about it. In modern Windows programming, there is absolutely no reason to call the old ANSI versions of functions or to deal with narrow strings at all. Forget that char* can even be used as a string type—those strings are dead to you. The only strings you're going to be using from now on are Unicode strings, composed of wchar_t characters. Thus the UNICODE symbol should always be defined for your code, and you should only use the W version of Windows API functions.
Looking again at the prototype for the CopyFileW function (the same one you get when you call CopyFile with UNICODE defined), we see:
BOOL WINAPI CopyFile(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
BOOL bFailIfExists);
Recall that you learned above that LPCWSTR is just a typedef synonym for const wchar_t*, a C-style string that is composed of wide characters. You already know why the parameters are marked const: because the function doesn't modify those values.
And because you also learned above that these are the only types of strings that you should be using anymore, the next step is to modify your FileTrans function to accept wide strings (and make them const if it's not going to modify them):
int _stdcall FileTrans(const wchar_t* InFile, const wchar_t* OutFile);
Now, from inside of FileTrans, you can call CopyFile without any problems because you have the right type of strings.
But a bit of free, extra advice: never use raw C-style strings in C++. Always use the C++ string class, defined in the std namespace by the <string> header.
There are two common variants of this class, std::string and std::wstring. As before, the w refers to wide strings, which are the only type you want to use in Windows. So std::wstring is your new replacement for CHAR* throughout your code base.
Change your declaration of the FileTrans function to look like this:
#include <string>
// ...some other stuff...
int __stdcall FileTrans(const std::wstring& InFile, const std::wstring& OutFile);
Note that I've changed your original CHAR* parameters to constant references to std::wstring objects. Constant references work well here, since you're not going to be changing either of those values inside of the function.
If you're unclear on what constant means, how to use references, or how class types generally work in C++, please consult your favorite C++ book)—this is required knowledge for all C++ programmers. Remember that C++ is not the same language as C and therefore the same idioms do not apply. In many cases, there is a better way to do things, and this is certainly an example of such a case.
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