How to get a PIDL from a Windows library's GUID? - c++

How can I get the PIDL of a library from its GUID?
For example, if I have the GUID of the Documents library ("{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}"), how can I convert that into the library's ID list?
I thought SHParseDisplayName would do the job, but it returns "file not found."
Bear in mind that what I need is the PIDL of the library, not of its default folder.
This is straight C++, no .Net.
TIA
Edit: This is the code that works, from the response below (without error checks). guid is a GUID string prepended with 'shell:::', e.g., 'shell:::{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}'.
IShellFolder* pDesktop;
LPITEMIDLIST pidl;
SHGetDesktopFolder(&pDesktop);
pDesktop->ParseDisplayName(nullptr, nullptr, guid, nullptr, &pidl, 0);
Edit 2: Even easier: SHParseDisplayName works if the 'shell:::' is prepended:
SHParseDisplayName(guid, nullptr, &pidl, 0, nullptr);

According to the documentation for IShellFolder::ParseDisplayName you can simply pass it a filename in the form ::{GUID} if you are using the desktop folder.
Edit: the documentation appears to be incomplete, according to this answer you need to add shell: to the start of the string.
p->ParseDisplayName(m_hWnd, NULL, _T("shell:::{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}"), NULL, &pidl, NULL);

You want the function SHGetKnownFolderIDList.
Given a KnownFolderID guid (e.g. FOLDERID_DocumentsLibrary - {7B0DB17D-9CD2-4A93-9733-46CC89022E7C})
returns you the absolute pidl of that KNOWNFOLDER
For example:
PIDLIST_ABSOLUTE pidl;
HRESULT hr = SHGetKnownFolderItem(FOLDERID_DocumentsLibrary, 0, NULL, out pidl);
Bonus Chatter
There are three shell functions for dealing with KNOWNFOLDERs
SHGetKnownFolderPath : Get the full path of a known folder (e.g. C:\Users\Chris\Documents)
SHGetKnownFolderIDList: Get the absolute pidl of a known folder
SHGetKnownFolderItem: Get the IShellItem of a known folder

Related

How to tell if there's no default file extension association on OS post-Windows XP?

Going back to the days of Windows XP one could use the following code to tell if there's no file association existed for an extension:
TCHAR buffPath[MAX_PATH] = {0};
DWORD dwszBuffPath = MAX_PATH;
HRESULT hR = ::AssocQueryString(
ASSOCF_NOFIXUPS | ASSOCF_VERIFY,
ASSOCSTR_EXECUTABLE,
_T(".weirdassextension"),
NULL,
buffPath,
&dwszBuffPath);
if(hR != S_OK &&
hR != E_POINTER)
{
//Association does not exist
}
But since Windows 8, the AssocQueryString API returns S_OK and buffPath is set to something like C:\WINDOWS\system32\OpenWith.exe if it doesn't find anything.
Is there a better way now to determine that file extension has no Shell association?
PS. I do not want to just compare the file name to OpenWith.exe. What if there's a legit executable called just that... There must be a better way.
I think I got it. The trick was to use the correct flags. This seems to work from XP and up:
WCHAR wbuffPath[MAX_PATH] = {0};
DWORD dwszBuffPath = MAX_PATH;
HRESULT hR = ::AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN,
ASSOCSTR_EXECUTABLE,
L".weirdassextension",
NULL,
wbuffPath,
&dwszBuffPath);
if(hR == 0x80070483) // HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)
{
//The association is missing
}
There's one other trick there, that took me some time to figure out -- DO NOT use AssocQueryStringA(). The shim for AssocQueryStringA() that converts its passed string parameters to Unicode has a bug in XP (and evidently in Vista as well) that will make that API fail on those OS. So, if you do your own ANSI-to-Unicode conversion and call AssocQueryStringW() the problem will go away (Evidently 14 years is not enough time for Microsoft to fix that bug?).

URLDownloadToFile QtCreator file not downloading

My issue today involve the usage of URLDownloadToFile() with QtCreator. I use the following code to download:
HRESULT hRez = URLDownloadToFile(NULL, TEXT(url), TEXT("C:\\image.png"), 0, NULL);
if (hRez != S_OK)
{
return false;
}
The code run with no errors however the file ins't downloaded. I've been searching through many solutions for my issue but none have been relevant not successful. What have I done wrong?
Well the documentation states:
szFileName:
A pointer to a string value containing the name or full path of the file to create for the download.
If szFileName includes a path, the target directory must already exist.
So I would assume this parameter needs to include not only a path but a filename as well. For instance
HRESULT hRez = URLDownloadToFile(NULL, TEXT(url), TEXT("C:\\downl.tmp"), 0, NULL);

ShellExecuteW not working well on Windows 8.1?

I call standard ShellExecuteW call on Windows8.1 to open PPS (powerpoint slide) file.
This works just fine on Windows 7. On Windows 8.1. it reports "There is no program associated to open the file". Of course, the file association is set and if file is saved and run from Explorer (double clicked) it opens just fine. I also tried to change association and to associate another program and then associate back to PPS viewer, no improvement. It just doesn't work for W8.1 but the same call works on earlier Windows.
Can anyone give me a clue what might be wrong here?
The code used to open file is very simple and I see no errors with it:
HINSTANCE hinst = ShellExecuteW(NULL, L"open", L"C:\\path\\to\\file.pps", NULL, NULL, SW_SHOWNORMAL);
// Check if result is error
if ((int)hinst <= 32)
{
wchar_t buf[512] = { 0 };
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 512, NULL);
MSGBOX(buf);
}
I use free PPS viewer as found here:
http://www.microsoft.com/en-us/download/details.aspx?id=13
I found something similar which points to that this could be a bug in Win8.1. Can anyone confirm this? Or reveal a workaround?
I found the solution myself.
The problem on W8.1 was that the verb open was not registered to the application so it used different default verb. So if the ShellExecute call is replaced with:
HINSTANCE hinst = ShellExecuteW(NULL, NULL, L"C:\\path\\to\\file.pps", NULL, NULL, SW_SHOWNORMAL);
Then the system looks for a default verb which may or may not be open (usually is), so by not using this verb explicitly it leaves this decision to the system.

URLDownloadToFile to the same directory

I am trying to achieve saving a random file from the net to the same directory where the .exe is located. The problem is that I only got it working when specifying the absolute directory.
The last code I tried was:
string home;
home = system("echo %HOMEDRIVE%%HOMEPATH%/aaa.gif");
HRESULT hr = URLDownloadToFile ( NULL, _T("http://stackoverflow.com/gif.gif"), (TCHAR*)home.c_str(), 0, NULL );
Also I tried:
HRESULT hr = URLDownloadToFile ( NULL, _T("http://stackoverflow.com/gif.gif"), "/aaa.gif", 0, NULL );
But it isn't working neither.
How can I sort it out? Thanks :)
Try using _T(".\\aaa.gif") as the file name. This will use the current directory for the file storage location. Alternatively you can also use GetModuleFileName to get the execution path of the exe and work out the path name for your save file.

How do I get the application data path in Windows using C++?

I looked all over the internet and there doesn't seem to be a decent solution that I could find. I want to be able to programmatically in C++ obtain the path "%ALLUSERSPROFILE%\Application Data" that explorer can translate into a real path.
Can I do this without relying on third-party code?
Use SHGetFolderPath with CSIDL_COMMON_APPDATA as the CSIDL.
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)))
{
//....
}
Just to suppliment interjay's answer
I had to include shlobj.h to use SHGetFolderPath.
Often you may need to read a file from appdata,
to do this you need to use the pathAppend function (shlwapi.h is needed for this).
#include <shlwapi.h>
#pragma comment(lib,"shlwapi.lib")
#include "shlobj.h"
TCHAR szPath[MAX_PATH];
// Get path for each computer, non-user specific and non-roaming data.
if ( SUCCEEDED( SHGetFolderPath( NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath ) ) )
{
// Append product-specific path
PathAppend( szPath, _T("\\My Company\\My Product\\1.0\\") );
}
See here for more details.
you can also read the value from the registry
path = HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
key = Common AppData