Re: FindFirstFileW
From: Rob Kennedy (me3_at_privacy.net)
Date: 03/08/05
- Next message: Dave Turner: "Re: FindFirstFileW"
- Previous message: J French: "Re: Solved half my problem myself."
- In reply to: Dave Turner: "Re: FindFirstFileW"
- Next in thread: Dave Turner: "Re: FindFirstFileW"
- Reply: Dave Turner: "Re: FindFirstFileW"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Tue, 08 Mar 2005 11:09:14 -0600
Dave Turner wrote:
> Ive been using other languages all my life and im new to Delphi so I'd just
> love to see a unicode version of FindFirstFile/FindNextFile, as thatd be
> almost like a good Hello World ansi vs unicode comparison
>
> MessageBoxA/W would also be sufficient, just not as fun 8)
Mostly, you just just tack a W to the end of every API function and type.
I searched Google for "FindFirstFile FindNextFile Delphi" and found this
example. I'll comment on it to describe what changes are necessary to
make it use Unicode.
http://www.luckie-online.de/Delphi/Sonstiges/FindFirstFile.html
type
TStringDynArray = array of string;
First change: string -> WideString
var
FileCount: Cardinal = 0;
Files : TStringDynArray = nil;
function FindAllFiles(RootFolder: string; Mask: string = '*.*'; Recurse:
Boolean = True): TStringDynArray;
Declare those string parameters as WideStrings, too. Also, declare Mask
as const. It should have been const in the non-Unicode version, too.
Without const, this function makes a copy of the parameter, and copying
a WideString is considerably more expensive than copying an AnsiString.
As long as you're changing the declaration, go ahead and turn this into
a procedure instead of a function. It never returns anything anyway.
var
wfd : TWin32FindData;
Declare the above as TWin32FindDataW.
hFile : THandle;
begin
if AnsiLastChar(RootFolder)^ <> '\' then
RootFolder := RootFolder + '\';
I don't know whether there is a WideLastChar function, but you don't
need it. Wide characters are always two bytes wide, whereas AnsiString
characters can have multiple widths. That's why this code calls
AnsiLastChar. You can do the WideString check with this:
RootFolder[Length(RootFolder)] <> '\'.
if Recurse then
begin
hFile := FindFirstFile(PChar(RootFolder + '*.*'), wfd);
Tack a W on the end of that function, and cast to PWideChar instead of
PChar.
if hFile <> INVALID_HANDLE_VALUE then
try
repeat
if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY =
FILE_ATTRIBUTE_DIRECTORY then
if (string(wfd.cFileName) <> '.') and (string(wfd.cFileName)
<> '..')
Don't cast those arrays to WideString. This code shouldn't cast to
AnsiString in the first place. It should instead use the function
designed for comparing character arrays, StrComp. For WideChar arrays,
you can use StrCompW from the JclWideString or JclUnicode units if you
have the JCL, or you can call the StrCmpW API function. (Delphi's
function name has an "o" in it; Windows' doesn't.)
then
FindAllFiles(RootFolder + wfd.cFileName, Mask, Recurse);
until FindNextFile(hFile, wfd) = False;
Tack a W on the end of that function's name, too.
finally
windows.FindClose(hFile);
There is no FindCloseW; it isn't necessary. FindClose already knows how
the find handle was opened.
end;
end;
hFile := FindFirstFile(PChar(RootFolder + '*.*'), wfd);
Add a W and cast to PWideChar.
if hFile <> INVALID_HANDLE_VALUE then
try
repeat
if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <>
FILE_ATTRIBUTE_DIRECTORY then
begin
FileCount := length(Files)+1;
Setlength(Files, FileCount);
Files[FileCount - 1] := RootFolder + String(wfd.cFileName);
This is a terrible example of how to use a dynamic array, but I didn't
choose this example for its dynarray use. Regardless, the type cast to
AnsiString isn't necessary, and neither is a cast to WideString. Just
append wfd.cFileName directly to RootFolder.
end;
until FindNextFile(hFile, wfd) = False;
Add a W to the name.
finally
Windows.FindClose(hFile);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i : Integer;
begin
Files := nil;
FindAllFiles('d:\Dokumente', '*.*', True);
for i := 0 to length(Files) - 1 do
begin
Listbox1.Items.Add(Files[i]);
This last part is probably the most frustrating part about using Unicode
with Delphi. The VCL controls don't support Unicode at all, so adding
all your Unicode strings to a non-Unicode list box undoes all the
changes you made above. I urge you to go download Troy Wolbrink's Tnt
Unicode controls. They're all descendants of Borland's non-Unicode
controls, so they have the same functionality as their ancestors.
Replace the TListBox with a TTntListBox, and the code in this event
handler won't need to change at all. TTntListBox introduces a
Unicode-aware Items property.
end;
end;
-- Rob
- Next message: Dave Turner: "Re: FindFirstFileW"
- Previous message: J French: "Re: Solved half my problem myself."
- In reply to: Dave Turner: "Re: FindFirstFileW"
- Next in thread: Dave Turner: "Re: FindFirstFileW"
- Reply: Dave Turner: "Re: FindFirstFileW"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]