DllImport 呼叫
-- LibPandoc.hs
module LibPandoc where
import Text.Pandoc
import Foreign.C.String
import Foreign.Ptr
foreign export ccall markdownToHtml :: CString -> IO CString
markdownToHtml :: CString -> IO CString
markdownToHtml cstr = do
md <- peekCString cstr
-- Pandoc 處理 Markdown -> HTML
html <- runIOorThrow $ do
doc <- readMarkdown def md
writeHtmlString def doc
newCString html -- 關鍵:配置新字串並回傳指標
#include
#include
extern void __stginit_LibPandoc(void);
BOOL STDCALL DllMain(HANDLE hModule, DWORD reason, void* reserved)
{
static char* args[] = {"libpandoc", NULL};
if (reason == DLL_PROCESS_ATTACH)
{
startupHaskell(1, args, __stginit_LibPandoc);
}
return TRUE;
}
#include "HsFFI.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HsPtr markdownToHtml(HsPtr a1);
#ifdef __cplusplus
}
#endif
class Native
{
[DllImport("libpandoc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern IntPtr markdownToHtml(byte[] markdown);
}
public class Processor
{
public string Process(string text)
{
var intPtr = Native.markdownToHtml(Encoding.UTF8.GetBytes(text));
var html = Marshal.PtrToStringAnsi(intPtr); // 疑點:CharSet.Unicode vs Ansi
return html;
}
}
System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
| 項目 | 現狀 | 潛在問題 |
|---|---|---|
| CharSet | C#: Unicode, Haskell: CString (Latin-1/ASCII) | 編碼不匹配導致記憶體誤讀 |
| 記憶體所有權 | Haskell 配置 (newCString),C# 負責釋放? | 缺少釋放函式匯出,造成洩漏或雙重釋放 |
| CallingConvention | Cdecl (雙方一致) | 正確 |
| Haskell Runtime | DllMain 啟動 startupHaskell | 單執行緒模式,並發呼叫會衝突 |
| GHC 版本 | 7.6.3 (2013) | 較舊,Windows 相容性有已知問題 |
| OS 環境 | WS2008 R2 編譯/執行失敗,WS2012 成功 | 載入器/記憶體管理差異 |
CharSet.Ansi 或 Haskell 改用 CWString (UTF-16)foreign export ccall freeHaskellString :: CString -> IO ()pandoc CLI 或 HTTP 微服務此為問題重現與程式碼分析記錄,完整解決過程請參考「C# 呼叫 Haskell 遭遇嘗試讀取或寫入受保護的記憶體:竟是 Windows Server 2008 的坑」。