How to obtain path to folder in which user made right click in its background to invoke context menu? For example, user opened "D:\projects" folder and made right click in empty background area of that folder and it sees a menu item in context menu named 'Display Path'. Upon clicking it, it should invoke a simple console app to display string "D:\projects".
It can be done by registry by adding "%V" as argument to command to console app, for example, "C:\myfolder\myapp.exe" "%V". Hence, this %V gives folder path to argument list of main() of myuapp.exe. Easy huh!
How it can be done using shell extension menu handler? I wrote a simple shell context menu dll which works fine and do its job, except that I don't known how to get that folder path as string where user made right click in background.
I found that path comes as PCIDLIST_ABSOLUTE pidl argument in IShellExtInit::Initialize() method. But, I couldn't get it in simple string format. The code is below which crashes, of course.
HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFilder, IDataObject* pdtobj, HKEY hkeyProgID)
{
std::wstring s = L"null";
// check msg, this msgbox is shown as expected
MessageBox(NULL, L"Before", L"Initialize()", MB_OK);
//have problem in this line, I guess
SHGetPathFromIDList((LPCITEMIDLIST) pidlFilder, (PWSTR) &s);
// check msg, sometimes this msgbox is also shown as expected
MessageBox(NULL, L"After", L"Initialize()", MB_OK);
// but this msgbox is never shown. I removed it but code still crashes
MessageBox(NULL, std::wstring(s).c_str(), L"Initialize()", MB_OK);
return S_OK;
}
When I right click on folder background, it crashes and explorer restarts.
Does anyone know the problem and its solution? How to get folder path when right clicking background of folder to invoke context menu using shell extension?
In addition, how to get file/folder path when right clicking on it to invoke context menu using shell extension?
Thanks in advance
tried using this code too, still crashes
IShellFolder *sf = NULL;
STRRET pName = {};
sf->GetDisplayNameOf(pidlFilder, SHGDN_FORPARSING, &pName);
wchar_t *d = new wchar_t;
lstrcpyW(d,L"nulld");
size_t inst = MAX_PATH, outst ;
mbstowcs_s(&outst, d, inst, pName.cStr, MAX_PATH);
s = std::wstring(d);
MessageBox(NULL, std::wstring(s).c_str(), L"Initialize()", MB_OK);
You are trying to make
SHGetPathFromIDList()write the string data to the memory address where astd::wstringobject resides, which will not work.Use a fixed
WCHAR[]array instead, eg:Alternatively, if you want to receive the string data into a
std::wstringobject, then you have to pre-allocate its internal character buffer and then receive into that buffer, eg:Otherwise, you can simply receive into a
WCHAR[]and then assign that to yourstd::wstring, eg:Your 2nd example doesn't work for several reasons:
Your
IShellFolder *sfdoesn't point anywhere meaningful. UseSHGetDesktopFolder()to get the top-levelIShellFolderobject which you can then use to parsepidlFilder.you are allocating only 1
wchar_tforwchar_t *dto point at, but then you are trying to copy more than 1wchar_tinto that memory. You don't really need to allocate any memory at all, as the parsedSTRRETalready contains the necessary string data, so just use it as-is. Otherwise, you can pass theSTRRETtoStrRetToBuf()orStrRetToStr()to get the data in a more usable format.you are not paying attention to the
STRRET::uTypefield to know what kind of string data it is holding. Don't access thecStrfield unless theuTypefield is set toSTRRET_CSTR.StrRetToBuf()/StrRetToStr()will handle this for you.Try this instead: