ProtectedVoid
ProtectedVoid

Reputation: 1315

C++ Winapi - Get Directory (path) identifier

I'm using Winapi's function SHBrowseForFolder and I need to set a default folder for browsing. To achieve that, I need to get the desired default folder's "PIDL". I can get the "PIDL" using this function: SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot); but as you can see, the second parameter is another identifier "nCSIDL" (type int).

How can I get a path's indentifier by path (LPCSTR)?

This is my code:

TCHAR szDir[MAX_PATH];
BROWSEINFO bInfo;
HWND hwnd = ObPanelAPI::GetPanelHandleByName("*Current");
bInfo.hwndOwner = hwnd;
bInfo.pszDisplayName = szDir;
bInfo.lpszTitle = "Seleccionar directorio"; //Dialog title
bInfo.ulFlags = 0 ;
bInfo.lpfn = NULL;
bInfo.lParam = 0;
bInfo.iImage = -1;

//Default folder set
LPITEMIDLIST pidlRoot = NULL;

//*******I NEED TO GET nCSIDL HERE********

SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot);
bInfo.pidlRoot = pidlRoot; 

LPITEMIDLIST lpItem = SHBrowseForFolder(&bInfo);

Upvotes: 0

Views: 1762

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597951

I'm using Winapi's function SHBrowseForFolder and I need to set a default folder for browsing. To achieve that, I need to get the desired default folder's "PIDL".

First, you need to differentiate something here. BROWSEINFO has a pidlRoot field, which specifies the top-most folder that the browse dialogs displays. A user cannot select items above that folder. This is NOT the same thing as a "default folder", which is just the folder that is initially selected within the chosen root when the dialog appears.

To set a "default folder", you actually do not need a PIDL, you can use a path string instead (the dialog accepts both). Assign a pointer to the path string to the BROWSEINFO.lParam field and provide a callback function in the BROWSEINFO.lpfn field. Inside the callback, when it receives the BFFM_INITIALIZED notification, it can send the dialog a BFFM_SETSELECTION message, setting the wParam parameter to TRUE and setting the lParam parameter to the path string pointer. This is documented on MSDN:

BFFCALLBACK function pointer

BFFM_SETSELECTION
Specifies the path of a folder to select. The path can be specified as a string or a PIDL.

Now, with that said, the BROWSEINFO.pidlRoot field requires a PIDL, and the BFFM_SETSELECTION message does accept a PIDL as input, so...

I can get the "PIDL" using this function: SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot); but as you can see, the second parameter is another identifier "nCSIDL" (type int).

That function is for retrieving PIDLs for special folders that are pre-defined by Microsoft, like Documents, AppData, User Profiles, etc. These are identified by constant CSIDL values (and KNOWNFOLDERID values on Vista+) which are consistent on every Windows version, though the particular paths may differ from one system to another based on user configuration.

How can I get a path's indentifier by path (LPCSTR)?

There are a few different ways:

  1. IShellFolder::ParseDisplayName(). Call SHGetDesktopFolder() to get the IShellFolder for the Shell namespace root, and then call its ParseDisplayName() to parse the path.

  2. SHParseDisplayName(). Similar to above, but with some additional options available. Do be aware of the following note in the documentation, though:

    You should call this function from a background thread. Failure to do so could cause the UI to stop responding.

  3. ILCreateFromPath(). However, it has been observed that ILCreateFromPath() does not always return the same PIDLs that IShellFolder::ParseDisplayName()/SHParseDisplayName() return, that sometimes that difference can cause things like SHBrowseForFolder() to behave incorrectly. I have not personally experienced this, but other people claim they have. You will just have to try it for yourself.

Upvotes: 4

Related Questions