shiftJisからUtf16、Utf16からshiftJisへの変換では、変換した後にpeekCString、peekCWString関数によってC文字列からHaskell文字列を作ります。C文字列はHaskell文字列返す前にメモリを解放しているのですが、ふとポインタで指している領域が消えると返す値まで消えてしまうのではないかと思いました。
そこで、peekCStringでCの文字列からHaskell文字列を作った後にC文字列が書き換えられてもHaskellの文字列に影響がないことを確認します。
HaskellはpeekCString、peekCWString関数によって新しくHaskell文字列を作りますのでメモリ解放しても影響は受けません。
{-# LANGUAGE ForeignFunctionInterface #-} -- ghc --make -Wall utf8.hs bstr.c -loleaut32 -o utf8 module Main where import Foreign.Marshal.Alloc import Foreign.C.String import Foreign.C.Types shiftJisToUtf16 :: String -> IO String shiftJisToUtf16 string = do cws <- newCWString "※※※※\n" bstr <- withCString string c_CStringToBSTR -- cswprintf bstr cws -- ここで上書きすれば出力も変わります。 str <- peekCWString bstr cswprintf bstr cws -- ここで cws を上書き cwprintf bstr -- 上書きした文字列を表示してみる。 "※※※※\n" cSysFreeString bstr return str utf16ToShiftJis :: String -> IO String utf16ToShiftJis string = do cstring <- withCWString string c_BSTRtoCString -- oprintf cstring -- ここで上書きすれば出力も変わります。 str <- peekCString cstring oprintf cstring -- ここでcstringを上書き cprintf cstring -- 上書きした文字列を表示してみる。 "hello,world!" free cstring return str -- C の関数を呼ぶための定義 foreign import ccall unsafe "CStringToBSTR" c_CStringToBSTR :: CString -> IO CWString foreign import ccall unsafe "BSTRtoCString" c_BSTRtoCString :: CWString -> IO CString foreign import stdcall "windows.h SysFreeString" cSysFreeString :: CWString -> IO () foreign import ccall "string.h strlen" cstrlen :: CString -> CUInt -- 同じ printf をHaskellでは2種類定義してみました。 foreign import ccall "stdio.h printf" cprintf :: CString -> IO () foreign import ccall "stdio.h printf" cprint2 :: CString -> CUInt -> CUInt -> IO () foreign import ccall "OverWriteCString" oprintf :: CString -> IO () foreign import ccall "wchar.h wprintf" cwprintf :: CWString -> IO () foreign import ccall "wchar.h swprintf" cswprintf :: CWString -> CWString -> IO () main :: IO () main = do cstr <- newCString "%d %d\n" cprint2 cstr 1 2 free cstr s <- utf16ToShiftJis "こんにちは" u <- shiftJisToUtf16 s putStrLn =<< (utf16ToShiftJis u) -- $ ./utf8|nkf -w -- こんにちは -- 1 2 -- hello,world! -- ※※※※ -- hello,world!
#include <stdio.h> #include <malloc.h> #include <windows.h> // 上書きするための関数 char* OverWriteCString(char *cstring){ sprintf(cstring,"hello,world!\n"); return cstring; } BSTR CStringToBSTR(char* cstring ){ int cstringlen, out_size; BSTR wstr; cstringlen = strlen(cstring); out_size = MultiByteToWideChar(CP_ACP, 0, cstring, cstringlen, NULL, 0); wstr = SysAllocStringLen(NULL, out_size); MultiByteToWideChar(CP_ACP, 0, cstring, cstringlen, wstr, out_size); return wstr; } char* BSTRtoCString(BSTR bstr){ int out_size; char *cstring; out_size = WideCharToMultiByte(CP_ACP, 0, (OLECHAR*)bstr, -1,NULL, 0, NULL, NULL); cstring = (char*)malloc((out_size+1) * sizeof(char)); WideCharToMultiByte(CP_ACP, 0, (OLECHAR*)bstr, -1, cstring,out_size, NULL, NULL); return cstring; }