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);
Related
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).
I have been playing with writing Unicode code using Windows API and have found one thing particularly frustrating.
I made a simple interface for wrapping "MessageBox" into an "alert", reducing number of arguments needed to call it from 4 to 1.
The issue is that this one argument MUST be called with L"My string", which I want to avoid.
Here is my interface so far:
UseCase.hpp
#pragma once
#include <string>
#include <iostream>
/**
* The User should not need to know any Windows API ideally.
* They will have to know L"Str" notation though...
*/
namespace UseCase
{
void alert(const wchar_t *message);
};
UseCase.cpp
#include <Windows.h>
#include "UseCase.hpp"
/**
* Kind-of like javascript:alert(message).
* This is a very common usecase, and heavily simplifies call convention.
*/
void UseCase::alert(const wchar_t *message)
{
MessageBox(0, message, L"message box", MB_OK | MB_ICONEXCLAMATION);
}
main.cpp
#include "UseCase.hpp"
using namespace UseCase;
const wchar_t *msg = L"Привет мир";
int wmain(int argc, wchar_t **argv)
{
alert(msg);
return 0;
}
My concern is that no matter how the main tries to call alert, it has to use L"String" notation which is visually annoying to me.
To elaborate why L is annoying to me, it is for two reasons:
It treats Rvalue string literals differently from variables containing an ascii string.
If you try to call it on an ascii string "hello, world", it will give a confusing error message to an average user.
It's obvious that the string cannot be stored in ascii, and you are trying to assign it to a unicode string, there shouldn't be much getting in a way of an automatic conversion.
Is there a way to get rid of the L"String" convention and make the program automatically treat the function input as wide character input?
Current viable solutions are:
Create a macro for calling messagebox with a string literal that wraps it in L for you. The issue with this approach is the cryptic error messages on variables passed into the function, as L cannot convert variables from ascii to unicode for you.
Others proposed but I haven't fully wrapped my head around implementing them.
Have the user register their string externally and stored as unicode
inside a file/binary cache. I can then provide an interface to load this string as a wide string and call the function using it.
If you want to be able to pass Unicode strings (i.e. use MessageBoxW, which takes wide-character strings), but you want to be able to use plain string literals without the L prefix, you'll need to decide on an encoding to use for the Unicode characters in a narrow string, and then perform a run-time conversion to a wide string according to the encoding.
UTF-8 might be a reasonable start. See this answer for how to convert from/to UTF-8 using standard Windows API.
You can get around this by making the actual call to alert a preprocessor macro, and using the _TEXT() macro provided by MS (or figure out how to do token pasting L ## msg yourself correctly.)
#define DMITRY_ALERT(msg) UseCase::alert(_TEXT(msg))
this will "magically" insert the L in any UNICODE build at the cost of having to use a macro wrapper (that needs to have an UGLY_LONG_NAME to prevent clashes).
Note: That macro can then only be called with string literals, not with a variable.
Whether that is worth the trouble seems doubtful to me.
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 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.
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