第273章 LHAによるファイルの解凍


今回は解凍をします。基本的には前章と似ています。 また、書庫ファイルからファイルを削除する機能も付けます。



ファイルを解凍するにはコマンド文字列を

e LZHファイル名 ファイル1 ファイル2...

というようにします。これで、とりあえず解凍されます。 解凍場所のディレクトリを指定したい場合は、LZHファイル名の 後ろに解凍場所ディレクトリを指定します。

では、プログラムを見てみましょう。

// unlha02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "書庫の新規作成(&N)...", IDM_NEW MENUITEM "書庫を開く(&O)...", IDM_OPEN MENUITEM SEPARATOR MENUITEM "書庫にファイルを追加(&A)...", IDM_ADD MENUITEM "書庫からファイルを削除(&D)...", IDM_DEL MENUITEM SEPARATOR MENUITEM "解凍(&E)...", IDM_EXTRACT MENUITEM SEPARATOR MENUITEM "終了(&X)...", IDM_END END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDIRDLG DIALOG DISCARDABLE 0, 0, 141, 151 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ディレクトリ指定" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,130,50,14 PUSHBUTTON "キャンセル",IDCANCEL,84,130,50,14 LISTBOX IDC_LIST1,7,31,126,90,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Static",IDC_STATIC1,7,7,127,19 END

メニューと、解凍先ディレクトリ指定用のダイアログボックスの リソース・スクリプトです。

// unlha02.cpp #ifndef STRICT #define STRICT #endif #define ID_LISTVIEW 100 // unlha32.hでtime_tを使うためtime.hが必要です #include <time.h> // sprintf()を使う関係上stdio.hが必要です #include <stdio.h> #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "unlha32.h" #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDirProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MyAdd(HWND, int); BOOL MyOpen(HWND, int); BOOL MySetColumn(HWND); BOOL MyExtract(HWND); BOOL MyDel(HWND hWnd); char szClassName[] = "unlha02"; //ウィンドウクラス char szWindowTitle[] = "猫でもわかるアーカイバ [%s]"; HINSTANCE hInst; char szCmdLine[1024]; char szLZHFile[MAX_PATH], szOrgFile[MAX_PATH], szTitle[MAX_PATH]; char szDir[MAX_PATH]; HWND hList;

ダイアログボックス用のマクロを使う関係でwindowsx.hをインクルードしました。 その他いくつかの関数プロトタイプ宣言が増えています。

WinMain, InitAppの各関数に変更はありません。

//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるアーカイバ", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 509, //幅 222, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

親ウィンドウの大きさを少し調整してあります。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; INITCOMMONCONTROLSEX ic; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&ic); hList = CreateWindowEx(0, WC_LISTVIEW, "", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hWnd, (HMENU)ID_LISTVIEW, hInst, NULL); ListView_SetExtendedListViewStyle(hList, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP); MySetColumn(hList); break; case WM_SIZE: MoveWindow(hList, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_ADD: //iOpt 1..追加 //iOpt 0..新規 MyAdd(hWnd, 1); break; case IDM_NEW: MyAdd(hWnd, 0); break; case IDM_OPEN: //iOpt 0...新規オープン MyOpen(hWnd, 0); break; case IDM_EXTRACT: MyExtract(hWnd); break; case IDM_DEL: MyDel(hWnd); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hList); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_CREATEメッセージが来て、リストビューを作るとき、拡張スタイルを 少し変えてあります。

メニューからIDM_EXTRACTが選択されたら、MyExtract関数を呼びます。

IDM_DELが選択されたら、MyDel関数を呼びます。

MyAdd, MyOpen, MySetColumnの各関数に変更はありません。

BOOL MyExtract(HWND hWnd) { int nItem = -1; char szName[MAX_PATH], szBuf[1024]; BOOL bDir = FALSE; if (ListView_GetSelectedCount(hList) == 0) { MessageBox(hWnd, "解凍するファイルが選択されていません", "Error", MB_OK); return FALSE; } if (MessageBox(hWnd, "解凍先ディレクトリを指定しますか", "ディレクトリ確認", MB_YESNO | MB_ICONQUESTION) == IDYES) { if (DialogBox(hInst, "MYDIRDLG", hWnd, (DLGPROC)MyDirProc) == IDCANCEL) return FALSE; bDir = TRUE; } strcpy(szCmdLine, "e "); strcat(szCmdLine, szLZHFile); if (bDir) { strcat(szCmdLine, " "); strcat(szCmdLine, "\""); strcat(szCmdLine, szDir); strcat(szCmdLine, "\""); } while ((nItem = ListView_GetNextItem(hList, nItem, LVNI_SELECTED)) != -1) { ListView_GetItemText(hList, nItem, 0, szName, sizeof(szName)); strcat(szCmdLine, " "); strcat(szCmdLine, szName); } if(Unlha(hWnd, szCmdLine, szBuf, sizeof(szBuf))) { MessageBox(hWnd, "エラーが発生しました", "Error", MB_OK); return FALSE; } MessageBox(hWnd, szBuf, "OK", MB_OK); MessageBox(hWnd, "解凍が完了しました", "完了", MB_OK); return TRUE; }

ファイルを解凍する関数です。

リストビューで何も選択されていないときは、その旨注意を促してFALSEを返します。

そのまま解凍するのか、解凍先ディレクトリを指定するのかを尋ねて、指定するので あれば、ダイアログボックスを出します。ダイアログボックスではディレクトリを グローバル変数のszDirに格納します。ダイアログボックスでキャンセルボタンが押されたときは 何もせずに戻ります。

unlha関数に渡すコマンド文字列を作ります。ディレクトリを指定する場合は、それも 文字列に加えます。指定ディレクトリにスペースが入っていてもよいように、ディレクトリ名を ダブルクォーテーションでくくっておきます。

リストビューで選択されているファイルを次々とコマンド文字列に追加します。 リストビューの複数項目選択については第199章を参照してください。 コマンド文字列ができあがったらunlha関数に渡して解凍を実行します。この時 解凍先に解凍ファイルと同じものがあった場合は上書きをしません。また、unlhaはエラーを 返しません。そこで、unlhaの3番目の引数を表示するようにしました。

BOOL MyDel(HWND hWnd) { int nItem = -1, nDelCount = 0, nItemCount; char szName[MAX_PATH], szBuf[1024]; if (ListView_GetSelectedCount(hList) == 0) { MessageBox(hWnd, "書庫から削除するファイルが選択されていません", "Error", MB_OK); return FALSE; } nItemCount = ListView_GetItemCount(hList); strcpy(szCmdLine, "d "); strcat(szCmdLine, "\""); strcat(szCmdLine, szLZHFile); strcat(szCmdLine, "\""); while ((nItem = ListView_GetNextItem(hList, nItem, LVNI_SELECTED)) != -1) { ListView_GetItemText(hList, nItem, 0, szName, sizeof(szName)); strcat(szCmdLine, " "); strcat(szCmdLine, szName); nDelCount++; } if (nDelCount == nItemCount) { MessageBox(hWnd, "書庫からすべてのファイルを削除することはできません。", "Error", MB_OK); return FALSE; } if (MessageBox(hWnd, "書庫から指定のファイルを削除しますかよろしいですか", "書庫からファイルの削除", MB_YESNO | MB_ICONQUESTION) == IDNO) { return FALSE; } if(Unlha(hWnd, szCmdLine, szBuf, sizeof(szBuf))) { MessageBox(hWnd, "エラーが発生しました", "Error", MB_OK); return FALSE; } MyOpen(hWnd, 1); MessageBox(hWnd, szBuf, "OK", MB_OK); MessageBox(hWnd, "ファイル削除が完了しました", "完了", MB_OK); return TRUE; }

書庫内のファイルを削除します。

リストビューで削除するファイルが1つも選択されていない場合は、その旨注意を 促して返ります。

リストビュー内のアイテム数を調べて、nItemCountに格納します。

コマンド文字列を作ります。「d LZHファイル名 削除ファイル1 削除ファイル2...」 という感じになります。

削除するファイルと、リストビューのアイテム数が同じ場合(すべてを削除する場合) ちょっと不都合が起こるので、注意を促して戻ることにしました。

unlha関数を実行してファイルを書庫から削除します。

削除したままでは、リストビューの表示は元のままなので、MyOpen関数を 呼び出して最新の表示にします。

LRESULT CALLBACK MyDirProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { char szBuf[MAX_PATH]; static HWND hStatic; switch (msg) { case WM_INITDIALOG: hStatic = GetDlgItem(hDlg, IDC_STATIC1); DlgDirList(hDlg, "*.", IDC_LIST1, IDC_STATIC1, DDL_DIRECTORY | DDL_DRIVES); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hStatic, szBuf, sizeof(szBuf)); strcpy(szDir, szBuf); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDC_LIST1: if (HIWORD(wp) == LBN_DBLCLK) { if (DlgDirSelectEx(hDlg, szDir, sizeof(szDir), IDC_LIST1)) { strcat(szDir, "*."); DlgDirList(hDlg, szDir, IDC_LIST1, IDC_STATIC1, DDL_DIRECTORY | DDL_DRIVES); } } return TRUE; } return FALSE; } return FALSE; }

解凍先のディレクトリを指定するダイアログボックスのプロシージャです。

DlgDirList, DlgDirSelectEx関数については第219章を参照してください。

いろいろ不満の残るプログラムですが、これで一応圧縮・解凍ができるようになりました。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 03/Jun/2000 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。