Date: | February 8, 2016 / year-entry #29 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20160208-00/?p=93001 |
Comments: | 19 |
Summary: | You ask it. |
A customer had a question about the
One question that comes to mind is why you are using this method
to begin with.
If you already know that you want the Documents folder, then use
But okay, let's answer the question anyway. The way to get the canonical name for a folder is to ask it! Today's smart pointer library is (rolls dice) ATL! #include <windows.h> #include <shlobj.h> #include <stdio.h> // horrors! Mixing stdio and C++! #include <atlbase.h> #include <atlalloc.h> int __cdecl main() { CCoInitialize init; CComPtr<IKnownFolderManager> mgr; CoCreateInstance(CLSID_KnownFolderManager, 0, CLSCTX_ALL, IID_PPV_ARGS(&mgr)); CComPtr<IKnownFolder> kf; mgr->GetFolder(FOLDERID_Documents, &kf); KNOWNFOLDER_DEFINITION def; kf->GetFolderDefinition(&def); printf("%ls\n", def.pszName); FreeKnownFolderDefinitionFields(&def); return 0; } Run this program and it tells you that the canonical name is Personal. Let's go one step further: Let's print the canonical names for all of the known folders. #include <windows.h> #include <shlobj.h> #include <stdio.h> // horrors! Mixing stdio and C++! #include <atlbase.h> #include <atlalloc.h> int __cdecl main() { CCoInitialize init; CComPtr<IKnownFolderManager> mgr; CoCreateInstance(CLSID_KnownFolderManager, 0, CLSCTX_ALL, IID_PPV_ARGS(&mgr)); UINT count; CComHeapPtr<KNOWNFOLDERID> kfids; mgr->GetFolderIds(&kfids, &count); for (UINT index = 0; index < count; index++) { CComPtr<IKnownFolder> kf; mgr->GetFolder(kfids[index], &kf); KNOWNFOLDER_DEFINITION def; kf->GetFolderDefinition(&def); printf("%ls\n", def.pszName); FreeKnownFolderDefinitionFields(&def); } return 0; } |
Comments (19)
Comments are closed. |
Searches
Windows
ProgramFilesCommon
MusicLibrary
PublicLibraries
Common Desktop
CD Burning
OneDriveCameraRoll
SavedPicturesLibrary
MAPIFolder
Common Start Menu
Games
My Video
Quick Launch
ProgramFilesCommonX86
OneDriveDocuments
3D Objects
ConnectionsFolder
PrintersFolder
VideosLibrary
My Pictures
ResourceDir
Common Startup
PublicGameTasks
SyncSetupFolder
CommonVideo
Desktop
History
SamplePictures
SyncResultsFolder
ConflictFolder
RecycleBinFolder
OneDrive
CSCFolder
Ringtones
Common Programs
NetHood
Contacts
UserProgramFilesCommon
Roaming Tiles
Local Pictures
UsersLibrariesFolder
Cookies
LocalizedResourcesDir
CommonRingtones
GameTasks
Favorites
Local Videos
SampleMusic
HomeGroupFolder
SendTo
PublicAccountPictures
ImplicitAppShortcuts
Administrative Tools
My Music
AddNewProgramsFolder
Captures
UserProfiles
InternetFolder
CameraRollLibrary
System
Programs
Camera Roll
UsersFilesFolder
MyComputerFolder
Common Administrative Tools
DocumentsLibrary
Application Shortcuts
Recent
Screenshots
SavedPictures
Common AppData
Local AppData
ThisPCDesktopFolder
CommonPictures
AppsFolder
PrintHood
Development Files
Profile
PhotoAlbums
Downloads
SampleVideos
Local Music
AppUpdatesFolder
CommonDownloads
Local Downloads
OneDriveMusic
Common Start Menu Places
PicturesLibrary
Public
RecordedTVLibrary
HomeGroupCurrentUserFolder
LocalAppDataLow
Roamed Tile Images
CryptoKeys
Original Images
User Pinned
ChangeRemoveProgramsFolder
Common Documents
SystemX86
AccountPictures
OneDrivePictures
CommonMusic
SearchHistoryFolder
ProgramFiles
Fonts
Startup
Recorded Calls
Start Menu
NetworkPlacesFolder
Playlists
DpapiKeys
Personal
OEM Links
SearchHomeFolder
Local Documents
AppData
Libraries
ThisDeviceFolder
SystemCertificates
Links
UserProgramFiles
Common Templates
Cache
Templates
Device Metadata Store
ControlPanelFolder
ProgramFilesX86
SyncCenterFolder
CredentialManager
SearchTemplatesFolder
SavedGames
Noting that known folders can be added dynamically, so this list can change.
It’s a bit weird that some names use CamelCase while others use spaces.
And for a trip down memory lane from before Vista when these things were called special folders:
There is no official way to get the canonical names (IIRC) but they are the same as the value names in the User Shell Folders key. You can however go from the canonical name to the path if you prefix the name with “shell:” before handing it to SHParseDisplayName.
— “Run this program and it tells you that the canonical name is Personal.”
LOL! There is nothing personal about “Documents” folder. It is a hybrid of “temp” folder and “AppData\Local”.
What do you mean? Few, if any, users treat “Documents” as temporary. Temp and AppData are both personal folders.
He means that so many programs treat it as their Temp or AppData folder, that it’s pretty much unusable as a documents folder.
Right. I keep my permanent documents in the “Documents” folder. Temp stuff is in %appdata%\Local\temp, or whatever magic name is given to C:\Windows\Temp. The first one is in the %username% hierarchy but not in Documents.
I just wish more software that used %TEMP% actually cleaned up after itself. Mine contains about a gig of data right now.
I guess that, as often happens, is something inherited from the past. “My Documents” Folder was introduced by Office for Windows 95. Windows NT had a Personal folder in the user profile. In fact if Office installation detected that it was being installed in Windows NT it used the personal folder as “My Documents” and created a new folder altogether if it detected it was being installed in Windows 9x since Windows 95 didn’t come with user profiles and only created a very basic one if a network was set up but with no security at all.
User profiles were an option in Windows 95 and they didn’t need a network.
True. I had forgotten that part.
Windows 95 RTM supports (My) Documents, Desktop, Start Menu etc and AppData (but not Local AppData) and the virtual folders like My Computer, Control Panel and Recycle Bin no matter what the setup is. In single user mode these folders just live in the root of %WinDir%.
Windows 95 RTM did not come with the folder My documents when it came out. It was installed with Office for Windows 95 and later versions. Windows 95 OSR2 and later versions of the Windows 9x had them out of the box. Windows NT did not renamed the Personal folder to “My Documents” to match with Windows 9x until Windows 2000.
This is what I get from trusting a old MSJ article :/
Turns out we are both wrong. OSR2 (at least the first version) does not have a Documents folder out of the box and you cannot create one either but one noticeable change from RTM is that CSIDL_FAVORITES can now be created if you call a undocumented shell function. SHGetSpecialFolderLocation(CSIDL_FAVORITES) is unable to create it so this API only starts working after the folder exists.
SHGetSpecialFolderLocation(CSIDL_PERSONAL) fails with the documented and undocumented APIs on both versions when I tested on clean systems: http://i.imgur.com/uVYsrNZ.png
I did not test to see if anything changes in multi-user mode. Maybe Raymond remembers the details?
And then there are these “developers” who don’t care at all and deal with “known folders” by abusing a specifc registry key which includes a warning to not use it by _someone_… ;)
Raymond,
You seem to mix-n-match your api-idioms. Is there a reason why?
After starting with CComPtr, you use win32-Api ::CoCreateInstance instead of CComPtr::CoCreateInstance.
I generally feel that if you’re going adopt a tool/feature/library (like CComPtr), you should generally go all-in on it, or not use it at all.
I neglected to mention that the dice roll specifically picked ATL 2.1, which doesn’t support CComPtr.CoCreateInstance. (This is actually a lie, because ATL 2.1 doesn’t have atlalloc.h. The real reason is that I learned ATL with ATL 2.1, so I always forget that there is a CoCreateInstance method directly on CComPtr.)
Thank you! I wasn’t aware that CoCreateInstance ever *wasn’t* part of CComPtr, as it seems so essential. But I can see how old habits die hard. :)