GetOpenFileName open at default directory 'Computer' possible? - c++

I'm using GetOpenFileName to open files in C++, is it possible to set the initial dir at "Computer" virtual location with lpstrInitialDir?
Thanks,
Lee.

This is not possible with GetOpenFileName because the location you wish to use is not part of the file system. Rather it is part of the wider shell namespace.
If you look at the documentation for GetOpenFileName you will see that it has been superseded (over 10 years ago in fact) by the Common Item Dialogs. Those dialogs do allow you to specify the initial folder as a shell item.

If you need to support legacy Windows older than Vista, where IFileDialog is not available, try specifying a Shell folder GUID. For example, the My Computer GUID is 20D04FE0-3AEA-1069-A2D8-08002B30309D. You can specify it like this:
ofn.lpstrInitialDir = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
However, it is worth noting that this method is almost doomed to fail on Windows 7 and later, due to behavioral changes
So, you are better off using IFileDialog on Vista and later instead.

Related

Windows Store C++ apps cannot create files using fopen() under Windows 8.1

We have several Windows 8 Store C++ apps that need to maintain configuration and data files.
Files are written in subfolders of Windows::Storage::ApplicationData::Current->LocalFolder. Example:
C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState\SubFolder1\SubFolder2\data.txt
In Windows 8.1 we have received a few reports from users that say state isn't remembered between app invocations. Upon closer inspection the files are not created (the subfolders are indeed created, but there are no files inside them)
Notes:
Subfolders are created using CreateDirectory(), files are created using fopen()
Files are created/opened using absolute paths
This always worked under Windows 8.0 and the code has not been changed since. In fact, one of our user reports stated that the app saved files fine under Windows 8.0, but stopped saving after the user upgraded to Windows 8.1.
We have not been able to replicate the issue locally using Windows 8.1. We're not sure how common this failure is, but we estimate that most users are unaffected. Affected users do not appear to have any special hardware/software configuration.
If a user is affected, then files are consistently never saved, even after retrying or uninstalling and re-installing the app (i.e., it's not a case of intermittent failure)
It's hard to get error information given (i) the rarity of the issue (ii) the fact that the logs that would reveal this are by definition not saved, and (iii) the apps don't require internet connectivity so there is no alternative communication channel.
Can anyone think of any reason why this might fail under Windows 8.1?
Are there non-ascii characters in path to appdata? CreateDirectory has unicode version, but fopen takes const char* strings as argument.
If I were you, I'd try to abstract away from OS-specific calls using something like boost or Qt. That should work, because Qt uses unicode string for opening files and Boost should have something similar (unsure about this one).
Also on windows compiler _wfopen may be present. It is the same as fopen, but takes wchar_t strings as argument. It should work for you, but you'll need a few ifdefs here and there.
You could also try setting current directory with function that supports unicode and then calling fopen, but I wouldn't call it a "clean" solution.
Anyway, when you run into problem that is related to system calls, then on machine with a problem you can monitor calls using something like process monitor. You could instruct user with a problem to do that and send you a log.
Why don't you use the Windows.Storage classes to work with filesystem? WinRT is recommended way to work with IO not legacy C API. I believe it is more robust approach and you could get more info about the cause from WinRT exception rather than from an unknown failure of old API.

SHGetFolderPath Deprecated: What is alternative to retrieve path for Windows folders?

The SHGetFolderPath() function is deprecated beginning with Windows Vista: http://msdn.microsoft.com/en-us/library/bb762181%28v=VS.85%29.aspx
What is the alternative way to retrieve the path to the Application Folder in Windows?
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)
Aside from that, why do I get those errors when using this function:
Error 1 error C2065: 'CSIDL_COMMON_APPDATA' : undeclared identifier
Error 2 error C3861: 'SHGetFolderPath': identifier not found
The alternative is described in the documentation to which you link. Namely it is SHGetKnownFolderPath.
However, SHGetKnownFolderPath is only available on Vista or later. So if you use load time linking, and run a program that calls SHGetKnownFolderPath on XP, then that program will fail to start. This is clearly a problem if you wish to support XP.
Now, you could switch to run time linking of SHGetKnownFolderPath. Carry out a version check before you call it, and if the function is not available, then fall back to SHGetFolderPath.
Personally, I would not let this deprecation worry you excessively. Microsoft are renowned for maintaining backwards compatibility. Don't expect SHGetFolderPath to disappear any time soon. You will find that SHGetFolderPath exists in Windows 8 and I would expect it still to be present in whatever Windows is current 10 years from now. My advice is to stick to load time linking, and only switch to SHGetKnownFolderPath when you give up supporting XP.
Your other question, that you ask in an edit, is how to call SHGetFolderPath. You need to respect the requirements which are laid out at the bottom of the MSDN documentation topic which you linked to in your question. Specifically, include Shlobj.h and pass Shlobj.lib to the linker.
It is linked right at the top, SHGetKnownFolderPath.
CSIDL_COMMON_APPDATA is replaced by FOLDERID_ProgramData in the new API.
I faced the same set of errors when I added few new header files to my already working solution.
I was already calling SHGetFolderPath and had also included #include <ShlObj.h> but it was in a different header file. The solution was compiling without any errors before I added new library header files to it.
I tried replacing SHGetFolderPath() with SHGetKnownFolderPath() but this just redirected the identifier not found error to SHGetKnownFolderPath.
On adding #include <ShlObj.h> to the header file of the class calling SHGetFolderPath, the
errors ceased and the solution compiled successfully again.
As mentioned in this page, calling SHGetFolderPath on Windows Vista or a higher OS, will internally call SHGetKnownFolderPath.
I have tested using the SHGetFolderPath() with Visual Studio 2015 Enterprise on a Windows 10 PC and it compiled and worked just fine to find the current user's home folder. In the Windows Dev Center page on SHGetFolderPath() SHGetFolderPath function there is the following note:
Note As of Windows Vista, this function is merely a wrapper for
SHGetKnownFolderPath. The CSIDL value is translated to its associated
KNOWNFOLDERID and then SHGetKnownFolderPath is called. New
applications should use the known folder system rather than the older
CSIDL system, which is supported only for backward compatibility.
As David Heffman pointed out in his answer, Microsoft has a history of keeping backwards compatibility for years especially when they can take the older function and just redirect it to the new function with the appropriate arguments. The CSIDL values seem to have a corresponding KNOWNFOLDERID value. See this table of the CSIDL constants with brief annotations and the corresponding KNOWNFOLDERID value.
An example of the use of the function follows. This use retrieves the current user's user folder (e.g. "C:\Users\myuser\Documents" under Windows 7) and then adds a folder name to the end of the path using the PathAppend() function.
TCHAR achDevice[MAX_PATH];
HRESULT hr;
// include file ShlObj.h contains list of CSIDL defines however only a subset
// are supported with Windows 7 and later.
// for the 3rd argument, hToken, can be a specified Access Token or SSID for
// a user other than the current user. Using NULL gives us the current user.
if (SUCCEEDED(hr = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, achDevice))) {
// append a folder name to the user's Documents directory.
// the Path Handling functions are pretty handy.
PathAppend(achDevice, L"xxx");
}
One possible failure is one or more invalid arguments (hr == E_INVALIDARG). A returned value of S_OK indicates the call succeeded.
There are a few CSIDL constants that can be used to modify the results of the function such as CSIDL_FLAG_CREATE by using the bitwise OR operator. I am not sure how well those operators will work with Windows 7 and later.
There are limits on the supported CSIDL constants with Windows 7 and later. It also looks like there may be possible issues to overcome in complex, remote mounted, redirected, and/or shared folders in an Active Directory or similar environment.
See also KNOWNFOLDERID which includes a table that indicates some of the limitations of CSIDL and SHGetFolderPath(). Some examples from the table of CSIDL constants that may be useful.
CSIDL_LOCAL_APPDATA - %USERPROFILE%\AppData\Local
CSIDL_MYDOCUMENTS - %USERPROFILE%\Document
CSIDL_PERSONAL - %USERPROFILE%\Documents
CSIDL_FONTS - %windir%\Fonts
CSIDL_MYMUSIC - %USERPROFILE%\Music
CSIDL_MYPICTURES - %USERPROFILE%\Pictures
CSIDL_COMMON_APPDATA - %ALLUSERSPROFILE% (%ProgramData%, %SystemDrive%\ProgramData)
CSIDL_COMMON_DOCUMENTS - %PUBLIC%\Documents
By the way, the Shell Path Handling Functions are a nice library of methods for manipulating file paths.
See also Where to put common writable application files?
From microsoft, the altenate is "SHGetKnownFolderPath"
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpatha
From my point of view, these functions are for c, c++ and similar languages.
From powershell, I just read the registry:
PS> cd hkcu:\Software\Microsoft\Windows\CurrentVersion\Explorer\
PS> dir
Here peek at "Shell Folders" and "User Shell Folders".
btw: These are for getting the values. I'd say that's fairly safe. For setting the values, better not use the registry direct, as it will ruin your day. Using the explorer -> properties of these 'directories' to move them, will also move the contents. Unfortunately, I donnot know a hook to use that in powershell.

Usage of GetOpenFileName() API in VC++ for opening a folder & NOT a file

BOOL WINAPI GetOpenFileName(
Inout LPOPENFILENAME lpofn
);
is used for opening a file in a VC++ program, say
C:\Hello\World\abc.txt
.
But I want to use this function to select a folder
C:\Hello\World
instaed of a file in it.
I guess I need to make some changes to the members of the structure "OPENFILENAME". Can anyone kindly lemme know how do I achieve this in a VC++ program. Thanks in advance.
GetOpenFileName does not support folder selection at all.
Your options are:
SHBrowseForFolder which is available on Windows 2000 and later, but looks a bit ugly.
IFileDialog which is the platform native folder chooser, but only available on Vista or later. To make the dialog behave as a folder picker, pass FOS_PICKFOLDERS to SetOptions.
In my opinion the best result for the user is to use IFileDialog where available, but fall back to SHBrowseForFolder for older operating systems.
There's ShBrowseForFolder. Plenty of C++ examples around if you search.

Windows Edit Start Up Applications C/C++

I was looking at a project that someone wanted done and in order to do it I need to edit Windows' Start Up Programs. I am unsure of where to begin looking. What I really need is just a reference to some Windows API functions that will let me do this.
Thanks
Startup programs is just a directory, I don't think there are any specific functions for it. You should be able to create shortcuts inside and that should be it.
c:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
As Nikola Smiljanić says the Startup area is just a directory with file shortcuts in it. However it is dangerous to use a hardcoded path because this changes with different versions of Windows.
You can get the path to the startup folder with the SHGetFolderPath function and CSIDL_STARTUP as a parameter.

Code for checking write-permissions for directories in Win2K/XP

Greetings!
I am trying to check directory write-permissions from within a Windows MFC/ATL program using C++. My first guess is to use the C-standard _access function, e.g.:
if (_access("C:\mydir", 2) == -1)
// Directory is not writable.
But apparently on Windows 2000 and XP, _access can't determine directory permissions. (i.e. the Security tab in the Properties dialog when you right-click on a directory in Explorer) So, is there an elegant way to determine a directory's write-permissions in Windows 2000/XP using any of the Windows C++ libraries? If so, how?
Thanks
Evan
You can call CreateFile with GENERIC_WRITE access to check this.
http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
It's not a C++ library but it still counts as elegant because it directly does what you want...
Use sec api.
You can ask on Adv. Win32 api newsgroup :
news://194.177.96.26/comp.os.ms-windows.programmer.win32
where it has often been discussed (C/C++ code)
There are many Windows security functions, although I wouldn't call their usage particularly elegant. I would recommend GetNamedSecurityInfo as a general solution, but the CreateFile solution has a certain simplicity and directness which I can also appreciate. :)