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

C# P/Invoke 呼叫 unlha32.dll 解壓縮 LHA 格式檔案完整封裝

     編輯:ASP.NET 基礎

背景

LHA (LZH) 是日本早期流行的壓縮格式,.NET Framework 內建不支援。常見做法是 P/Invoke 呼叫開源的 `unlha32.dll` (C 語言實作)。本文提供完整的 C# 靜態類別封裝,含版本檢查、執行狀態檢查、檔案驗證、解壓縮與錯誤代碼對照。

完整封裝類別

using System;
using System.IO;
using System.Runtime.InteropServices;

public static class LhaExtractor
{
    // --- 1. DLL 匯入宣告 ---
    [DllImport("unlha32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern ushort UnlhaGetVersion();

    [DllImport("unlha32.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnlhaGetRunning();

    [DllImport("unlha32.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnlhaCheckArchive(string szFileName, int iMode);

    [DllImport("unlha32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern int Unlha(int hwnd, string szCmdLine, string szOutput, int dwSize);

    // --- 2. 錯誤代碼對照 ---
    private enum UnlhaErrorCode
    {
        Success = 0,
        Cancelled = 32800, // 使用者取消
        // 其他代碼參考 DLL 文件
    }

    // --- 3. 公開解壓方法 ---
    /// 
    /// 解壓 LHA 檔案
    /// 
    /// .lha 檔案完整路徑
    /// 解壓目標目錄 (null/empty 同檔案名建立子目錄)
    /// 解壓成功後是否刪除原壓縮檔
    /// 成功 true / 失敗拋出例外
    public static bool Extract(string archivePath, string extractDir = null, bool deleteArchive = false)
    {
        if (!File.Exists(archivePath))
            throw new FileNotFoundException("找不到壓縮檔", archivePath);

        // 1. 檢查 DLL 是否存在
        try { var _ = UnlhaGetVersion(); }
        catch (DllNotFoundException)
        { throw new DllNotFoundException("unlha32.dll 不在 PATH 或應用程式目錄中"); }

        // 2. 檢查 DLL 是否忙碌
        if (UnlhaGetRunning())
            throw new InvalidOperationException("DLL 正在執行其他解壓作業,請稍後再試");

        // 3. 檢查檔案有效性
        if (!UnlhaCheckArchive(archivePath, 0))
            throw new InvalidDataException("檔案損壞或非有效 LHA 格式");

        // 4. 決定解壓路徑
        string targetDir = string.IsNullOrEmpty(extractDir)
            ? Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                           Path.GetFileNameWithoutExtension(archivePath))
            : extractDir;

        if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir);

        // 5. 呼叫解壓 (命令列參數: x "來源" "目標")
        string cmd = $"x \"{archivePath}\" \"{targetDir}\"";
        int ret = Unlha(0, cmd, null, 0);

        // 6. 結果判斷
        if (ret != (int)UnlhaErrorCode.Success)
        {
            string msg = ret == (int)UnlhaErrorCode.Cancelled
                ? "使用者取消解壓"
                : $"解壓失敗,錯誤代碼: {ret}";
            throw new Exception(msg);
        }

        // 7. 選擇性刪除原檔
        if (deleteArchive) File.Delete(archivePath);

        return true;
    }
}

部署注意事項

  1. DLL 位元數必須一致:專案若為 x64,需 64 位元 `unlha32.dll` (或設定 Prefer 32-bit 使用 32 位元 DLL)。
  2. 放置位置:建議放在專案輸出目錄 (`bin\Debug\` / `bin\Release\`) 或設置 `PATH` 環境變數,避免放入 `C:\Windows\System32` 污染系統。
  3. 相依性:`unlha32.dll` 可能依賴 VC++ Runtime,確保目標機器已安裝對應版本。

使用範例

try
{
    bool ok = LhaExtractor.Extract(@"C:\Data\archive.lha", @"C:\Output\", deleteArchive: true);
    Console.WriteLine("解壓完成");
}
catch (Exception ex)
{
    Console.WriteLine($"錯誤: {ex.Message}");
}

現代替代方案 (純 Managed、無 DLL 相依)

  • SharpCompress:NuGet `SharpCompress`,支援 LZH/LHA、RAR、7Z、TAR 等格式,純 C# 實作,跨平台 (Linux/Docker/ARM) 零相依。
  • var archive = ArchiveFactory.Open(stream); archive.WriteToDirectory(dir);
  • SevenZipSharp:封裝 7-Zip 命令列,格式支援最全,但需部署 7z.dll。

小結

P/Invoke 呼叫 `unlha32.dll` 是解決舊系統 LHA 相容性的快速方案,但部署麻煩、平台受限。新專案**強烈建議改用 SharpCompress 等純 Managed 函式庫**,一次解決所有壓縮格式支援問題。

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