Issues with SHGetPathFromiDList

Posted on 2013-05-22
Last Modified: 2013-08-22
I'm trying to pull the paths from an IDataObject, however the string added to the list is always empty. The following method is being called from "IShellExtInit.Initialize".

function ProcessItemIDListData(lpdobj: IDataObject; filesList: TStringList): HResult;
stgMedium: TStgMedium;
formatEtc: TFormatEtc;
i: integer;
lpRootPidl: PItemiDList;
lpPidl: PItemiDList;
lpFileName: array[0..MAX_PATH] of Char;
    formatEtc.cfFormat := RegisterClipboardFormat(CFSTR_SHELLIDLIST);
    formatEtc.ptd := nil;
    formatEtc.dwAspect := DVASPECT_CONTENT;
    formatEtc.lindex := -1;
    formatEtc.tymed := TYMED_HGLOBAL;
    Result := lpdobj.GetData(formatEtc, stgMedium);

    if not Failed(Result) then
                lpIDA := GlobalLock(stgMedium.hGlobal);
                    lpRootPidl := PItemiDList(LPBYTE(lpIDA) + lpIDA.aoffset[0]);
                    for i := 1 to lpIDA.cidl do
                            lpPidl := ILCombine(lpRootPidl, PItemiDList(LPBYTE(lpIDA) + lpIDA.aoffset[i]));
                            if lpPidl <> nil then
                                    SHGetPathFromiDList(lpPidl, lpFileName);
                    Result := NOERROR;
            Result := NOERROR;

Open in new window

There are a few things I have noted.
1) SHGetPathFromiDList always returns false??
2) If I change the code to something like (where s is a string)
SetLength(s, 1024);
SHGetPathFromiDList(lpPidl, PChar(s));

Open in new window

I actually get a path for the object, except the string is not trimmed correctly (and I have also tried filesList.Add(StrPas(PChar(s))); etc)

Can anyone help, or point me in the right direction?

Question by:thebeersmith
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
LVL 36

Assisted Solution

mccarl earned 100 total points
ID: 39189745
It's been a while since I have done anything Delphi related so this may not be anything close to the answer, but in case you get nothing else, here are my thoughts...

Could the problem be to do with mismatches between 1-byte characters and 2-byte characters, eg. Unicode or wide chars? In my dealings with this a long time ago, I do remember there being issue when interfacing my code (which always just used 1-byte chars) and System calls such as SHGetPath... that used 2-byte chars. Are you able to do low level debugging and see exactly what memory is getting allocated for lpFileName and exactly how that memory is being filled?

Because it has been a while for me, your code might even be correctly taking all that into account, but I just thought I would throw that idea out there, in case it can be of some use to you!
LVL 34

Expert Comment

ID: 39190072
if the SHGetPathFromIDList returns 0  (false), it has failed. the contents of the buffer you provided was not (likely to be) filled.

you may call GetLastError after call what should give a more specific error.


Author Comment

ID: 39190093
@Sara - Well that is what you would expect, however GetLastError reports "The operation completed successfully". This is why I removed the checking of the result (as a side note, all sample code I've looked at, in C++ and Delphi does not check the result of this call, which is odd)... this also does not explain why using the string method returns something... albeit a bit wacky.
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

LVL 34

Assisted Solution

sarabande earned 400 total points
ID: 39190147
ok. i wonder why SHGetPathFromIDList returns 0  what is FALSE if there is no error.

anyhow, mccarl probably is on the right track. the SHGetPathFromIDList takes a LPTSTR as second argument. that is a pointer to TCHAR what is 8-bit char if the project settings are 'multibyte characterset' or 16-bit wchar_t if 'unicode characterset' is the default.

when using StrPas function the argument expected is a PAnsiChar what is char (ansi == 8-bit) while the SHGetPathFromIDList might expect a wide char buffer. if using a string s with sufficient size, the pointer you were passing to SHGetPathFromIDList at least points to a sufficiently large buffer. however a pascal string obviously doesn't contain only a buffer but also has length attributes which were not properly filled in your case. that's why you see the string 'is not trimmed correctly'.

you might go one of the following ways:

- try to change from UNICODE to ANSI if that is possible
- use an array of WideChar characters for lpFileName and assign it to a string
- try to 'trim' the string you passed as buffer to SHGetPathFromIDList after call by
  iterating all characters and check for two zero bytes. that is the end of the
  path string and you could set your string length accordingly


Author Comment

ID: 39206034
@Sara - Thanks for the input. I'm using Delphi XE3 which supports unicode, and as such a PChar is in fact a PWideChar (so lpFileName is a PWideChar) and SHGetPathFromIDList is expecting PWideChar. The same is true of StrPas, this is overloaded to handle either ansi or unicode.
LVL 34

Accepted Solution

sarabande earned 400 total points
ID: 39209070
then i would recommend to using second choice 'use an array of WideChar characters and assign it to a string'.

the received string should not need any further conversions and should print properly after assignment.


Featured Post

Enroll in July's Course of the Month

July's Course of the Month is now available! Enroll to learn HTML5 and prepare for certification. It's free for Premium Members, Team Accounts, and Qualified Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What do responsible coders do? They don't take detrimental shortcuts. They do take reasonable security precautions, create important automation, implement sufficient logging, fix things they break, and care about users.
Q&A with Course Creator, Mark Lassoff, on the importance of HTML5 in the career of a modern-day developer.
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…
Suggested Courses
Course of the Month4 days, 3 hours left to enroll

630 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question