[plt-scheme] String as output parameter of FFI call to W32 API GetLogicalDriveStringsW?

From: Andrea Girotto (andrea.girotto at gmail.com)
Date: Mon Feb 1 16:41:04 EST 2010

Hello,
I have a problem calling via FFI a Windows API function:
GetLogicalDrivesStringsW.

First of all, if I write:

#lang scheme
(require scheme/foreign)
(unsafe!)

(define kernel32 (ffi-lib "kernel32"))

(define get-logical-drive
  (get-ffi-obj "GetLogicalDrives" kernel32
               (_fun #:abi 'stdcall -> _uint32)
               (lambda () (error 'kernel32 "Missing GetLogicalDrives")) ) )

(let ((drives (get-logical-drive)))
   (display drives)
   (display #\tab)
   (display (number->string drives 2))(newline) )

the answer is:

262157  1000000000000001101

So it is telling me that there are A:, C:, D: and S: (and FFI is
working! :-)). That's correct, and I have the same answer with:

> (display (filesystem-root-list))(newline)
(C:\ D:\ S:\)

(the disk A: is missing because, in my opinion, the
"filesystem_root_list" function in src/mzscheme/src/file.c is checking
it with the "GetDiskFreeSpace" and there's absolutely no floppy in the
system...).

Now I need to get the same information in another way (...long story:
at the end of this path I will enumerate the USB sticks connected to
the computer, that is a relatively simple task with Linux, but such an
incredible complex task with Windows API, maybe it's only me and my
inexperience with Windows...):

(define get-logical-drive-strings-w
  (get-ffi-obj "GetLogicalDriveStringsW" kernel32
               (_fun #:abi 'stdcall
                     _uint32
                     _string
                     -> _uint32)
               (lambda () (error 'kernel32 "Missing
GetLogicalDriveStrings")) ) )

(define get-logical-drive-strings
  (let* ((n 128)
	 (s (make-string n #\~)))
    (display (get-logical-drive-strings-w 128 s))(newline)
    (display s)(newline)
    (display (string->list s))(newline) ) )

I'm filling 128 chars with the "~" character before calling the
GetLogicalDriveStringsW.
This Windows API should return the number of characters written in the
string. Instead, the answer is:

16
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 ~ ~ ~ ~ ~ ~ ~ ~)

The "16" number is the GetLogicaDriveStringsW that it is telling me
having written 16 characters...
But in the string there is only the sequence of "~" that I used to
initialize it...

My suspect :-) is that I cannot call a FFI function using a Scheme
string as output parameter.

BTW: the "filesystem_root_list" function in src/mzscheme/src/file.c is
calling "GetLogicalDriveStrings" to list the filesystems' roots. I
think that "GetLogicalDriveStrings" is a C/C++ macro of
"GetLogicalDriveStringsW" or "GetLogicalDriveStringsA", because the
first one is triggering the error message of "get-ffi-obj", the others
two are not...

So how can I pass a string as output parameter (to be filled from
GetLogicalDriveStringsW) and read it back?

Thank you,
Best regards,
Andrew.


Posted on the users mailing list.