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
  • 3
  • 2
LVL 35

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 33

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.
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

LVL 33

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 33

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

Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
egit plugin on eclipse 8 64
Filename to be appended with DateTimeof Download 3 57
iSeries email authority 6 57
Query group by data in SQL Server - cursor? 3 34
This article will show, step by step, how to integrate R code into a R Sweave document
This is an explanation of a simple data model to help parse a JSON feed
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

803 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