ZIPファイルをメモリへ解凍するには?


ASAKUSA  2006-01-08 01:30:38  No: 129436

VB6+Windwos2000+Unzip32.dllでZIPファイルの中のテキストファイルを
メモリへ解凍して、テキストボックスに内容を表示させるプログラムを
作っています。

APIを調べてUnZipExtractMemを使えばいいことはわかり
下のプログラムを組んでみました。
(テキストボックスに表示させるところはまだですが。)

Public Declare Function UnZipExtractMem Lib "UnZip32" ( _
    ByVal hWnd As Long, _
    ByVal szCmdLine As String, _
    ByRef lpBuffer As Byte, _
    ByVal dwSize As Long, _
    lpTime As Long, _
    lpwAttr As String, _
    lpdwWriteSize As Long _
) As Long

Private Sub Command4_Click()
    Dim ZipFile         As String
    Dim ExtractFileName As String
    Dim CmdLine         As String
    Dim Buffer          As Byte
    Dim BufSize         As Long
    Dim lpTime          As Long
    Dim lpwAttr         As String
    Dim lpdwWriteSize   As Long
    Dim ret             As Long

    ZipFile = """D:\TEST.zip"""
    ExtractFileName = """SAMPLE.txt"""
    BufSize = 1000
    
    CmdLine = ZipFile & " " & ExtractFileName

    ret = UnZipExtractMem(Me.hWnd, CmdLine, Buffer, BufSize, lpTime, lpwAttr, lpdwWriteSize)

    Stop
End Sub

このプログラムを実行するとUnZipExtractMemのところで、
VB6ごと強制終了してしまいました。
exeで実行してもやはりexeが強制終了してしまいました。

ZIPの解凍状況の表示ダイアログは表示されるので、
解凍自体は行われているようなのですがどこが悪いのでしょうか?
よろしくお願いします。


魔界の仮面弁士  2006-01-08 03:12:53  No: 129437

バッファサイズに 1000 を指定しているのに、実際に用意したバッファは
1バイト分の領域しかありませんよね。そのため、変数領域外のメモリに
対して書き込みが行われてしまい、不正な処理として強制終了されるのでしょう。

たとえば、バッファ宣言を
  Dim Buffer(999) As Byte
のように 1000 バイト分用意して、それを
  ret = UnZipExtractMem(〜〜, Buffer(0), BufSize, 〜〜)
のようにしてみたら、結果は変わりますか?


ASAKUSA  2006-01-08 05:47:46  No: 129438

レスありがとうございます。

早速やってみましたが、うまくいきませんでした。
ただ今回は強制終了することはなく、

アプリケーションエラー
〜の命令が〜のメモリを参照しました。メモリがreadになることはできませんでした。
・・・

とエラーメッセージが出ました。

実際のサイズより多めに確保しても駄目だったので、
UnZipGetOriginalSizeでファイルサイズを取得して
Redimでサイズ分確保してやってみましたが、
上記アプリケーションエラーが出てしまいました。

もう少しいろいろやってみようとは思いますが、
何かアドバイスがあればよろしいくお願いします。


魔界の仮面弁士  2006-01-08 08:42:03  No: 129439

UNZIP32.DLL Ver 5.4x API の SDK を確認してみてました。
それによると、

int WINAPI UnZipExtractMem(
   const HWND hWnd,
   LPCSTR szCmdLine,
   LPBYTE szBuffer,
   const DWORD dwSize,
   time_t *lpTime,
   LPWORD lpwAttr,
   LPDWORD lpdwWriteSize);

として定義されていますね。

一方、お使いの Declare 宣言では、第6引数の LPWORD 型の引数を、
ByRef String で宣言していますよね。ここに問題があるのでは。

普通の API では、ByRef String で宣言する事なんて無いですよね。
(OLE 系の API でも無い限りは……)

LPWORD って、"16ビット符号なし整数型へのポインタ" の意味ですから、
そのまま VB6 に翻訳するならば、ByRef Integer あたりが無難かと。


魔界の仮面弁士  2006-01-08 08:57:39  No: 129440

第6引数の仕様をみると、このように書かれていますね。

》lpwAttr:
》  解凍されたファイルの属性を得ます。 必要ない場合は NULLを指定します。

もしも属性情報が不要なら、変数を渡す必要はなさそうですね。
同様に、サイズ情報や日付情報も、不要なら変数を渡す必要は無いでしょう。

たとえば、属性を常に受け取りたいのであれば、ByRef As Integer で
宣言しておき、Integer変数を渡す必要がありますが、属性情報が不要ならば、
ByVal As Long で宣言しておき、そこに 0& を渡すだけで十分だと思います。

あるいは、属性の取得/非取得の両方に対応した宣言にしておきたいのなら、
第6引数を ByRef As Any にて宣言しておくと良いでしょう。
この場合は、属性情報を受け取るときは Integer変数を渡し、
それが不要なときは「ByVal 0&」を渡す…という形になりますね。

# または、ByVal As Long で宣言しておき、VarPtr関数を併用するという手も。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加