ZIPファイルの解凍

[戻る]
ゲキアツ 2014/01/13(月) 18:50:40
プログラム作成環境は、Windows 7 Ultimate、VS2010 Pro です。
プロジェクトは、MFC、SDI、FormView です。

ZIPファイルを解凍するステップがあるのですが、7-zip32.dll を使って作ったところ、
Windows 8.1 で動作しませんでした。
Windows 7 では問題なく動作します。
7-zip32.dll のバージョンは、最新の 9.20.00.02(2010.12.19)です。
http://www.madobe.net/archiver/lib/7-zip32.html
@ これが Windows 8.1 で動作するかどうかについてご存じの方はおられませんか?

代わりになるものを調べたところ、zlib 1.2.8 (2013.4.28)がありました。
http://www.zlib.net/
http://blog.systemjp.net/entry/20091209/p5
A この方が新しいので、これからトライしようと思っていますが、Windows 8.1 での動
作や日本語の扱いで問題ないか等、ご存じでしたら教えてください。

なお、UNZIP32.dll については以前使用したことがあり、Windows 7 で不安定でした。

よろしくお願いいたします。

ITO 2014/01/13(月) 19:32:51
  う-ん、
 最新WINへの対応の確認は、あまり進んでいないのが現状だと思います。
 実際にゲキアツさんが確認してこの場にて報告してもらえると該当者は
 逆に助かるのではと思います。

ゲキアツ 2014/01/14(火) 18:34:36
ITO様、有り難うございます。
情報は、なかなか無いようで、自分でやってみるしかないようですね。
このまましばらく保留にしておきます。

AR 2014/01/15(水) 12:31:25
1、うちのソフトですが、正常動作が確認できています。
 世の中にも対応ソフトはいっぱい出回ってるので、問題はないと思います。

2、こちらは不勉強です。

>なお、UNZIP32.dll については以前使用したことがあり、Windows 7 で不安定でした。
 これも、世の中に対応ソフトが出回っていますので、使い方が悪かったのではないか?
という気がします。

ゲキアツ 2014/01/15(水) 18:55:50
AR様、有力な情報を有り難うございます。
自分の場合、Windows 7 で問題なく、Windows 8.1 で動作不良となるのは、メモリの衝突
みたいなことではないかという気がしているのですが、初心者のため解決方法が全く判り
ません。
自分のコードを以下に記します。
お気づきのことがありましたら、どうぞご教示お願いいたします。
********************
#include "7-zip32.h"
********************
// ZIPファイル"gekiatsu.zip"の解凍・・・中身は"gekiatsu.csv"(1個のみ)
HMODULE hModule = ::LoadLibrary(_T("7-zip32.dll"));
typedef HARC (WINAPI *OPENARC)(const HWND, LPCSTR, const DWORD);
typedef int (WINAPI *CLOSEARC)(HARC);
typedef int (WINAPI *FINDFIRST)(HARC, LPCSTR, INDIVIDUALINFO*);
typedef int (WINAPI *FINDNEXT)(HARC, INDIVIDUALINFO*);
typedef int (WINAPI *UNZIP)(const HWND, LPCSTR, LPSTR, const DWORD);
OPENARC OpenArc = (OPENARC)GetProcAddress(hModule, "SevenZipOpenArchive");
CLOSEARC CloseArc = (CLOSEARC)GetProcAddress(hModule, "SevenZipCloseArchive");
FINDFIRST FindFirst = (FINDFIRST)GetProcAddress(hModule, "SevenZipFindFirst");
FINDNEXT FindNext = (FINDNEXT)GetProcAddress(hModule, "SevenZipFindNext");
UNZIP UnZip = (UNZIP)GetProcAddress(hModule, "SevenZip");
INDIVIDUALINFO inf;
DWORD len;
HARC hArc = OpenArc(this->m_hWnd, "gekiatsu.zip", M_CHECK_FILENAME_ONLY);
if (FindFirst(hArc, "*.*", &inf) != -1) {
    do len = inf.dwOriginalSize;
    while (FindNext(hArc, &inf) != -1);
}
CloseArc(hArc);
char* buf_gekiatsu = new char[len+1];
UnZip(m_hWnd, "e -aoa -hide gekiatsu.zip", buf_gekiatsu, len);
if (buf_gekiatsu) delete [] buf_gekiatsu;
************************
以上です。

AR 2014/01/16(木) 11:11:01
 とりあえず気がついたところだけです。
 統合アーカイバ系のDLLは、戻りバッファを扱うと適切な値を返してこないものが存在
しますので無視する形にします。
 (単純に展開だけなら、これだけで平気なはずです)
 また、同じ実装で主要な統合アーカイバプロジェクトDLLは、Windows2000〜8.1までで
問題なく稼動し、OS依存しないことを確認してます。

char* buf_gekiatsu = new char[len+1];
UnZip(m_hWnd, "e -aoa -hide gekiatsu.zip", buf_gekiatsu, len);
if (buf_gekiatsu) delete [] buf_gekiatsu;
↓
//OpenArc()〜CloseArc()までの記述は全展開するだけなら不要
char buf_gekiatsu[1] = "";
UnZip(m_hWnd, "e -aoa -hide gekiatsu.zip", buf_gekiatsu, 1);

※コマンドライン部は検証してません。そのまま転記しています。
※UnZip()で渡す戻りバッファは初期化した方が、DLLごとの差異を吸収できるので推奨です。
※GetProcAddressや、LoadLibraryのエラー処理や後処理もきちんと書いてください。

ゲキアツ 2014/01/17(金) 08:08:11
教えて戴いたコードで問題ないことを、Windows 7 で確認しました。
Windows 8.1 は今手元にないので、後日確認してご報告いたします。
申し訳ありません。
なお、GetProcAddressや、LoadLibraryのエラー処理や後処理は入れています。
この投稿では省略しました。

> 主要な統合アーカイバプロジェクトDLLは、Windows2000〜8.1までで
> 問題なく稼動し、OS依存しないことを確認してます。

これをお聞きして安心しました。
ありがとうございました。

ということは、ZIPファイルの解凍で動作停止したのではなく、その前後のステップに問
題があることになります。
実は、次の3ステップを1度に確認しました。Windows 8.1 で。
@インターネットからZIPファイルのダウンロード
AZIPファイルの解凍
B解凍したCSVファイルから不要なデータを取り除いて、軽量なCSVファイルの作成
次のときはステップを分けて確認いたします。

AR 2014/01/17(金) 09:45:31
@インターネットからZIPファイルのダウンロード
・取得ファイルが破損していないか確認。
 DLLの書庫チェックAPIだとDLLによってヘッダしか見てくれないので、適切に書庫の圧
縮データ部が揃っているかは判定できません。
 プロトコルがHTTPでもFTPでもオリジナルサイズは取れるので、そちらとサイズ比較す
ると良いでしょう。

・ダウンロードした先のディスクフォーマットがNTFSの場合、アクセスブロック属性の影
響がないか確認。(Zip/Cab/Lha限定)
 代表的な例は、ネットから取得したファイルをエクスプローラーなどでダブルクリック
すると閲覧を拒否される現象で、ファイルオープンに失敗するケースがあります。
 これは、副ストリームにアクセスブロック属性が書き込まれていることが原因です。
 副ストリームを削除するか、副ストリームを保存できないディスクに保存するか、影響
を受けないAPIを使用すべきです。

AZIPファイルの解凍
・展開先のアクセス権限の確認。
 Program files、ドライブルート、ライブラリ配下など、避けた方が良いフォルダが存
在するので、確実に展開できる場所を指定すべきです。

B解凍したCSVファイルから不要なデータを取り除いて、軽量なCSVファイルの作成
 もうここは個別案件ですね。
 頑張ってください。

ゲキアツ 2014/01/19(日) 14:25:10
有り難うございます。

Windows 8.1 でテストしました。
結果は、あっさり動作してしまいました。元のコードのままでも動作しました。
実を言うと、前回動作不良になったときも、今回も、Windows 8.1 Release Preview 版を
クリーン・インストーしてテストしました。
今回は、Release Preview 版の有効期限1月15日を過ぎていたので、インストールは出
来たのですが、Aeroモードにならず、Basicモードとなりました。
前回は Aeroモードでした。

このモードの違いが影響するだろうかと非常に疑問に思うのですが、どうやらその程度の
ことが影響しているようです。

正規版の Windows 8.1 でテスト出来るのは少し先になります。
また、ご報告します。

ゲキアツ 2014/01/29(水) 06:18:19
Windows 8.1 32bit DSP版で、動作停止となる現象が再現しました。
動作停止となるのは、ZIPファイルの解凍ステップではなく、その前のインターネットか
らのダウンロードステップで発生します。

よく確かめず、7-zip32.dllを疑ったことをお詫びいたします。

次の2つの条件が揃ったとき発生します。
@ 実行ファイルが、C:\Program File の下にあり、しかも
A「管理者として実行」ではなく、単にダブルクリックで起動した場合

普通のフォルダ(例えば、C:\gekiatsu)の中にあれば発生しません。
また管理者として実行すれば、C:\Program File の下にあっても発生しません。

Windows 7 でも同様に発生します。
但し、UAC(ユーザーアカウント制御)のレベルを一番緩い4段階目にすれば発生しませ
ん。
Windows 8.1 では、UACのどのレベルでも発生します。

一つ前の書き込みで”Aeroモード”云々と書いたのは間違いです。取り消します。

そこで、問題のダウンロードステップのコードを以下に記します。
お気づきのことがあれば、どうぞご教示ください。
◆ zipFile.Open から zipFile.Close までを消せば問題は生じません。
問題はこの箇所です。

// 日本郵便から郵便番号ファイルをダウンロード
#include <wininet.h>
・・・・・・・・・・
CString url1 = _T("http://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zi
p");
CString fn1 = _T("ken_all.zip");
CHttpFile* pHttpFile;
CInternetSession sess(NULL, 1, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
try{
    pHttpFile = (CHttpFile*)sess.OpenURL(url1, 1, INTERNET_FLAG_TRANSFER_BINARY 
| INTERNET_FLAG_RELOAD, NULL, 0);
}
catch (CInternetException* pEx){
    AfxMessageBox(_T("インターネットに接続されていません"), MB_OK | MB_ICONWARNI
NG);
    pEx->Delete();
    return;
}
if (pHttpFile == NULL){
    AfxMessageBox(_T("ダウンロードに失敗しました"), MB_OK | MB_ICONWARNING);
    return;
}
CStdioFile zipFile;
const int BUF_LEN=1024;
BYTE lpBuff[BUF_LEN];
DWORD dwRead;
zipFile.Open(fn1, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
while (true){
    dwRead = pHttpFile->Read(lpBuff, BUF_LEN);
    if (dwRead > 0) zipFile.Write(lpBuff, dwRead);
    if (dwRead < 1024) break;
}
zipFile.Close();
pHttpFile->Close();
delete pHttpFile;

a 2014/01/29(水) 17:35:01
> 動作停止となるのは、ZIPファイルの解凍ステップではなく、その前のインターネット
からのダウンロードステップで発生します。

>

「インターネット〜」ではなく、ファイルを「C:\Program Files」に作成しようとすると
例外エラーが発生しているのだと思う。

↓VB.NET,C#.NETを取り扱っているHPだけど現象的にはこれですね。(Vista出たての頃に
結構話題出てましたね。)

http://dobon.net/vb/dotnet/system/uac.html

ゲキアツ 2014/01/30(木) 06:35:37
a 様、有り難うございます。

> ファイルを「C:\Program Files」に作成しようとすると例外エラーが発生しているのだ
と思う。

解りました。これだったのですね。
今、ユーザーのアプリケーション・データ・パスの取得方法で四苦八苦しています。
うまくいったら、ご報告します。

ゲキアツ 2014/01/31(金) 08:57:05
無事解決しました。マイドキュメントに入れることにしました。
皆様、ありがとうございました。

wchar_t lpszPath[MAX_PATH];
LPITEMIDLIST pidl;
if(::SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DOCUMENTS, &pidl) == NOERROR)
{
    ::SHGetPathFromIDList(pidl, lpszPath);
    ::CoTaskMemFree(pidl);
}
else AfxMessageBox(_T("・・・省略・・・"), MB_OK | MB_ICONWARNING);
::SetCurrentDirectory(CString(lpszPath));

ゲキアツ 2014/01/31(金) 08:57:57
[[解決]]
解決マークの付け忘れです。

古いスレッドには追加発言できません。