views:

1493

answers:

4

Yo.

I need to scan a directory and its sub-folders, I used FindFirst and FindNext procedures, but the TSearchRec's Name property is a string, thus unicode folder names (hebrew, arabic etc) are '?????' in the Name property.

I tried using TntComponent, with WideFindFirst, WideFindNext and TSearchRecW. But I still get ?????? for folder names.

 Flname:=WideExtractFileName(FileSpec);
 validres := WideFindFirst(FileSpec+'\*', faDirectory, SearchRec);
 AssignFile(LogFile, ResultFilePath);

 while validres=0 do begin
   if (SearchRec.Attr and faDirectory>0) and (SearchRec.Name[1]<>'.') then begin
     {invalid entry Findnext returns}
     Append(LogFile);
     WriteLn(LogFile, FileSpec+'\'+LowerCase(SearchRec.Name));
     CloseFile(LogFile);
     DirScan(FileSpec+'\'+SearchRec.Name, ResultFilePath)
   end;
   validres:=WideFindNext(SearchRec);
 end;
 WideFindClose(SearchRec);
+2  A: 

Delphi versions prior to 2009 have very limited unicode support. So if you really want unicode, then I strongly advise you to upgrade to 2009. In 2009 the default string is unicode.

You say that you still got garbage characters with the wide versions. Have you tried to inspect the values with the debugger? The vcl of pre 2009 delphi can not show unicode chars.

Gamecat
I've installed 2009, but there wasn't a FindFirst/Next with unicode support.
Yarin Miran
Yes, there is. The entire VCL/RTL has been updated in 2009 to call the Unicode version of the Win32 API functions (in this case, FindFirstFileW() and FindNextFileW()) instead of the Ansi functions. Also, Delphi's 'String' type is Unicode in 2009 as well, so TSearchRec.Name will contain the actual Unicode filenames that FindFirstFileW() and FindNextFileW() return. And don't forget that TSearchRec provides access to the original WIN32_FIND_DATA structure, which is also Unicode in 2009.
Remy Lebeau - TeamB
A: 

Some update.. If I use UTF8Encode on the SearchRec.Name I get the unicode string! Next problem is TFileStream I use. I couldn't find a WideString version for it(for filenames).

Yarin Miran
Open the file with CreateFileW. Then create a THandleStream with that handle.
Rob Kennedy
A: 

You could use CreateFileW to open the file and get a handle then use THandleStream instead of TFileStream to read the file.

Tnt Unicode (TMS Unicode now) has a TTntFileStream which can open files based on widestring. And as Gamecat stated, if you want to do unicode you should really upgrade to Delphi 2009. (awesome release in general)

PetriW
+3  A: 

Delphi does support unicode in the compiler by using WideString.

But you'll face the following problems:

  • Delphi < 2009 does not support unicode in their VCL.
  • A lot of API mapping is done on the ANSI (OpenFileA for instance) variants of the API.
  • The delphi compiler will convert the WideStrings to a string a lot, so be very explicit about them.

It will work if you use the raw unicode windows api's.

So FindFirst uses the api FindFirstFile which delphi maps to the FindFirstFileA variant, and you'll need to directly call FindFirstW.

So you'll have 2 options.

  1. Upgrade to Delphi 2009 and have a lot of unicode mapping done for you
  2. Write your own unicode mapping functions

For the text file writing you might be able to use the GpTextFile or GpTextSteam by Primoz Gabrijelcic (aka gabr), they have unicode support.

Her is an example of opening a file with a unicode filename:

function OpenLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle;  overload;
begin
  if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]), @('\\'[1]), 2) then
    { Allready an UNC path }
    Result := CreateFileW(PWideChar(ALongFileName), GENERIC_READ, SharingMode, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
  else
    Result := CreateFileW(PWideChar('\\?\' + ALongFileName), GENERIC_READ, SharingMode, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
end;

function CreateLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload;
begin
  if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]), @('\\'[1]), 2) then
    { Allready an UNC path }
    Result := CreateFileW(PWideChar(ALongFileName), GENERIC_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
  else
    Result := CreateFileW(PWideChar('\\?\' + ALongFileName), GENERIC_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
end;

I've used these functions because the ANSI api's have a path limit of 254 chars, the unicode have a limit of 2^16 chars if I'm not mistaken.

After you've got the handle to the file you can just call the regular ReadFile delphi api mapping, to read data from your file.

Davy Landman
I'm trying to correct an error that appears to be increasing in frequency. The word 'allot' means to distribute by portions. The words 'a lot' means many. I'm not sure if you meant 'The delphi compiler will convert the WideStrings to a string a lot' or something else altogether.
thursdaysgeek
Hi, it's indeed something I frequently mistype (I stained about 20 questions on SO using allot)... Must be due to the fact English is not my native language. I'll change all my answers to remove the incorrect spelling... Thanks for telling me about it, I'll try to remember it!
Davy Landman
(And, of course, I made a grammatical error in telling you about it. I think that's Muphry's Law (yes, that at least was spelled correctly.))
thursdaysgeek