perl-unicode

Win32::API and Unicode filenames

2005-06-17 10:38:31
Hello!

Considering Perl cannot open files with Unicode filenames by default I decided 
to create a Win32 module which imports functions like CreateFileW from 
kernel32.dll and let it write/read files through that. The OS I am writing this 
for will always be Windows, and in all cases >= 2K (so 2K, XP, 2K3, etc). I 
have no interest in supporting older systems like 9x and NT (yet?). I've 
already implemented a some of the functions (fopen, fclose, fread, fwrite, 
fseek) and the basic thing works, but, there is one "slight" problem/oddity.

I have the following code:

my $fname = pack("H*", "e68aa5e7bab82e706c");
   $fname = decode("utf8", $fname);
   $fname = encode("UTF-16LE", $fname);

# Open a file handle to the file :)
if(fopen(\my $fh, ">", $fname)) { # Fails!

This however fails miserably, with an error that it cannot create the file 
(even though it is UTF-16LE, which is supposely the encoding used on NTFS). 
But, when I bump in a "print" in the middle it works like a charm (creates the 
file, then later on in the if() block writes "Hello World!" to it).. This, to 
me, is very odd because "print" shouldn't do anything with the variable (but 
when using non-Unicode filenames the print is not required and everything runs 
OK!):

my $fname = pack("H*", "e68aa5e7bab82e706c");
   $fname = decode("utf8", $fname);
   $fname = encode("UTF-16LE", $fname);

print "$fname\n";

# Open a file handle to the file :)
if(fopen(\my $fh, ">", $fname)) { # Works?!

Does anyone have a solution to this of the top of their head? I've included the 
fopen() subroutine for reference. The __mode() sub simply converts the mode 
types like ">" and "<" to their corrosponding LONG values. $apis is an array 
reference filled with the APIs I use (I didn't want the imported functions 
directly into the modules namespace).

Any help would be appreciated! :)

Siebe Tolsma
BOT2K3 Team [ http://bot2k3.net ]

------

sub fopen {
    # open FILEHANDLE,MODE,EXPR
    my $sref = shift; # Reference
    my $mode = shift; # < > >> +< +> +>>
    my $file = shift; # Filename

    # Check what mode we want..
    my $fmode = __mode($mode);
 
    # Valid mode?
    if($fmode > 0) {
        # HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD 
dwShareMode, 
        # LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD 
dwCreationDisposition, DWORD dwFlagsAndAttributes, 
        # HANDLE hTemplateFile );
    
        # Determine how to open (and create if necessary) the file
        my $fop = ($mode =~ />>/ ? OPEN_ALWAYS : ($mode =~ /</ ? OPEN_EXISTING 
: CREATE_ALWAYS));
    
        # Open the file with the API..
        my $fh = $apis->[0]->Call($file, $fmode, 0, 0, $fop, 
FILE_ATTRIBUTE_NORMAL, 0);
        if($fh != INVALID_HANDLE_VALUE) {
            # Bless the object and pass it back
            return bless($$sref = [$fh,$mode,$fmode], __PACKAGE__);
   
        } else { cluck("Could not create handle to file \"$file\"\n"); }
    } else { cluck("Could not determine mode for opening from \"$mode\"\n"); }
    return 0;
}
<Prev in Thread] Current Thread [Next in Thread>
  • Win32::API and Unicode filenames, Siebe Tolsma <=