I have been unable to find any decent documentation on this function. The code base I am working with uses a function from winuser.h called LoadStringW which takes as arguments: (HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax).
What is this function? What is it for? When might it return 0?
It might be worth a mention that nearly all Win32 APIs that deal with strings have an 'A' and a 'W' variant.
The variant actually called is determined by the definition of macros that don't end in 'A' or 'W' - those macro names are what you might usually think of as the API function's name (LoadString() in this case). UNICODE builds will use the 'W' names and non-UNICODE builds will use the 'A' names.
https://learn.microsoft.com/en-us/windows/desktop/Intl/unicode-in-the-windows-api
There are times when you might want to call a Unicode version of an API even if the build isn't Unicode, in which case you just directly use the name with the 'W' tacked on to the end (it's less often necessary to need to call the non-Unicode APIs in a Unicode build, but it's just as possible). Since the non-Unicode versions of Windows are obsolete, Microsoft has started more and more to implement only Unicode versions of APIs. Note that in nearly all cases, all that the non-Unicode versions of the APIs do is to convert the ANSI/MBCS strings to Unicode, call the 'W' function, then clean up afterward.
LoadStringW is the Unicode version of LoadString.
The documentation states "If the function succeeds, the return value is the number of TCHARs copied into the buffer, not including the terminating NULL character, or zero if the string resource does not exist. To get extended error information, call GetLastError."
Here is the documentation for LoadString(): http://msdn.microsoft.com/en-us/library/ms647486%28VS.85%29.aspx
.. and here is the documentation explaining the differences between ANSI and Unicode functions in the Windows API: http://msdn.microsoft.com/en-us/library/cc500321.aspx.
Basically, the function LoadString comes in two flavours, ANSI and Unicode. LoadStringW is the Unicode-specific version of LoadString.
Edit: Just to be clear, there aren't really two completely separate functions. The ANSI version really just converts the string and calls the unicode version, which does all of the real work.
LoadStringW() is the WideCharacter version of the LoadString function.
See MSDN
It loads a widestring from a stringtable resource using the Windows Unicode Layer for Win95 and NT 3.51. See MSDN for details (see the remarks section).
For the umpteenth time, I just confirmed that when the resource compiler is instructed to null terminate the strings, the count returned by LoadString includes the terminal NULL character. I did so by examining the output buffer that I made available to LoadString.
Resource strings are not null terminated by default. In that case, the returned count excludes the terminal null character, as described in the documentation, because the null is appended by the function after the string is copied into the output buffer.
I suspect this behavior is due to the fact that LoadString disregards the fact that the resource compiler was instructed to null terminate the strings. Indeed, I suspect that it has no way of knowing that they were.
With respect to why you would want to null terminate your resource strings in the first place, when they work just fine without them, and your PE file is thereby a tad smaller, the reason is that the wide character implementation of LoadString, at the LoadStringW entry point, returns a pointer to the string, rather than copying it into a buffer, if the buffer address passed into it is a NULL pointer. Unless your strings are null terminated, using LoadString in this way produces quite unwelcome results.
Since resource strings are always stored as Unicode (wide character) strings, the ANSI implementation of LoadString cannot return a pointer, as the string must be converted to ANSI; hence, it cannot simply be copied.
Related
I have a C/C++ winapi program that I'd like to extend a command line functionality to (which I've seen done in C#, but never C++). If the executable is opened with no arguments, it opens the window as normal, but when called from a command line with arguments such as an input or output file, the window does not open and all user interaction is done through the command line. How could I accomplish this? Preferably I'd like to be able to do it in C, as that's where my WinMain() function is.
Thanks in advance for any help!
There is LPSTR lpCmdLine parameter in WinMain. You can use CommandLineToArgvW function to parse lpCmdLine. When necessary parameters exist, you will not create or show program window and do the job.
There are several ways you can get the (parsed) command line arguments passed to your application.
Entry point
The CRT passes the command line into the user-provided entry point (WinMain) as the third argument. Depending on whether your application is compiled for Unicode or not this is either a wide character string or a narrow character string. Using the narrow character version cannot be guaranteed to work when accepting input you do not control. The command line is accepting input you do not control, so you must compile for Unicode (by defining the UNICODE and _UNICODE preprocessor symbols).
Either way, the command line is passed as a single character string. As such it is of limited utility unless you parse out the individual arguments.
Using the Windows API
The Windows API provides the GetCommandLineW function that allows you get a pointer to the command line at any point in your program. Again, this only returns a single character string. The string can be parsed into individual arguments by calling CommandLineToArgvW, producing both an array of arguments as well as its size. Take note that there is no narrow character version of CommandLineToArgvW, so you cannot apply it to the command line argument passed into WinMain if you aren't compiling for Unicode.
Regardless, both of these API calls are available even if you aren't compiling for Unicode.
CRT
If you don't care about portability, Microsoft's CRT implementation provides the __argc, __argv, __wargv global variables, that can be used anywhere in your program to get the parsed command line. While convenient, it depends on the preprocessor symbols defined whether __wargv stores a valid pointer. It only does if _UNICODE is defined.
My problem is as follows. When I pass in strings into the methods/classes of the win32 api, I get the Problem, that the type "const char*" cannot be used to assign variables of type LPCWSTR. I than made a helper method, that converts const char* manually to LPCWSTR. In the most cases, this did the trick, but In the CreateWindow() function the same error remains.
I then read online, that to easily avoid this problem, one could change the Character set to UTF-8, but soon found out that vs2019 does not have this setting, where it was 2017.
What I want to know, basically, is whether there is a way change the character set in vs2019, or a way to manually force those Methods to expand to the A type instead of W by default (CreateWindow should automatically expand to CreateWindowA, instead of expanding to CreateWindowW).
CreateWindow expands to CreateWindowW if UNICODE is defined during compiling, otherwise it expands to CreateWindowA. Same with TCHAR (wchar_t/char, respectively) and all other W/A-based APIs.
So, either set the project's character set to ANSI/MBCS, or you can simply #undef UNICODE where needed. Prior to Windows 10 version 1903 (build 18362), the A APIs simply do not support UTF-8 at all. But since then, you can opt in to enable UTF-8 support via the application manifest.
That being said, you should not rely on the TCHAR-based APIs if your string data is not using TCHAR to begin with.
If you are working with char data specifically, use the A APIs directly (CreateWindowA, etc), unless your data is UTF-8 (or different than the user's locale), in which case convert it to UTF-16 using MultiByteToWideChar or equivalent and then call the W APIs directly.
If you are working with wchar_t data specifically, use the W APIs directly (CreateWindowW, etc).
In MS Visual Studio, when you do not set the character set, the likes of AfxMessageBox() (and countless other API functions) will happily accept a CStringA argument. But the moment you set the character set to Unicode, what appear to be the very same functions will only accept CStringW arguments.
Now this is precisely what the documentation says should happen... but...
where exactly did those non-Unicode API functions go? Are they still there to be linked to under other names (AfxMessageBoxA() perhaps?). By what magic does one API disappear and another one appear in its place... or alternatively... by what mischievous hacker trick can one make them reappear? And if it is possible to make them reappear in the presence of Unicode, should one (judiciously) use such hacker mischief?
The declaration of AfxMessageBox() in afxwin.h is:
int AFXAPI AfxMessageBox(LPCTSTR lpszText, UINT nType = MB_OK,
UINT nIDHelp = 0);
It is LPCTSTR that adapts the string type. If you compile with UNICODE in effect then it is an alias for const wchar_t*. Without it is const char*. There is no AfxMessageBoxA() version.
This is very different from the way the winapi functions work, necessarily so since this is a C++ function that mangles differently. Technically they could have provided another overload of the function, they didn't. You'll also have a different link demand, you need to link the non-Unicode version of the MFC library to keep the linker happy. Notable is that it is deprecated and no longer ships with recent VS editions, but still available (right now) as a separate download.
This should answer your question, it doesn't go anywhere, it simply doesn't exist. Mixing cannot work, you'll need A2W() to convert the string. You could of course simply write your own overload if necessary.
I want to save file in temporary folder which can be easy found when type at run by putting "%temp%", but don't know how to navigate to them from c++.
I try using function like "GetTempPathA" or "GetTempFileNameA()" but they don't return char value. For my purpose I use "SaveToFile" method from "TResourceStream" and need UnicodeString, how to find those information?
No, neither GetTempPath nor GetTempFileName return a char value. In general, C functions do not ever return strings. Instead, you pass in a string buffer and the length of that string buffer, and the function fills in the string buffer with the requested string.
For example, to call GetTempPath, you would write the following code:
TCHAR szTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH, // length of the buffer
szTempPathBuffer); // the buffer to fill
szTempPathBuffer will contain the path to the temporary directory.
Do note that you should probably not be explicitly calling the ANSI functions (those with an A suffix). Windows has been fully Unicode for over a decade now. Either use the macros defined by the Windows headers, which automatically resolve to the correct version of the function depending on whether _UNICODE is defined, or explicitly call the Unicode versions (those with a W suffix).
Since you're calling the ANSI versions, you're getting an ANSI string (composed of char values), rather than a Unicode string (composed of wchar_t values), which is presumably what the SaveToFile method that you're trying to call expects.
One can use also getenv(), but it's deprecated and consider as "non-safe":
#pragma warning(disable:4996) //disable getenv warning
char* p = getenv("TEMP");
std::string path(p);
I'm porting an existing Windows application to Linux.
The most of the OS APIs\ Microsoft non-standard extension functions can be easily (more or less...) replaced by equivalent Linux\ GCC APIs, however, I don't know how to deal with sprintf_s which gets variable numbers of arguments.
Does anyone have an idea (If you can please put the code example as well) for that?
Thank you all in advance.
First, can you just port your code to use C++ iostreams instead (for example ostringstream)? This would completely remove all the possible issues with the sprintf line of functions, and if there are a limited number of call points is probably the best option.
If that isn't an option: The sprintf_s function is basically a helper to prevent mistakes (and external abuse to cause buffer overflows. From http://msdn.microsoft.com/en-us/library/ce3zzk1k%28VS.80%29.aspx we learn that it does two things: It checks the format string for valid formats (this doesn't mean it does type checking - it still can't do that), and it allows a max length to be specified.
The best replacement will be snprintf which does have limitations compared to sprintf_s. It won't do format string validation. And not all versions guarantee that the final string will be null terminated: You always want to also store a null into the last character of your buffer after the call to ensure that the final string is null terminated.
Add to end of your header file or beginning of source file:
#ifndef _WIN32
#define sprintf_s(dest,len,format,...) sprintf(dest,format,__VA_ARGS__)
#endif
snprintf has the same signature, but AFAIK it behaves in a slightly different way.
sprintf_s is just a "secure" version (takes buffer length as extra argument) of sprintf , cant you just use sprintf for your port ?
Why not just provide a conditionally compiled implementation of sprintf_s for Linux? This implementation could simply ignore the extra argument and call through to sprintf().