[Haskell-cafe] Why am I not allowed to use CStringLen inforeignexport?

Brian Hulley brianh at metamilk.com
Fri Sep 15 16:07:25 EDT 2006

Brian Hulley wrote:
> I assume that this means that on 32 bit Windows, the format of a BSTR
> is:
>     Word16 -- low word of length
>     Word16 -- high word of length
>     Word16 -- first char of string
>      ...

The above is not quite correct. It appears from 
http://www.oreilly.com/catalog/win32api/chapter/ch06.html that the length 
must preceed the actual BSTR, thus you must give VBA a pointer to the first 
*char* in the string not the actual start of the array of Word16's in 
memory. Furthermore, it appears that a terminating NULL is still needed even 
though the string itself can contain NULL characters. No only that, but the 
length must be given as the number of *bytes* (excluding the terminating 
NULL) not the number of characters.

Therefore here is a revised attempt at creating a Win32 BSTR:

    import Data.Word
    import Data.Bits
    import Foreign.Marshal.Array
    import Foreign.Ptr

    type BSTR = Ptr Word16

    createBSTR :: [Char] -> IO BSTR
    createBSTR s = do
            len :: Word32 = fromIntegral (length s * 2)
            low :: Word16 = fromIntegral (len .&. 0xFFFF)
            high :: Word16 = fromIntegral (shiftR len 16 .&. 0xFFFF)
        arr <- newArray ([low, high] ++ map (fromIntegral . fromEnum) s ++ 
        return $! plusPtr arr 4

    foreign export stdcall hello :: IO BSTR
    hello :: IO BSTR
    hello = createBSTR "Hello world!"

Regards, Brian. 

More information about the Haskell-Cafe mailing list