How to get the parent folder of a Windows user's profile path using C++ - winapi

I am trying get the parent folder of a Windows user's profile path. But I couldn't find any "parameter" to get this using SHGetSpecialFolderPath, so far I am using CSIDL_PROFILE.
Expected Path:
Win7 - "C:\Users"
Windows XP - "C:\Documents and Settings"

For most purposes other than displaying the path to a user, it should work to append "\\.." (or "..\\" if it ends with a backslash) to the path in question.

With the shell libary version 6.0 you have the CSIDL_PROFILES (not to be confused with CSIDL_PROFILE) which gives you what you want. This value was removed (see here), you have to use your own workaround.
On any prior version you'll have to implement your own workaround, such as looking for the possible path separator(s), i.e. \ and / on Windows, and terminate the string at the last one. A simple version of this could use strrchr (or wcsrchr) to locate the backslash and then, assuming the string is writable, terminate the string at that location.
Example:
char* path;
// Retrieve the path at this point, e.g. "C:\\Users\\username"
char* lastSlash = strrchr(path, '\\');
if(!lastSlash)
lastSlash = strrchr(path, '/');
if(lastSlash)
*lastSlash = 0;
Or of course GetProfilesDirectory (that eluded me) which you pointed out in a comment to this answer.

Related

Haskell Directory creates invalid symlink on Windows

This year System.Directory was updated to include createFileLink and createDirectoryLink actions, and for me on Windows 10 both work fine for relative paths.
When I use either on an absolute path (of about 50 character length, so I suppose in unicode it exceeds 260) it prepends \\?\ (i.e. "\\\\?\\") to the paths, which can be seen from DIR as follows
<SYMLINKD> source [\\?\T:\Code\hLink\binaries\dest]
<SYMLINK> source.txt [\\?\T:\Code\hLink\binaries\dest\source.txt]
The directory link works fine, but the file link doesn't do anything, it doesn't even say that the target file is missing.
When I create a file link using MKLINK without \\?\ in the absolute path it works fine as well, and when I create either link using MKLINKwith \\?\ it has the same result.
Is this a Windows problem? Can I make Haskell use short path format instead? (Using Win10 so apparently I can enable long paths via registry)
Should the Windows api be passing the \\?\ header to symlinks at all?
References:
MaxPath and the meaning of \\?\, plus disabling path limitations on Win10
https://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
Changelog reporting the addition of \\?\ to win32 calls https://hackage.haskell.org/package/directory-1.3.1.1/changelog

open UNC path with spaces in windows explorer with perl

Hello stackoverflowers,
i'm afraid i can't figure out how to open an UNC path with spaces within Windows Explorer in perl.
Purpose is, i want the user to put a file within the path. To make it more comfortable, the path should open in explorer automatically. Which it does for any local drives.
The UNC path that should open is: \\srvr1\mean space dir
My code so far:
use strict
use warnings
my $sourceDir = "\\\\srvr1\\mean space dir";
system("start $sourceDir");
Which gives the error: "Win can't access \\srvr1\mean."
Ok, so i tried to quote the string:
my $sourceDir = "\\\\srvr1\\\"mean space dir\"";
Which lead to: "Win can't access \\srvr1\"mean space dir"."
Next thing i tried was:
my $sourceDir = q{"\\\srvr1\\mean space dir"}
Which lead to an cmd window being opened with the correct path within the title?!
Is maybe the system call itself wrong?
I really appreciate any help. Thanks.
The second form is correct, but then you have to account for the fact that the start command treats its first quoted argument as a window title. If you want to start a quoted path, you need to give a window title argument too (the empty string is fine).
Like so:
my $sourceDir = q{\\\\srvr1\\mean space dir};
system(qq{start "" "$sourceDir"});
For this kind of thing the array style system call is a good fit. You don't need to worry about quoting the path or escaping as much.
$path = '\\\\srvr1\mean space dir';
system('start', '', $path);
Quoting (or forgetting to quote) paths in system calls is a significant source of bugs where I've worked. A habit of doing it as above means you never need to worry about it.

What is common practice for the location of temporary files after Windows XP [duplicate]

Currently I am using following function to get the temporary folder path for current user:
string tempPath = System.IO.Path.GetTempPath();
On some machines it gives me temp folder path of current user like:
C:\Documents and Settings\administrator\Local Settings\Temp\
On some machines it gives me system temp folder path like:
C:\Windows\TEMP
MSDN Documentation also says that above API returns current system's temporary folder.
Is there any other API available which gives me current user's temporary folder path like this:
C:\Documents and Settings\administrator\Local Settings\Temp\
System.IO.Path.GetTempPath() is just a wrapper for a native call to GetTempPath(..) in Kernel32.
Have a look at http://msdn.microsoft.com/en-us/library/aa364992(VS.85).aspx
Copied from that page:
The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
The path specified by the TMP environment variable.
The path specified by the TEMP environment variable.
The path specified by the USERPROFILE environment variable.
The Windows directory.
It's not entirely clear to me whether "The Windows directory" means the temp directory under windows or the windows directory itself. Dumping temp files in the windows directory itself sounds like an undesirable case, but who knows.
So combining that page with your post I would guess that either one of the TMP, TEMP or USERPROFILE variables for your Administrator user points to the windows path, or else they're not set and it's taking a fallback to the windows temp path.
DO NOT use this:
System.Environment.GetEnvironmentVariable("TEMP")
Environment variables can be overridden, so the TEMP variable is not necessarily the directory.
The correct way is to use System.IO.Path.GetTempPath() as in the accepted answer.
I have this same requirement - we want to put logs in a specific root directory that should exist within the environment.
public static readonly string DefaultLogFilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
If I want to combine this with a sub-directory, I should be able to use Path.Combine( ... ).
The GetFolderPath method has an overload for special folder options which allows you to control whether the specified path be created or simply verified.

Why is FindNextFile failing on Windows 7

This code works on Windows XP at home but fails at work on 64bit Windows 7. The loop isn't entered even once although there are more than 50 files in the supplied folder. Not only it doesn't enter, it also returns ERROR_NO_MORE_FILES for GetLastError. Why?
string dir = "d:\\validfolder";
WIN32_FIND_DATA ffd;
HANDLE h = FindFirstFile(dir.c_str(), &ffd);
while(FindNextFile(h, &ffd))
{
// some operation
}
DWORD dw = GetLastError();// returns ERROR_NO_MORE_FILES
I tried Wow64DisableWow64FsRedirection but that has no effect.
You need to add a file wildcard to your dir:
string dir = "d:\\validfolder\\*";
For it to list the files in a directory. Otherwise you are only asking for information about the directory itself.
At least that's how I read the documentation for FindFirstFile
To examine a directory that is not a root directory, use the path to
that directory, without a trailing backslash. For example, an argument
of "C:\Windows" returns information about the directory "C:\Windows",
not about a directory or file in "C:\Windows". To examine the files
and directories in "C:\Windows", use an lpFileName of "C:\Windows*".
I don't know why it's working for you on XP
This code is incorrect in a number of ways.
You must check the return value of FindFirstFile. If the call to FindFirstFile succeeds then you already have the first file in ffd. As your code stands, you throw away the first file. So you need to re-jig your loop logic to account for that. Naturally, if GetLastError returns ERROR_NO_MORE_FILES then that means the search has exhausted all files.
So, what is probably happening is you ask for the first file matching the search string "d:\\validfolder". This is returned in ffd after the call to FindFirstFile. You then ignore that information and ask for the next match. But there is no subsequent match since there is only one object matching "d:\\validfolder" since you included no wildcards in your search pattern.
This code will behave exactly the same on XP as it does on Windows 7 and I suspect that you are not running the same code on both systems.
If you want to enumerate the contents of the folder then you need to search for "d:\\validfolder\\*". Something like this:
string dir = "d:\\validfolder\\*";
WIN32_FIND_DATA ffd;
HANDLE h = FindFirstFile(dir.c_str(), &ffd);
BOOL success = h<>INVALID_HANDLE_VALUE;
while(success)
{
// do something with ffd
success = FindNextFile(h, &ffd));
}

Where should my windows app store cache and tempfiles? [duplicate]

Currently I am using following function to get the temporary folder path for current user:
string tempPath = System.IO.Path.GetTempPath();
On some machines it gives me temp folder path of current user like:
C:\Documents and Settings\administrator\Local Settings\Temp\
On some machines it gives me system temp folder path like:
C:\Windows\TEMP
MSDN Documentation also says that above API returns current system's temporary folder.
Is there any other API available which gives me current user's temporary folder path like this:
C:\Documents and Settings\administrator\Local Settings\Temp\
System.IO.Path.GetTempPath() is just a wrapper for a native call to GetTempPath(..) in Kernel32.
Have a look at http://msdn.microsoft.com/en-us/library/aa364992(VS.85).aspx
Copied from that page:
The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
The path specified by the TMP environment variable.
The path specified by the TEMP environment variable.
The path specified by the USERPROFILE environment variable.
The Windows directory.
It's not entirely clear to me whether "The Windows directory" means the temp directory under windows or the windows directory itself. Dumping temp files in the windows directory itself sounds like an undesirable case, but who knows.
So combining that page with your post I would guess that either one of the TMP, TEMP or USERPROFILE variables for your Administrator user points to the windows path, or else they're not set and it's taking a fallback to the windows temp path.
DO NOT use this:
System.Environment.GetEnvironmentVariable("TEMP")
Environment variables can be overridden, so the TEMP variable is not necessarily the directory.
The correct way is to use System.IO.Path.GetTempPath() as in the accepted answer.
I have this same requirement - we want to put logs in a specific root directory that should exist within the environment.
public static readonly string DefaultLogFilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
If I want to combine this with a sub-directory, I should be able to use Path.Combine( ... ).
The GetFolderPath method has an overload for special folder options which allows you to control whether the specified path be created or simply verified.

Resources