
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
Thanks a lot for this information it helped a lot.
Because I use the VBA 6 version the string characters are supposed to be a
byte so I changed your code to
type BSTR8 = Ptr Word8
createBSTR8 :: String -> IO BSTR8
createBSTR8 s = do
let
len :: Word32 = fromIntegral (length s)
low_l :: Word8 = fromIntegral (len .&. 0xFFFF)
low_h :: Word8 = fromIntegral (shiftR len 8 .&. 0xFFFF)
high_l :: Word8 = fromIntegral (shiftR len 16 .&. 0xFFFF)
high_h :: Word8 = fromIntegral (shiftR len 24 .&. 0xFFFF)
arr <- newArray ([low_l,low_h,high_l,high_h] ++ map (fromIntegral .
fromEnum) s ++ [0])
return $! plusPtr arr 4
Maybe this helps some one else too.
I am thinking about creating a wikipage about Haskell<->VBA interfacing
through a DLL.
Is it okay for you if I put your code there?
I am a bit concerned about the memory. newArray states that the memory has
to be freed after usage. Is this needed here? How can it be done?
Thanks to everyone who responded,
Andreas
----- Original Message -----
From: "Brian Hulley"
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 let 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 ++ [0]) return $! plusPtr arr 4
foreign export stdcall hello :: IO BSTR hello :: IO BSTR hello = createBSTR "Hello world!"
Regards, Brian.