#include "stdafx.h"
#include "context.h"
#include "openarc.h"
#include "r7manifest.h"

// 外部変数宣言
HINSTANCE hInst;								// このプログラムのインスタンス
const char *szTitle = "Ext.CCM for Rnsf7";		// このプログラムのウィンドウタイトル
//#ifndef _WIN64
//	BOOL  isNT;										// OS種別
//#endif /* _WIN64 */
WORD  winver;									// OSバージョン

// プロトタイプ宣言
void EasySkrx( const char *path );
void AddApplicationPath( const char *path );
bool setWallPaper( char *bmp );
bool tChangeFileTimeDate( const char *fname );
bool showMD5file( const char *fname );
bool tCopyClipboard( const char *text );
bool t2CopyClipboard( const char *text );
bool CompareFiles( char *fname1 );

bool OpenExtractor( const char *arcfile, int oetype );
bool OpenExtractorDir( const char *arcfile, int oetype );
bool OpenExtractorDesktop( const char *arcfile, int oetype );
bool OpenExtractorCD( const char *arcfile, int oetype );
bool OpenExtractorOwnDir( const char *arcfile, int oetype );
bool makeCompressIcon( void );
bool ExpandLzh( const char *arcfile, const char *folder );
bool ExpandZip( const char *arcfile, const char *folder );
bool Expand7Zip( const char *arcfile, const char *folder );
bool makeShortcutIcon( const char *szShortcutName, const char *szParam, int iIconNum );

// Expand*** 関数への配列
bool (*ExpandFunctions[3])( const char *arcfile, const char *folder ) = { ExpandLzh, ExpandZip, Expand7Zip };

LRESULT CALLBACK FTimeProc(HWND, UINT, WPARAM, LPARAM);

// 何文字スキップしたらスペースでなくなるかを返す
int skipSpace( const char *cline )
{
	int i = 0;

	for(i=0 ; cline[i] == ' ' || cline[i] == '\t' ; i++)
		;

	if ( cline[i] ) {
		return i;
	}
	else {
		return -1;
	}
}

// ShellExecuteのエラー受け取り＆エラーメッセージ出力
// エラーが発生していない場合は、何も行わない
HINSTANCE SHE(HWND hWnd, HINSTANCE hInstSE)
{
	if ( (HINSTANCE)32 > hInstSE ) {
		char *pmes;
#pragma warning( disable:4311 )
		switch ( (UINT)hInstSE ) {
#pragma warning( default:4311 )
			case 0:
				pmes = "プログラムを開始できません。\n\n原因：メモリまたはリソースが不足しています。";
				break;
			case SE_ERR_OOM:
				pmes = "プログラムを開始できません。\n\n原因：作業を完了するためのメモリが足りません。";
				break;
			case ERROR_FILE_NOT_FOUND:
				pmes = "プログラムを開始できません。\n\n原因：指定されたファイルまたはフォルダが見つかりませんでした。ショートカットが指定された場合、ショートカット先のファイルまたはフォルダが見つかりませんでした。";
				break;
			case ERROR_PATH_NOT_FOUND:
				pmes = "プログラムを開始できません。\n\n原因：指定されたパスが見つかりませんでした。";
				break;
			case ERROR_BAD_FORMAT:
				pmes = "プログラムを開始できません。\n\n原因：実行ファイルが無効です。";
				break;
			case SE_ERR_ACCESSDENIED:
				pmes = "プログラムを開始できません。\n\n原因：アクセスを拒否されました。";
				break;
			case SE_ERR_ASSOCINCOMPLETE:
				pmes = "プログラムを開始できません。\n\n原因：ファイル名の関連付けが不完全または無効です。";
				break;
			case SE_ERR_DDEBUSY:
			case SE_ERR_DDEFAIL:
			case SE_ERR_DDETIMEOUT:
				pmes = "プログラムを開始できません。\n\n原因：DDEエラー。";
				break;
			case SE_ERR_DLLNOTFOUND:
				pmes = "プログラムを開始できません。\n\n原因：指定されたDLLが見つかりませんでした。";
				break;
			case SE_ERR_NOASSOC:
				pmes = "プログラムを開始できません。\n\n原因：指定された拡張子に関連付けられたプログラムがありません。";
				break;
			case SE_ERR_SHARE:
				pmes = "プログラムを開始できません。\n\n原因：共有違反が発生しました。";
				break;
			default:
				pmes = "プログラムを開始できません。\n\n原因：不明なエラーが発生しました。";
				break;
		}
		MessageBox(hWnd, pmes, "プログラム実行エラー", MB_OK | MB_ICONSTOP);
	}

	return hInstSE;
}

char getFreeDrive()
{
	char rootpath[4] = "Z:\\";

	// Zドライブから逆方向に走査し、存在しないドライブを調べる
	for(rootpath[0]='Z' ; rootpath[0]>='A' ; --rootpath[0]) {
		if (DRIVE_NO_ROOT_DIR == GetDriveType(rootpath)) {
			return rootpath[0];
		}
	}

	return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, int)
{
	hInst = hInstance;

#if _MSC_VER < 1500
#ifndef _WIN64
	isNT = tf_isNT();
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
	winver = tf_getWinVer();

	if ( lpCmdLine == NULL || lpCmdLine[0] == 0 ) {
		MessageBox( NULL, "このプログラムは「いじくるつくーる」(Rnsf7.exe)より間接的に呼び出されます。", szTitle, MB_OK | MB_ICONINFORMATION );
		return 1;
	}
	else if ( lpCmdLine[0] == '/' ) {
		// エクスプローラ等からのDrag&Dropを許可する（Vista以上でUACを使っていると、メッセージがフィルタされるので）
		if (winver >= 600) {
			typedef BOOL (__stdcall *CWMF_FUNCTYPE)(UINT, DWORD);

			HMODULE hDll = LoadLibrary_System32("user32.dll");
			if (hDll) {
				CWMF_FUNCTYPE p_ChangeWindowMessageFilter = (CWMF_FUNCTYPE)GetProcAddress(hDll, "ChangeWindowMessageFilter"); // Vista以上の関数

				if(p_ChangeWindowMessageFilter) {
					// WM_DROPFILESは単一のメッセージのみで動いているものではないので、色々許可しなければならない
					p_ChangeWindowMessageFilter(WM_DROPFILES, 1 /*MSGFLT_ADD*/);
					p_ChangeWindowMessageFilter(WM_COPYDATA, 1 /*MSGFLT_ADD*/);
					p_ChangeWindowMessageFilter(0x0049, 1 /*MSGFLT_ADD*/);
				}
				FreeLibrary(hDll);
			}
		}

		int i;
		// -------------------------------------------------------------------------
		if ( 0 == _stricmp(lpCmdLine, "/SHUTDOWN") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:SHUTDOWN") ) {
			if (IDOK == MessageBox(NULL, "Windowsを終了します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:SHUTDOWN") ) {
			return makeShortcutIcon("Windowsの終了", "/A:SHUTDOWN", -138) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/REBOOT") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_REBOOT, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:REBOOT") ) {
			if (IDOK == MessageBox(NULL, "Windowsを再起動します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_REBOOT, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:REBOOT") ) {
			return makeShortcutIcon("Windowsの再起動", "/A:REBOOT", -137) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/LOGOFF") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_LOGOFF, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:LOGOFF") ) {
			if (IDOK == MessageBox(NULL, "ログオフします。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_LOGOFF, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:LOGOFF") ) {
			return makeShortcutIcon("ログオフ", "/A:LOGOFF", -136) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/SUSPEND") ) {
			GetQuitRight();
			return SetSystemPowerState( TRUE, FALSE )?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:SUSPEND") ) {
			if (IDOK == MessageBox(NULL, "サスペンドします。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( TRUE, FALSE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:SUSPEND") ) {
			return makeShortcutIcon("サスペンド", "/A:SUSPEND", -135) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/HIBERNATION") || 0 == _stricmp(lpCmdLine, "/STANDBY") ) {
			GetQuitRight();
			return SetSystemPowerState( FALSE, FALSE )?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:HIBERNATION") ) {
			if (IDOK == MessageBox(NULL, "休止状態へ移行します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( FALSE, FALSE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:STANDBY") ) {
			if (IDOK == MessageBox(NULL, "スタンバイ状態へ移行します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( FALSE, FALSE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:HIBERNATION") ) {
			return makeShortcutIcon("休止状態へ", "/A:HIBERNATION", -135) ? 0 : 1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:STANDBY") ) {
			return makeShortcutIcon("スタンバイ", "/A:STANDBY", -135) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/SHUTDOWN FORCE") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCE, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:SHUTDOWN FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制終了します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF | EWX_FORCE, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:SHUTDOWN FORCE") ) {
			return makeShortcutIcon("Windowsの終了(強制)", "/A:SHUTDOWN FORCE", -138) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/REBOOT FORCE") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:REBOOT FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制再起動します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:REBOOT FORCE") ) {
			return makeShortcutIcon("Windowsの再起動(強制)", "/A:REBOOT FORCE", -137) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/LOGOFF FORCE") ) {
			GetQuitRight();
			return ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, 0)?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:LOGOFF FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制ログオフします。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, 0)?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:LOGOFF FORCE") ) {
			return makeShortcutIcon("ログオフ(強制)", "/A:LOGOFF FORCE", -136) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/SUSPEND FORCE") ) {
			GetQuitRight();
			return SetSystemPowerState( TRUE, TRUE )?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:SUSPEND FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制サスペンドします。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( TRUE, TRUE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:SUSPEND FORCE") ) {
			return makeShortcutIcon("サスペンド(強制)", "/A:SUSPEND FORCE", -135) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/HIBERNATION FORCE") || 0 == _stricmp(lpCmdLine, "/STANDBY FORCE") ) {
			GetQuitRight();
			return SetSystemPowerState( FALSE, TRUE )?0:1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:HIBERNATION FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制的に休止状態へ移行します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( FALSE, TRUE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/A:STANDBY FORCE") ) {
			if (IDOK == MessageBox(NULL, "Windowsを強制的にスタンバイ状態へ移行します。", szTitle, MB_OKCANCEL | MB_ICONQUESTION)) {
				GetQuitRight();
				return SetSystemPowerState( FALSE, TRUE )?0:1;
			}
			else {
				return 0;
			}
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:HIBERNATION FORCE") ) {
			return makeShortcutIcon("休止状態へ(強制)", "/A:HIBERNATION FORCE", -135) ? 0 : 1;
		}
		else if ( 0 == _stricmp(lpCmdLine, "/B:STANDBY FORCE") ) {
			return makeShortcutIcon("スタンバイ(強制)", "/A:STANDBY FORCE", -135) ? 0 : 1;
		}
		// -------------------------------------------------------------------------

		else if ( 0 == _stricmp(lpCmdLine, "/WriteManifestR7 asInvoker") || 0 == _stricmp(lpCmdLine, "/WriteManifestR7 highestAvailable") || 0 == _stricmp(lpCmdLine, "/WriteManifestR7 requireAdministrator") ) {
			SetCurrentDirectoryOwnDir();
			FILE *fp = NULL;

			if (0 == fopen_s(&fp, "RNSF7.EXE.manifest", "wb")) {
				int iWriteSize = fprintf_s(fp, r7manifest_utf8, &lpCmdLine[17]);
				fclose(fp);

				if (iWriteSize == 0) {
					return 1;
				}
			}
			else {
				return 1;
			}

			return 0;
		}
		else if ( 0 == _strnicmp(lpCmdLine, "/SUBST:", 7) ) {

			// 空きドライブを調べる
			char freedrive = getFreeDrive();

			if (freedrive == 0) {
				MessageBox(NULL, "空きドライブがありません(/SUBST)", szTitle, MB_OK | MB_ICONSTOP);
				return 1;
			}
			else {
				const char *targetdir = &lpCmdLine[7];
				char subst_param[1025];

				wsprintf(subst_param, "/C SUBST %c: \"%s\"&IF ERRORLEVEL 1 PAUSE", freedrive, targetdir);
				SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", subst_param, ".", SW_SHOWNORMAL));
				return 0;
			}
		}
		else {
			switch ( lpCmdLine[1] ) {
				case 'A':
				case 'a': // アプリケーションパスに登録する
					if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/A)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}			
					AddApplicationPath(&lpCmdLine[2+i]);
					break;

				case 'X':
				case 'x': // 簡易すっきり実行する
					if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/X)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}			
					EasySkrx(&lpCmdLine[2+i]);
					break;

				case 'W':
				case 'w': // 壁紙に設定する
					if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/W)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}			
					setWallPaper( &lpCmdLine[2+i] );
					break;

				case 'T':
				case 't': // ファイル日時の変更
					if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/T)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}			
					tChangeFileTimeDate( &lpCmdLine[2+i] );
					break;

				case '5': // MD5の算出
					if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/5)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}
					CoInitialize( NULL );
					showMD5file( &lpCmdLine[2+i] );
					CoUninitialize();
					break;

				case 'C':
				case 'c':
					switch ( lpCmdLine[2] ) {
						case 'P':
						case 'p': // 単純にクリップボードへコピー
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/CP)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							tCopyClipboard( &lpCmdLine[3+i] );
							break;

						case 'D':
						case 'd': // \を2重にしてクリップボードへコピー
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/CD)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							t2CopyClipboard( &lpCmdLine[3+i] );
							break;

						case 'A':
						case 'a': // 圧縮ダイアログを開く
							OpenArchiver();
							break;

						case 'M':
						case 'm': // 比較ダイアログを開く
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/CM)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}
							CoInitialize( NULL );
							CompareFiles( &lpCmdLine[3+i] );
							CoUninitialize();
							break;
					}
					break;

				case 'L':
				case 'l': // LZHを展開
#ifdef _WIN64
					{
						// 64bit DLLが見つからない場合は、32bit版context.exeを呼出し、32bit版 DLLを試行する
						int rv_dll = call_unlha32(NULL, NULL);

						if (rv_dll == T_TF_DLLNOTFOUND || rv_dll == T_TF_ILLEGALDLL) {
							char exename[MAX_PATH * 2];
							char drv[_MAX_DRIVE*2], dir[_MAX_DIR*2], fname[_MAX_FNAME*2];
							char *new_fname;

							GetModuleFileName(NULL, exename, _countof(exename));
							_splitpath_s(exename, drv, _countof(drv), dir, _countof(dir), fname, _countof(fname), NULL, 0);
							if (lstrcmpi(fname, "context_noadm") == 0) {
								new_fname = "context_x86_noadm";
							}
							else {
								new_fname = "context_x86";
							}
							_makepath_s(exename, _countof(exename), drv, dir, new_fname, ".exe");

							SHE(NULL, ShellExecute(NULL, "open", exename, lpCmdLine, ".", SW_SHOWNORMAL));
							break;
						}
					}
#endif /* _WIN64 */
					switch ( lpCmdLine[2] ) {
						case 'H':
						case 'h': // あらかじめ指定されたフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/LH)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractor( &lpCmdLine[3+i], OET_LZH );
							break;

						case 'D':
						case 'd': // これからフォルダを指定して展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/LD)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDir( &lpCmdLine[3+i], OET_LZH );
							break;

						case 'A':
						case 'a': // デスクトップに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/LA)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDesktop( &lpCmdLine[3+i], OET_LZH );
							break;

						case 'C':
						case 'c': // カレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/LC)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorCD( &lpCmdLine[3+i], OET_LZH );
							break;

						case 'X':
						case 'x': // このプログラムのカレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/LX)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorOwnDir( &lpCmdLine[3+i], OET_LZH );
							break;
					}
					break;

				case 'Z':
				case 'z': // ZIPを展開
#ifdef _WIN64
					{
						// 64bit DLLが見つからない場合は、32bit版context.exeを呼出し、32bit版 DLLを試行する
						int rv_dll = call_unzip32(NULL, NULL);

						if (rv_dll == T_TF_DLLNOTFOUND || rv_dll == T_TF_ILLEGALDLL) {
							char exename[MAX_PATH * 2];
							char drv[_MAX_DRIVE*2], dir[_MAX_DIR*2], fname[_MAX_FNAME*2];
							char *new_fname;

							GetModuleFileName(NULL, exename, _countof(exename));
							_splitpath_s(exename, drv, _countof(drv), dir, _countof(dir), fname, _countof(fname), NULL, 0);
							if (lstrcmpi(fname, "context_noadm") == 0) {
								new_fname = "context_x86_noadm";
							}
							else {
								new_fname = "context_x86";
							}
							_makepath_s(exename, _countof(exename), drv, dir, new_fname, ".exe");

							SHE(NULL, ShellExecute(NULL, "open", exename, lpCmdLine, ".", SW_SHOWNORMAL));
							break;
						}
					}
#endif /* _WIN64 */
					switch ( lpCmdLine[2] ) {
						case 'I':
						case 'i': // あらかじめ指定されたフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/ZI)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractor( &lpCmdLine[3+i], OET_ZIP );
							break;

						case 'D':
						case 'd': // これからフォルダを指定して展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/ZD)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDir( &lpCmdLine[3+i], OET_ZIP );
							break;

						case 'A':
						case 'a': // デスクトップに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/ZA)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDesktop( &lpCmdLine[3+i], OET_ZIP );
							break;

						case 'C':
						case 'c': // カレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/ZC)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorCD( &lpCmdLine[3+i], OET_ZIP );
							break;

						case 'X':
						case 'x': // このプログラムのカレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/ZX)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorOwnDir( &lpCmdLine[3+i], OET_ZIP );
							break;
					}
					break;

				case '7': // 7Zipを展開
#ifdef _WIN64
					{
						// 64bit DLLが見つからない場合は、32bit版context.exeを呼出し、32bit版 DLLを試行する
						int rv_dll = call_7zip32(NULL, NULL);

						if (rv_dll == T_TF_DLLNOTFOUND || rv_dll == T_TF_ILLEGALDLL) {
							char exename[MAX_PATH * 2];
							char drv[_MAX_DRIVE*2], dir[_MAX_DIR*2], fname[_MAX_FNAME*2];
							char *new_fname;

							GetModuleFileName(NULL, exename, _countof(exename));
							_splitpath_s(exename, drv, _countof(drv), dir, _countof(dir), fname, _countof(fname), NULL, 0);
							if (lstrcmpi(fname, "context_noadm") == 0) {
								new_fname = "context_x86_noadm";
							}
							else {
								new_fname = "context_x86";
							}
							_makepath_s(exename, _countof(exename), drv, dir, new_fname, ".exe");

							SHE(NULL, ShellExecute(NULL, "open", exename, lpCmdLine, ".", SW_SHOWNORMAL));
							break;
						}
					}
#endif /* _WIN64 */

					switch ( lpCmdLine[2] ) {
						case 'I':
						case 'i': // あらかじめ指定されたフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/7I)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractor( &lpCmdLine[3+i], OET_7Z );
							break;

						case 'D':
						case 'd': // これからフォルダを指定して展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/7D)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDir( &lpCmdLine[3+i], OET_7Z );
							break;

						case 'A':
						case 'a': // デスクトップに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/7A)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorDesktop( &lpCmdLine[3+i], OET_7Z );
							break;

						case 'C':
						case 'c': // カレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/7C)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorCD( &lpCmdLine[3+i], OET_7Z );
							break;

						case 'X':
						case 'x': // このプログラムのカレントフォルダに展開
							if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/7X)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}			
							OpenExtractorOwnDir( &lpCmdLine[3+i], OET_7Z );
							break;
					}
					break;

				case 'M':
				case 'm': // 指定したフォルダ・ファイル等の一つ上のフォルダで、DOSプロンプトやコマンドプロンプトを開く
					{
						char drv[_MAX_DRIVE*2], dir[_MAX_DIR*2], path[MAX_PATH*2];
						int  length;

						if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
							MessageBox( NULL, "パラメタの解析に失敗しました(/M)。", szTitle, MB_OK | MB_ICONSTOP );
							return 1;
						}			
						_splitpath_s( &lpCmdLine[3+i], drv, _countof(drv), dir, _countof(dir), NULL, 0, NULL, 0 );
						_makepath_s( path, _countof(path), drv, dir, NULL, NULL );
						length = lstrlen(path);
						if ( length > 3 && !isKanji1(path,length-2) && path[length-1] == '\\' ) {
							path[length-1] = 0;
						}

						switch ( lpCmdLine[2] ) {
							case 'D': // MS-DOSプロンプト
							case 'd':
								SHE(NULL, ShellExecute(NULL, "open", "COMMAND.COM", NULL, path, SW_SHOW));
								break;

							case 'C': // コマンドプロンプト
							case 'c':
								SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", NULL, path, SW_SHOW));
								break;

							case 'P': // ネットワークパス可能版コマンドプロンプト
							case 'p':
								{
									char pushcmd[1025];
									wsprintf(pushcmd, "/K PUSHD \"%s\"", path);
									SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", pushcmd, ".", SW_SHOW));
								}
								break;
						}
					}
					break;

				case 'N':
				case 'n': // (context.exeが管理者特権が必要なプログラムであることを利用して)管理者としてコマンドプロンプトを開く
					if ( -1 == (i = skipSpace( &lpCmdLine[3] )) ) {
						MessageBox( NULL, "パラメタの解析に失敗しました(/N)。", szTitle, MB_OK | MB_ICONSTOP );
						return 1;
					}			

					switch ( lpCmdLine[2] ) {
						case 'D': // MS-DOSプロンプト
						case 'd':
							SHE(NULL, ShellExecute(NULL, "open", "COMMAND.COM", NULL, &lpCmdLine[3+i], SW_SHOW));
							break;

						case 'C': // コマンドプロンプト
						case 'c':
							SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", NULL, &lpCmdLine[3+i], SW_SHOW));
							break;

						case 'P': // ネットワークパス可能版コマンドプロンプト
						case 'p':
							{
								char pushcmd[1025];
								wsprintf(pushcmd, "/K PUSHD \"%s\"", &lpCmdLine[3+i]);
								SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", pushcmd, ".", SW_SHOW));
							}
							break;

						case 'O': // command.comで任意のコマンドを実行(/K … １行コマンド実行後に復帰しない)
						case 'o':
							{
								char cmd[1025];
								wsprintf(cmd, "/K %s", &lpCmdLine[3+i]);
								SHE(NULL, ShellExecute(NULL, "open", "COMMAND.COM", cmd, ".", SW_SHOW));
							}
							break;
						case 'A': // cmd.exeで任意のコマンドを実行(/K … １行コマンド実行後に復帰しない)
						case 'a':
							{
								char cmd[1025];
								wsprintf(cmd, "/K %s", &lpCmdLine[3+i]);
								SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", cmd, ".", SW_SHOW));
							}
							break;

						case 'L': // command.comで任意のコマンドを実行(/C … １行コマンド実行後に復帰)
						case 'l':
							{
								char cmd[1025];
								wsprintf(cmd, "/C %s", &lpCmdLine[3+i]);
								SHE(NULL, ShellExecute(NULL, "open", "COMMAND.COM", cmd, ".", SW_SHOW));
							}
							break;
						case 'N': // cmd.exeで任意のコマンドを実行(/C … １行コマンド実行後に復帰)
						case 'n':
							{
								char cmd[1025];
								wsprintf(cmd, "/C %s", &lpCmdLine[3+i]);
								SHE(NULL, ShellExecute(NULL, "open", "CMD.EXE", cmd, ".", SW_SHOW));
							}
							break;
					}
					break;

				case 'B': // 「-圧縮-」アイコンを作成する
				case 'b':
					CoInitialize( NULL );
					//CoInitializeEx(NULL, COINIT_MULTITHREADED);
					if ( false == makeCompressIcon() ) {
						MessageBox( NULL, "圧縮アイコンの作成に失敗しました。", szTitle, MB_OK | MB_ICONSTOP );
						CoUninitialize();
						return 1;
					}
					CoUninitialize();
					break;

				case 'I': // ショートカットのターゲットが置かれているフォルダを開く
				case 'i':
				case 'J': // J:フォルダ表示型
				case 'j':
				case 'O': // O:ファイル名部分（最後の\より右）を自力で取り除く型
				case 'o':
					{
						char szLinkFile[MAX_PATH*2], target[MAX_PATH*2];
						char szExplorerOptions[MAX_PATH*2 + 20] = "/E,/SELECT,";
						int  i, iLen;

						if ( lpCmdLine[1] == 'I' || lpCmdLine[1] == 'i' ) {
							lstrcpy( szExplorerOptions, "/E,/SELECT," );
							if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/I)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}
						}
						else if ( lpCmdLine[1] == 'J' || lpCmdLine[1] == 'j' ) {
							lstrcpy( szExplorerOptions, "/SELECT," );
							if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/J)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}
						}
						else { // if ( lpCmdLine[1] == 'O' || lpCmdLine[1] == 'o' ) { を想定
							lpCmdLine[1] = 'O';
							if ( -1 == (i = skipSpace( &lpCmdLine[2] )) ) {
								MessageBox( NULL, "パラメタの解析に失敗しました(/O)。", szTitle, MB_OK | MB_ICONSTOP );
								return 1;
							}
						}

						if ( lpCmdLine[2+i] == '"' ) {
							lstrcpy( szLinkFile, &lpCmdLine[2+i+1] );
							iLen = lstrlen( szLinkFile );
							if ( szLinkFile[iLen-1] == '"' ) {
								szLinkFile[iLen-1] = 0;
							}
						}
						else {
							lstrcpy( szLinkFile, &lpCmdLine[2+i] );
						}

						CoInitialize( NULL );
						//CoInitializeEx(NULL, COINIT_MULTITHREADED);
						if ( FALSE == QueryLink(szLinkFile, target, NULL, NULL, NULL) ) {
							MessageBox( NULL, "ショートカットファイルの読み込みに失敗しました。", szTitle, MB_OK | MB_ICONSTOP );
							CoUninitialize();
							return 1;
						}
						CoUninitialize();

						if ( lpCmdLine[1] == 'O' ) {
							// 自力でフォルダ名を生成して開く - 現在関連づけられているアプリにて開く
							// 後ろからサーチして、最初に見つかった\のところを終端に置き換える
							// 残った部分が、開かれるべきフォルダ名
							i = lstrlen(target) - 1;
							for(; i>0 ; i--) {
								if ( target[i] == '\\' ) {
									target[i] = 0;
									break;
								}
							}

							// フォルダ(Folder)に標準に関連づけられたプログラムを探し、
							// ShellExecuteの第２引数に指定する文字列とする。
							// 読み出しできなかった場合は、従来通り "open" となる。
							REG   reg;
							char *szWay = NULL;

							if ( reg.OpenKey(HKEY_CLASSES_ROOT, "Folder\\shell", TREG_OPEN_READONLY) ) {
								szWay = reg.new_ReadString("", "open");
								reg.CloseKey();
							}

							SHE(NULL, ShellExecute(NULL, szWay?szWay:"open" , target, NULL, target, SW_SHOWNORMAL));
							safedelete(szWay);
						}
						else {
							// エクスプローラにて開く - 
							// ターゲット先のファイルに、カーソルがセットされた状態で開く(/SELECT)
							lstrcat(szExplorerOptions, target);
							SHE(NULL, ShellExecute(NULL, "open", "EXPLORER.EXE", szExplorerOptions, ".", SW_SHOWNORMAL));
						}
						break;
					}

				case 'S':
				case 's':
					{
#if _MSC_VER < 1500
#ifndef _WIN64
						unsigned char scanreg[4] = {0x90, 0x04, 0x00, 0x00};
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
						char szChkdskOptions[30];
						REG reg;

						switch( lpCmdLine[2] ) {
							case '0': // 通常のスキャン
#if _MSC_VER < 1500
#ifndef _WIN64
								if ( isNT ) {
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
									wsprintf(szChkdskOptions, "%c:", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "CHKDSK.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
#if _MSC_VER < 1500
#ifndef _WIN64
								}
								else {
									if (reg.OpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Check Drive", TREG_OPEN_CREATE)) {
										if (false == reg.ReadString("Settings",(char *)scanreg, 4)) {
											scanreg[0] = 0x90;
											scanreg[1] = 0x04;
											scanreg[2] = scanreg[3] = 0x00;
										}
										scanreg[1] |= 0x05;	// 修復しない 05を立てる
										scanreg[1] &= 0xfb;	// 修復しない 04を寝かす
										scanreg[0] |= 0x10; // クラスタスキャンをしない
										reg.WriteBinary("Settings",(char *)scanreg,4);
										reg.CloseKey();
									}
									wsprintf(szChkdskOptions, "%c:", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "SCANDSKW.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
								}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
								break;

							case '1': // 修復を行うためのスキャン
#if _MSC_VER < 1500
#ifndef _WIN64
								if ( isNT ) {
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
									wsprintf(szChkdskOptions, "%c: /f", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "CHKDSK.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
#if _MSC_VER < 1500
#ifndef _WIN64
								}
								else {
									if (reg.OpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Check Drive", TREG_OPEN_CREATE)) {
										if (false == reg.ReadString("Settings",(char *)scanreg, 4)) {
											scanreg[0] = 0x90;
											scanreg[1] = 0x04;
											scanreg[2] = scanreg[3] = 0x00;
										}
										scanreg[1] &= 0xfa;	// 必ず修復する 05の消去
										scanreg[1] |= 0x04;	// 必ず修復する 04を立てる
										scanreg[0] |= 0x10; // クラスタスキャンをしない
										reg.WriteBinary("Settings",(char *)scanreg,4);
										reg.CloseKey();
									}
									wsprintf(szChkdskOptions, "%c:", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "SCANDSKW.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
								}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
								break;

							case '2': // セクタ検査／クラスタスキャンを伴う非修復スキャン
#if _MSC_VER < 1500
#ifndef _WIN64
								if ( isNT ) {
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
									wsprintf(szChkdskOptions, "%c: /r", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "CHKDSK.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
#if _MSC_VER < 1500
#ifndef _WIN64
								}
								else {
									if (reg.OpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Check Drive", TREG_OPEN_CREATE)) {
										if (false == reg.ReadString("Settings",(char *)scanreg, 4)) {
											scanreg[0] = 0x90;
											scanreg[1] = 0x04;
											scanreg[2] = scanreg[3] = 0x00;
										}
										scanreg[1] |= 0x05;	// 修復しない 05を立てる
										scanreg[1] &= 0xfb;	// 修復しない 04を寝かす
										scanreg[0] &= (~0x10); // クラスタスキャンをする
										reg.WriteBinary("Settings",(char *)scanreg,4);
										reg.CloseKey();
									}
									wsprintf(szChkdskOptions, "%c:", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "SCANDSKW.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
								}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
								break;

							case '3': // セクタ検査／クラスタスキャンを伴う修復スキャン
#if _MSC_VER < 1500
#ifndef _WIN64
								if ( isNT ) {
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
									wsprintf(szChkdskOptions, "%c: /f /r", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "CHKDSK.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
#if _MSC_VER < 1500
#ifndef _WIN64
								}
								else {
									if (reg.OpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Check Drive", TREG_OPEN_CREATE)) {
										if (false == reg.ReadString("Settings",(char *)scanreg, 4)) {
											scanreg[0] = 0x90;
											scanreg[1] = 0x04;
											scanreg[2] = scanreg[3] = 0x00;
										}
										scanreg[1] &= 0xfa;	// 必ず修復する 05の消去
										scanreg[1] |= 0x04;	// 必ず修復する 04を立てる
										scanreg[0] &= (~0x10); // クラスタスキャンをする
										reg.WriteBinary("Settings",(char *)scanreg,4);
										reg.CloseKey();
									}
									wsprintf(szChkdskOptions, "%c:", lpCmdLine[3]);
									SHE(NULL, ShellExecute(NULL, "open", "SCANDSKW.EXE", szChkdskOptions, ".", SW_SHOWNORMAL));
								}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
								break;

						}
					}
					break;
			}
		}
	}
	else {
		int i;

		i = lstrlen( lpCmdLine );
		if ( i >= 5 ) { // Opera対策(指示を無視してオプションをそのまま渡すようなので)
			if ( (lpCmdLine[i-4] == '.' && (lpCmdLine[i-3] == 'l' || lpCmdLine[i-3] == 'L') && (lpCmdLine[i-2] == 'z' || lpCmdLine[i-2] == 'Z') && (lpCmdLine[i-1] == 'h' || lpCmdLine[i-1] == 'H')) ||
			     (lpCmdLine[i-5] == '.' && (lpCmdLine[i-4] == 'l' || lpCmdLine[i-4] == 'L') && (lpCmdLine[i-3] == 'z' || lpCmdLine[i-3] == 'Z') && (lpCmdLine[i-2] == 'h' || lpCmdLine[i-2] == 'H') && lpCmdLine[i-1] == '\"') ) {
				OpenExtractor( lpCmdLine, OET_LZH );
				return 1;
			}
			else if ( (lpCmdLine[i-4] == '.' && (lpCmdLine[i-3] == 'z' || lpCmdLine[i-3] == 'Z') && (lpCmdLine[i-2] == 'i' || lpCmdLine[i-2] == 'I') && (lpCmdLine[i-1] == 'p' || lpCmdLine[i-1] == 'P')) ||
				      (lpCmdLine[i-5] == '.' && (lpCmdLine[i-4] == 'z' || lpCmdLine[i-4] == 'Z') && (lpCmdLine[i-3] == 'i' || lpCmdLine[i-3] == 'I') && (lpCmdLine[i-2] == 'p' || lpCmdLine[i-2] == 'P') && lpCmdLine[i-1] == '\"') ) {
				OpenExtractor( lpCmdLine, OET_ZIP );
				return 1;
			}
		}
	}

	return 0;
}

void EasySkrx( const char *path )
{
	char *mes;
	REG  reg;

	mes = zalloc(lstrlen(path) + 100);
    wsprintf(mes,"%s\n\nこのプログラムを簡易すっきり実行します。\n再起動してもよろしいですか?", path);	

	if (IDYES == MessageBox(NULL, mes, "いじくるつくーる", MB_YESNO | MB_ICONQUESTION)) {
		if (reg.OpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", TREG_OPEN_CREATE)) {
			reg.WriteString("RnsfSkrx", path);
			reg.CloseKey();

			GetQuitRight();
			if ( 0 == ExitWindowsEx(EWX_REBOOT,0) ) {
				MessageBox(NULL, "再起動に失敗しました。すっきり実行は次回起動時に行われます。", "いじくるつくーる", MB_OK | MB_ICONSTOP);
			}
		}
		else {
			MessageBox(NULL, "簡易すっきり実行を登録するレジストリキーを開けませんでした。", "いじくるつくーる", MB_OK | MB_ICONSTOP);
		}
	}
	safefree(mes);
}

void AddApplicationPath( const char *path )
{
	char drive[MAX_PATH*2], dir[_MAX_DIR*2], fname[MAX_PATH*2], fext[_MAX_EXT*2];
	REG reg;

	_splitpath_s(path, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), fext, _countof(fext));	// 与えられたフルパスを分離
	lstrcat(drive, dir);	// ディレクトリ名を構成
	lstrcat(fname, fext);	// ファイル名を構成
	if ( reg.OpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths", TREG_OPEN_CREATE) ) {
		REG reg2;

		if ( reg2.OpenKey(reg.GetHKey(), fname) ) {
			if ( IDYES == MessageBox(NULL, "同じ名前のファイル名が、すでにアプリケーション パスに登録されています。\n上書き登録してもよろしいですか?", fname, MB_YESNO | MB_ICONQUESTION) ) {
				reg2.WriteString( "", path, 2 );
				reg2.WriteString( "Path", drive, 2 );
				MessageBox(NULL, "アプリケーション パスに登録しました。\n登録を取り消したいときは「いじくるつくーる」の「アプリケーション パス」から削除して下さい。", fname, MB_OK | MB_ICONINFORMATION);
			}
			reg2.CloseKey();
		}
		else if ( IDYES == MessageBox(NULL, "アプリケーション パスに登録すると、「ファイル名を指定して実行」からファイル名の入力だけで目的のプログラムが実行できるようになります。\nアプリケーション パスに登録してもよろしいですか?", fname, MB_YESNO | MB_ICONQUESTION) ) {
			if ( reg2.OpenKey(reg.GetHKey(), fname, TREG_OPEN_CREATE) ) {
				reg2.WriteString("", path, 2);
				reg2.WriteString("Path", drive, 2);
				reg2.CloseKey();
				MessageBox(NULL, "アプリケーション パスに登録しました。\n登録を取り消したいときは「いじくるつくーる」の「アプリケーションパス」から削除して下さい。", fname, MB_OK | MB_ICONINFORMATION);
			}
			else
				MessageBox(NULL, "アプリケーション パスに登録できませんでした。", fname, MB_OK | MB_ICONSTOP);
		}
		reg.CloseKey();
	}
}

// 壁紙の設定
bool setWallPaper( char *bmp )
{
	REG reg;

	if (reg.OpenKey(HKEY_CURRENT_USER, "Control Panel\\desktop", TREG_OPEN_CREATE)) {
		reg.WriteString("Wallpaper", bmp);
		reg.CloseKey();
	}

	return (SystemParametersInfo(SPI_SETDESKWALLPAPER,0,bmp,SPIF_SENDCHANGE))?true:false;
}

list<string> fnames_tChangeFileTimeDate;

// ファイル日時変更用ダイアログプロシージャ
static LRESULT CALLBACK DlgProc_tChangeFileTimeDate( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			// 現在は、ダイアログは MS P ゴシックで固定
			// SetChildWindowFont(hDlg);
			{
				WIN32_FIND_DATA520 wfd;
				HANDLE handle;
				FILETIME   fct, fwt; // ローカルファイルタイム：作成日時, 最終更新日時
				SYSTEMTIME sct, swt; // システムタイム：作成日時, 最終更新日時

				SetDlgItemText(hDlg, IDC_EDIT_FNAME, fnames_tChangeFileTimeDate.front().c_str());
				handle = FindFirstFile520(fnames_tChangeFileTimeDate.front().c_str(), &wfd);
				if ( handle == INVALID_HANDLE_VALUE ) { // ファイルが見つからない
					MessageBox(hDlg, "ファイルが見つかりません。", "タイムスタンプ変更", MB_OK | MB_ICONSTOP);
					EndDialog(hDlg, FALSE);
					return TRUE;
				}
				FindClose( handle );

				// UFTからシステムタイム（扱いやすい形）に変換
				FileTimeToLocalFileTime(&wfd.ftCreationTime  , &fct);
				FileTimeToSystemTime(&fct, &sct);
				FileTimeToLocalFileTime(&wfd.ftLastWriteTime , &fwt);
				FileTimeToSystemTime(&fwt, &swt);
			
				// ダイアログへ各値を代入
				SetDlgItemInt(hDlg, IDC_EDIT_CYEAR  , sct.wYear  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMONTH , sct.wMonth , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CDAY   , sct.wDay   , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CHOUR  , sct.wHour  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMINUTE, sct.wMinute, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CSECOND, sct.wSecond, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMILSEC, sct.wMilliseconds, FALSE);

				SetDlgItemInt(hDlg, IDC_EDIT_WYEAR  , swt.wYear  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMONTH , swt.wMonth , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WDAY   , swt.wDay   , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WHOUR  , swt.wHour  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMINUTE, swt.wMinute, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WSECOND, swt.wSecond, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMILSEC, swt.wMilliseconds, FALSE);

				// フォーカスを最初の年に設定
				SetFocus(GetDlgItem(hDlg, IDC_EDIT_CYEAR));
			}
			return FALSE; // フォーカスを変えているのでFALSEを返す

		case WM_DROPFILES:
			// エクスプローラからファイルをドロップ
			{
				WIN32_FIND_DATA520 wfd;
				HANDLE handle;
				FILETIME   fct, fwt; // ローカルファイルタイム：作成日時, 最終更新日時
				SYSTEMTIME sct, swt; // システムタイム：作成日時, 最終更新日時
				char fname[MAX_PATH*2] = "";

				DragQueryFile((HDROP)wParam, 0, fname, _countof(fname));
				
				handle = FindFirstFile520(fname, &wfd);
				if ( handle == INVALID_HANDLE_VALUE ) { // ファイルが見つからない
					return TRUE;
				}
				FindClose( handle );

				// UFTからシステムタイム（扱いやすい形）に変換
				FileTimeToLocalFileTime(&wfd.ftCreationTime  , &fct);
				FileTimeToSystemTime(&fct, &sct);
				FileTimeToLocalFileTime(&wfd.ftLastWriteTime , &fwt);
				FileTimeToSystemTime(&fwt, &swt);
			
				// ダイアログへ各値を代入
				SetDlgItemInt(hDlg, IDC_EDIT_CYEAR  , sct.wYear  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMONTH , sct.wMonth , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CDAY   , sct.wDay   , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CHOUR  , sct.wHour  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMINUTE, sct.wMinute, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CSECOND, sct.wSecond, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_CMILSEC, sct.wMilliseconds, FALSE);

				SetDlgItemInt(hDlg, IDC_EDIT_WYEAR  , swt.wYear  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMONTH , swt.wMonth , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WDAY   , swt.wDay   , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WHOUR  , swt.wHour  , FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMINUTE, swt.wMinute, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WSECOND, swt.wSecond, FALSE);
				SetDlgItemInt(hDlg, IDC_EDIT_WMILSEC, swt.wMilliseconds, FALSE);

				DragFinish((HDROP)wParam);
			}
			return TRUE;


		case WM_COMMAND:
			switch ( LOWORD(wParam) ) {
				case IDOK:
					{
						FILETIME   ufct, ufwt; // Uファイルタイム：作成日時, 最終アクセス日, 最終更新日時
						FILETIME   fct, fwt; // ローカルファイルタイム：作成日時, 最終アクセス日, 最終更新日時
						SYSTEMTIME sct, swt; // システムタイム：作成日時, 最終アクセス日, 最終更新日時
						HANDLE handle;
						DWORD  attr;
						BOOL   rv = FALSE;

						// ダイアログから各数値を得る
						sct.wYear   = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CYEAR  , NULL, FALSE);
						sct.wMonth  = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CMONTH , NULL, FALSE);
						sct.wDay    = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CDAY   , NULL, FALSE);
						sct.wHour   = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CHOUR  , NULL, FALSE);
						sct.wMinute = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CMINUTE, NULL, FALSE);
						sct.wSecond = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CSECOND, NULL, FALSE);
						sct.wMilliseconds = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_CMILSEC, NULL, FALSE);

						swt.wYear   = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WYEAR  , NULL, FALSE);
						swt.wMonth  = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WMONTH , NULL, FALSE);
						swt.wDay    = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WDAY   , NULL, FALSE);
						swt.wHour   = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WHOUR  , NULL, FALSE);
						swt.wMinute = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WMINUTE, NULL, FALSE);
						swt.wSecond = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WSECOND, NULL, FALSE);
						swt.wMilliseconds = (WORD)GetDlgItemInt(hDlg, IDC_EDIT_WMILSEC, NULL, FALSE);

						// システムタイム形式からUFTへ変更
						SystemTimeToFileTime(&sct, &fct);
						LocalFileTimeToFileTime(&fct, &ufct);
						SystemTimeToFileTime(&swt, &fwt);
						LocalFileTimeToFileTime(&fwt, &ufwt);

						const char *fname_tChangeFileTimeDate;
						for(list<string>::iterator iter = fnames_tChangeFileTimeDate.begin() ; iter != fnames_tChangeFileTimeDate.end() ; ++iter) {
							fname_tChangeFileTimeDate = iter->c_str();
							char errmes[80+MAX_PATH*2];

							// 属性を一時的に変更
							attr = GetFileAttributes( fname_tChangeFileTimeDate );
							SetFileAttributes( fname_tChangeFileTimeDate, FILE_ATTRIBUTE_NORMAL );

							// ファイルを開いて各日時を変更
							if ( INVALID_HANDLE_VALUE != (handle = CreateFile(fname_tChangeFileTimeDate, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) ) {
								rv = SetFileTime(handle, &ufct, NULL, &ufwt);
								CloseHandle( handle );
								if (rv == 0) {
									wsprintf(errmes, "%s\nファイルのタイムスタンプを変更できません。", fname_tChangeFileTimeDate);
									MessageBox(hDlg, errmes, "タイムスタンプ変更", MB_OK | MB_ICONSTOP);
								}
							}
							else {
								wsprintf(errmes, "%s\nファイルを書き込みモードで開けません。", fname_tChangeFileTimeDate);
								MessageBox(hDlg, errmes, "タイムスタンプ変更", MB_OK | MB_ICONSTOP);
							}

							// 属性を元に戻す
							SetFileAttributes( fname_tChangeFileTimeDate, attr );
						}
						EndDialog(hDlg, (INT_PTR)rv);
					}
					return TRUE;

				case IDCANCEL:
					EndDialog(hDlg, FALSE);
					return TRUE;
			}
			break;

		case WM_COPYDATA:
			// ファイル名の受信
			{
				COPYDATASTRUCT *pcpds = (COPYDATASTRUCT *)lParam;

				if (pcpds->dwData == FCHANGE_KDT) {
					fnames_tChangeFileTimeDate.push_back((const char *)(pcpds->lpData));
					int len = GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_FNAME)) + 3 + lstrlen((const char *)(pcpds->lpData));
					char *buf = zalloc(len);

					if (buf) {
						GetDlgItemText(hDlg, IDC_EDIT_FNAME, buf, len);
						lstrcat(buf, ", ");
						lstrcat(buf, (const char *)(pcpds->lpData));
						SetDlgItemText(hDlg, IDC_EDIT_FNAME, buf);
						free(buf);
					}
					return TRUE;
				}
			}
			return FALSE;
	}
    return FALSE;
}

BOOL CALLBACK tChangeFileTimeDate_EnumWindow(HWND hWnd, LPARAM lParam)
{
	char title[80];

	if (0 < GetWindowText(hWnd, title, _countof(title))) {
		if (lstrcmp(title, "ファイルのタイムスタンプ変更") == 0) {
			COPYDATASTRUCT cpds;

			cpds.dwData = FCHANGE_KDT;
			cpds.cbData = lstrlen((const char *)lParam) + 1;
			cpds.lpData = (PVOID)(const char *)lParam;

			if (TRUE == SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cpds)) {
				SetForegroundWindow(hWnd);
				return FALSE;
			}
		}
	}

	return TRUE;
}

// ファイルの最終更新日時などを変更する
bool tChangeFileTimeDate( const char *fname )
{
	// mutexにより、同一プロセスが上がっているかどうかをチェック
	HWND mutexhd;

	mutexhd = (HWND)CreateMutex(NULL, true, "Rnsfldr_context_tChangeFileTimeDate");
	if (GetLastError() == ERROR_ALREADY_EXISTS) {
		// すでに同一プロセスが上がっている場合は、そのプロセスに対しファイル名を送信する
		Sleep(500); // その前に 0.5s スリープ
		EnumWindows(tChangeFileTimeDate_EnumWindow, (LPARAM)fname);
		return true;
	}
	else {
		// 1番目の実行。listにファイル名の蓄積を開始
		fnames_tChangeFileTimeDate.clear();
		fnames_tChangeFileTimeDate.push_back(fname);
		bool rv = DialogBox(hInst, (LPCTSTR)IDD_CHANGE_FTIME, NULL, (DLGPROC)DlgProc_tChangeFileTimeDate)?true:false;
		CloseHandle(mutexhd);

		return rv;
	}
}

static volatile HWND cts_hdlg;				// MD5算出ダイアログのハンドル
static volatile bool th_md5_abort_flag = 1;	// MD5算出中止フラグ

// md5fileからのコールバック関数。中止の場合はFALSEを返す。そうでない場合は進捗状況をlNow/lMaxより作り出す
BOOL smd5_cbfunc(long lNow, long lMax)
{
	if (th_md5_abort_flag) return FALSE;

	SendDlgItemMessage(cts_hdlg, IDC_PROGRESS1, PBM_SETPOS, (WPARAM)lNow, 0);
	w7tbProgress(cts_hdlg, 2 /*TBPF_NORMAL*/, lNow, lMax); // Win7のタスクバープログレス

	return TRUE;
}

typedef struct {
	HWND hDlg;
	const char *fname;
	long fsize;
} CTS, *PCTS;

// ファイルを比較（戻り値は結果を示す文字列）[ _beginthread() から呼ばれる ]
static void th_md5_files(void *_cts)
{
	char md5[33] = "MD5算出に失敗しました";
	PCTS pcts = (PCTS)_cts;

	cts_hdlg = pcts->hDlg;
	SendDlgItemMessage(pcts->hDlg, IDC_PROGRESS1, PBM_SETRANGE32, 0, (LPARAM)pcts->fsize);
	if (FALSE == md5file(pcts->fname, md5, smd5_cbfunc)) {
		// 中止
		SendDlgItemMessage(pcts->hDlg, IDC_PROGRESS1, PBM_SETPOS, (WPARAM)pcts->fsize, 0);
		w7tbProgress(pcts->hDlg, 4 /*TBPF_ERROR*/, 1, 1); // Win7のタスクバープログレス
	}
	else {
		// 成功
		SetDlgItemText(pcts->hDlg, IDC_EDITMD5, md5);
		EnableWindow(GetDlgItem(pcts->hDlg, IDYES), TRUE);
	}

	w7tbProgress(NULL, 0, 0, 0); // Win7のタスクバープログレス解放

	_endthread();
}

const static char *fname_showMD5file;

// MD5表示用ダイアログプロシージャ
static LRESULT CALLBACK DlgProc_showMD5file( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			// 現在は、ダイアログは MS P ゴシックで固定
			// SetChildWindowFont(hDlg);
			{
				char szSize[50] = "ファイルを開けません。";
				long lsize;
				FILE *fp;
				
				SetDlgItemText(hDlg, IDC_EDITMD5, "MD5を算出中です...");
				if ( 0 == fopen_s(&fp, fname_showMD5file, "rb") ) {
					char cmbuf[16], cmbuf2[16];

					fseek(fp, 0, SEEK_END);
					lsize = ftell(fp);
					fclose(fp);
					wsprintf(szSize, "%sバイト (%sKB)", commaex(lsize, cmbuf), commaex((0 < lsize && lsize < 2048)?1:(lsize/1024), cmbuf2));
					SetDlgItemText(hDlg, IDC_EDIT_FNAME, fname_showMD5file);

					static CTS cts;
					cts.hDlg = hDlg;
					cts.fname = fname_showMD5file;
					cts.fsize = lsize;
					th_md5_abort_flag = 0;

					w7tbProgress(hDlg, 2 /*TBPF_NORMAL*/, 0, lsize); // Win7のタスクバープログレス
					if( -1 == _beginthread( th_md5_files, 0, (void *)&cts ) ) {
						SetDlgItemText(hDlg, IDC_EDITMD5, "MD5の算出開始に失敗しました。");
					}
				}
				SetDlgItemText(hDlg, IDC_EDITSIZE, szSize);
			}
			return TRUE;

		case WM_COMMAND:
			switch ( LOWORD(wParam) ) {
				case IDYES:
					{
						char md5[33] = "A", md5b[35] = "B";

						GetDlgItemText(hDlg, IDC_EDITMD5, md5, 33);
						GetDlgItemText(hDlg, IDC_EDIT_COMPARE, md5b, 34);

						if (lstrlen(md5b) == 0) {
							MessageBox(hDlg, "「比較」欄に、比較相手のMD5を入力してください。", "MD5比較", MB_OK | MB_ICONINFORMATION );
						}
						else if (lstrlen(md5b) < 32) {
							MessageBox(hDlg, "「比較」欄のMD5の文字数が足りません。32文字で入力してください。", "MD5比較", MB_OK | MB_ICONINFORMATION );
						}
						else {
							MessageBox(hDlg, _stricmp(md5, md5b) == 0 ? "MD5一致" : "MD5不一致", "MD5比較", MB_OK | MB_ICONINFORMATION );
						}
					}
					return TRUE;

				case IDCANCEL:
					th_md5_abort_flag = 1;
					EndDialog(hDlg, FALSE);
					return TRUE;

				case IDC_EDIT_COMPARE:
					if ( HIWORD(wParam) == EN_CHANGE ) {
						char md5b[35];

						GetDlgItemText(hDlg, IDC_EDIT_COMPARE, md5b, 34);
						if ( lstrlen(md5b) >= 33 ) {
                            md5b[32] = 0;
							SetDlgItemText(hDlg, IDC_EDIT_COMPARE, md5b);
						}
                    }
					return TRUE;
			}
			break;
	}
    return FALSE;
}

// ファイルの最終更新日時などを変更する
bool showMD5file( const char *fname )
{
	fname_showMD5file = fname; // static外部変数にfnameをコピー
	return DialogBox(hInst, (LPCTSTR)IDD_SHOWMD5FILE, NULL, (DLGPROC)DlgProc_showMD5file)?true:false;
}

// textをクリップボードにコピー
bool tCopyClipboard( const char *text )
{
	if( OpenClipboard(NULL) ) {
		char *pPtr;
		int gsize;
		HGLOBAL hMem;
		HANDLE hRet;

		gsize = lstrlen(text) + 1;
		if ( NULL != (hMem = GlobalAlloc(GHND, gsize)) ) {
			pPtr = (char *)::GlobalLock(hMem);
			if (pPtr) {
				lstrcpy(pPtr, text);
				GlobalUnlock( hMem );
				if (EmptyClipboard()) {
					hRet = SetClipboardData(CF_TEXT, hMem);
					if (hRet == NULL) {
						CloseClipboard();
						safegfree(hMem);
						MessageBox(NULL, "クリップボードへの文字列設定中にエラーが発生しました。","いじくるつくーる",MB_OK | MB_ICONSTOP);
						return false;
					}
					else {
						CloseClipboard();
						return true;
					}
				}
				else {
					CloseClipboard();
					safegfree(hMem);
					MessageBox(NULL, "クリップボードを空にできません。","いじくるつくーる",MB_OK | MB_ICONSTOP);
					return false;
				}
			}
			else {
				CloseClipboard();
				safegfree(hMem);
				MessageBox(NULL, "GlobalLock失敗。","いじくるつくーる",MB_OK | MB_ICONSTOP);
				return false;
			}
		}
		else {
			CloseClipboard();
			MessageBox(NULL, "作業用のメモリが足りません。","いじくるつくーる",MB_OK | MB_ICONSTOP);
			return false;
		}
	}
	else {
		MessageBox(NULL, "クリップボードを開けません。","いじくるつくーる",MB_OK | MB_ICONSTOP);
		return false;
	}
}

// textの中で\を2重にしてクリップボードにコピー
bool t2CopyClipboard( const char *text )
{
	int  i, j;
	bool rv = false;

	char *s = zalloc(lstrlen(text)*2 + 1);
	if ( s ) {
		for(i=j=0 ; text[i] ; i++,j++) {
			s[j] = text[i];
			if ( !isKanji1(s,j-1) && s[j] == '\\' ) {
				s[++j] = '\\';
			}
		}
		s[j] = 0;

		rv = tCopyClipboard(s);
		free(s);
	}

	return rv;
}

// dir と (lzhnameの主ファイル名部分) を使って、lzhを展開するoutputdirを作る
static char *makeefolder(const char *dir, const char *arcfile, char *outputdir, size_t outputdirsize)
{
	if (dir && arcfile && outputdir) {
		int fnamesize = lstrlen(arcfile) + 1;
		char *fname = zalloc(fnamesize);
		if ( fname ) {
			_splitpath_s( arcfile, NULL, 0, NULL, 0, fname, fnamesize, NULL, 0);
			_makepath_s( outputdir, outputdirsize, NULL, dir, fname, NULL );
			free(fname);
			return outputdir;
		}
	}

	return NULL;
}

// lzhファイルの展開
bool ExpandLzh( const char *arcfile, const char *folder )
{
	REG reg;
	size_t outdirsize;
	char *outdir;
	bool rv = false;
	int  rvd;
	char szOutputBuf[ARCDLL_OUTBUFSIZE+1];

	if (folder) {
		outdirsize = lstrlen(arcfile) + lstrlen(folder) + 1;
		outdir = zalloc(outdirsize);
		if (outdir == NULL) return rv;
		makeefolder(folder, arcfile, outdir, outdirsize);
		CreateDir( outdir );
	}
	else {
		outdirsize = 0;
		outdir = ".";
	}

	while(1) { // unlha32.dllが使用中だった場合の対策：0.5秒スリープしてretry
		rvd = call_unlha32d_log(NULL, arcfile, outdir, szOutputBuf, ARCDLL_OUTBUFSIZE);
		if (rvd == T_TF_SUCCESS) {
            rv = true;
			break;
		}
		else if (rvd == T_TF_DLLNOTFOUND) {
			MessageBox(NULL, UNLHA32DLL"が見つかりません。", UNLHA32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALDLL) {
			MessageBox(NULL, UNLHA32DLL"が正しくありません。", UNLHA32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALCALL) {
			MessageBox(NULL, "不正な呼び出しです。", UNLHA32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else {
			if ( call_unlha32_getrunning() ) {
				Sleep(500);
			}
			else {
				ShowOutputDlg( NULL, "展開に失敗したか、中断しました。", UNLHA32DLL, szOutputBuf, MB_ICONSTOP );
				RemoveDirectory( outdir );
				rv = false;
				break;
			}
		}
	}

	if ( rv ) {
		if( reg.OpenKey(HKEY_CURRENT_USER, RNSF7REGKEY) ) {
			if ( 1 == reg.ReadInteger( "LzhZipOpenFolder" ) ) {
				SHE(NULL, ShellExecute(NULL, "explore", outdir, NULL, NULL, SW_SHOW));
			}
			reg.CloseKey();
		}
	}
	if (outdirsize != 0) free(outdir);
	return rv;
}

// zipファイルの展開
bool ExpandZip( const char *arcfile, const char *folder )
{
	REG reg;
	size_t outdirsize;
	char *outdir;
	bool rv = false;
	int  rvd;
	char szOutputBuf[ARCDLL_OUTBUFSIZE+1];

	if (folder) {
		outdirsize = lstrlen(arcfile) + lstrlen(folder) + 1;
		outdir = zalloc(outdirsize);
		if (outdir == NULL) return rv;
		makeefolder(folder, arcfile, outdir, outdirsize);
		CreateDir( outdir );
	}
	else {
		outdirsize = 0;
		outdir = ".";
	}

	while(1) { // unzip32.dllが使用中だった場合の対策：0.5秒スリープしてretry
		rvd = call_unzip32d_log(NULL, arcfile, outdir, szOutputBuf, ARCDLL_OUTBUFSIZE);
		if (rvd == T_TF_SUCCESS) {
            rv = true;
			break;
		}
		else if (rvd == T_TF_DLLNOTFOUND) {
			MessageBox(NULL, UNZIP32DLL"が見つかりません。", UNZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALDLL) {
			MessageBox(NULL, UNZIP32DLL"が正しくありません。", UNZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALCALL) {
			MessageBox(NULL, "不正な呼び出しです。", UNZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else {
			if ( call_unzip32_getrunning() ) {
				Sleep(500);
			}
			else {
				char *szOutputBuf2 = replacestr(szOutputBuf, "\n", "\r\n");
				ShowOutputDlg( NULL, "展開に失敗したか、中断しました。", UNZIP32DLL, szOutputBuf2, MB_ICONSTOP );
				safefree(szOutputBuf2);
				RemoveDirectory( outdir );
				rv = false;
				break;
			}
		}
	}

	if ( rv ) {
		if( reg.OpenKey(HKEY_CURRENT_USER, RNSF7REGKEY) ) {
			if ( 1 == reg.ReadInteger( "LzhZipOpenFolder" ) ) {
				SHE(NULL, ShellExecute(NULL, "explore", outdir, NULL, NULL, SW_SHOW));
			}
			reg.CloseKey();
		}
	}
	if (outdirsize != 0) safefree(outdir);
	return rv;
}

// 7Zipファイルの展開
bool Expand7Zip( const char *arcfile, const char *folder )
{
	REG reg;
	size_t outdirsize;
	char *outdir;
	bool rv = false;
	int  rvd;
	char szOutputBuf[ARCDLL_OUTBUFSIZE+1];

	if (folder) {
		outdirsize = lstrlen(arcfile) + lstrlen(folder) + 1;
		outdir = zalloc(outdirsize);
		if (outdir == NULL) return rv;
		makeefolder(folder, arcfile, outdir, outdirsize);
		CreateDir( outdir );
	}
	else {
		outdirsize = 0;
		outdir = ".";
	}

	while(1) { // 7zip32.dllが使用中だった場合の対策：0.5秒スリープしてretry
		rvd = call_7zip32d_log(NULL, arcfile, outdir, szOutputBuf, ARCDLL_OUTBUFSIZE);
		if (rvd == T_TF_SUCCESS) {
            rv = true;
			break;
		}
		else if (rvd == T_TF_DLLNOTFOUND) {
			MessageBox(NULL, SEVENZIP32DLL"が見つかりません。", SEVENZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALDLL) {
			MessageBox(NULL, SEVENZIP32DLL"が正しくありません。", SEVENZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else if (rvd == T_TF_ILLEGALCALL) {
			MessageBox(NULL, "不正な呼び出しです。", SEVENZIP32DLL, MB_OK | MB_ICONSTOP);
			RemoveDirectory( outdir );
			rv = false;
			break;
		}
		else {
			if ( call_7zip32_getrunning() ) {
				Sleep(500);
			}
			else {
				ShowOutputDlg( NULL, "展開に失敗したか、中断しました。", SEVENZIP32DLL, szOutputBuf, MB_ICONSTOP );
				RemoveDirectory( outdir );
				rv = false;
				break;
			}
		}
	}

	if ( rv ) {
		if( reg.OpenKey(HKEY_CURRENT_USER, RNSF7REGKEY) ) {
			if ( 1 == reg.ReadInteger( "LzhZipOpenFolder" ) ) {
				SHE(NULL, ShellExecute(NULL, "explore", outdir, NULL, NULL, SW_SHOW));
			}
			reg.CloseKey();
		}
	}
	if (outdirsize != 0) free(outdir);
	return rv;
}

// あらかじめ指定されたフォルダに、arcfile(.lzh) を展開する
bool OpenExtractor( const char *arcfile, int oetype )
{
	REG reg;
	char *folder = NULL;
	bool rv;

	if( reg.OpenKey(HKEY_CURRENT_USER, RNSF7REGKEY) ) {
		folder = reg.new_ReadString( "LzhZipFolder", NULL );
		reg.CloseKey();
	}

	if ( folder && folder[0] ) {
        rv = (ExpandFunctions[oetype])( arcfile, folder );
        safedelete(folder);
		return rv;
	}
	else { // レジストリからフォルダを読めなかったら、フォルダを選択させる
		safedelete(folder);
		return OpenExtractorDir( arcfile, oetype );
	}
}

// 展開先フォルダを指定し、arcfile(.lzh) を展開する
bool OpenExtractorDir( const char *arcfile, int oetype )
{
	BOOL			bRes;
	LPITEMIDLIST	pidlRetFolder;
	BROWSEINFO		stBInfo;
	char			dir[MAX_PATH*2]="", *title, fname[_MAX_FNAME*2], fext[_MAX_EXT*2];

	// タイトルバー文字列の生成
	title = zalloc(_MAX_FNAME*2 + _MAX_EXT*2 + 30);
	_splitpath_s(arcfile, NULL, 0, NULL, 0, fname, _countof(fname), fext, _countof(fext));
	wsprintf(title, "%s%sの解凍先フォルダを選択", fname, fext);

	//　構造体を初期化します。
	stBInfo.pidlRoot = NULL;	//ルートフォルダです。
	stBInfo.hwndOwner = NULL;	//表示するダイアログの親ウィンドウのハンドルです。
	stBInfo.pszDisplayName = dir;	//選択されているフォルダ名を受けます。
	stBInfo.lpszTitle = title;	//説明の文字列です。
	stBInfo.ulFlags = BIF_RETURNONLYFSDIRS;	//表示フラグです。
	stBInfo.lpfn = NULL;	//ダイアログプロシージャへのポインタです。
	stBInfo.lParam = 0L;	//プロシージャに送るパラメーターです。

	//　ダイアログボックスを表示します。
	pidlRetFolder = ::SHBrowseForFolder( &stBInfo );
	safefree(title);

	if( pidlRetFolder != NULL ) {
		//　フルパスを取得します。
		bRes = ::SHGetPathFromIDList( pidlRetFolder, dir );
		if( bRes != FALSE ) {
			return (ExpandFunctions[oetype])( arcfile, dir );
		}
		::CoTaskMemFree( pidlRetFolder );
	}
	return false;
}

// デスクトップに arcfile(.lzh) を展開する
bool OpenExtractorDesktop( const char *arcfile, int oetype )
{
	return (ExpandFunctions[oetype])( arcfile, GetDesktopFolder() );
}

// カレントディレクトリ[ファイルと同じフォルダ]に arcfile(.lzh) を展開する
bool OpenExtractorCD( const char *arcfile, int oetype )
{
	char drv[_MAX_DRIVE*2], dir[_MAX_DIR*2], path[MAX_PATH*2];

	_splitpath_s(arcfile, drv, _countof(drv), dir, _countof(dir), NULL, 0, NULL, 0);
	_makepath_s(path, _countof(path), drv, dir, NULL, NULL);

	return (ExpandFunctions[oetype])( arcfile, path );
}

// カレントディレクトリ[exeと同じフォルダ]に arcfile(.lzh) を展開する
bool OpenExtractorOwnDir( const char *arcfile, int oetype )
{
	return (ExpandFunctions[oetype])( arcfile, NULL );
}

static volatile bool abort_flag = 1;
typedef struct {
	char *file1;
	char *file2;
	HWND hStaticCompare;
	HWND hProgressBar;
	DWORD fsize;
} CFS, *PCFS;
#define COMPARE_BUFSIZE (1024*1024)

// ファイルを比較（戻り値は結果を示す文字列）[ _beginthread() から呼ばれる ]
static void comparefiles(void *_cfs)
{
	char   *buf1 , *buf2;
	HANDLE hFile1, hFile2;
	DWORD  read1, read2, read_size;
	char   *rv = "不明";
	PCFS pcfs = (PCFS)_cfs;

	buf1 = (char *)malloc( COMPARE_BUFSIZE );
	if( buf1 == NULL ) {
		SetWindowText(pcfs->hStaticCompare, "メモリ不足で比較できませんでした。");
	}

	buf2 = (char *)malloc( COMPARE_BUFSIZE );
	if ( buf2 == NULL ) {
		safefree( buf1 );
		SetWindowText(pcfs->hStaticCompare, "メモリ不足で比較できませんでした。");
	}

	hFile1 = CreateFile(pcfs->file1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if ( hFile1 == INVALID_HANDLE_VALUE ) {
		safefree( buf1 );
		safefree( buf2 );
		SetWindowText(pcfs->hStaticCompare, "第1ファイルを開けませんでした。");
	}

	hFile2 = CreateFile(pcfs->file2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if ( hFile2 == INVALID_HANDLE_VALUE ) {
		safefree( buf1 );
		safefree( buf2 );
		CloseHandle( hFile1 );
		SetWindowText(pcfs->hStaticCompare, "第2ファイルを開けませんでした。");
	}

	read_size = 0;
	SendMessage(pcfs->hProgressBar, PBM_SETRANGE32, 0, (LPARAM)pcfs->fsize);
	while(1) {
		read1 = read2 = 0;
		ReadFile(hFile1, buf1, (DWORD)COMPARE_BUFSIZE, &read1, NULL);
		ReadFile(hFile2, buf2, (DWORD)COMPARE_BUFSIZE, &read2, NULL);

		read_size += read1;
		SendMessage(pcfs->hProgressBar, PBM_SETPOS, (WPARAM)read_size, 0);
		w7tbProgress(GetAncestor(pcfs->hProgressBar, GA_ROOTOWNER), 2 /*TBPF_NORMAL*/, read_size, pcfs->fsize); // Win7のタスクバープログレス

		if ( abort_flag == 1 ) {
			rv = "中断されました。";
			w7tbProgress(GetAncestor(pcfs->hProgressBar, GA_ROOTOWNER), 8 /*TBPF_PAUSED*/, 1, 1); // Win7のタスクバープログレス
			break;
		}

		if ( read1 != read2 ) {
			rv = "内容に違いがあるか、読み出しエラーです。";
			w7tbProgress(GetAncestor(pcfs->hProgressBar, GA_ROOTOWNER), 4 /*TBPF_ERROR*/, 1, 1); // Win7のタスクバープログレス
			break;
		}
		else {
			if (read1 == 0 || 0 == memcmp(buf1, buf2, read1)) {
                if ( COMPARE_BUFSIZE != read1 ) {
                    rv = "ファイルの内容は一致しています。";
					w7tbProgress(GetAncestor(pcfs->hProgressBar, GA_ROOTOWNER), 2 /*TBPF_NORMAL*/, 1, 1); // Win7のタスクバープログレス
					break;
				}
			}
			else {
				rv = "ファイル内容に違いが見つかりました。";
				w7tbProgress(GetAncestor(pcfs->hProgressBar, GA_ROOTOWNER), 2 /*TBPF_NORMAL*/, 1, 1); // Win7のタスクバープログレス
				break;
			}
		}
	}

	SendMessage(pcfs->hProgressBar, PBM_SETPOS, (WPARAM)pcfs->fsize, 0);
	w7tbProgress(NULL, 0, 0, 0); // Win7のタスクバープログレス解放

	safefree( buf1 );
	safefree( buf2 );
	CloseHandle( hFile1 );
	CloseHandle( hFile2 );

	abort_flag = 1;
	SetWindowText(pcfs->hStaticCompare, rv);
	_endthread();
}

static char *fname1, fname2[MAX_PATH*2];

// ウィンドウ用ダイアログプロシージャ
static LRESULT CALLBACK DlgProc_compare( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			{
				OPENFILENAME ofn;
				WIN32_FIND_DATA520 wfd1, wfd2;
				HANDLE			hf1, hf2;
				char *title, fname[_MAX_FNAME*2], fext[_MAX_EXT*2];
				char *result;

				// 比較対象のファイルを選択
				// 選択ダイアログのタイトルバー文字列の生成
				title = zalloc(_MAX_FNAME*2 + _MAX_EXT*2 + 30);
				_splitpath_s(fname1, NULL, 0, NULL, 0, fname, _countof(fname), fext, _countof(fext));
				wsprintf(title, "%s%sと比較するファイルを選択", fname, fext);

				fname2[0] = 0;

				ofn.lStructSize = sizeof(OPENFILENAME);
				ofn.hwndOwner = NULL;
				ofn.lpstrFilter = "すべてのファイル(*.*)\0*.*\0\0";
				ofn.nFilterIndex = 1;
				ofn.lpstrCustomFilter = (LPSTR) NULL;
				ofn.nMaxCustFilter = 0L;
				ofn.lpstrFile = fname2;
				ofn.nMaxFile = _countof(fname2);
				ofn.lpstrFileTitle = NULL;
				ofn.nMaxFileTitle = 0;
				ofn.lpstrInitialDir = NULL;
				ofn.lpstrTitle = title;
				ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
				ofn.nFileOffset = 0;
				ofn.nFileExtension = 0;
				ofn.lpstrDefExt = NULL; 

				if ( !GetOpenFileName(&ofn) ) {
					safefree(title);
					EndDialog(hDlg, FALSE);
					return TRUE;
				}
				safefree(title);

				// ファイル日時の比較 (FindFirstFileとCompareFileTimeで)
				hf1 = FindFirstFile520(fname1, &wfd1);
				if ( hf1 == INVALID_HANDLE_VALUE  ) {
					char *s = zalloc(lstrlen(fname1) + 20);

					if ( s ) {
						wsprintf(s, "%sが見つかりません。", fname1);
						MessageBox(NULL, s, "簡易比較", MB_OK);
						safefree(s);
					}
					EndDialog(hDlg, FALSE);
					return TRUE;
				}
				FindClose( hf1 );

				hf2 = FindFirstFile520(fname2, &wfd2);
				if ( hf2 == INVALID_HANDLE_VALUE  ) {
					char *s = zalloc(lstrlen(fname2) + 20);

					if ( s ) {
						wsprintf(s, "%sが見つかりません。", fname2);
						MessageBox(NULL, s, "簡易比較", MB_OK);
						safefree(s);
					}
					EndDialog(hDlg, FALSE);
					return TRUE;
				}
				FindClose( hf2 );

				result = NULL;

				result = _strdup( fname1 );
				result = realloc_strcat( result, "(第1ファイル)と" );
				result = realloc_strcat( result, fname2 );
				result = realloc_strcat( result, "(第2ファイル)の比較結果です。\n\n作成日時：" );

				switch (CompareFileTime(&wfd1.ftCreationTime, &wfd2.ftCreationTime)) {
					case -1:result = realloc_strcat( result, "第2ファイルの方が新しい" ); break;
					case  0:result = realloc_strcat( result, "同じ" ); break;
					case  1:result = realloc_strcat( result, "第1ファイルの方が新しい" ); break;
				}

				result = realloc_strcat( result, "\n\n更新日時：" );

				switch (CompareFileTime(&wfd1.ftLastWriteTime, &wfd2.ftLastWriteTime)) {
					case -1:result = realloc_strcat( result, "第2ファイルの方が新しい" ); break;
					case  0:result = realloc_strcat( result, "同じ" ); break;
					case  1:result = realloc_strcat( result, "第1ファイルの方が新しい" ); break;
				}

				result = realloc_strcat( result, "\n\n大きさ：" );

				if ( wfd1.nFileSizeHigh > wfd2.nFileSizeHigh ) {
					result = realloc_strcat( result, "第1ファイルの方が大きい" );
				}
				else if ( wfd1.nFileSizeHigh < wfd2.nFileSizeHigh ) {
					result = realloc_strcat( result, "第2ファイルの方が大きい" );
				}
				else { // wfd1.nFileSizeHigh == wfd2.nFileSizeHigh
					if ( wfd1.nFileSizeLow > wfd2.nFileSizeLow ) {
						result = realloc_strcat( result, "第1ファイルの方が大きい" );
						SetDlgItemText(hDlg, IDC_STATIC_COMPARE, "");
					}
					else if ( wfd1.nFileSizeLow < wfd2.nFileSizeLow ) {
						result = realloc_strcat( result, "第2ファイルの方が大きい" );
						SetDlgItemText(hDlg, IDC_STATIC_COMPARE, "");
					}
					else if ( wfd1.nFileSizeLow == wfd2.nFileSizeLow ){
						static CFS cfs; // 他スレッドで使うため、このブロックを抜けても有効である必要がある
						cfs.file1 = fname1;
						cfs.file2 = fname2;
						cfs.fsize = wfd1.nFileSizeLow;
						cfs.hProgressBar = GetDlgItem(hDlg, IDC_PROGRESS1);

						result = realloc_strcat( result, "同じ" );
						cfs.hStaticCompare = GetDlgItem(hDlg, IDC_STATIC_COMPARE);
						
						abort_flag = 0;
						// コンペア用にスレッドを生成
						if( -1 == _beginthread( comparefiles, 0, (void *)&cfs ) ) {
							SetDlgItemText(hDlg, IDC_STATIC_COMPARE, "コンペアの開始に失敗しました。");
						}
					}
				}

				SetDlgItemText( hDlg, IDC_STATIC_RESULT, result );
				safefree(result);
			}
			return TRUE;

		case WM_COMMAND:
			switch( LOWORD(wParam) ) {
				case IDCANCEL:
					if ( abort_flag == 1 ) {
						EndDialog(hDlg, 0);
					}
					else {
						abort_flag = 1;
					}
					return TRUE;
			}
	}
    return FALSE;
}

// ファイル同士を比較する
bool CompareFiles( char *_fname1 )
{
	fname1 = _fname1;
	return DialogBox(hInst, (LPCTSTR)IDD_DIALOG_COMPARE, NULL, (DLGPROC)DlgProc_compare) != 0 ? true : false;
}

// 簡易圧縮アイコンをデスクトップ上に作成する
bool makeCompressIcon( void )
{
	char DesktopLink[MAX_PATH*2], exename[MAX_PATH*2];

	GetModuleFileName(NULL, exename, _countof(exename));
	lstrcpy(DesktopLink, GetDesktopFolder());
#ifdef _WIN64
	lstrcat(DesktopLink, "\\-圧縮- [x64].lnk");
#else
	lstrcat(DesktopLink, "\\-圧縮-.lnk");
#endif

	return MakeLinkIcon(exename, "/CA", DesktopLink, exename, -133) ? true : false;

	// -133 … 本プログラムが準備している、圧縮を表すアイコン。負の数は、リソース番号指定であることを表す。
}

// Context.exeへショートカットをデスクトップ上に作成する
bool makeShortcutIcon( const char *szShortcutName, const char *szParam, int iIconNum )
{
	char DesktopLink[MAX_PATH*2], exename[MAX_PATH*2];
	char szMes[MAX_PATH*2];

	wsprintf(szMes, "%sアイコンをデスクトップ上に作成しますか?", szShortcutName);
	if (IDNO == MessageBox( NULL, szMes, szTitle, MB_YESNO | MB_ICONQUESTION )) {
		return false;
	}

	GetModuleFileName(NULL, exename, _countof(exename));
	lstrcpy(DesktopLink, GetDesktopFolder());
	lstrcat(DesktopLink, "\\");
	lstrcat(DesktopLink, szShortcutName);
	lstrcat(DesktopLink, ".lnk");

	CoInitialize( NULL );
	BOOL rv = MakeLinkIcon(exename, szParam, DesktopLink, exename, iIconNum);
	CoUninitialize();
	if (rv) {
		wsprintf(szMes, "%sアイコンを作成しました。", szShortcutName);
		MessageBox( NULL, szMes, szTitle, MB_OK | MB_ICONINFORMATION );
		return true;
	}
	else {
		wsprintf(szMes, "%sアイコンの作成に失敗しました。", szShortcutName);
		MessageBox( NULL, "圧縮アイコンの作成に失敗しました。", szTitle, MB_OK | MB_ICONSTOP );
		return false;
	}
}
