概要

ある業務ソフトのアップデート処理のための専用のソフトを開発するために、LZHファイルの解凍をサポートする必要がありました。
本プログラムは、LZHファイルの圧縮・解凍を行います。
圧縮するファイル及び圧縮結果のLZHファイル、解凍するLZHファイル、解凍先はソースコードの文字列で記述しています。
現在、LHAはサポートを中止しているので、過去の遺産を処理する以外の新規採用は推奨しない。
UNLHA32.DLLは以下のホームページよりダウンロードできる。
Micco's HomePage http://micco.mars.jp/mysoft/unlha32.htm

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32bit マルチバイト/UNICODE

実行環境

Windows 7 Enterprise Service Pack 1 64bit(Sandy Bridge-E)

プログラムソースの概要

本プログラムは、UNLHA32.DLLを動的に呼び出しますので、DLLのロードや関数へのポインタの取得などが必要となります。
定形処理なので、クラス化しました。
カレントフォルダーにある1.txt 2.txt ファイルを圧縮しtest.lzhに保存します。
test.lzhファイルを解凍し、D:\testフォルダーに解凍します。

UNLHA32.DLLの使い方

DLLを動的に呼び出す場合、LoadLibrary APIによりDLLを呼び出し、GetProcAddress APIにより関数へのポインタを取得します。
圧縮や解凍はUnLha関数を呼び出すことにより実行します。
UnLha(const HWND _hwnd, LPCSTR _szCmdLine, LPSTR _szOutput, const DWORD _dwSize);
戻り値は0の場合正常終了です。

hWnd

親ウィンドウのハンドルです。親ハンドルがない場合は0を指定します。

szCmdLine

lha.exeと同形式のコマンドラインオプションを指定します。UNICODE文字列の場合はシフトJISに変換してから渡します。
オプションの詳細は、lha.exeを検索してください。
圧縮する場合
以下の様に記述します。ソースファイルは空白で複数指定できます。空白を含むファイル名の場合はダブルコーテーションでくくります。uが圧縮を示し、-a1はファイルの属性を保存することを指定しています。
u -a1 LZHファイル名 ソースファイル
解凍する場合
以下の様に記述します。空白を含むファイル名の場合はダブルコーテーションでくくります。eが解凍示し、-a1はファイルの属性を再現(日付等)することを指定しています。
e -a1 LZHファイル名 展開先フォルダー

szOutput

UNLHA32.DLLの実行結果の文字列が保存されます。

dwSize

szOutputの大きさを設定します。

クラス UnLhaLib

DLLのロード・解放及び関数へのポインタの取得及びUNICODE/マルチバイトによる圧縮・解凍をサポートします。

コンストラクター UnLhaLib

UnLhaLibのオブジェクトの初期化時に自動的に呼び出されます。
DLLロード及び関数へのポインタの取得を行います。

Init

UNLHA32.DLL及び関数が使用可能どうかを返します。

圧縮 pack

srcDirフォルダとsrcFilesで指定された複数のファイルを圧縮し、lzhFileで指定したファイルに保存します。
すでにLZHファイルが存在する場合は、ファイルを追加します。
複数のファイルをダブルコーテーションで囲まれ空白で区切られた1つの文字列に変換するために必要なメモリサイズを引数szで指定します。
ファイルが大量に存在する場合、かなりのメモリ容量が必要なので、動的に確保するようにしました。szを省略した場合4096バイトとなります。
UNICODEでコンパイルした場合、WideCharToMultiByte APIによりSJISに変換して、UnLha関数を呼び出します。 outstr配列はUnLha関数の実行時のメッセージが保存されます。

解凍 extract

srcFileで指定されたLZHファイルをdtcDirフォルダに解凍します。
dtcDirフォルダが存在しない場合は、ダイアログボックスが表示され、フォルダを作成するかどうか尋ねてきます。
UNICODEでコンパイルした場合、WideCharToMultiByte APIによりSJISに変換して、UnLha関数を呼び出します。 outstr配列はUnLha関数の実行時のメッセージが保存されます。

デストラクタ ~UnLhaLib

UnLhaLibオブジェクトが解放される前に自動的に呼び出されます。
ライブラリの解放を行います。

_tWinMain

UnLhaLibオブジェクトを作成し、Initメンバ関数によりUNLHA32.DLLが使用可能かどうかを確認します。
packメンバー関数により圧縮、extractメンバー関数により解凍を行います。

ソースコード

//	UNLHA32.DLLを使用した基本的な圧縮・解凍のサンプルプログラム
//	Visual C++ 2008/2013 Unicode/マルチバイト 32bit専用

//	UNLHA32.DLL ダウンロード先 http://micco.mars.jp/mysoft/unlha32.htm
//	インストルール先 Windows 32bit C:\Program Files\ArchiverDll\UNLHA32
//	インストルール先 Windows 64bit C:\Program Files (x86)\ArchiverDll\UNLHA32

#ifdef _WIN64
	#error 64bitでコンパイルするとUNLHA32.DLLが使用できません
#endif


#include <windows.h>
#include <stdio.h>
#include <tchar.h>

class UnLhaLib{
	typedef int (WINAPI *UNLHAFUNC)(const HWND _hwnd, LPCSTR _szCmdLine, LPSTR _szOutput, const DWORD _dwSize);
	HINSTANCE hMod;
	UNLHAFUNC UnlhaFunc;
public:
	UnLhaLib(){
		UnlhaFunc=0;
		hMod = LoadLibrary(_TEXT("unlha32.dll"));
		if(hMod==0)
			UnlhaFunc=0;
		else
			UnlhaFunc = (UNLHAFUNC)GetProcAddress(hMod,"Unlha");
	}
	//	UNLHA.DLLが使用可能かチェックする
	bool Init(void){
		return UnlhaFunc==0 ? false : true;
	}
	~UnLhaLib(){
		if(hMod)
			FreeLibrary(hMod);
	}
	
	//	圧縮
	int pack(HWND hWnd,TCHAR* lzhFile,TCHAR* srcDir,TCHAR** srcFiles,int sz=0){
		char outstr[32768];
		int ret;
		outstr[0]='\0';

		if(sz==0)
			sz=4096;
		TCHAR* cmd=new TCHAR[sz];
		if(cmd==0)
			return -1;

		_stprintf_s(cmd,sz,_TEXT("u -a1 \"%s\" \"%s\""),lzhFile,srcDir);
		TCHAR** p=srcFiles;
		TCHAR file[MAX_PATH+2];
		while(*p){
			_stprintf_s(file,sizeof(file)/sizeof(TCHAR),_TEXT(" \"%s\""),*p);
			_tcscat_s(cmd,sz,file);
			++p;
		}
#ifdef UNICODE
		char* cmd_sjis=new char[sz];

		if(cmd_sjis==0){
			delete []cmd;
			return -1;
		}
		WideCharToMultiByte(932,0,cmd,-1,cmd_sjis,sizeof(cmd_sjis),NULL,NULL);

		ret= (*UnlhaFunc)(hWnd, cmd_sjis, outstr ,32767);
		delete []cmd_sjis;
#else
		ret= (*UnlhaFunc)(hWnd, cmd, outstr ,32767);
#endif
		delete []cmd;
		return ret;
	}

	//	解凍
	int extract(HWND hWnd,TCHAR* dtcDir,TCHAR* srcFile){
		char outstr[32768];
		outstr[0] = '\0';
		TCHAR cmd[MAX_PATH*2+8];

		_stprintf_s(cmd,sizeof(cmd)/sizeof(TCHAR),_TEXT("e -a1 \"%s\" \"%s\""),srcFile,dtcDir);

#ifdef UNICODE
		char cmd_sjis[sizeof(cmd)];
		WideCharToMultiByte(932,0,cmd,-1,cmd_sjis,sizeof(cmd_sjis),NULL,NULL);

		return (*UnlhaFunc)(hWnd, cmd_sjis, outstr ,32767);
#else
		return (*UnlhaFunc)(hWnd, cmd, outstr ,32767);
#endif
	}
};


//	圧縮するファイルを指定
TCHAR* packSrcFiles[]={ _TEXT("1.txt"),_TEXT("2.txt"),0 };

//	圧縮結果を保存するLZHファイルを指定
TCHAR* packLzhFile=_TEXT("test.lzh");

//	圧縮するファイルのディレクトリを指定
TCHAR* packSrcDir=_TEXT("");

//	解凍するLZHファイルを指定
TCHAR* extractSrcFile=_TEXT("test.lzh");

//	解凍先ディレクトリを指定
TCHAR* extractDtcDir=_TEXT("d:\\test\\");


int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,TCHAR* lpsCmdLine, int nCmdShow){
	UnLhaLib lha;

	if(lha.Init()==false){
		MessageBox(0,_TEXT("UNLHA32.DLLが使用できません。"),_TEXT("エラー"),MB_OK);
		return 1;
	}
	if(lha.pack(0,packLzhFile,packSrcDir,packSrcFiles,0)!=0){
		MessageBox(0,_TEXT("UNLHA32.DLL::Unlha関数 圧縮中にエラーが発生しました。"),_TEXT("エラー"),MB_OK);
		return 2;
	}

	if(lha.extract(0,extractDtcDir,extractSrcFile)!=0){
		MessageBox(0,_TEXT("UNLHA32.DLL::Unlha関数 解凍中にエラーが発生しました。"),_TEXT("エラー"),MB_OK);
		return 3;
	}
	return 0;
}

実行ファイルとソースファイルのダウンロード