首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 呼叫 Haskell 完整實作指南:從環境建置到 P/Invoke 呼叫

     編輯:關於C#

系統環境需求

  • Windows Server 2008 R2(註:Haskell Platform 不支援 WS2012)
  • Haskell Platform 2013.2.0.0 (GHC 7.6.3, Cabal 1.16.0)
  • Visual Studio 2010+ (C# 專案)

完整建置流程

1. 安裝 Haskell Platform

下載 Windows 版安裝,包含 GHC、Cabal、核心庫。

2. 撰寫 Haskell 代碼 (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
    html <- runIOorThrow $ do
        doc <- readMarkdown def md
        writeHtmlString def doc
    newCString html

3. 撰寫 C 封裝層 (pandoc.c)


#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;
}

4. 撰寫 Cabal 設定 (libpandoc.cabal)


Name: libpandoc
Version: 0.5
Cabal-Version: >= 1.2
Build-Type: Simple

Executable libpandoc.dll
If os(windows)
  CPP-Options: -DWIN32
Extensions: ForeignFunctionInterface
Hs-Source-Dirs: src
Include-Dirs: src
C-Sources: src/pandoc.c
Install-Includes: pandoc.h
Main-Is: LibPandoc.hs
Ghc-Options: -no-hs-main -optl-shared -optl-s

5. 編譯產出 DLL


# 在專案目錄執行
cabal build

成功後產出:

  • dist/build/libpandoc.dll/libpandoc.dll (主要 DLL)
  • dist/build/libpandoc.dll/libpandoc.dll-tmp/LibPandoc_stub.h (C# 參考用 header)

6. 建立 C# 專案並呼叫


// 複製 libpandoc.dll 至 C# 專案 bin/Debug 目錄

class Native
{
    [DllImport("libpandoc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public static extern IntPtr markdownToHtml(byte[] markdown);
}

public class Processor
{
    public string Process(string text)
    {
        var ptr = Native.markdownToHtml(Encoding.UTF8.GetBytes(text));
        var html = Marshal.PtrToStringAnsi(ptr);
        // TODO: 呼叫 Haskell 匯出的 free 函式釋放記憶體
        return html;
    }
}

關鍵技術點總結

項目說明
CallingConventionCdecl (Haskell FFI 預設)
CharSetAnsi (對應 Haskell CString),或 Unicode (對應 CWString)
Haskell Runtime 初始化DllMain 中呼叫 startupHaskell
記憶體管理Haskell 配置 (newCString) → C# 需釋放 (需匯出 free 函式)
執行緒安全Haskell RTS 非執行緒安全,C# 需自行同步或使用單例模式
錯誤處理Haskell 例外需在 FFI 邊界捕獲轉為錯誤碼

已知限制與改進方向

  • WS2008 必須:Haskell Platform 2013 不支援 WS2012 安裝(見 10725 解決方案)
  • GHC 版本舊:建議升級至 GHC 9.x 並使用 stack 建置
  • 記憶體洩漏風險:務必實作並呼叫釋放函式
  • 替代架構:Pandoc CLI + Process.Start / HTTP 微服務 / gRPC,避免 P/Invoke 複雜度

參考資源

此指南記錄了 2014 年實際專案的完整建置流程,現代專案建議採用更新的工具鏈與架構模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved