How to get temp folder and set a temp file path? - c++

How to get temp folder and set a temp file path? I tried code bellow but it have error. Thank you very much!
TCHAR temp_folder [255];
GetTempPath(255, temp_folder);
LPSTR temp_file = temp_folder + "temp1.txt";
//Error: IntelliSense: expression must have integral or unscoped enum type

This code is adding two pointers.
LPSTR temp_file = temp_folder + "temp1.txt";
It's not concatenating the strings and it's not creating any storage for the resultant string you want.
For C-style strings, use lstrcpy and lstrcat
TCHAR temp_file[255+9]; // Storage for the new string
lstrcpy( temp_file, temp_folder ); // Copies temp_folder
lstrcat( temp_file, T("temp1.txt") ); // Concatenates "temp1.txt" to the end
Based on the documentation for GetTempPath, it would also be wise to replace all occurances of 255 in your code with MAX_PATH+1.

You can't add two character arrays together and get a meaningful result. They're pointers, not a class like std::string which provides such useful operations.
Create a large enough TCHAR array and use GetTempPath, then use strcat to add the file name to it.
TCHAR temp_file [265];
GetTempPath(255, temp_file);
strcat(temp_file, "temp1.txt");
Ideally, you should also test the result of GetTempPath for failure. As far as I can see from the documentation linked in the other answer, the most likely reason for failure is that the path variable supplied is too small. Use MAX_PATH+1+9 as recommended there.

Related

Why does my colon character disappear when I go from char[] to string?

In an old Windows application I'm working on I need to get a path from an environment variable and then append onto it to build a path to a file. So the code looks something like this:
static std::string PathRoot; // Private variable stored in class' header file
char EnvVarValue[1024];
if (! GetEnvironmentVariable(L"ENV_ROOT", (LPWSTR) EnvVarValue, 1024))
{
cout << "Could not retrieve the ROOT env variable" << endl;
return;
}
else
{
PathRoot = EnvVarValue;
}
// Added just for testing purposes - Returning -1
int foundAt = PathRoot.find_first_of(':');
std::string FullFilePath = PathRoot;
FullFilePath.append("\\data\\Config.xml");
The environment value for ENV_ROOT is set to "c:\RootDir" in the Windows System Control Panel. But when I run the program I keep ending up with a string in FullFilePath that is missing the colon char and anything that followed in the root folder. It looks like this: "c\data\Config.xml".
Using the Visual Studio debugger I looked at EnvVarValue after passing the GetEnvironmentVariable line and it shows me an array that seems to have all the characters I'd expect, including the colon. But after it gets assigned to PathRoot, mousing over PathRoot only shows the C and drilling down it says something about a bad ptr. As I noted the find_first_of() call doesn't find the colon char. And when the append is done it only keeps the initial C and drops the rest of the RootDir value.
So there seems to be something about the colon character that is confusing the string constructor. Yes, there are a number of ways I could work around this by leaving the colon out of the env variable and adding it later in the code. But I'd prefer to find a way to have it read and used properly from the environment variable as it is.
You cannot simply cast a char* to a wchar_t* (by casting to LPWSTR) and expect things to work. The two are fundamentally distinct types, and in Windows, they signify different encoding.
You obviously have WinAPI defines set such that GetEnvironmentVariable resolves to GetEnvironmentVariableW, which uses UTF-16 to encode the string. In practice, this means a 0 byte follows every ASCII character in memory.
You then construct a std::string out of this, so it takes the first 0 byte (at char index 1) as the string terminator, so you get just "c".
You have several options:
Use std::wstring and wchar_t EnvVarValue[1024];
Call GetEnvironmentVariableA() (which uses char and ASCII)
Use wchar_t EnvVarValue[1024]; and convert the returned value to a std::string using something like wcstombs.
It seems you are building with wide-character functions (as indicated by your cast to LPWSTR). This means that the string in EnvVarValue is a wide-character string, and you you should be using wchar_t and std::wstring instead.
I would guess that the contents in the array array after the GetEnvironmentVariable call is actually the ASCII values 0x43 0x00 0x3a 0x00 0x5c 0x00 etc. (that is the wide-char representation of "C:\"). The first zero acts as the string terminator for a narrow-character string, which is why the narrow-character string PathRoot only contains the 'C'.
The problem might be that EnvVarValue is not a wchar. Try using wchar_t and std::wstrîng.

How do I store value to string with RegOpenKeyEx?

I need to grab the path from the registry. The following code works except for the last part where I'm storing the path to the string. Running the debugger in Visual Studio 2008 the char array has the path, but every other character is a zero. This results in the string only being assigned the first letter. I've tried changing char res[1024] to char *res = new char[1024] and this just makes it store the first letter in the char array instead of the string. The rest of the program needs the path as a string datatype so it can't stay as a char array. What am I missing here?
unsigned long type=REG_SZ, size=1024;
string path;
char res[1024];
HKEY key;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Classes\\dsn\\shell\\open\\command"), NULL, KEY_READ, &key)==ERROR_SUCCESS){
RegQueryValueEx(key,
NULL,// YOUR value
NULL,
&type,
(LPBYTE)res,
&size);
RegCloseKey(key);
path = string(res);
}
You're getting back a Unicode string, but assigning it to a char-based string.
You could switch path's class to being a 'tstring' or 'wstring', or use RegQueryValueExA (A for ASCII).
You are compiling in Unicode. Go to Project Settings>Configuration Properties>General and change "Character Set" to "Not Set", and rebuild your project.
RegOpenKey is actually a macro defined in the WINAPI headers. If Unicode is enabled, it resolves to RegOpenKeyW, if not then it resolves to RegOpenKeyA. If you want to continue to compile under unicode, then you can just call RetgOpenKeyA directly instead of using the macro.
Otherwise, you'll need to deal with Unicode strings which, if needed, we can help you with also.
For C++, you may prefer to access the Registry using the ATL helper class CRegKey. The method for storing string values is QueryStringValue. There are other (somewhat) typesafe methods for retrieving and setting different registry value types.
It's not the best C++ interface (eg. no std::string support) but a little smoother than native Win32.

ExpandEnvironmentStrings Not Expanding My Variables

I have a process under the Run key in the registry. It is trying to access an environment variable that I have defined in a previous session. I'm using ExpandEnvironmentStrings to expand the variable within a path. The environment variable is a user profile variable. When I run my process on the command line it does not expand as well. If I call 'set' I can see the variable.
Some code...
CString strPath = "\\\\server\\%share%"
TCHAR cOutputPath[32000];
DWORD result = ExpandEnvironmentStrings((LPSTR)&strPath, (LPSTR)&cOutputPath, _tcslen(strPath) + 1);
if ( !result )
{
int lastError = GetLastError();
pLog->Log(_T( "Failed to expand environment strings. GetLastError=%d"),1, lastError);
}
When debugging Output path is exactly the same as Path. No error code is returned.
What is goin on?
One problem is that you are providing the wrong parameters to ExpandEnvironmentStrings and then using a cast to hide that fact (although you do need a cast to get the correct type out of a CString).
You are also using the wrong value for the last parameter. That should be the size of the output buffer, not the size of the input length (from the documentation the maximum number of characters that can be stored in the buffer pointed to by the lpDst parameter)
Putting that altogether, you want:
ExpandEnvironmentStrings((LPCTSTR)strPath,
cOutputPath,
sizeof(cOuputPath) / sizeof(*cOutputPath));
I don't see any error checking code in your snippet, you don't assert the return value. If there's a problem, you'd never discover it. Also, you are using ANSI strings, beware of the weirdo requirement for the nSize argument (1 extra).
What about buffersize ? Is it initialized - to the right value ?
The documentation states that If the destination buffer is too small to hold the expanded string, the return value is the required buffer size, in characters.

How to delete folder into recycle bin

I am programing under C++, MFC, windows.
I want to delete a folder into recycle bin.
How can I do this?
CString filePath = directorytoBeDeletePath;
TCHAR ToBuf[MAX_PATH + 10];
TCHAR FromBuf[MAX_PATH + 10];
ZeroMemory(ToBuf, sizeof(ToBuf));
ZeroMemory(FromBuf, sizeof(FromBuf));
lstrcpy(FromBuf, filePath);
SHFILEOPSTRUCT FileOp;
FileOp.hwnd = NULL
FileOp.wFunc=FO_DELETE;
FileOp.pFrom=FromBuf;
FileOp.pTo = NULL;
FileOp.fFlags=FOF_ALLOWUNDO|FOF_NOCONFIRMATION;
FileOp.hNameMappings=NULL;
bRet=SHFileOperation(&FileOp);
Any thing wrong with the code above?
It always failed.
I found the problem:
filePath should be : "c:\abc" not "c:\abc\"
The return value from SHFileOperation is an int, and should specify the error code. What do you get?
i know it is not the right way but if you cant find a solution you can try this..
download file nircmd.exe or another exe that can empty recycle bin.
then you call these functions by system("nircmd.exe emptybin")
You have found a solution that works, however it's only by accident. The actual problem here is that the pFrom parameter is in a special format. According to the MSDN docs for SHFILEOPTS, it stores a list of file paths, each one null-terminated, and an extra null after the last one.
In your case this happens to work because the FromBuf array is longer than the filename and all the entries are initialised to zero. The more general solution is to create a buffer that is long enough for the filename and then add two nul characters after it. Note that Windows filenames can be longer than _MAX_PATH, eg see https://learn.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation

image subdirectory in c++

Basically, I was hoping to sort of keep my files sorted instead of having them all in the same folder as my executable, but referencing files in sub folders relative to my executable has proven difficult.
// DEFINES
#define IMAGE_BACKGROUND "\\content\\images\\background.bmp"
#define FONT_MAIN "\\content\\fonts\\sai.ttf"
The above code obviously does not work.
I read supposedly args[0] is somehow my path? Anyone care to elaborate a little more?
int main(int argc, char* args[])
{
I should mention that Boost.Filesystem is a nice library that can help you out.
args[0] is the full path name (well, but that is also decided by the OS and shell, so you may get a short file name which is not full) to your "executable file", not its folder. you must truncate it.
try splitpath and joinpath.
args[0] is the name used to call your executable, which is not necessarily the full path of your executable. You're interested in the working directory of your executable, which is OS-dependent.
In any case, you have to be careful with relative paths. If your user calls your program from a different directory, your working directory may be something unexpected, and you won't properly reference your files.
Since you're in Windows, you can use the GetModuleFileName function (see the documentation) to get the full name of your executable, like so:
GetModuleFileName(NULL, buffer, length);
Have you tryed doing:
#define IMAGE_BACKGROUND "\content\images\background.bmp"
That might be the problem (as i have used images from sub folders like that before)
This code should work:
#define IMAGE_BACKGROUND "\\content\\images\\background.bmp"
int main(int argc, char* args[])
{
char buf[512];
int endOfPath = strrchr(args[0], '\\') - args[0];
strncpy_s(buf, sizeof(buf), args[0], endOfPath);
strcat(buf, IMAGE_BACKGROUND);
Like the other person said, args[0] is the full path of the executeble, so you can't use that as is. The strrchr function (TWO r's in the middle) finds the last occurrence of a given character and returns a pointer to it. Assuming that you are using one-byte characters, subtracting args[0] from the returned pointer will give you the number of characters between the two pointers -- When you subtract two pointers, your actually subtracting the memory addresses, so what you're left with is an offset, or distance between the pointers. This distance is like the index of the character that was found.
I then use the strncpy_s function to copy endOfPath number of characters from args[0] to our temporary buffer. Now, if your program path was
"C:\Windows\Users\Me\Desktop\myProgram\theProgram.exe"
the buf variable will contain
"C:\Windows\Users\Me\Desktop\myProgram"
I then used the strcat (conCATenation) function to append your constant onto the end.
Note that with your #define, the "\\" is REQUIRED in C/C++, and also note that the " marks will be included where ever you use IMAGE_BACKGROUND.
After those lines of code, buf will contain:
"C:\Windows\Users\Me\Desktop\myProgram\content\images\background.bmp"
Hope that helps and is not too confusing...
I actually solved it by using the following code, thank you all for the responses:
// DEFINES
#define IMAGE_BACKGROUND ".\\content\\images\\background.png"
#define IMAGE_BLUEBLOCK ".\\content\\images\\blueblock.png"
#define FONT_MAIN ".\\content\\fonts\\sai.ttf"
Turns out the . gets the "working path directory".