PIDL.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. unit PIDL;
  2. {
  3. Description
  4. ===========
  5. Some methods to pidls. Purpose of methods are described in the code.
  6. Disclaimer
  7. ==========
  8. The author disclaims all warranties, expressed or implied, including,
  9. without limitation, the warranties of merchantability and of fitness
  10. for any purpose. The author assumes no liability for damages, direct or
  11. consequential, which may result from the use of this unit.
  12. Restrictions on Using the Unit
  13. ==============================
  14. This unit is copyright 1998 by Dieter Steinwedel. ALL RIGHTS
  15. ARE RESERVED BY DIETER STEINWEDEL. You are allowed to use it freely
  16. subject to the following restrictions:
  17. • You are not allowed delete or alter the author's name and
  18. copyright in any manner
  19. • You are not allowed to publish a copy, modified version or
  20. compilation neither for payment in any kind nor freely
  21. • You are allowed to create a link to the download in the WWW
  22. • These restrictions and terms apply to you as long as until
  23. I alter them. Changes can found on my homepage
  24. Contact
  25. =======
  26. homepage: http://godard.oec.uni-osnabrueck.de/student_home/dsteinwe/delphi/DietersDelphiSite.htm
  27. }
  28. interface
  29. uses ShlObj, Windows, ActiveX;
  30. function PIDL_GetNextItem(PIDL: PItemIDList):PItemIDList;
  31. function PIDL_GetSize(pidl: PITEMIDLIST): integer;
  32. function PIDL_Create(Size: UINT): PItemIDList;
  33. function PIDL_Concatenate(pidl1, pidl2: PItemIDList): PItemIDList;
  34. function PIDL_Copy(pidlSource: PItemIDList): PItemIDList;
  35. function PIDL_GetDisplayName(piFolder: IShellFolder; pidl: PItemIDList;
  36. dwFlags: DWORD; pszName: PChar; cchMax: UINT): boolean;
  37. function Pidl_GetFullyQualified(const PiParentFolder: IShellFolder;
  38. pidl: PItemIDList): PItemIDList;
  39. procedure PIDL_GetRelative(var pidlFQ, ppidlRoot, ppidlItem: PItemIDList);
  40. function PIDL_GetFromPath(pszFile: PChar): PItemIDList;
  41. function PIDL_GetFileFolder(pidl: PItemIDList; var piFolder: IShellFolder):boolean;
  42. function PIDL_GetFromParentFolder(pParentFolder: IShellFolder; pszFile: PChar): PItemIDList;
  43. procedure PIDL_Free(PIDL:PItemIDList);
  44. function PIDL_Equal(PIDL1,PIDL2:PItemIDList):boolean;
  45. {
  46. WINSHELLAPI BOOL WINAPI SHGetPathFromIDList( LPCITEMIDLIST pidl,
  47. LPSTR pszPath);
  48. Converts an item identifier list to a file system path. For more infomation
  49. check the online-help.
  50. }
  51. var ShellMalloc: IMalloc;
  52. CF_FILECONTENTS:UInt; // don't modify value
  53. CF_FILEDESCRIPTOR:UInt; // don't modify value
  54. CF_FILENAME:UInt; // don't modify value
  55. CF_FILENAMEMAP:UInt; // don't modify value
  56. CF_FILENAMEMAPW:UInt; // don't modify value
  57. CF_INDRAGLOOP:UInt; // don't modify value
  58. CF_NETRESOURCES:UInt; // don't modify value
  59. CF_PASTESUCCEEDED:UInt; // don't modify value
  60. CF_PERFORMEDDROPEFFECT:UInt; // don't modify value
  61. CF_PREFERREDDROPEFFECT:UInt; // don't modify value
  62. CF_PRINTERGROUP:UInt; // don't modify value
  63. CF_SHELLIDLIST:UInt; // don't modify value
  64. CF_SHELLIDLISTOFFSET:UInt; // don't modify value
  65. CF_SHELLURL:UInt; // don't modify value
  66. implementation
  67. const NullTerm=2;
  68. function PIDL_GetNextItem(PIDL: PItemIDList):PItemIDList;
  69. // PURPOSE: Returns a pointer to the next item in the ITEMIDLIST.
  70. // PARAMETERS:
  71. // pidl - Pointer to an ITEMIDLIST to walk through
  72. begin
  73. if PIDL<>nil then Result:=PItemIDList(PChar(PIDL)+PIDL^.mkid.cb)
  74. else Result:=nil
  75. end;
  76. function PIDL_GetSize(pidl: PITEMIDLIST): integer;
  77. // PURPOSE: Returns the total number of bytes in an ITEMIDLIST.
  78. // PARAMETERS:
  79. // pidl - Pointer to the ITEMIDLIST that you want the size of.
  80. begin
  81. Result:=0;
  82. if pidl<>nil then
  83. begin
  84. Inc(Result, SizeOf(pidl^.mkid.cb));
  85. while pidl^.mkid.cb <> 0 do
  86. begin
  87. Inc(Result, pidl^.mkid.cb);
  88. Inc(longint(pidl), pidl^.mkid.cb);
  89. end;
  90. end;
  91. end;
  92. function PIDL_Create(Size: UINT): PItemIDList;
  93. // PURPOSE: Creates a new ITEMIDLIST of the specified size.
  94. // PARAMETERS:
  95. // piMalloc - Pointer to the allocator interface that should allocate memory.
  96. // cbSize - Size of the ITEMIDLIST to create.
  97. // RETURN VALUE:
  98. // Returns a pointer to the new ITEMIDLIST, or NULL if a problem occured.
  99. begin
  100. Result:=ShellMalloc.Alloc(Size);
  101. if Result<>nil then
  102. FillChar(Result^, Size, #0);
  103. end;
  104. function PIDL_Concatenate(pidl1, pidl2: PItemIDList): PItemIDList;
  105. // PURPOSE: Creates a new ITEMIDLIST with pidl2 appended to pidl1.
  106. // PARAMETERS:
  107. // piMalloc - Pointer to the allocator interface that should create the new ITEMIDLIST.
  108. // pidl1 - Pointer to an ITEMIDLIST that contains the root.
  109. // pidl2 - Pointer to an ITEMIDLIST that contains what should be appended to the root.
  110. // RETURN VALUE:
  111. // Returns a new ITEMIDLIST if successful, NULL otherwise.
  112. var cb1, cb2: UINT;
  113. begin
  114. if (pidl1<>nil) then cb1:=PIDL_GetSize(pidl1)-NullTerm else cb1:=0;
  115. cb2:=PIDL_GetSize(pidl2);
  116. Result:=PIDL_Create(cb1 + cb2);
  117. if Result<>nil then
  118. begin
  119. if pidl1<>nil then CopyMemory(Result,pidl1,cb1);
  120. CopyMemory(PChar(Result)+cb1,pidl2,cb2);
  121. end;
  122. end;
  123. function PIDL_Copy(pidlSource: PItemIDList): PItemIDList;
  124. // PURPOSE: Creates a new copy of an ITEMIDLIST.
  125. // PARAMETERS:
  126. // piMalloc - Pointer to the allocator interfaced to be used to allocate the new ITEMIDLIST.
  127. // RETURN VALUE:
  128. // Returns a pointer to the new ITEMIDLIST, or NULL if an error occurs.
  129. var cbSource:UINT;
  130. begin
  131. Result:=nil;
  132. if pidlSource=nil then exit;
  133. cbSource:=PIDL_GetSize(pidlSource);
  134. Result:=PIDL_Create(cbSource);
  135. if Result=nil then exit;
  136. CopyMemory(Result,pidlSource,cbSource);
  137. end;
  138. function PIDL_GetDisplayName(piFolder: IShellFolder; pidl: PItemIDList;
  139. dwFlags: DWORD; pszName: PChar; cchMax: UINT): boolean;
  140. // PURPOSE: Returns the display name for the item pointed to by pidl. The
  141. // function assumes the pidl is relative to piFolder. If piFolder
  142. // is NULL, the function assumes the item is fully qualified.
  143. // PARAMETERS:
  144. // piFolder - Pointer to the IShellFolder for the folder containing the item.
  145. // pidl - Pointer to an ITEMIDLIST relative to piFolder that we want
  146. // the display name for.
  147. // dwFlags - Flags to pass to ISF::GetDisplayNameOf().
  148. // pszName - Pointer to the string where the display name is returned.
  149. // cchMax - Maximum number of characters in pszName.
  150. // RETURN VALUE:
  151. // Returns TRUE if successful, FALSE otherwise.
  152. var Str: TStrRet;
  153. begin
  154. if (piFolder=nil) and (Failed(SHGetDesktopFolder(piFolder))) then
  155. begin
  156. Result:=false;
  157. exit;
  158. end;
  159. Result:=TRUE;
  160. if piFolder.GetDisplayNameOf(pidl, dwFlags, Str) = NOERROR then
  161. begin
  162. case Str.uType of
  163. STRRET_WSTR:
  164. WideCharToMultiByte(CP_ACP, 0, str.pOleStr, -1, pszName, cchMax, nil, nil);
  165. STRRET_OFFSET:
  166. lstrcpyn(pszName, PChar(pidl)+str.uOffset, cchMax);
  167. STRRET_CSTR:
  168. lstrcpyn(pszName, str.cStr, cchMax);
  169. else Result := FALSE;
  170. end;
  171. end
  172. else Result:=FALSE;
  173. // piFolder._Release; -> automaticly done by D4
  174. end;
  175. function Pidl_GetFullyQualified(const PiParentFolder: IShellFolder;
  176. pidl: PItemIDList): PItemIDList;
  177. // PURPOSE: Takes a relative PIDL and it's parent IShellFolder, and returns
  178. // a fully qualified ITEMIDLIST.
  179. // PARAMETERS:
  180. // piParentFolder - Pointer to the IShellFolder of the parent folder.
  181. // pidl - ITEMIDLIST relative to piParentFolder
  182. // RETURN VALUE:
  183. // Returns a fully qualified ITEMIDLIST or NULL if there is a problem.
  184. var piDesktopFolder:IShellFolder;
  185. szBuffer: array[1..Max_Path] of char;
  186. szOleChar: array[1..Max_Path] of TOLECHAR;
  187. ulEaten, ulAttribs:ULong;
  188. begin
  189. Result:=nil;
  190. if Failed(SHGetDesktopFolder(piDesktopFolder)) then exit;
  191. if PIDL_GetDisplayName(piParentFolder, pidl, SHGDN_FORPARSING, @szBuffer, sizeof(szBuffer))=false then
  192. exit;
  193. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, @szBuffer, -1, @szOleChar, sizeof(szOleChar));
  194. if Failed(piDesktopFolder.ParseDisplayName(0, nil, @szOleChar, ulEaten,
  195. Result, ulAttribs)) then Result:=nil;
  196. // piDesktopFolder._Release; automaticly done by D4
  197. end;
  198. procedure PIDL_GetRelative(var pidlFQ, ppidlRoot, ppidlItem: PItemIDList);
  199. // PURPOSE: Takes a fully qualified pidl and returns the the relative pidl
  200. // and the root part of that pidl.
  201. // PARAMETERS:
  202. // pidlFQ - Pointer to the fully qualified ITEMIDLIST that needs to be parsed.
  203. // pidlRoot - Points to the pidl that will contain the root after parsing.
  204. // pidlItem - Points to the item relative to pidlRoot after parsing.
  205. var pidlTemp, pidlNext: PItemIDList;
  206. begin
  207. if pidlFQ=nil then
  208. begin
  209. ppidlRoot:=nil;
  210. ppidlItem:=nil;
  211. exit;
  212. end;
  213. ppidlItem:=nil;
  214. ppidlRoot:=PIDL_Copy(pidlFQ);
  215. pidlTemp:=ppidlRoot;
  216. while pidlTemp^.mkid.cb>0 do
  217. begin
  218. pidlNext:=PIDL_GetNextItem(pidlTemp);
  219. if pidlNext^.mkid.cb=0 then
  220. begin
  221. ppidlItem:=PIDL_Copy(pidlTemp);
  222. pidlTemp^.mkid.cb:=0;
  223. pidlTemp^.mkid.abID[0]:=0;
  224. end;
  225. pidlTemp:=pidlNext;
  226. end;
  227. end;
  228. function PIDL_GetFromPath(pszFile: PChar): PItemIDList;
  229. // PURPOSE: This routine takes a full path to a file and converts that
  230. // to a fully qualified ITEMIDLIST.
  231. // PARAMETERS:
  232. // pszFile - Full path to the file.
  233. // RETURN VALUE:
  234. // Returns a fully qualified ITEMIDLIST, or NULL if an error occurs.
  235. var piDesktop: IShellFolder;
  236. olePath: array[1..Max_Path] of TOleChar;
  237. ulEaten, ulAttribs:ULong;
  238. begin
  239. Result:=nil;
  240. if Failed(SHGetDesktopFolder(piDesktop)) then exit;
  241. piDesktop._AddRef;
  242. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszFile, -1, @olePath, sizeof(olepath));
  243. if Failed(piDesktop.ParseDisplayName(0, nil, @OlePath, ulEaten,
  244. Result, ulAttribs)) then Result:=nil;
  245. // piDesktop._Release; -> automaticly done by D4
  246. end;
  247. function PIDL_GetFileFolder(pidl: PItemIDList; var piFolder: IShellFolder):boolean;
  248. // PURPOSE: This routine takes a fully qualified pidl for a folder and returns
  249. // the IShellFolder pointer for that pidl
  250. // PARAMETERS:
  251. // pidl - Pointer to a fully qualified ITEMIDLIST for the folder
  252. // piParentFolder - Pointer to the IShellFolder of the folder (Return value).
  253. // RETURN VALUE:
  254. // Returns TRUE if successful, FALSE otherwise.
  255. var piDesktopFolder: IShellFolder;
  256. {MP}// i:integer;
  257. begin
  258. Result:=false;
  259. if Failed(SHGetDesktopFolder(piDesktopFolder)) then exit;
  260. if assigned(PiFolder)=false then
  261. if Failed(SHGetDesktopFolder(PiFolder)) then exit;
  262. if (Failed(piDesktopFolder.BindToObject(pidl, nil, IID_IShellFolder,
  263. pointer(PiFolder)))=false) or
  264. (assigned(pidl) and (pidl^.mkid.cb=0)) then Result:=true
  265. //piDesktopFolder._Release; -> automaticly done by D4
  266. end;
  267. function PIDL_GetFromParentFolder(pParentFolder: IShellFolder; pszFile: PChar): PItemIDList;
  268. // PURPOSE: This routine takes a Shell folder for the parent and the FileName in the folder
  269. // and converts that to a relative ITEMIDLIST.
  270. // PARAMETERS:
  271. // pParentFolder - Pointer to the IShellFolder for the folder containing the
  272. // fileName.
  273. // pszFile - file name in the folder.
  274. // RETURN VALUE:
  275. // Returns a relative ITEMIDLIST, or NULL if an error occurs.
  276. var olePath: array[1..Max_Path] of TOleChar;
  277. chEaten, dwAttributes: ULONG;
  278. begin
  279. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszFile, -1, @olePath, sizeOf(olePath));
  280. if Failed(pParentFolder.ParseDisplayName(0, nil, @olePath, chEaten, Result,
  281. dwAttributes)) then Result:=nil;
  282. end;
  283. procedure PIDL_Free(PIDL:PItemIDList);
  284. begin
  285. if PIDL<>nil then
  286. ShellMalloc.Free(PIDL);
  287. end;
  288. function PIDL_Equal(PIDL1,PIDL2:PItemIDList):boolean;
  289. var i,size:integer;
  290. p1,p2:pchar;
  291. begin
  292. Result:=false;
  293. if (PIDL1=nil) or (PIDL2=nil) then exit;
  294. size:=PIDL_GetSize(PIDL1);
  295. if size<>PIDL_GetSize(PIDL2) then exit;
  296. i:=0;
  297. p1:=PChar(PIDL1);
  298. p2:=PChar(PIDL2);
  299. while i<size do
  300. if p1[i]<>p2[i] then exit else inc(i);
  301. Result:=true;
  302. end;
  303. initialization
  304. SHGetMalloc(ShellMalloc);
  305. CF_FILECONTENTS:=RegisterClipboardFormat('FileContents');
  306. CF_FILEDESCRIPTOR:=RegisterClipboardFormat('FileGroupDescriptor');
  307. CF_FILENAME:=RegisterClipboardFormat('FileName');
  308. CF_FILENAMEMAP:=RegisterClipboardFormat('FileNameMap');
  309. CF_FILENAMEMAPW:=RegisterClipboardFormat('FileNameMapW');
  310. CF_INDRAGLOOP:=RegisterClipboardFormat('InShellDragLoop');
  311. CF_NETRESOURCES:=RegisterClipboardFormat('Net Resource');
  312. CF_PASTESUCCEEDED:=RegisterClipboardFormat('Paste Succeeded');
  313. CF_PERFORMEDDROPEFFECT:=RegisterClipboardFormat('Performed DropEffect');
  314. CF_PREFERREDDROPEFFECT:=RegisterClipboardFormat('Preferred DropEffect');
  315. CF_PRINTERGROUP:=RegisterClipboardFormat('PrinterFriendlyName');
  316. CF_SHELLIDLIST:=RegisterClipboardFormat('Shell IDList Array');
  317. CF_SHELLIDLISTOFFSET:=RegisterClipboardFormat('Shell Object Offsets');
  318. CF_SHELLURL:=RegisterClipboardFormat('UniformResourceLocator');
  319. finalization
  320. // ShellMalloc._Release; -> automaticly done by D4
  321. end.