« 7-zip32.dllのUTF-8モードをC#から使用する(1) | トップページ | 7-zip32.dllでサロゲートペア文字を使用した場合の動作結果 »

2010年12月11日 (土)

7-zip32.dllのUTF-8モードをC#から使用する(2)

さて、前回保留していた書庫一覧の取得を行ないます。

1.INDIVIDUALINFO 構造体の定義
書庫一覧取得には、INDIVIDUALINFO 構造体の定義が必要となります。前回のサンプル用APは、元々UNLHA32.DLLのテスト用だったので、同じ統合アーカイバプロジェクトである 7-zip32.dll も、ここで定義してあった INDIVIDUALINFO 構造体が、本来はそのまま使えます。
しかし、これは UTF-8 モードでない場合の話です。UTF-8 モードになれば、当然文字列部分には、UTF-8 コードで格納されるので、適切な定義に修正してやる必要があります。

では、UTF-8用の INDIVIDUALINFO 構造体を定義してみます。

/// <summary>
/// INDIVIDUALINFO 構造体(UTF-8 文字列用)の定義
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct INDIVIDUALINFOU
{
    /// <summary>ファイルのサイズ</summary>
    public uint dwOriginalSize;
    /// <summary>ファイルの圧縮後のサイズ</summary>
    public uint dwCompressedSize;
    /// <summary>格納ファイルのチェックサム用CRC</summary>
    public uint dwCRC;
    /// <summary>Unicode文字列パラメータを格納する為のメンバ</summary>
    public uint uFlag;
    /// <summary>このメンバ作成に使用されたOS</summary>
    public uint uOSType;
    /// <summary>圧縮率(‰)</summary>
    public ushort wRatio;
    /// <summary>ftime の上位バイトと同じ構造で表現された日付</summary>
    public ushort wDate;
    /// <summary>ftime の下位バイトと同じ構造で表現された時間</summary>
    public ushort wTime;
    /// <summary>書庫内ファイル名</summary>
    /// <remarks>szFileName後方のdummy[3]を含める為、Size=516としている</remarks>
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 516)]
    public byte[] szFileName;
    /// <summary>格納ファイルの属性</summary>
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] szAttribute;
    /// <summary>格納ファイルの形式</summary>
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] szMode;
}

違いは、文字列が格納される部分を、MarshalAs(UnmanagedType.ByValArray, ~と、byte 配列に定義し直している点です。もっとも、szAttribute や szMode メンバは、恐らくASCII文字だけしか格納されないので、string のままでも CharSet = CharSet.Ansi の条件ならいけそうですが、ここではやりません。

2.デリゲートの定義
次に、書庫一覧に必要なデリゲートを定義してみます。

delegate IntPtr OpenArchiveU(IntPtr hWnd, byte[] szFileName, uint uMode);
delegate int FindFirstU(IntPtr hArc, string szFileName, out INDIVIDUALINFOU IInfo);
delegate int FindNextU(IntPtr hArc, out INDIVIDUALINFOU IInfo);
delegate int CloseArchive(IntPtr hArc);

ここは、stringの部分を、byte配列に修正したのと、新たに定義した INDIVIDUALINFOU 構造体を引数にする様に指定してある部分だけが違います。なお、FindFirstU の szFileName 引数が、string 型のままなのは、ここでは "*" という固定の文字列を渡すだけだからです。"*"なら、UTF-8でもANSIでも同じコードになるので、string のままでも問題ありません。

3.書庫一覧の実行コード
書庫一覧の実行部分については、これまでに触れて来た事をやれば、問題ありません。実際の定義は以下のとおりです。

/// <summary>
/// Unicode文字列による書庫一覧取得・表示(方法1)
/// </summary>
/// <param name="archiveFile">LHA書庫ファイルのフルパス</param>
private void UnicodeFileList(string archiveFile)
{
    lstMember.Items.Clear();
    using (UnmanagedLink dl = new UnmanagedLink("7-zip32.dll"))
    {
        SetUnicodeMode setUnicodeMode = (SetUnicodeMode)dl.MethodGen(typeof(SetUnicodeMode),
            "SevenZipSetUnicodeMode");
        OpenArchiveU openArchive = (OpenArchiveU)dl.MethodGen(typeof(OpenArchiveU),
            "SevenZipOpenArchive");
        FindFirstU findFirst = (FindFirstU)dl.MethodGen(typeof(FindFirstU),
            "SevenZipFindFirst");
        FindNextU findNext = (FindNextU)dl.MethodGen(typeof(FindNextU),
            "SevenZipFindNext");
        CloseArchive closeArchive = (CloseArchive)dl.MethodGen(typeof(CloseArchive),
            "SevenZipCloseArchive");
        if (!setUnicodeMode(true)) return;
        IntPtr harc = openArchive(this.Handle, EncodeUTF8(archiveFile), 0);
        if (harc == IntPtr.Zero) return;
        INDIVIDUALINFOU memberInfo;
        int status = findFirst(harc, "*", out memberInfo);
        while (status == 0)
        {
            lstMember.Items.Add(DecodeUTF8(memberInfo.szFileName));
            status = findNext(harc, out memberInfo);
        }
        closeArchive(harc);
    }
}

4.書庫一覧の実行
これで書庫一覧実行の準備が出来たので、前回作成した各種オプション別の書庫ファイルの一覧を取ってみます。

-mcl=off -mcu=off -mcl=off -mcu=on -mcl=on -mcu=off -mcl=on -mcu=on
-mcl=off -mcu=off で
作成した書庫
-mcl=off -mcu=on で
作成した書庫
-mcl=on -mcu=off で
作成した書庫
-mcl=on -mcu=on で
作成した書庫

-mcl=off -mcu=off で作成した書庫の場合
Unicode固有の文字を持つファイル名だけUTF-8で記録される書庫ですが、見ての通り正常なファイル名で表示されます。

-mcl=off -mcu=on で作成した書庫の場合
非ASCII文字がUTF-8で記録される書庫ですが、これも正常なファイル名で表示されます。

-mcl=on -mcu=off で作成した書庫の場合
常にローカルコードページを使用するので、これはShift-JIS変換されたファイル名で格納されている書庫です。さすがにこれは、元のファイル名表示にはなりません。Shift-JIS変換されたファイル名で一覧が出ます。まあ、これは当然の結果ですけど。

-mcl=on -mcu=onで作成した書庫の場合
-mcl=off -mcu=onと同じ結果になった書庫なので、これも正常なファイル名で表示されます。

UTF-8 で格納されたファイル名は、きちんと UTF-8 と認識してファイル名を表示している様で、さすがに文字化けはしない様ですね。

ファイル名がきちんと一覧で出るので、問題ないと予想できますが、一応、解凍もやってみて、一覧表示と同じファイル名で解凍された事を付け加えておきます。なお解凍部分については、技術的トピックがないので(渡すコマンドが違う以外、書庫作成と同じなので)、記事としては省略します。但し、本記事最後でダウンロードできるテストAPソースの中には、解凍処理も入れてあるので、興味ある人はそちらを見て下さい。

以上、UTF-8モードの使用については、C#でも問題無く呼び出せる事がわかりました。

では最後に、今回の記事に使用したテストAPソース一式をCAB形式で圧縮して、ここに置いておきます。
「Utf8Test2.cab」をダウンロード


« 7-zip32.dllのUTF-8モードをC#から使用する(1) | トップページ | 7-zip32.dllでサロゲートペア文字を使用した場合の動作結果 »

C#研究」カテゴリの記事

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: 7-zip32.dllのUTF-8モードをC#から使用する(2):

« 7-zip32.dllのUTF-8モードをC#から使用する(1) | トップページ | 7-zip32.dllでサロゲートペア文字を使用した場合の動作結果 »