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の解凍状況の表示ダイアログは表示されるので、
解凍自体は行われているようなのですがどこが悪いのでしょうか?
よろしくお願いします。
バッファサイズに 1000 を指定しているのに、実際に用意したバッファは
1バイト分の領域しかありませんよね。そのため、変数領域外のメモリに
対して書き込みが行われてしまい、不正な処理として強制終了されるのでしょう。
たとえば、バッファ宣言を
Dim Buffer(999) As Byte
のように 1000 バイト分用意して、それを
ret = UnZipExtractMem(〜〜, Buffer(0), BufSize, 〜〜)
のようにしてみたら、結果は変わりますか?
レスありがとうございます。
早速やってみましたが、うまくいきませんでした。
ただ今回は強制終了することはなく、
アプリケーションエラー
〜の命令が〜のメモリを参照しました。メモリがreadになることはできませんでした。
・・・
とエラーメッセージが出ました。
実際のサイズより多めに確保しても駄目だったので、
UnZipGetOriginalSizeでファイルサイズを取得して
Redimでサイズ分確保してやってみましたが、
上記アプリケーションエラーが出てしまいました。
もう少しいろいろやってみようとは思いますが、
何かアドバイスがあればよろしいくお願いします。
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 あたりが無難かと。
第6引数の仕様をみると、このように書かれていますね。
》lpwAttr:
》 解凍されたファイルの属性を得ます。 必要ない場合は NULLを指定します。
もしも属性情報が不要なら、変数を渡す必要はなさそうですね。
同様に、サイズ情報や日付情報も、不要なら変数を渡す必要は無いでしょう。
たとえば、属性を常に受け取りたいのであれば、ByRef As Integer で
宣言しておき、Integer変数を渡す必要がありますが、属性情報が不要ならば、
ByVal As Long で宣言しておき、そこに 0& を渡すだけで十分だと思います。
あるいは、属性の取得/非取得の両方に対応した宣言にしておきたいのなら、
第6引数を ByRef As Any にて宣言しておくと良いでしょう。
この場合は、属性情報を受け取るときは Integer変数を渡し、
それが不要なときは「ByVal 0&」を渡す…という形になりますね。
# または、ByVal As Long で宣言しておき、VarPtr関数を併用するという手も。
| ツイート |
|