Recent

Author Topic: SHGetFileInfoW and extra-long pathes  (Read 1558 times)

HomeBoy38

  • New Member
  • *
  • Posts: 49
SHGetFileInfoW and extra-long pathes
« on: November 13, 2021, 09:01:05 am »
Hello,

Context:
My program search for files, and make some actions on them. So far, there was a chance to have errors when the path+name was exceeding MAX_PATH, which was an opportunity to detect those.
I was looking at a bug (unhandled error) and I came to this from Microsoft : https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd. They are mentioning the "\\?\" and "\\?\UNC\" syntax which I tried (so far with a bit success, but I need a lot more tests).

Issue:
The unhandled error I was previously referring to was due to SHGetFileInfoW which was causing an error when the path was too long (and my code was wrong).
But, this function seems to fail because of the "\\?\" and "\\?\UNC\" syntax and the Microsoft's page (https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetfileinfow) let me think it has not been handled.

Bonus:
SHGetFileInfoW: on the forum, I saw that using SHGFI_USEFILEATTRIBUTES should speed up the function but I did not see a real difference. May I keep it anyway?
EDIT: I removed it because it does not work for folders

Function:
Code: Pascal  [Select][+][-]
  1. // Get a file's associated icon
  2. function GetFileIcon(FileName: String; MyIcon: TIcon): Boolean;
  3. var
  4.  FileInfo: SHFILEINFOW;
  5.  Res: DWORD;
  6. begin
  7.  // Get imagelist index, display name and type of file
  8.  Res := SHGetFileInfoW(PWideChar(UTF8ToUTF16(FileName)), 0, FileInfo, SizeOf(FileInfo),
  9.                        SHGFI_USEFILEATTRIBUTES or SHGFI_ICON or SHGFI_SMALLICON or SHGFI_SYSICONINDEX);
  10.  if Res <> 0 then
  11.  begin
  12.   MyIcon.Handle := FileInfo.hIcon;
  13.   Result := True;
  14.  end
  15.  else
  16.   Result := False;
  17. end;
  18.  

Calling function:
Code: Pascal  [Select][+][-]
  1.    MyIcon := TIcon.Create;
  2.    MyFilePath := PathName + PathDelim + FileName;
  3.    if GetFileIcon(MyFilePath, MyIcon) = True then
  4.    begin
  5.     ListItem.ImageIndex := Icons.AddIcon(MyIcon);
  6.     ListItem.ImageIndex := ImageList_ReplaceIcon(Icons.ResolutionByIndex[0].Reference.Handle, ListItem.ImageIndex, MyIcon.Handle);
  7.     if (MyEXT = '.LNK') or (MyEXT = '.EXE') or (MyEXT = '.ICO') then
  8.      VLEIcons.InsertRow(IntToStr(ListItem.Index), IntToStr(ListItem.ImageIndex), True)
  9.     else
  10.      VLEIcons.InsertRow(MyEXT, IntToStr(ListItem.ImageIndex), True);
  11.    end;
  12.    MyIcon.Free;
  13.  
Note: VLEIcons is a TValueListEditor.

Summary:
Thanks for your input on this
« Last Edit: November 13, 2021, 09:36:37 am by HomeBoy38 »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9778
  • FPC developer.
Re: SHGetFileInfoW and extra-long pathes
« Reply #1 on: November 13, 2021, 12:15:46 pm »
(Hint: try to just enable long file support in the resources tab of program options, please report back how it worked)

HomeBoy38

  • New Member
  • *
  • Posts: 49
Re: SHGetFileInfoW and extra-long pathes
« Reply #2 on: November 13, 2021, 01:45:30 pm »
I was not aware of such option and unfortunately, I do not find it nor found instructions how to access it: do you have any screenshot to point it to me, maybe because of my French version.

ASerge

  • Hero Member
  • *****
  • Posts: 1906
Re: SHGetFileInfoW and extra-long pathes
« Reply #3 on: November 13, 2021, 04:14:58 pm »
I was not aware of such option and unfortunately, I do not find it nor found instructions how to access it: do you have any screenshot to point it to me, maybe because of my French version.
activer les chemins d’accès longs dans Windows 10, Version 1607 et versions ultérieures.
But as far as I know, shell functions still don't support long names.
And the introduced "innovation" is intended only for programs that are not written by you (without using shell functions, of course). Because in your programs, you can simply add a prefix \\?\ to the name, which removes the restriction. And it's been working for a very long time.

HomeBoy38

  • New Member
  • *
  • Posts: 49
Re: SHGetFileInfoW and extra-long pathes
« Reply #4 on: November 13, 2021, 04:38:28 pm »
I am a bit confused now: I thought marcov's suggestion was a Lazarus option to enable before building my program?

I do not want to change the operating system, \\?\ option was a good alternative to me (I will make a few tests under 7, and 32/64 OS - so far, only Win10x64 21H1 tested), only the icon retrieval was failing so far.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9778
  • FPC developer.
Re: SHGetFileInfoW and extra-long pathes
« Reply #5 on: November 13, 2021, 05:14:12 pm »
Exactly that yes, an option in Lazarus.

While you can workaround with \\?\ (and I did in some cases before this option), the advantage is that one missing \\?| doesn't lead to a broken program (since these kinds of issues are typically not that often tested/encountered). Also using the option the program contains less non-portable code.

The price is an upping of the Windows version, but that will get less by time. Note also the utf-8 unicode option.



HomeBoy38

  • New Member
  • *
  • Posts: 49
Re: SHGetFileInfoW and extra-long pathes
« Reply #6 on: November 13, 2021, 06:21:20 pm »
Thanks for your help, I really appreciate.

I definitely need to change my glasses  :o

I made a quick test using the latest Lazarus RC2:
- remove \\?\... with long file option activated: quite all Windows functions I use failed (I might need to investigate more if need)
- put back \\?\... with long file option activated: quite all Windows functions I use work
In both cases, the icon seem to be working normally. I do not really know what this option does, but at the first sight, it seems to be working on my particular issue.

I will try to build again with the previous stable version, testing x86, Windows Seven, ... I also need to modify a few functions that seem to continue to fail.

I might have not understood the price you mentionned. I ignored the utf8 option as a Windows 10 seems to be a prerequisite.

I also might have not understood: I can make some testing of those Windows functions with this option activated and \\?\ not passed to those functions and test the result in my environment (it took me less than a minute to find a 276 characters long file+path name in my environment, do you mean it should be interesting in the project?

EDIT: I do not have the option under 2.0.8, so maybe I will make some tests and results with 2.2.0RC2 and post them here if it is somehow useful. Unfortunately, so far, my test computer is under hardware maintenance for the week
« Last Edit: November 15, 2021, 11:30:37 am by HomeBoy38 »

 

TinyPortal © 2005-2018