Recent

Author Topic: Writing file to folder with caron š in the name  (Read 543 times)

bobonwhidbey

  • Sr. Member
  • ****
  • Posts: 438
    • Double Dummy Solver - free download
Writing file to folder with caron š in the name
« on: February 12, 2020, 06:43:03 pm »
A user (with Windows 10) from Czech Republic has Aleš  as his account name. The first time he runs my app it fails when it tries to store a file in a new folder: C:\Users\Aleš\AppData\Roaming\MyAppName.  I obtain the folder name with
Code: Pascal  [Select][+][-]
  1.  
  2. Folder := GetSpecialFolder(CSIDL_APPDATA);
  3.  
  4. function GetSpecialFolder(const CSIDL: integer): string;
  5. var
  6.   RecPath: PChar;
  7. begin
  8.   RecPath := StrAlloc(MAX_PATH);
  9.   try
  10.     FillChar(RecPath^, MAX_PATH, 0);
  11.     if SHGetSpecialFolderPath(0, RecPath, CSIDL, False) then
  12.       Result := RecPath
  13.     else
  14.       Result := '';
  15.   finally
  16.     StrDispose(RecPath);
  17.   end;
  18. end;
  19.  
  20.  

where SHGetSpecialFolderPath is from the shlobj library.

I'm pretty sure the problem is because of the caron. What's the solution?
Win10 64-bit / Lazarus 32-bit 2.0.10 / FPC 3.2.0

lucamar

  • Hero Member
  • *****
  • Posts: 3079
Re: Writing file to folder with caron š in the name
« Reply #1 on: February 12, 2020, 06:52:26 pm »
A frequently recommended "fix" for those problems is to use the UnicodeString(/WideString) variants of the API calls (IIRC, SHGetSpecialFolderPathW in this case), to avoid the potential problems with automatic Windows codepage and UTF-8 conversions which might happen with ANSIString.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

bobonwhidbey

  • Sr. Member
  • ****
  • Posts: 438
    • Double Dummy Solver - free download
Re: Writing file to folder with caron š in the name
« Reply #2 on: February 12, 2020, 08:20:08 pm »
With "regular" strings, I use:
Code: Pascal  [Select][+][-]
  1. var
  2. Folder : Pchar;
  3.  
  4.     Folder := StrAlloc(MAX_PATH);
  5.     FillChar(Folder^, MAX_PATH, 0);
  6.     SHGetSpecialFolderPath(0, Folder, CSIDL_APPDATA, False);    

When I tried to convert to wide strings, the compiler didn't like my StrAlloc line.
Code: Pascal  [Select][+][-]
  1. var
  2. Folder : Pwidechar;
  3.  
  4.     Folder := StrAlloc(MAX_PATH);
  5.     FillChar(Folder^, MAX_PATH, 0);
  6.     SHGetSpecialFolderPathW(0, Folder, CSIDL_APPDATA, False);    

How can I get the wide string folder name?
Win10 64-bit / Lazarus 32-bit 2.0.10 / FPC 3.2.0

GetMem

  • Hero Member
  • *****
  • Posts: 3758
Re: Writing file to folder with caron š in the name
« Reply #3 on: February 12, 2020, 08:36:49 pm »
Try this:
Code: Pascal  [Select][+][-]
  1. uses shlobj;
  2.  
  3. function TForm1.GetSpecialFolder(const CSIDL: LongInt): string;
  4. var
  5.   Buffer: array[0..MaxPathLen] of WideChar;
  6. begin
  7.   Result := '';
  8.   if SHGetFolderPathW(Handle, CSIDL, 0, SHGFP_TYPE_CURRENT, Buffer) = S_OK then
  9.     Result := Buffer;
  10. end;
  11.  
  12. procedure TForm1.Button1Click(Sender: TObject);
  13. begin
  14.   ShowMessage(GetSpecialFolder(CSIDL_APPDATA));
  15. end;
  16.  




lucamar

  • Hero Member
  • *****
  • Posts: 3079
Re: Writing file to folder with caron š in the name
« Reply #4 on: February 12, 2020, 08:51:29 pm »
Barebones, something like:

Code: Pascal  [Select][+][-]
  1. function GetAppData: WideString;
  2. var
  3.     Folder : WideString;
  4. begin    
  5.   SetLength(Folder, MAX_PATH+1);
  6.   if SHGetSpecialFolderPath(0, PWideChar(Folder), CSIDL_APPDATA, False) then
  7.     SetLength(Folder, StrLen(PChar(Folder)))
  8.   Result := Folder;
  9. end;

Note that you can also allocate space for the string with:
Code: Pascal  [Select][+][-]
  1. APWideChar := WideStrAlloc(SomeLength);
so you could also do:
Code: Pascal  [Select][+][-]
  1. var
  2.     Folder : PWideChar;
  3.  
  4. [...etc ...]
  5.  
  6.   Folder := WideStrAlloc(MAX_PATH);
  7.   SHGetSpecialFolderPath(0, Folder, CSIDL_APPDATA, False);
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

bobonwhidbey

  • Sr. Member
  • ****
  • Posts: 438
    • Double Dummy Solver - free download
Re: Writing file to folder with caron š in the name
« Reply #5 on: February 12, 2020, 09:02:31 pm »
Thanks Lucamar and GetMem, I've sent a test copy off to the user in Czech Republic to test. I'll report back when I can.
Win10 64-bit / Lazarus 32-bit 2.0.10 / FPC 3.2.0

Bart

  • Hero Member
  • *****
  • Posts: 3943
    • Bart en Mariska's Webstek
Re: Writing file to folder with caron š in the name
« Reply #6 on: February 12, 2020, 10:23:07 pm »
Unit Windirs has this function:

function GetWindowsSpecialDirUnicode(ID: Integer; CreateIfNotExists: Boolean = True): UnicodeString;

Bart

bobonwhidbey

  • Sr. Member
  • ****
  • Posts: 438
    • Double Dummy Solver - free download
Re: Writing file to folder with caron š in the name
« Reply #7 on: February 14, 2020, 11:49:15 pm »
It seems that many (most) dialogs don't accept Unicodestring variables, as opposed to string variables. For example, this:

Code: Pascal  [Select][+][-]
  1. OpenDialog1.InitialDir := SomeUnicodeStringFolder:

results in a compiler warning. I have little familiarity with UnicodeStrings so I don't know what happens here. It would seem that the UnicodeString variable would be converted to string, and the wrong InitDir would appear. Is that right.
Win10 64-bit / Lazarus 32-bit 2.0.10 / FPC 3.2.0

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3865
  • I like bugs.
Re: Writing file to folder with caron š in the name
« Reply #8 on: February 15, 2020, 01:05:27 am »
It seems that many (most) dialogs don't accept Unicodestring variables, as opposed to string variables.
Yes. Lazarus and LCL use "String" with UTF-8 encoding in the Unicode system. Please read this carefully:
 https://wiki.freepascal.org/Unicode_Support_in_Lazarus
You should also use the cross-platform code from libraries instead of calling WinAPI directly, when possible. It makes programming easier and your application becomes cross-platform automatically.

Try function GetUserDir from unit sysutils.
« Last Edit: February 15, 2020, 01:39:39 am by JuhaManninen »
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux.

 

TinyPortal © 2005-2018