// toolfunc.cpp : 汎用ツールライブラリ
/*

　Copyright(C) 2002-2014 INASOFT 矢吹拓也/Ayacy

　これは、TOOLFUNC.LIB を生成するためのソースプログラムです。
　Windows、一般のDLL、いくつかの問題解決を一般的に扱うためのユーティリティ系の
　関数が含まれています。

*/

#include "stdafx.h"

#define OWN__TOOLFUNC__

#include "toolfunc.h"

// ダイアログ枠のウィンドウに対しサイズ変更枠を「追加」し、
// リサイズできるようにメニューの追加も行う。
LibExport BOOL addResizableBorderA(HWND hWnd, const char    *name_resizeitem)
{
	if (hWnd && IsWindow(hWnd)) {
		// サイズ変更枠を追加
		LONG_PTR lpStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
		if (0 != SetWindowLongPtr(hWnd, GWL_STYLE, lpStyle | WS_THICKFRAME)) {
			// リサイズできるようにメニューを追加
			HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
			if (hSysMenu) {
				if (AppendMenuA(hSysMenu, MF_STRING, SC_SIZE, name_resizeitem)) {
					return TRUE;
				}
			}
		}
	}
	
	return FALSE;
}

LibExport BOOL addResizableBorderW(HWND hWnd, const wchar_t *name_resizeitem)
{
	if (hWnd && IsWindow(hWnd)) {
		// サイズ変更枠を追加
		LONG_PTR lpStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
		if (0 != SetWindowLongPtr(hWnd, GWL_STYLE, lpStyle | WS_THICKFRAME)) {
			// リサイズできるようにメニューを追加
			HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
			if (hSysMenu) {
				if (AppendMenuW(hSysMenu, MF_STRING, SC_SIZE, name_resizeitem)) {
					return TRUE;
				}
			}
		}
	}
	
	return FALSE;
}

// toolfunc.libのバージョン番号を返す
// 整数部×10000＋小数部×100＋内部リリースNo.
LibExport DWORD toolfunclib_GetVersion( VOID )
{
	return TOOLFUNC_H_VERSIONNUMBER;
}

// リージョンをコピーしつつ設定
int SetWindowRgn2(HWND hWnd, HRGN hRgn, BOOL bRedraw)
{
	if ( hRgn == NULL ) {
		// リージョンをNULLに設定
		return SetWindowRgn( hWnd, NULL, bRedraw );
	}
	else {
		HRGN hRgn2 = CreateRectRgn( 0, 0, 0, 0 ); 
		CombineRgn(hRgn2, hRgn, 0, RGN_COPY);
		int iRet = SetWindowRgn( hWnd, hRgn2, bRedraw );

		if ( iRet == 0 ) {
			// リージョンの設定に失敗
			DeleteObject(hRgn2);
		}
		return iRet;
	}
}

// fnameの中にスペースがあったら、ダブルコーテーションを付けて返す
// fnameはリテラルではダメ
LibExport char *insert_dcA(char *fname)
{
	int  i, n;
	char *fn;
	
	if ( fname ) {
		if ( fname[0] == '"' ) {
			return fname;
		}
		else {
			n = lstrlen(fname);

			for(i=0 ; i<n ; i++) {
				if (fname[i] == ' ') {
					fn = zalloc(n+1);
					lstrcpy(fn,fname);
					wsprintf(fname,"\"%s\"",fn);
					safefree(fn);
					break;
				}
			}

			return fname;
		}
	}
	return NULL;
}

LibExport wchar_t *insert_dcW(wchar_t *fname)
{
	int  i, n;
	wchar_t *fn;
	
	if ( fname ) {
		if ( fname[0] == L'"' ) {
			return fname;
		}
		else {
			n = lstrlenW(fname);

			for(i=0 ; i<n ; i++) {
				if (fname[i] == ' ') {
					fn = walloc(n+1);
					lstrcpyW(fn, fname);
					wsprintfW(fname, L"\"%s\"", fn);
					safefree(fn);
					break;
				}
			}

			return fname;
		}
	}
	return NULL;
}

// std::stringバージョン
// ダブルコーテーションを加えたら true を返す
bool insert_dcA(string &fname)
{
	if ( !fname.empty() ) {
		// 空文字列でなく
		if ( fname[0] != '"' ) {
			// すでにダブルコーテーションで囲まれているわけでもなく
			if ( fname.find(' ') != string::npos ) {
				// スペースが含まれているならば
				// ダブルコーテーションで囲む
				fname.insert(0, "\"");
				fname.append("\"");
				return true;
			}
		}
	}

	return false;
}

bool insert_dcW(wstring &fname)
{
	if ( !fname.empty() ) {
		// 空文字列でなく
		if ( fname[0] != L'"' ) {
			// すでにダブルコーテーションで囲まれているわけでもなく
			if ( fname.find(L' ') != wstring::npos ) {
				// スペースが含まれているならば
				// ダブルコーテーションで囲む
				fname.insert(0, L"\"");
				fname.append(L"\"");
				return true;
			}
		}
	}

	return false;
}

// fnameの中がダブルコーテーションで始まっていたら、両端がダブルコーテーションで囲まれていると
// みなして取り除く（引数がconstではありません。引数で与えられたメモリを直接いじります）
LibExport char *delete_dcA(char *fname)
{
	if ( fname != NULL && fname[0] == '"' ) {
		int n = lstrlen(fname) - 2;
		int i;

		for(i=0 ; i<n ; ++i) {
			fname[i] = fname[i+1];
		}

		fname[i] = 0;
	}
	return fname;
}

LibExport wchar_t *delete_dcW(wchar_t *fname)
{
	if ( fname != NULL && fname[0] == L'"' ) {
		int n = lstrlenW(fname) - 2;
		int i;

		for(i=0 ; i<n ; ++i) {
			fname[i] = fname[i+1];
		}

		fname[i] = 0;
	}
	return fname;
}

// std::stringバージョン
// ダブルコーテーションを取り除いたら true を返す
bool delete_dcA(string &fname)
{
	if ( !fname.empty() ) {
		// 空文字列でなく
		if ( fname[0] == '"' ) {
			// すでにダブルコーテーションで囲まれていたら
			fname.erase(0, 1);
			fname.erase(fname.end()-1);
			return true;
		}
	}

	return false;
}

bool delete_dcW(wstring &fname)
{
	if ( !fname.empty() ) {
		// 空文字列でなく
		if ( fname[0] == L'"' ) {
			// すでにダブルコーテーションで囲まれていたら
			fname.erase(0, 1);
			fname.erase(fname.end()-1);
			return true;
		}
	}

	return false;
}

// 260〜519バイトになるようなファイル名を扱う場合のANSI版FindFirstFile
LibExport HANDLE FindFirstFile520A(LPCSTR lpFileName, LPWIN32_FIND_DATA520 lpFindFileData)
{
	HANDLE hResult;

	if (lpFileName == NULL || lpFindFileData == NULL) { // 入力エラー
		return INVALID_HANDLE_VALUE;
	}

	ZeroMemory(lpFindFileData, sizeof(LPWIN32_FIND_DATA520));
	if (tf_isNT()) {
		WIN32_FIND_DATAW ffd;

		ZeroMemory(&ffd, sizeof(ffd));

		wchar_t *strFileName = mb2wc(lpFileName);
		hResult = FindFirstFileW(strFileName, &ffd);
		free(strFileName);
		if (hResult != INVALID_HANDLE_VALUE) {
			lpFindFileData->dwFileAttributes = ffd.dwFileAttributes;
    		lpFindFileData->ftCreationTime = ffd.ftCreationTime;
    		lpFindFileData->ftLastAccessTime = ffd.ftLastAccessTime;
    		lpFindFileData->ftLastWriteTime = ffd.ftLastWriteTime;
    		lpFindFileData->nFileSizeHigh = ffd.nFileSizeHigh;
    		lpFindFileData->nFileSizeLow = ffd.nFileSizeLow;
    		lpFindFileData->dwReserved0 = ffd.dwReserved0;
    		lpFindFileData->dwReserved1 = ffd.dwReserved1;
			WideCharToMultiByte(GetACP(), 0, ffd.cFileName, -1,
				                lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName), NULL, NULL);
			WideCharToMultiByte(GetACP(), 0, ffd.cAlternateFileName, -1,
				                lpFindFileData->cAlternateFileName, sizeof(lpFindFileData->cAlternateFileName), NULL, NULL);
			
#ifdef _MAC
    		lpFindFileData->dwFileType = ffd.dwFileType;
    		lpFindFileData->dwCreatorType = ffd.dwCreatorType;
    		lpFindFileData->wFinderFlags = ffd.wFinderFlags;
#endif
		}
	}
	else {
		WIN32_FIND_DATAA ffd;

		ZeroMemory(&ffd, sizeof(ffd));

		hResult = FindFirstFileA(lpFileName, &ffd);
		if (hResult != INVALID_HANDLE_VALUE) {
			lpFindFileData->dwFileAttributes = ffd.dwFileAttributes;
    		lpFindFileData->ftCreationTime = ffd.ftCreationTime;
    		lpFindFileData->ftLastAccessTime = ffd.ftLastAccessTime;
    		lpFindFileData->ftLastWriteTime = ffd.ftLastWriteTime;
    		lpFindFileData->nFileSizeHigh = ffd.nFileSizeHigh;
    		lpFindFileData->nFileSizeLow = ffd.nFileSizeLow;
    		lpFindFileData->dwReserved0 = ffd.dwReserved0;
    		lpFindFileData->dwReserved1 = ffd.dwReserved1;
    		memcpy(lpFindFileData->cFileName, ffd.cFileName, sizeof(ffd.cFileName));
    		memcpy(lpFindFileData->cAlternateFileName, ffd.cAlternateFileName, sizeof(ffd.cAlternateFileName));
#ifdef _MAC
    		lpFindFileData->dwFileType = ffd.dwFileType;
    		lpFindFileData->dwCreatorType = ffd.dwCreatorType;
    		lpFindFileData->wFinderFlags = ffd.wFinderFlags;
#endif
		}
	}

	return hResult;
}

// 260〜519バイトになるようなファイル名を扱う場合のANSI版FindNextFile
LibExport BOOL   FindNextFile520A(HANDLE hFindFile, LPWIN32_FIND_DATA520 lpFindFileData)
{
	BOOL bResult;

	if (hFindFile == INVALID_HANDLE_VALUE || lpFindFileData == NULL) { // 入力エラー
		return FALSE;
	}


	ZeroMemory(lpFindFileData, sizeof(LPWIN32_FIND_DATA520));
	if (tf_isNT()) {
		WIN32_FIND_DATAW ffd;

		ZeroMemory(&ffd, sizeof(ffd));

		bResult = FindNextFileW(hFindFile, &ffd);
		if (bResult != FALSE) {
			lpFindFileData->dwFileAttributes = ffd.dwFileAttributes;
    		lpFindFileData->ftCreationTime = ffd.ftCreationTime;
    		lpFindFileData->ftLastAccessTime = ffd.ftLastAccessTime;
    		lpFindFileData->ftLastWriteTime = ffd.ftLastWriteTime;
    		lpFindFileData->nFileSizeHigh = ffd.nFileSizeHigh;
    		lpFindFileData->nFileSizeLow = ffd.nFileSizeLow;
    		lpFindFileData->dwReserved0 = ffd.dwReserved0;
    		lpFindFileData->dwReserved1 = ffd.dwReserved1;
			WideCharToMultiByte(GetACP(), 0, ffd.cFileName, -1,
				                lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName), NULL, NULL);
			WideCharToMultiByte(GetACP(), 0, ffd.cAlternateFileName, -1,
				                lpFindFileData->cAlternateFileName, sizeof(lpFindFileData->cAlternateFileName), NULL, NULL);
			
#ifdef _MAC
    		lpFindFileData->dwFileType = ffd.dwFileType;
    		lpFindFileData->dwCreatorType = ffd.dwCreatorType;
    		lpFindFileData->wFinderFlags = ffd.wFinderFlags;
#endif
		}
	}
	else {
		WIN32_FIND_DATAA ffd;

		ZeroMemory(&ffd, sizeof(ffd));

		bResult = FindNextFileA(hFindFile, &ffd);
		if (bResult != FALSE) {
			lpFindFileData->dwFileAttributes = ffd.dwFileAttributes;
    		lpFindFileData->ftCreationTime = ffd.ftCreationTime;
    		lpFindFileData->ftLastAccessTime = ffd.ftLastAccessTime;
    		lpFindFileData->ftLastWriteTime = ffd.ftLastWriteTime;
    		lpFindFileData->nFileSizeHigh = ffd.nFileSizeHigh;
    		lpFindFileData->nFileSizeLow = ffd.nFileSizeLow;
    		lpFindFileData->dwReserved0 = ffd.dwReserved0;
    		lpFindFileData->dwReserved1 = ffd.dwReserved1;
    		memcpy(lpFindFileData->cFileName, ffd.cFileName, sizeof(ffd.cFileName));
    		memcpy(lpFindFileData->cAlternateFileName, ffd.cAlternateFileName, sizeof(ffd.cAlternateFileName));
#ifdef _MAC
    		lpFindFileData->dwFileType = ffd.dwFileType;
    		lpFindFileData->dwCreatorType = ffd.dwCreatorType;
    		lpFindFileData->wFinderFlags = ffd.wFinderFlags;
#endif
		}
	}

	return bResult;
}

// ファイルが存在するかどうか
LibExport BOOL tFileExistA(const char *fname)
{
	if ( fname ) {
		WIN32_FIND_DATA520 ffd;
		HANDLE hf;
		UINT uOldErrMode;
			
		uOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
		hf = FindFirstFile520(fname, &ffd);
		SetErrorMode( uOldErrMode );

		if (hf != INVALID_HANDLE_VALUE) {
			FindClose( hf );
			return TRUE; // ファイルが存在した
		}
		else {
			return FALSE; // ファイルが存在しなかった
		}
	}
	return FALSE; // エラー
}

LibExport BOOL tFileExistW(const wchar_t *fname)
{
	if ( fname ) {
		WIN32_FIND_DATAW ffd;
		HANDLE hf;
		UINT uOldErrMode;

		uOldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
		hf = FindFirstFileW(fname, &ffd);
		SetErrorMode( uOldErrMode );

		if (hf != INVALID_HANDLE_VALUE) {
			FindClose( hf );
			return TRUE; // ファイルが存在した
		}
		else {
			return FALSE; // ファイルが存在しなかった
		}
	}
	return FALSE; // エラー
}

// デバッグ用のメッセージ出力
LibExport void DebugMesA(const char *mes)
{
	if ( mes ) {
		MessageBox(NULL, mes, "DebugMes()", MB_OK | MB_TOPMOST);
	}
}

LibExport void DebugMesW(const wchar_t *mes)
{
	if ( mes ) {
		MessageBoxW(NULL, mes, L"DebugMes()", MB_OK | MB_TOPMOST);
	}
}

// Windows NT 終了権限の取得
LibExport void GetQuitRight(void)
{
	HANDLE          hToken;
	TOKEN_PRIVILEGES    tkp;
#ifndef _WIN64
	OSVERSIONINFO	verinfo;

	verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&verinfo);
	if ( verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
#endif /* _WIN64 */
	{
		if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
			if (LookupPrivilegeValue((LPSTR)NULL, SE_SHUTDOWN_NAME, &(tkp.Privileges[0].Luid))) {
				tkp.PrivilegeCount = 1;
				tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
				AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL);
			}
		}
	}
}

// 数値を10進数の文字列に直す (返すのは関数内部のstaticなバッファへのポインタであることに注意)
LibExport char *itoa10A(UINT n)
{
	static char buf[11];

	if ( 0 == _ultoa_s((unsigned long)n, buf, UBOUND(buf), 10) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

LibExport wchar_t *itoa10W(UINT n)
{
	static wchar_t buf[11];

	if ( 0 == _ultow_s((unsigned long)n, buf, UBOUND(buf), 10) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

// 上の符号付きバージョン (返すのは関数内部のstaticなバッファへのポインタであることに注意)
LibExport char *s_itoa10A(int n)
{
	static char buf[12];

	if ( 0 == _itoa_s(n, buf, UBOUND(buf), 10) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

LibExport wchar_t *s_itoa10W(int n)
{
	static wchar_t buf[12];

	if ( 0 == _itow_s(n, buf, UBOUND(buf), 10) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

// 数値を16進数の文字列に直す (返すのは関数内部のstaticなバッファへのポインタであることに注意)
LibExport char *itoa16A(int n)
{
	static char buf[16];

	if ( 0 == _ultoa_s((unsigned long)n, buf, UBOUND(buf), 16) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

LibExport wchar_t *itoa16W(int n)
{
	static wchar_t buf[16];

	if ( 0 == _ultow_s((unsigned long)n, buf, UBOUND(buf), 16) ) {
		return buf;
	}
	else {
		return NULL;
	}
}

// 「ファイル名,番号」からアイコンハンドルを得る
LibExport HICON LoadIconFromFileA(HINSTANCE hInst, const char *fname_num)
{
	int    i = 0, num = 0;
	char  *fnameonly = NULL;
	HICON  hicon = NULL;

	if (fname_num == NULL || fname_num[0] == 0) {
		fnameonly = _strdup("");
	}
	else {
		fnameonly = zalloc(lstrlen(fname_num)+1);
		do {
			if (fname_num[i] == ',') {
				fnameonly[i] = 0;
				num = atoi(&fname_num[i+1]);
				break;
			}
			fnameonly[i] = fname_num[i];
		} while(fname_num[i++]);
	}

	hicon = ExtractIcon(hInst, fnameonly, num);
#pragma warning( disable : 4311 )
	if ((int)hicon == 0 || (int)hicon == 1) 
#pragma warning( default : 4311 )
		hicon = NULL;

	safefree(fnameonly);
	return hicon;
}

LibExport HICON LoadIconFromFileW(HINSTANCE hInst, const wchar_t *fname_num)
{
	int      i = 0, num = 0;
	wchar_t  *fnameonly = NULL;
	HICON    hicon = NULL;

	if (fname_num == NULL || fname_num[0] == 0) {
		fnameonly = _wcsdup(L"");
	}
	else {
		fnameonly = walloc(lstrlenW(fname_num)+1);
		do {
			if (fname_num[i] == L',') {
				fnameonly[i] = 0;
				num = _wtoi(&fname_num[i+1]);
				break;
			}
			fnameonly[i] = fname_num[i];
		} while(fname_num[i++]);
	}

	hicon = ExtractIconW(hInst, fnameonly, num);
#pragma warning( disable : 4311 )
	if ((int)hicon == 0 || (int)hicon == 1) 
#pragma warning( default : 4311 )
		hicon = NULL;

	safefree(fnameonly);
	return hicon;
}

// 「ファイル名,番号」から、アイコンハンドルを得る。大きいサイズと小さいサイズの両方。
LibExport UINT LoadIconFromFileExA(const char *fname_num, HICON *phIcon, HICON *phSmallIcon)
{
	int    i = 0, num = 0;
	char  *fnameonly = NULL;
	UINT   uRet = 0;

	if (fname_num == NULL || fname_num[0] == 0) {
		fnameonly = _strdup("");
	}
	else {
		fnameonly = zalloc(lstrlen(fname_num)+1);
		do {
			if (fname_num[i] == ',') {
				fnameonly[i] = 0;
				num = atoi(&fname_num[i+1]);
				break;
			}
			fnameonly[i] = fname_num[i];
		} while(fname_num[i++]);
	}

	uRet = ExtractIconEx(fnameonly, num, phIcon, phSmallIcon, 1);

	safefree(fnameonly);
	return uRet;
}

LibExport UINT LoadIconFromFileExW(const wchar_t *fname_num, HICON *phIcon, HICON *phSmallIcon)
{
	int      i = 0, num = 0;
	wchar_t  *fnameonly = NULL;
	UINT     uRet = 0;

	if (fname_num == NULL || fname_num[0] == 0) {
		fnameonly = _wcsdup(L"");
	}
	else {
		fnameonly = walloc(lstrlenW(fname_num)+1);
		do {
			if (fname_num[i] == L',') {
				fnameonly[i] = 0;
				num = _wtoi(&fname_num[i+1]);
				break;
			}
			fnameonly[i] = fname_num[i];
		} while(fname_num[i++]);
	}

	uRet = ExtractIconExW(fnameonly, num, phIcon, phSmallIcon, 1);

	safefree(fnameonly);
	return uRet;
}

// リストビューのカーソル位置取得(複数のカーソルが置かれている場合は最初のもの)
/*LibExport int  GetLVCursor(HWND hListView)
{
	int i, n;

	if ( hListView ) {
		n = ListView_GetItemCount(hListView);

		for(i=0 ; i<n ; i++) {
			if (LVIS_SELECTED == ListView_GetItemState(hListView,i,LVIS_SELECTED)) {
				return i;
			}
		}
	}
	return -1;
}*/
// ↑現在ではヘッダファイルでマクロ展開されている

// realloc を使って strcat
LibExport char *realloc_strcatA( char *str1, const char *str2 )
{
	if ( str2  ) {
		if ( str1 == NULL ) {
			str1 = _strdup( str2 );
		}
		else {
			size_t str1size = (strlen(str1)+strlen(str2)+1);

			str1 = (char *)realloc( str1, sizeof(char)*str1size );
			if ( str1 ) {
				strcat_s( str1, str1size, str2 );
			}
		}
	}
	return str1;
}

LibExport wchar_t *realloc_strcatW( wchar_t *str1, const wchar_t *str2 )
{
	if ( str2  ) {
		if ( str1 == NULL ) {
			str1 = _wcsdup( str2 );
		}
		else {
			size_t str1size = (wcslen(str1)+wcslen(str2)+1);

			str1 = (wchar_t *)realloc( str1, sizeof(wchar_t)*str1size );
			if ( str1 ) {
				wcscat_s( str1, str1size, str2 );
			}
		}
	}
	return str1;
}

// 文字列strのn文字目は、Shift JIS漢字の第1バイト目か?
LibExport BOOL isKanji1A( const char *str, int n )
{
	int i = 0;

	if ( n >= 0 ) {
		for(i=0 ; str[i] ; i++) {
			if ( ISKANJI1MA(str[i]) ) {
				if ( i == n ) {
					return TRUE;
				}
				if ( str[++i] == 0 ) {
					break;
				}
			}
			if ( i == n ) {
				return FALSE;
			}
		}
	}
	return FALSE;
}

LibExport BOOL isKanji1W( const wchar_t *, int )
{
	return FALSE;
}

// リストビューのスタイル変更
LibExport void ChangeLVStyle(HWND hWnd, HWND hwndListView, int style, BOOL Repaint)
{

	if ( hWnd && hwndListView ) {
		LONG_PTR lpStyle = GetWindowLongPtr(hwndListView, GWL_STYLE);
		LONG_PTR lpNewStyle;

		switch(style) {
			case 1 :lpNewStyle = LVS_ICON;
					break;
			case 2 :lpNewStyle = LVS_SMALLICON;
					break;
			case 3 :lpNewStyle = LVS_LIST;
					break;
			default:lpNewStyle = LVS_REPORT;
					break;
		}

		SetWindowLongPtr(hwndListView, GWL_STYLE, (lpStyle & ~LVS_TYPEMASK) | lpNewStyle);
		if (Repaint) {
			InvalidateRect(hWnd, NULL, true);
		}
	}
}

// =====================================================================
// DLLの関数を呼び出すための準備
typedef int(WINAPI *ARCFUNC)(const HWND, LPCSTR, LPSTR, const DWORD);
typedef int(WINAPI *ARCFUNCW)(const HWND, LPCWSTR, LPWSTR, const DWORD);
typedef BOOL(WINAPI *ARCFUNC_GETRUNNING)(VOID);
typedef WORD(WINAPI *ARCFUNC_GETVERSION)(VOID);
typedef BOOL(WINAPI *ARCFUNC_SETUSELANGUE)(VOID);

// ======================= UNLHA32.DLL =================================

// Unlha32.dllを呼び出して、バージョン情報を取得する
LibExport DWORD call_unlha32_GetVersion(VOID)
{
	HINSTANCE lib = NULL;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return 0;
	}

	// メジャーバージョン・マイナーバージョンを取得
	ARCFUNC_GETVERSION UnArcGetVersion = (ARCFUNC_GETVERSION)GetProcAddress(lib, "UnlhaGetVersion");
	if ( UnArcGetVersion == NULL ) {
		return 0;
	}
	DWORD rv = UnArcGetVersion() * 10000;

	// サブバージョンを取得
	UnArcGetVersion = (ARCFUNC_GETVERSION)GetProcAddress(lib, "UnlhaGetSubVersion");
	if ( UnArcGetVersion != NULL ) {
		rv |= UnArcGetVersion();
	}

	FreeLibrary( lib );
	return rv;
}

// Unlha32.dllを呼び出して、使用言語を設定する
// englishflag = TRUE:英語モード / FALSE:日本語モード
LibExport BOOL call_unlha32_UseEnglishMode(BOOL englishflag)
{
	HINSTANCE lib = NULL;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return 0;
	}

	// 言語モード設定用関数へのアドレスを取得
	ARCFUNC_SETUSELANGUE UnArcSetUseLangue = (ARCFUNC_SETUSELANGUE)GetProcAddress(lib, englishflag ? "SetLangueEnglish" : "SetLangueJapanese");
	if ( UnArcSetUseLangue == NULL ) {
		return FALSE;
	}
	BOOL rv = UnArcSetUseLangue();

	// ライブラリの開放
	FreeLibrary( lib );
	return rv;
}

// Unlha32.dllを呼び出して、カレントディレクトリにlzhnameを解凍する(x -a1 -jf0)
LibExport int call_unlha32A(HWND hWnd, LPCSTR lzhname)
{
	return call_unlha32_logA(hWnd, lzhname, NULL, 0);
}
LibExport int call_unlha32W(HWND hWnd, LPCWSTR lzhname)
{
	return call_unlha32_logW(hWnd, lzhname, NULL, 0);
}

LibExport int call_unlha32_logA(HWND hWnd, LPCSTR lzhname, LPSTR szOutput, DWORD dwOutputSize)
{
	return call_unlha32d_logA(hWnd, lzhname, NULL, szOutput, dwOutputSize);
}
LibExport int call_unlha32_logW(HWND hWnd, LPCWSTR lzhname, LPWSTR szOutput, DWORD dwOutputSize)
{
	return call_unlha32d_logW(hWnd, lzhname, NULL, szOutput, dwOutputSize);
}

// Unlha32.dllを呼び出して、指定ディレクトリにlzhnameを解凍する(x -a1 -jf0)
LibExport int call_unlha32dA(HWND hWnd, LPCSTR lzhname, LPCSTR dir)
{
	return call_unlha32d_logA(hWnd, lzhname, dir, NULL, 0);
}
LibExport int call_unlha32dW(HWND hWnd, LPCWSTR lzhname, LPCWSTR dir)
{
	return call_unlha32d_logW(hWnd, lzhname, dir, NULL, 0);
}

LibExport int call_unlha32d_logA(HWND hWnd, LPCSTR lzhname, LPCSTR dir, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string lhacommand;			// Unlha() に渡されるコマンド　例：x -a1 -jf0 -gb"lzhname" "dir\"
	string dirname;				// 解凍先ディレクトリ　　　　　例："dir\"
	string lzhfilename;			// lzhファイル名　　　　　　　 例："lzhname"
	int    i  = 0;
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC Unlha = (ARCFUNC)GetProcAddress(lib, "Unlha");

	if (Unlha == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dcA( lzhfilename );

			// dirnameの生成 - dirに対して、必要があれば "" で囲い、最後に \ がなければ、\を付加する
			// 注意：ダブルコーテーションの中に、最後の \ があるのではダメで、ダブルコーテーションの後ろに
			//       なければならない様子
			if ( dir && dir[0] ) {
				dirname = dir;
				insert_dc( dirname );
				i = (int)dirname.length(); // dirnameの長さを取得
				const char *c_dirname = dirname.c_str();

				if ( !isKanji1A(c_dirname,i-2) && c_dirname[i-1] == '\\' ) // \で終わっていれば、それでよい。
					;
				else { // 終わりに \ を付加する
					dirname.append("\\");
				}
			}

			// コマンドラインの生成
			lhacommand = "x -a1 -jf0 -gb";
			lhacommand += lzhfilename;
			if ( !dirname.empty() ) { // 解凍先ディレクトリ指定があった場合
				lhacommand += " ";
				lhacommand += dirname;
			}

			if (0 != Unlha(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}
	FreeLibrary( lib );
	return rv;
}
LibExport int call_unlha32d_logW(HWND hWnd, LPCWSTR lzhname, LPCWSTR dir, LPWSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	wstring lhacommand;			// UnlhaW() に渡されるコマンド　例：x -a1 -jf0 -gb"lzhname" "dir\"
	wstring dirname;				// 解凍先ディレクトリ　　　　　例："dir\"
	wstring lzhfilename;			// lzhファイル名　　　　　　　 例："lzhname"
	int    i  = 0;
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32W(L_UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32W(L_UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNCW UnlhaW = (ARCFUNCW)GetProcAddress(lib, "UnlhaW");

	if (UnlhaW == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dcW( lzhfilename );

			// dirnameの生成 - dirに対して、必要があれば "" で囲い、最後に \ がなければ、\を付加する
			// 注意：ダブルコーテーションの中に、最後の \ があるのではダメで、ダブルコーテーションの後ろに
			//       なければならない様子
			if ( dir && dir[0] ) {
				dirname = dir;
				insert_dcW( dirname );
				i = (int)dirname.length(); // dirnameの長さを取得
				const wchar_t *c_dirname = dirname.c_str();

				if ( c_dirname[i-1] == L'\\' ) // \で終わっていれば、それでよい。
					;
				else { // 終わりに \ を付加する
					dirname.append(L"\\");
				}
			}

			// コマンドラインの生成
			lhacommand = L"x -a1 -jf0 -gb";
			lhacommand += lzhfilename;
			if ( !dirname.empty() ) { // 解凍先ディレクトリ指定があった場合
				lhacommand += L" ";
				lhacommand += dirname;
			}

			if (0 != UnlhaW(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}
	FreeLibrary( lib );
	return rv;
}

// Unlha32.dllを呼び出して、指定されたファイル群をlzhnameに圧縮する(a -rxad)
LibExport int call_unlha32rA(HWND hWnd, LPCSTR lzhname, LPCSTR response_file, LPCSTR option)
{
	return call_unlha32r_logA(hWnd, lzhname, response_file, option, NULL, 0);
}
LibExport int call_unlha32rW(HWND hWnd, LPCWSTR lzhname, LPCWSTR response_file, LPCWSTR option)
{
	return call_unlha32r_logW(hWnd, lzhname, response_file, option, NULL, 0);
}

LibExport int call_unlha32r_logA(HWND hWnd, LPCSTR lzhname, LPCSTR response_file, LPCSTR option, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string lhacommand;	// Unlha() に渡されるコマンド。例：a -rxad [option] -gb"lzhname" "@response_file"
	string respname;	// レスポンスファイル。　　　　例："@response_file"
	string lzhfilename;	// lzhファイル名。　　　　　　 例："lzhname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC Unlha = (ARCFUNC)GetProcAddress(lib, "Unlha");

	if (Unlha == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 || response_file == NULL || response_file[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dc( lzhfilename );

			// respnameの生成 - response_fileに対して、必要があれば "" で囲う
			// (@の追加は、コマンドライン生成時に行う)
			respname = response_file;
			insert_dcA( respname );

			// コマンド文字列の生成
			lhacommand = "a -rxad ";
			if ( option && option[0] ) {
				lhacommand += option;
				lhacommand += " ";
			}

			lhacommand += "-gb";
			lhacommand += lzhfilename;
			lhacommand += " @";
			lhacommand += respname;

			if (0 != Unlha(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

LibExport int call_unlha32r_logW(HWND hWnd, LPCWSTR lzhname, LPCWSTR response_file, LPCWSTR option, LPWSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	wstring lhacommand;	// UnlhaW() に渡されるコマンド。例：a -rxad [option] -gb"lzhname" "@response_file"
	wstring respname;	// レスポンスファイル。　　　　例："@response_file"
	wstring lzhfilename;	// lzhファイル名。　　　　　　 例："lzhname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32W(L_UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32W(L_UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNCW UnlhaW = (ARCFUNCW)GetProcAddress(lib, "UnlhaW");

	if (UnlhaW == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 || response_file == NULL || response_file[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dcW( lzhfilename );

			// respnameの生成 - response_fileに対して、必要があれば "" で囲う
			// (@の追加は、コマンドライン生成時に行う)
			respname = response_file;
			insert_dcW( respname );

			// コマンド文字列の生成
			lhacommand = L"a -rxad ";
			if ( option && option[0] ) {
				lhacommand += option;
				lhacommand += L" ";
			}

			lhacommand += L"-gb";
			lhacommand += lzhfilename;
			lhacommand += L" @";
			lhacommand += respname;

			if (0 != UnlhaW(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

// Unlha32.dllを呼び出して、lzhをexe(WinSFX32)に変換する(s -gw1)
LibExport int call_unlha32_toexeA(HWND hWnd, LPCSTR lzhname)
{
	return call_unlha32_toexe_logA(hWnd, lzhname, NULL, 0);
}
LibExport int call_unlha32_toexeW(HWND hWnd, LPCWSTR lzhname)
{
	return call_unlha32_toexe_logW(hWnd, lzhname, NULL, 0);
}

LibExport int call_unlha32_toexe_logA(HWND hWnd, LPCSTR lzhname, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string lhacommand;			// Unlha() に渡されるコマンド。例： s -gw1 -gb"lzhname"
	string lzhfilename;			// lzhファイル名。例： "lzhname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC Unlha = (ARCFUNC)GetProcAddress(lib, "Unlha");

	if (Unlha == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dcA( lzhfilename );

			// コマンド文字列の生成
			lhacommand = "s -gw1 -gb";
			lhacommand += lzhfilename;

			if (0 != Unlha(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

LibExport int call_unlha32_toexe_logW(HWND hWnd, LPCWSTR lzhname, LPWSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	wstring lhacommand;			// Unlha() に渡されるコマンド。例： s -gw1 -gb"lzhname"
	wstring lzhfilename;		// lzhファイル名。例： "lzhname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32W(L_UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32W(L_UNLHA64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNCW UnlhaW = (ARCFUNCW)GetProcAddress(lib, "Unlha");

	if (UnlhaW == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( lzhname == NULL || lzhname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// lzhfilenameの生成 - lzhnameに対して、必要があれば "" で囲う
			lzhfilename = lzhname;
			insert_dcW( lzhfilename );

			// コマンド文字列の生成
			lhacommand = L"s -gw1 -gb";
			lhacommand += lzhfilename;

			if (0 != UnlhaW(hWnd, lhacommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

// Unlha32.dllを呼び出して、Unlha()が使用中かどうかを確かめる
LibExport BOOL call_unlha32_getrunning( void )
{
	HINSTANCE lib = NULL;
	BOOL	rv = FALSE;

	lib = LoadLibrary_System32(UNLHA32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNLHA64DLL);
		if (lib == NULL)
#endif
		return FALSE;
	}

	ARCFUNC_GETRUNNING UnlhaGetRunning = (ARCFUNC_GETRUNNING)GetProcAddress(lib,"UnlhaGetRunning");

	if ( UnlhaGetRunning ) {
		rv = UnlhaGetRunning();
	}

	FreeLibrary( lib );
	return rv;
}

// ================== UNZIP32.DLL/ZIP32J.DLL =========================
// Unzip32.dllを呼び出して、カレントディレクトリにzipnameを解凍する
LibExport int call_unzip32(HWND hWnd, LPCSTR zipname)
{
	return call_unzip32_log(hWnd, zipname, NULL, 0);
}
LibExport int call_unzip32_log(HWND hWnd, LPCSTR zipname, LPSTR szOutput, DWORD dwOutputSize)
{
	return call_unzip32d_log(hWnd, zipname, NULL, szOutput, dwOutputSize);
}

// Unzip32.dllを呼び出して、指定ディレクトリにzipnameを解凍する
LibExport int call_unzip32d(HWND hWnd, LPCSTR zipname, LPCSTR dir)
{
	return call_unzip32d_log(hWnd, zipname, dir, NULL, 0);
}
LibExport int call_unzip32d_log(HWND hWnd, LPCSTR zipname, LPCSTR dir, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string zipcommand;	// UnZip() に渡されるコマンド。例："zipname" "dir\"
	string dirname;		// 解凍先ディレクトリ。　　　　例："dir\"
	string zipfilename;	// lzhファイル名。　　　　　　 例："zipname"
	int    i = 0;
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(UNZIP32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNZIP64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC UnZip = (ARCFUNC)GetProcAddress(lib, "UnZip");

	if (UnZip == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( zipname == NULL || zipname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// zipfilenameの生成 - zipnameに対して、必要があれば "" で囲う
			zipfilename = zipname;
			insert_dc( zipfilename );

			// dirnameの生成 - dirに対して、必要があれば "" で囲い、最後に \ がなければ、\を付加する
			if ( dir && dir[0] ) {
				dirname = dir;
				delete_dc( dirname );
				i = (int)dirname.length(); // dirnameの長さを取得
				if ( !isKanji1A(dirname.c_str(),i-2) && dirname[i-1] == '\\' ) // \で終わっていれば、それでよい。
					;
				else { // 終わりに \ を付加する
					dirname.append("\\");
				}
				insert_dc( dirname );
			}

			// コマンドラインの生成
			zipcommand = zipfilename;
			if ( !dirname.empty() ) { // 解凍先ディレクトリ指定があった場合
				zipcommand += " ";
				zipcommand += dirname;
			}

			if (0 != UnZip(hWnd, zipcommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}
	FreeLibrary( lib );
	return rv;
}

// Unzip32.dllを呼び出して、Unzip()が使用中かどうかを確かめる
LibExport BOOL call_unzip32_getrunning( void )
{
	HINSTANCE lib = NULL;
	BOOL	rv = 0;

	lib = LoadLibrary_System32(UNZIP32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(UNZIP64DLL);
		if (lib == NULL)
#endif
		return FALSE;
	}

	ARCFUNC_GETRUNNING UnzipGetRunning = (ARCFUNC_GETRUNNING)GetProcAddress(lib,"UnzipGetRunning");

	if ( UnzipGetRunning ) {
		rv = UnzipGetRunning();
	}
	else {
		rv = FALSE;
	}

	FreeLibrary( lib );
	return rv;
}

// zip32j.dllを呼び出して、指定されたファイル群をzipnameに圧縮する
LibExport int call_zip32j(HWND hWnd, LPCSTR zipname, LPCSTR response_file, LPCSTR option)
{
	return call_zip32j_log(hWnd, zipname, response_file, option, NULL, 0);
}
LibExport int call_zip32j_log(HWND hWnd, LPCSTR zipname, LPCSTR response_file, LPCSTR option, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string zipcommand;		// Zip() に渡されるコマンド。例： -r [option] "zipname" "@response_file"
	string respname;		// レスポンスファイル。　　　例："@response_file"
	string zipfilename;		// zipファイル名。　　　　　 例："zipname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(ZIP32JDLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(ZIP64JDLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC Zip = (ARCFUNC)GetProcAddress(lib, "Zip");

	if (Zip == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( zipname == NULL || zipname[0] == 0 || response_file == NULL || response_file[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// zipfilenameの生成 - zipnameに対して、必要があれば "" で囲う
			zipfilename = zipname;
			insert_dc( zipfilename );

			// respnameの生成 - response_fileに対して、必要があれば "" で囲い、最初に@を追加する
			respname = response_file;
			insert_dc( respname );

			if ( respname[0] == '\"' ) { // "で始まっている場合 - "の次に@を挿入する(理由はよくわからないが、zip32j.dllのルールのようだ)
				if ( respname[1] != '@' ) {
					respname.insert(1, "@");
				}
			}
			else { // "で始まっていない場合 - 先頭に@を挿入する
				if ( respname[0] != '@' ) {
					respname.insert(0, "@");
				}
			}

			// コマンド文字列の生成
			zipcommand = "-r ";
			if ( option && option[0] ) {
				zipcommand += option;
				zipcommand += " ";
			}

			zipcommand += zipfilename;
			zipcommand += " ";
			zipcommand += respname;

			if (0 != Zip(hWnd, zipcommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}
	FreeLibrary( lib );
	return rv;
}

// zip32j.dllを呼び出して、zipをexe(SFX)に変換する(--sfx)
LibExport int call_zip32_toexe(HWND hWnd, LPCSTR zipname)
{
	return call_zip32_toexe_log(hWnd, zipname, NULL, 0);
}
LibExport int call_zip32_toexe_log(HWND hWnd, LPCSTR zipname, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string zipcommand;		// Zip() に渡されるコマンド。例： --sfx "zipname"
	string zipfilename;		// zipファイル名。　　　　　 例： "zipname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(ZIP32JDLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(ZIP64JDLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC Zip = (ARCFUNC)GetProcAddress(lib, "Zip");

	if (Zip == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( zipname == NULL || zipname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// zipfilenameの生成 - zipnameに対して、必要があれば "" で囲う
			zipfilename = zipname;
			insert_dc( zipfilename );

			// コマンド文字列の生成
			zipcommand = "--sfx ";
			zipcommand += zipfilename;

			if (0 != Zip(hWnd, zipcommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

// Zip32j.dllを呼び出して、Unzip()が使用中かどうかを確かめる
LibExport BOOL call_zip32j_getrunning( void )
{
	HINSTANCE lib = NULL;
	BOOL	  rv  = FALSE;

	lib = LoadLibrary_System32(ZIP32JDLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(ZIP64JDLL);
		if (lib == NULL)
#endif
		return FALSE;
	}

	ARCFUNC_GETRUNNING ZipGetRunning = (ARCFUNC_GETRUNNING)GetProcAddress(lib,"ZipGetRunning");

	if ( ZipGetRunning ) {
		rv = ZipGetRunning();
	}

	FreeLibrary( lib );
	return rv;
}

// ======================= 7-ZIP32.DLL ==============================
// 7-Zip32.dllを呼び出して、カレントディレクトリにsznameを解凍する(x)
LibExport int call_7zip32(HWND hWnd, LPCSTR szname)
{
	return call_7zip32_log(hWnd, szname, NULL, 0);
}
LibExport int call_7zip32_log(HWND hWnd, LPCSTR szname, LPSTR szOutput, DWORD dwOutputSize)
{
	return call_7zip32d_log(hWnd, szname, NULL, szOutput, dwOutputSize);
}

// 7-zip32.dllを呼び出して、指定ディレクトリにsznameを解凍する(x -o<dir>)
LibExport int call_7zip32d(HWND hWnd, LPCSTR szname, LPCSTR dir)
{
	return call_7zip32d_log(hWnd, szname, dir, NULL, 0);
}
LibExport int call_7zip32d_log(HWND hWnd, LPCSTR szname, LPCSTR dir, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string szcommand;			// SevenZip() に渡されるコマンド　例：x -o"dir" -r -- "szname"
	string dirname;				// 解凍先ディレクトリ　　　　　例："dir"
	string szfilename;			// 7zファイル名 　　　　　　　 例："szname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(SEVENZIP32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(SEVENZIP64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC SevenZip = (ARCFUNC)GetProcAddress(lib, "SevenZip");

	if (SevenZip == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( szname == NULL || szname[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// szfilenameの生成 - sznameに対して、必要があれば "" で囲う
			szfilename = szname;
			insert_dc( szfilename );

			// dirnameの生成 - dirに対して、必要があれば "" で囲う
			if ( dir && dir[0] ) {
				dirname = dir;
				insert_dc( dirname );
			}

			// コマンドラインの生成
			szcommand = "x ";
			if ( !dirname.empty() ) { // 解凍先ディレクトリ指定があった場合
				szcommand += "-o";	// スペースを空けずに続けてディレクトリ名
				szcommand += dirname;
				szcommand += " ";
			}
			szcommand += "-r -- ";
			szcommand += szfilename;

			if (0 != SevenZip(hWnd, szcommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}
	FreeLibrary( lib );
	return rv;
}

// 7-Zip32.dllを呼び出して、指定されたファイル群をsznameに圧縮する(a -t??? ***)
# define SZTYPE_7Z		0	// 7z
# define SZTYPE_ZIP		1	// zip
# define SZTYPE_EXE		2	// exe(7z sfx)
LibExport int call_7zip32r(HWND hWnd, LPCSTR szname, LPCSTR list_file, LPCSTR option)
{
	return call_7zip32r_log(hWnd, szname, list_file, option, NULL, 0);
}
LibExport int call_7zip32r_log(HWND hWnd, LPCSTR szname, LPCSTR list_file, LPCSTR option, LPSTR szOutput, DWORD dwOutputSize)
{
	HINSTANCE lib = NULL;
	string szcommand;	// SevenZip() に渡されるコマンド。例：a -t7z [option] (-ms=off) (-sfx) -r -- "szname" @"list_file"
	string listfile;	// 圧縮対象リストファイル。　　例：@"list_file"
	string szfilename;	// 7zファイル名。　　　 　　　 例："szname"
	int    rv = T_TF_SUCCESS;

	lib = LoadLibrary_System32(SEVENZIP32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(SEVENZIP64DLL);
		if (lib == NULL)
#endif
		return T_TF_DLLNOTFOUND;
	}

	ARCFUNC SevenZip = (ARCFUNC)GetProcAddress(lib, "SevenZip");

	if (SevenZip == NULL) {
		rv = T_TF_ILLEGALDLL;
	}
	else {
		if ( szname == NULL || szname[0] == 0 || list_file == NULL || list_file[0] == 0 ) {
			rv = T_TF_ILLEGALCALL;
		}
		else {
			// szfilenameの生成 - sznameに対して、必要があれば "" で囲う
			szfilename = szname;
			insert_dc( szfilename );

			// listfileの生成 - list_fileに対して、必要があれば "" で囲う
			// (@の追加は、コマンドライン生成時に行う)
			listfile = list_file;
			insert_dc( listfile );

			// コマンド文字列の生成
			szcommand = "a ";

			// 圧縮ファイルの拡張子を見て、オプションを決定する
			int i7zType = SZTYPE_7Z; // 0:7z, 1:zip, 2:exe(7z sfx)
			char szExt[_MAX_EXT*2];

			_splitpath_s(szname, NULL, 0, NULL, 0, NULL, 0, szExt, UBOUND(szExt));
			if (_strcmpi(szExt, ".zip") == 0 || _strcmpi(szExt, ".jar") == 0 || _strcmpi(szExt, ".xpi") == 0) {
				i7zType = SZTYPE_ZIP;
				szcommand += "-tzip ";
			}
			else if (_strcmpi(szExt, ".exe") == 0) {
				i7zType = SZTYPE_EXE;
				szcommand += "-t7z ";
			}
			else {
				szcommand += "-t7z ";
			}
			
			if ( option && option[0] ) {
				szcommand += option;
				szcommand += " ";

				if ( i7zType == SZTYPE_ZIP ) {
					// -mmt=on/off があると失敗するらしいので取り除く
					string::size_type ds;

					ds = szcommand.find("-mmt=on");
					if ( ds != string::npos ) {
						szcommand.erase(ds, 7);
					}
					else {
						ds = szcommand.find("-mmt=off");
						szcommand.erase(ds, 8);
					}
				}
			}

			if ( i7zType == SZTYPE_7Z || i7zType == SZTYPE_EXE ) {
				szcommand += "-ms=off ";
			}
			if ( i7zType == SZTYPE_EXE ) {
				szcommand += "-sfx ";
			}
			szcommand += "-r0 -- ";

			szcommand += szfilename;
			szcommand += " @";
			szcommand += listfile;

			if (0 != SevenZip(hWnd, szcommand.c_str(), szOutput, dwOutputSize)) {
				rv = T_TF_ERROR;
			}
		}
	}

	FreeLibrary( lib );
	return rv;
}

// 7-Zip32.dllを呼び出して、SevenZip()が使用中かどうかを確かめる
LibExport BOOL call_7zip32_getrunning( void )
{
	HINSTANCE lib = NULL;
	BOOL	  rv  = FALSE;

	lib = LoadLibrary_System32(SEVENZIP32DLL);
	if (lib == NULL) {
#ifdef _WIN64
		lib = LoadLibrary_System32(SEVENZIP64DLL);
		if (lib == NULL)
#endif
		return FALSE;
	}

	ARCFUNC_GETRUNNING SevenZipGetRunning = (ARCFUNC_GETRUNNING)GetProcAddress(lib,"SevenZipGetRunning");

	if ( SevenZipGetRunning ) {
		rv = SevenZipGetRunning();
	}

	FreeLibrary( lib );
	return rv;
}

// ==================================================================
//---------------------------------------------------------------------------
// TFI_TaskBarAddIcon() タスクバーのシステムトレイにアイコンを追加する
// 戻り値：TRUE成功 FALSE失敗
// hwnd - コールバック先のウィンドウハンドル
// uID - 追加するアイコンID
// hicon - 追加するアイコンのハンドル
// lpszTip - アイコンにマウスを置いたときに表示されるテキスト
// messageID - MYWM_NOTIFYICON (hwndにコールバックするメッセージとして使う整数値)
//
// (このソースコードは、MSDNのライブラリのものを参考に作られています)
//---------------------------------------------------------------------------
LibExport BOOL TFI_TaskBarAddIconA(HWND hwnd, UINT uID, HICON hicon, LPCSTR lpszTip, int messageID)
{
    NOTIFYICONDATAA tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = messageID;
    tnid.hIcon = hicon;
	if (lpszTip) {
        lstrcpynA(tnid.szTip, lpszTip, _countof(tnid.szTip));
	}

    return Shell_NotifyIconA(NIM_ADD, &tnid);
}

LibExport BOOL TFI_TaskBarAddIconW(HWND hwnd, UINT uID, HICON hicon, LPCWSTR lpszTip, int messageID)
{
    NOTIFYICONDATAW tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = messageID;
    tnid.hIcon = hicon;
	if (lpszTip) {
        lstrcpynW(tnid.szTip, lpszTip, _countof(tnid.szTip));
	}

    return Shell_NotifyIconW(NIM_ADD, &tnid);
}

//---------------------------------------------------------------------------
// TFI_TaskBarModifyIcon() タスクバーのシステムトレイにアイコンを変更する
// 戻り値：TRUE成功 FALSE失敗
// hwnd - コールバック先のウィンドウハンドル（変更対象とするもの）
// uID - 追加するアイコンID（変更対象とするもの）
// hicon - 追加するアイコンのハンドル
// lpszTip - アイコンにマウスを置いたときに表示されるテキスト
// messageID - MYWM_NOTIFYICON (hwndにコールバックするメッセージとして使う整数値)
//---------------------------------------------------------------------------
LibExport BOOL TFI_TaskBarModifyIconA(HWND hwnd, UINT uID, HICON hicon, LPCSTR lpszTip, int messageID)
{
    NOTIFYICONDATA tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = messageID;
    tnid.hIcon = hicon;
	if (lpszTip) {
        lstrcpynA(tnid.szTip, lpszTip, _countof(tnid.szTip));
	}

	return Shell_NotifyIconA(NIM_MODIFY, &tnid);
}

LibExport BOOL TFI_TaskBarModifyIconW(HWND hwnd, UINT uID, HICON hicon, LPCWSTR lpszTip, int messageID)
{
    NOTIFYICONDATAW tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = messageID;
    tnid.hIcon = hicon;
	if (lpszTip) {
        lstrcpynW(tnid.szTip, lpszTip, _countof(tnid.szTip));
	}

	return Shell_NotifyIconW(NIM_MODIFY, &tnid);
}

//---------------------------------------------------------------------------
// TFI_TaskBarDeleteIcon() タスクバーのシステムトレイからアイコンを削除する
// 戻り値：TRUE成功 FALSE失敗
// hwnd - アイコンを追加したウィンドウハンドル
// uID - 追加するときに指定したID
//
// (このソースコードは、MSDNのライブラリのものを参考に作られています)
//---------------------------------------------------------------------------
LibExport BOOL TFI_TaskBarDeleteIconA(HWND hwnd, UINT uID)
{
    NOTIFYICONDATAA tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    return Shell_NotifyIconA(NIM_DELETE, &tnid);
}

LibExport BOOL TFI_TaskBarDeleteIconW(HWND hwnd, UINT uID)
{
    NOTIFYICONDATAW tnid;

	ZeroMemory(&tnid, sizeof(tnid));
    tnid.cbSize = sizeof(tnid);
    tnid.hWnd = hwnd;
    tnid.uID = uID;

    return Shell_NotifyIconW(NIM_DELETE, &tnid);
}

// SHEmptyRecycleBin のコール (ごみ箱を空にする) testflag = 1 このAPIが利用できるかどうかを確認
LibExport BOOL EmptyRecycleBinA(BOOL testflag)
{
	if (testflag) {
		return 1;
	}

	if (S_OK == SHEmptyRecycleBin(NULL, NULL, SHERB_NOCONFIRMATION | SHERB_NOSOUND)) {
		return 1;
	}
	else {
		return 0;
	}
}

typedef DWORD (WINAPI *PFUNC_SHEmptyRecycleBinW)(HWND,LPCWSTR,DWORD);

LibExport BOOL EmptyRecycleBinW(BOOL testflag)
{
	HMODULE hDLL;
	PFUNC_SHEmptyRecycleBinW pFunc;  

	hDLL = LoadLibrary_System32W(L"SHELL32.DLL");
	if (hDLL == NULL)
		return 0;
	pFunc=(PFUNC_SHEmptyRecycleBinW)GetProcAddress(hDLL, "SHEmptyRecycleBinW");
	if (pFunc == NULL) {
		FreeLibrary( hDLL );
		return 0;
	}

	if (testflag) {
		FreeLibrary( hDLL );
		return 1;
	}

	if (S_OK == pFunc(NULL, NULL, SHERB_NOCONFIRMATION | SHERB_NOSOUND)) {
		FreeLibrary( hDLL );
		return 1;
	}
	else {
		FreeLibrary( hDLL );
		return 0;
	}
}

// カレントディレクトリを自分のところにセット
LibExport BOOL SetCurrentDirectoryOwnDirA( void )
{
	char exename[MAX_PATH*2];

	if ( GetModuleFileNameA(NULL, exename, _countof(exename)) ) {
		int i = lstrlenA(exename);

		do {
			i--;
		} while(i>0 && (exename[i] != '\\' || isKanji1A(exename,i-1)));
		if (i > 0) {
			if (i > 4) {
				exename[i] = 0;
			}
			else {
				exename[i+1] = 0;
			}
			return SetCurrentDirectoryA(exename);
		}
		else {
			return FALSE;
		}
	}
	return FALSE;
}

LibExport BOOL SetCurrentDirectoryOwnDirW( void )
{
	wchar_t exename[MAX_PATH];

	if ( GetModuleFileNameW(NULL, exename, _countof(exename)) ) {
		int i = lstrlenW(exename);

		do {
			i--;
		} while(i>0 && (exename[i] != L'\\'));
		if (i > 0) {
			if (i > 4) {
				exename[i] = 0;
			}
			else {
				exename[i+1] = 0;
			}
			return SetCurrentDirectoryW(exename);
		}
		else {
			return FALSE;
		}
	}
	return FALSE;
}

// ショートカットの作成
LibExport BOOL MakeLinkA(LPCSTR exe, LPCSTR args, LPCSTR lnk)
{
	return MakeLinkIcon(exe, args, lnk, NULL, 0);
}
LibExport BOOL MakeLinkW(LPCWSTR exe, LPCWSTR args, LPCWSTR lnk)
{
	return MakeLinkIconW(exe, args, lnk, NULL, 0);
}

// ショートカットの作成（アイコンも指定）
// このソースコードは、どこかのサイト(忘れました)のサンプルを一部改造して利用しています
LibExport BOOL MakeLinkIconA(LPCSTR exe, LPCSTR args, LPCSTR lnk, LPCSTR icon, int no)
{
	IShellLink	*m_pShellLink = NULL;
	IPersistFile	*m_pPersistFile = NULL;
	OLECHAR	ochLinkFile[MAX_PATH*2];
	HRESULT hRes = 0;

/*	// OLE使用前の初期化 -- この関数を呼び出すプログラムの冒頭で、初期化はすませておくこと！
	hRes = CoInitialize( NULL );

	if( hRes == E_OUTOFMEMORY || hRes == E_INVALIDARG || hRes == E_UNEXPECTED )
		return FALSE;
*/
	// 準備
	hRes = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&m_pShellLink );

	if( false == SUCCEEDED(hRes) ) {
		return FALSE;
	}

	// IPersistFileを生成
	hRes = m_pShellLink->QueryInterface( IID_IPersistFile, (LPVOID *)&m_pPersistFile );

	if( false == SUCCEEDED(hRes) ) {
		return FALSE;
	}

	// リンク情報の作成
	m_pShellLink->SetPath( exe );		//リンク先のexeファイル。
	m_pShellLink->SetShowCmd( SW_SHOW );	//標準の表示。
	m_pShellLink->SetWorkingDirectory( "" );	//カレントフォルダなし。
	m_pShellLink->SetIconLocation( icon, no );	//アイコンの指定(icon=NULL, no=0 で普通のアイコン)
	m_pShellLink->SetHotkey( 0 );			//ホットキーナシ。
	m_pShellLink->SetDescription( "" );	//タイトルナシ。
	m_pShellLink->SetArguments( args );	//引数指定。

	// ユニコード変換
	MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lnk, -1, ochLinkFile, _countof(ochLinkFile) );

	// ショートカットファイルの書き込み
	hRes = m_pPersistFile->Save( ochLinkFile, TRUE );

	// IPersistFileを解放
	m_pPersistFile->Release();

	// IShellLinkを解放
	m_pShellLink->Release();

/*	CoUninitialize(); */ // - この関数を呼び出すプログラムの最後で、解放は行っておくこと

	return ((hRes == S_OK) ? TRUE : FALSE);
}

LibExport BOOL MakeLinkIconW(LPCWSTR exe, LPCWSTR args, LPCWSTR lnk, LPCWSTR icon, int no)
{
	IShellLinkW	*m_pShellLink = NULL;
	IPersistFile	*m_pPersistFile = NULL;
	HRESULT hRes = 0;

/*	// OLE使用前の初期化 -- この関数を呼び出すプログラムの冒頭で、初期化はすませておくこと！
	hRes = CoInitialize( NULL );

	if( hRes == E_OUTOFMEMORY || hRes == E_INVALIDARG || hRes == E_UNEXPECTED )
		return FALSE;
*/

	// 準備
	hRes = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&m_pShellLink );

	if( false == SUCCEEDED(hRes) ) {
		return FALSE;
	}

	// IPersistFileを生成
	hRes = m_pShellLink->QueryInterface( IID_IPersistFile, (LPVOID *)&m_pPersistFile );

	if( false == SUCCEEDED(hRes) ) {
		return FALSE;
	}

	// リンク情報の作成
	m_pShellLink->SetPath( exe );		//リンク先のexeファイル。
	m_pShellLink->SetShowCmd( SW_SHOW );	//標準の表示。
	m_pShellLink->SetWorkingDirectory( L"" );	//カレントフォルダなし。
	m_pShellLink->SetIconLocation( icon, no );	//アイコンの指定(icon=NULL, no=0 で普通のアイコン)
	m_pShellLink->SetHotkey( 0 );			//ホットキーナシ。
	m_pShellLink->SetDescription( L"" );	//タイトルナシ。
	m_pShellLink->SetArguments( args );	//引数指定。

	// ショートカットファイルの書き込み
	hRes = m_pPersistFile->Save( lnk, TRUE );

	// IPersistFileを解放
	m_pPersistFile->Release();

	// IShellLinkを解放
	m_pShellLink->Release();

/*	CoUninitialize(); */ // - この関数を呼び出すプログラムの最後で、解放は行っておくこと

	return ((hRes == S_OK) ? TRUE : FALSE);
}

// ショートカットの読み出し
// このソースコードは、ネット上に公開されていたサンプルを一部改造して利用しています
LibExport BOOL QueryLinkA(const char *pszLinkFile, char *pszTarget, char *pszOption,
						        char *pszIcon, int *piIconIndex) {

    IShellLink      *ShellLink = NULL;
    IPersistFile    *PersistFile = NULL;
    HRESULT         hResult = 0;
    WCHAR           wszShortcutFile[MAX_PATH*2];
    WIN32_FIND_DATA wfd;
	BOOL            bResult = TRUE;

	if ( pszLinkFile == NULL ) {
		return FALSE;
	}

/*	// OLE使用前の初期化 -- この関数を呼び出すプログラムの冒頭で、初期化はすませておくこと！
	hRes = CoInitialize( NULL );

	if( hRes == E_OUTOFMEMORY || hRes == E_INVALIDARG || hRes == E_UNEXPECTED )
		return FALSE;
*/

    //  IShellLinkオブジェクトの取得
    hResult = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
                               (void **)&ShellLink);

    if (false == SUCCEEDED(hResult)) {
        return FALSE;
    }

    //  IPersistFileインターフェイスの取得
    hResult = ShellLink->QueryInterface(IID_IPersistFile, (void **)&PersistFile);
    if (false == SUCCEEDED(hResult)) {
		ShellLink->Release();
        return FALSE;
    }

    //  ショートカットファイルの読み込み
    MultiByteToWideChar(GetACP(), 0, pszLinkFile, -1, wszShortcutFile, _countof(wszShortcutFile));
    hResult = PersistFile->Load(wszShortcutFile, STGM_READ);
    if ( SUCCEEDED(hResult) ) {
		if ( pszTarget ) {
			// ターゲットファイルの取得
			ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA));
			hResult = ShellLink->GetPath(pszTarget, MAX_PATH*2, &wfd, SLGP_UNCPRIORITY);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}

		if ( pszOption ) {
			// オプションの取得
			hResult = ShellLink->GetArguments(pszOption, MAX_PATH*2);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}

		if ( pszIcon && piIconIndex ) {
			//  アイコン情報の取得
			hResult = ShellLink->GetIconLocation(pszIcon, MAX_PATH*2, piIconIndex);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}
	}
	else {
		bResult = FALSE;
	}

    //  IPersistFileインターフェイスの解放
    PersistFile->Release();

    //  IShellLinkオブジェクトの解放
    ShellLink->Release();

/*	CoUninitialize(); */ // - この関数を呼び出すプログラムの最後で、解放は行っておくこと

    return bResult;
}

LibExport BOOL QueryLinkW(const wchar_t *pszLinkFile, wchar_t *pszTarget, wchar_t *pszOption,
						        wchar_t *pszIcon, int *piIconIndex) {

    IShellLinkW     *ShellLink = NULL;
    IPersistFile    *PersistFile = NULL;
    HRESULT         hResult = 0;
    WIN32_FIND_DATAW wfd;
	BOOL            bResult = TRUE;

	if ( pszLinkFile == NULL ) {
		return FALSE;
	}

/*	// OLE使用前の初期化 -- この関数を呼び出すプログラムの冒頭で、初期化はすませておくこと！
	hRes = CoInitialize( NULL );

	if( hRes == E_OUTOFMEMORY || hRes == E_INVALIDARG || hRes == E_UNEXPECTED )
		return FALSE;
*/

    //  IShellLinkオブジェクトの取得
    hResult = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
                               (void **)&ShellLink);

    if (false == SUCCEEDED(hResult)) {
        return FALSE;
    }

    //  IPersistFileインターフェイスの取得
    hResult = ShellLink->QueryInterface(IID_IPersistFile, (void **)&PersistFile);
    if (false == SUCCEEDED(hResult)) {
		ShellLink->Release();
        return FALSE;
    }

    //  ショートカットファイルの読み込み
    hResult = PersistFile->Load(pszLinkFile, STGM_READ);
    if ( SUCCEEDED(hResult) ) {
		if ( pszTarget ) {
			// ターゲットファイルの取得
			ZeroMemory(&wfd, sizeof(WIN32_FIND_DATAW));
			hResult = ShellLink->GetPath(pszTarget, MAX_PATH, &wfd, SLGP_UNCPRIORITY);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}

		if ( pszOption ) {
			// オプションの取得
			hResult = ShellLink->GetArguments(pszOption, MAX_PATH);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}

		if ( pszIcon && piIconIndex ) {
			//  アイコン情報の取得
			hResult = ShellLink->GetIconLocation(pszIcon, MAX_PATH, piIconIndex);
			if ( false == SUCCEEDED(hResult) ) {
				bResult = FALSE;
			}
		}
	}
	else {
		bResult = FALSE;
	}

    //  IPersistFileインターフェイスの解放
    PersistFile->Release();

    //  IShellLinkオブジェクトの解放
    ShellLink->Release();

/*	CoUninitialize(); */ // - この関数を呼び出すプログラムの最後で、解放は行っておくこと

    return bResult;
}

// _strdupのnew版
LibExport char *new_strcpyA(const char *src)
{
	char *des;

	if ( src ) {
		des = new char [lstrlen(src)+1];
		if ( des ) {
			return lstrcpy(des, src);
		}
	}
	return NULL;
}
LibExport wchar_t *new_strcpyW(const wchar_t *src)
{
	wchar_t *des;

	if ( src ) {
		des = new wchar_t [lstrlenW(src)+1];
		if ( des ) {
			return lstrcpyW(des, src);
		}
	}
	return NULL;
}

// new_strcpyのstrcat版
LibExport char *new_strcatA(char *ptr, const char *str)
{
	char *des;

	if ( str ) {
		if ( ptr ) {
			des = new char [lstrlen(str)+lstrlen(ptr)+1];
			if ( des ) {
				lstrcpy(des, ptr);
				delete[] ptr;
				lstrcat(des, str);
			}
			else
				return NULL;
		}
		else {
			des = new_strcpy(str);
		}

		return des;
	}
	else {
		return ptr;
	}
}

LibExport wchar_t *new_strcatW(wchar_t *ptr, const wchar_t *str)
{
	wchar_t *des;

	if ( str ) {
		if ( ptr ) {
			des = new wchar_t [lstrlenW(str)+lstrlenW(ptr)+1];
			if ( des ) {
				lstrcpyW(des, ptr);
				delete[] ptr;
				lstrcatW(des, str);
			}
			else
				return NULL;
		}
		else {
			des = new_strcpyW(str);
		}

		return des;
	}
	else {
		return ptr;
	}
}

// スタートメニュー:プログラムのフォルダ（個人用）を得る
LibExport char *GetProgramFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　プログラムフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_PROGRAMS, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetProgramFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t  *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　プログラムフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_PROGRAMS, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// スタートメニュー:プログラムのフォルダ（全ユーザー用）を得る
LibExport char *GetCommonProgramFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　プログラムフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_PROGRAMS, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetCommonProgramFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t  *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　プログラムフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_PROGRAMS, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// デスクトップフォルダ（個人用）を得る
LibExport char *GetDesktopFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　デスクトップフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_DESKTOPDIRECTORY, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetDesktopFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　デスクトップフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_DESKTOPDIRECTORY, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// デスクトップフォルダ（全ユーザー用）を得る
LibExport char *GetCommonDesktopFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　デスクトップフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetCommonDesktopFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　デスクトップフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// スタートアップフォルダ（個人用）を得る
LibExport char *GetStartUpFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　スタートアップフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_STARTUP, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetStartUpFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　スタートアップフォルダ（個人）
		SHGetSpecialFolderLocation( NULL, CSIDL_STARTUP, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// スタートアップフォルダ（全ユーザー用）を得る
LibExport char *GetCommonStartUpFolderA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　スタートアップフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_STARTUP, &pidl );
		SHGetPathFromIDList( pidl, chPath );
		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetCommonStartUpFolderW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t *return_p = NULL;
	LPITEMIDLIST	pidl;

	if ( !return_p ) {
		//　スタートアップフォルダ（全ユーザー）
		SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_STARTUP, &pidl );
		SHGetPathFromIDListW( pidl, chPath );
		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// 起動ディレクトリ(Windowsフォルダではない)を得る
LibExport char *GetBootDirectoryA(void)
{
	char	        chPath[MAX_PATH*2];
	static char    *return_p = NULL;

	if ( !return_p ) {
		//　レジストリから情報を得るが、なかったときのために Windowsディレクトリからの推測もする。
		GetWindowsDirectory(chPath, _countof(chPath));
		chPath[3] = 0;

		// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup の BootDir
		HKEY  hkey;
		char  regPath[MAX_PATH*2];
		DWORD regtype, regPathSize = _countof(regPath);

		if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Setup", NULL, KEY_QUERY_VALUE, &hkey ) ) {
			if ( ERROR_SUCCESS == RegQueryValueEx(hkey, "BootDir", NULL, &regtype, (LPBYTE)regPath, &regPathSize) ) {
				if ( regtype == REG_SZ || regtype == REG_EXPAND_SZ ) {
                    lstrcpy( chPath, regPath );
				}
			}
			RegCloseKey( hkey );
		}

		return_p = _strdup( chPath );
	}
	return return_p;
}

LibExport wchar_t *GetBootDirectoryW(void)
{
	wchar_t	        chPath[MAX_PATH];
	static wchar_t  *return_p = NULL;

	if ( !return_p ) {
		//　レジストリから情報を得るが、なかったときのために Windowsディレクトリからの推測もする。
		GetWindowsDirectoryW(chPath, _countof(chPath));
		chPath[3] = 0;

		// HKLM\Software\Microsoft\Windows\CurrentVersion\Setup の BootDir
		HKEY  hkey;
		wchar_t  regPath[MAX_PATH];
		DWORD regtype, regPathSize = _countof(regPath);

		if ( ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup", NULL, KEY_QUERY_VALUE, &hkey ) ) {
			if ( ERROR_SUCCESS == RegQueryValueExW(hkey, L"BootDir", NULL, &regtype, (LPBYTE)regPath, &regPathSize) ) {
				if ( regtype == REG_SZ || regtype == REG_EXPAND_SZ ) {
                    lstrcpyW( chPath, regPath );
				}
			}
			RegCloseKey( hkey );
		}

		return_p = _wcsdup( chPath );
	}
	return return_p;
}

// ダイアログから文字列を読みとり、そのまま領域ごと返す。あとで delete[] すること！
LibExport char *new_GetDlgItemTextA(HWND hDlg, int nIDDlgItem)
{
	int n;
	char *str;

	n = GetWindowTextLength(GetDlgItem(hDlg, nIDDlgItem))+1;
	str = new char [n];
	if ( str ) {
		GetDlgItemText(hDlg, nIDDlgItem, str, n);
	}
	return str;
}

LibExport wchar_t *new_GetDlgItemTextW(HWND hDlg, int nIDDlgItem)
{
	int n;
	wchar_t *str;

	n = GetWindowTextLengthW(GetDlgItem(hDlg, nIDDlgItem))+1;
	str = new wchar_t [n];
	if ( str ) {
		GetDlgItemTextW(hDlg, nIDDlgItem, str, n);
	}
	return str;
}

// ツールチップの作成
LibExport HWND CreateToolTipA(HINSTANCE hInst, HWND hWnd, const struct DEFTOOLTIP *dtt)
{
	HWND hTooltip;
	TOOLINFO ti;

	if (NULL == (hTooltip=CreateWindow(TOOLTIPS_CLASS, "", TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,
		                               CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL)))
		return NULL;

	ZeroMemory(&ti, sizeof(ti));
	ti.cbSize = sizeof(ti);
	ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;// uIDはツールチップを表示するウィンドウを識別するハンドル / サブクラス化もお任せ
	ti.hwnd=hWnd;	// ツールチップを持つウィンドウ

	while(dtt->cid != 0 && dtt->tip != NULL) {
#pragma warning( disable : 4311 )
		ti.uId = (UINT)GetDlgItem(hWnd, dtt->cid);
#pragma warning( default : 4311 )
		ti.lpszText = dtt->tip;// チップ
		SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
		dtt++;
	}
	return hTooltip;
}

LibExport HWND CreateToolTipW(HINSTANCE hInst, HWND hWnd, const struct DEFTOOLTIPW *dtt)
{
	HWND hTooltip;
	TOOLINFOW ti;

	if (NULL == (hTooltip=CreateWindowW(TOOLTIPS_CLASSW, L"", TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT,
		                                CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL)))
		return NULL;

	ZeroMemory(&ti, sizeof(ti));
	ti.cbSize = sizeof(ti);
	ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;// uIDはツールチップを表示するウィンドウを識別するハンドル / サブクラス化もお任せ
	ti.hwnd=hWnd;	// ツールチップを持つウィンドウ

	while(dtt->cid != 0 && dtt->tip != NULL) {
#pragma warning( disable : 4311 )
		ti.uId = (UINT)GetDlgItem(hWnd, dtt->cid);
#pragma warning( default : 4311 )
		ti.lpszText = dtt->tip;// チップ
		SendMessageW(hTooltip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
		dtt++;
	}
	return hTooltip;
}

// 列挙された子ウィンドウを受け取る (↓SetChildWindowFontで使う)
static BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM)
{
	SendMessage(hWnd,WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
	return TRUE;
}

// 指定したダイアログの子ウィンドウ(コントロール)のフォントを MS UI Gothic にしてしまう
LibExport void SetChildWindowFont(HWND hWnd)
{
	EnumChildWindows(hWnd, EnumChildProc, 0);
}

// 文字列を表示させる。
LibExport BOOL TextOutLengthA(HDC hdc, const char *str, int x0, int y0)
{
	return TextOut(hdc, x0, y0, str, lstrlen(str));
}
LibExport BOOL TextOutLengthW(HDC hdc, const wchar_t *str, int x0, int y0)
{
	return TextOutW(hdc, x0, y0, str, lstrlenW(str));
}

// 指定された四角の中に、文字列を表示させる(自動改行、強制改行付き)。
LibExport int DrawTextRectA(HDC hdc, const char *str, int x0, int y0, int x1, int y1)
{
	RECT rt;

	rt.left   = x0;
	rt.top    = y0;
	rt.right  = x1;
	rt.bottom = y1;

	return DrawText( hdc, str, lstrlen(str), &rt, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK );
}
LibExport int DrawTextRectW(HDC hdc, const wchar_t *str, int x0, int y0, int x1, int y1)
{
	RECT rt;

	rt.left   = x0;
	rt.top    = y0;
	rt.right  = x1;
	rt.bottom = y1;

	return DrawTextW( hdc, str, lstrlenW(str), &rt, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK );
}

typedef DWORD (WINAPI *PFUNC_SetLayeredWindowAttributes)(HWND,DWORD,BYTE,DWORD);
typedef DWORD (WINAPI *QFUNC_GetLayeredWindowAttributes)(HWND,LPDWORD,LPBYTE,LPDWORD);

// 指定されたウインドウを半透明にする n:α値
LibExport int SetExl(HWND hWnd, BYTE n)
{
	if (n != 255) {
		SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
	}
	SetLayeredWindowAttributes(hWnd, 0, n, 2);
	if (n == 255) {
		SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) & (~WS_EX_LAYERED));
	}
	return 1;
}

// 指定されたウインドウのα値を得る
LibExport int GetExl(HWND hWnd)
{
	BYTE n = 255;

	if (GetLayeredWindowAttributes(hWnd,NULL,&n,NULL)) {
		return (int)n;
	}
	else {
		return 255;
	}
}

// エディットボックスの中身が数値かどうかを見て、違ったら 0 を入れる
LibExport BOOL CheckNumericDlgEdit(HWND hWnd, WORD id) 
{
	static volatile bool flag=0; // 再入チェック
	UINT   value;
	char   buf[12]="";

	if (flag == 1) {
		return TRUE;
	}

	if (GetWindowLongPtr(GetDlgItem(hWnd,id), GWL_STYLE) & ES_NUMBER) {
		flag = 1;
		value = GetDlgItemInt(hWnd, id, NULL, 0);
		GetDlgItemText(hWnd, id, buf, 11);
		if (buf[0] && 0 != _ultoa_s(value, buf, UBOUND(buf), 10)) {
			SetDlgItemInt(hWnd, id, value, 0);
		}
		flag = 0;
	}
	return FALSE;
}

// 16進数を10進数へ
LibExport int atoi16A(const char *str)
{
	int rv = 0;

	if ( str ) {
		while( *str ) {
			rv <<= 4;
			switch( *str ) {
				case '1': rv |= 0x1; break;
				case '2': rv |= 0x2; break;
				case '3': rv |= 0x3; break;
				case '4': rv |= 0x4; break;
				case '5': rv |= 0x5; break;
				case '6': rv |= 0x6; break;
				case '7': rv |= 0x7; break;
				case '8': rv |= 0x8; break;
				case '9': rv |= 0x9; break;
				case 'A':
				case 'a': rv |= 0xa; break;
				case 'B':
				case 'b': rv |= 0xb; break;
				case 'C':
				case 'c': rv |= 0xc; break;
				case 'D':
				case 'd': rv |= 0xd; break;
				case 'E':
				case 'e': rv |= 0xe; break;
				case 'F':
				case 'f': rv |= 0xf; break;
			}
			str++;
		}
	}
	return rv;
}
LibExport int atoi16W(const wchar_t *str)
{
	int rv = 0;

	if ( str ) {
		while( *str ) {
			rv <<= 4;
			switch( *str ) {
				case L'1': rv |= 0x1; break;
				case L'2': rv |= 0x2; break;
				case L'3': rv |= 0x3; break;
				case L'4': rv |= 0x4; break;
				case L'5': rv |= 0x5; break;
				case L'6': rv |= 0x6; break;
				case L'7': rv |= 0x7; break;
				case L'8': rv |= 0x8; break;
				case L'9': rv |= 0x9; break;
				case L'A':
				case L'a': rv |= 0xa; break;
				case L'B':
				case L'b': rv |= 0xb; break;
				case L'C':
				case L'c': rv |= 0xc; break;
				case L'D':
				case L'd': rv |= 0xd; break;
				case L'E':
				case L'e': rv |= 0xe; break;
				case L'F':
				case L'f': rv |= 0xf; break;
			}
			str++;
		}
	}
	return rv;
}

// 3桁ごとのカンマを付ける (返すのは関数内部のstaticなバッファへのポインタであることに注意)
LibExport char *commaA(unsigned int value)
{
	static char s[2][14];          // return 後にも、領域が生き残る
	static volatile bool flag = 0;

	flag = !flag;
	return commaexA(value, s[flag]);
}
LibExport wchar_t *commaW(unsigned int value)
{
	static wchar_t s[2][14];          // return 後にも、領域が生き残る
	static volatile bool flag = 0;

	flag = !flag;
	return commaexW(value, s[flag]);
}

// ●3桁ごとのカンマを付ける (再入可能版。14バイトの文字列が格納できるバッファを渡すこと)
LibExport char *commaexA(unsigned int value, char *rp)
{
	char s1[11], n1, n2;

	if ( rp ) {
		wsprintf(s1, "%10u", value);

		rp[13] = 0;
		for(n1=0,n2=0 ; n1<11 ; n1++,n2++) {
			rp[12-n2] = s1[9-n1];
			if (s1[8-n1] == ' ') {
				rp = &rp[12-n2];
				break;
			}
			if (n1==2 || n1==5 || n1==8) {
				rp[12-(++n2)] = ',';
			}
		}
	}

    return rp;
}
LibExport wchar_t *commaexW(unsigned int value, wchar_t *rp)
{
	wchar_t s1[11], n1, n2;

	if ( rp ) {
		wsprintfW(s1, L"%10u", value);

		rp[13] = 0;
		for(n1=0,n2=0 ; n1<11 ; n1++,n2++) {
			rp[12-n2] = s1[9-n1];
			if (s1[8-n1] == L' ') {
				rp = &rp[12-n2];
				break;
			}
			if (n1==2 || n1==5 || n1==8) {
				rp[12-(++n2)] = L',';
			}
		}
	}

    return rp;
}

// フルパスからファイル名の部分だけを取り出す (ダブルコーテーションがあるとうまくいきません)
LibExport const char *GetOnlyFileNameA(const char *path)
{
	int i;

	if ( path ) {
		for(i=lstrlen(path) ; i>=0 ; i--) {
			if ((path[i] == '\\' || path[i] == ':') && !isKanji1A(path, i-1) ) {
				i++;
				break;
			}
		}

		return &path[i];
	}
	else {
		return NULL;
	}
}

LibExport const wchar_t *GetOnlyFileNameW(const wchar_t *path)
{
	int i;

	if ( path ) {
		for(i=lstrlenW(path) ; i>=0 ; i--) {
			if ( path[i] == L'\\' || path[i] == L':' ) {
				i++;
				break;
			}
		}

		return &path[i];
	}
	else {
		return NULL;
	}
}

// CreateDir補助関数
static int  aux_CreateDirA(char *dirname)
{
	char cdir[MAX_PATH*2]; // 現在のカレントフォルダを保存
	int  i;

	GetCurrentDirectory(_countof(cdir), cdir);
	if (SetCurrentDirectory(dirname)) {
		SetCurrentDirectory(cdir);
		return 1;
	}
	else {
		SetCurrentDirectory(cdir);
		for(i=0 ; dirname[i] ; i++) {
			if ( !isKanji1A(dirname,i-1) && dirname[i] == '\\' ) {
				dirname[i] = 0;
				CreateDirectory(dirname,NULL);
				dirname[i] = '\\';
			}
		}
		if ( !isKanji1A(dirname,i-1) && dirname[i-1] == '\\' )
			dirname[i-1] = 0;
		return CreateDirectory(dirname, NULL);
	}
}

static int  aux_CreateDirW(wchar_t *dirname)
{
	wchar_t cdir[MAX_PATH]; // 現在のカレントフォルダを保存
	int  i;

	GetCurrentDirectoryW(_countof(cdir), cdir);
	if (SetCurrentDirectoryW(dirname)) {
		SetCurrentDirectoryW(cdir);
		return 1;
	}
	else {
		SetCurrentDirectoryW(cdir);
		for(i=0 ; dirname[i] ; i++) {
			if ( dirname[i] == L'\\' ) {
				dirname[i] = 0;
				CreateDirectoryW(dirname, NULL);
				dirname[i] = L'\\';
			}
		}
		if ( dirname[i-1] == L'\\' )
			dirname[i-1] = 0;
		return CreateDirectoryW(dirname,NULL);
	}
}

// フォルダの作成(親フォルダがいなくても強制的に作成)
LibExport int  CreateDirA(const char *dirname)
{
	char *mdir = _strdup(dirname);
	int  result = 0;

	if ( mdir ) {
		result = aux_CreateDirA( mdir );
		safefree(mdir);
	}

	return result;
}

LibExport int  CreateDirW(const wchar_t *dirname)
{
	wchar_t *mdir = _wcsdup(dirname);
	int  result = 0;

	if ( mdir ) {
		result = aux_CreateDirW( mdir );
		safefree(mdir);
	}

	return result;
}

// 文字列→UINT
LibExport unsigned atouA(const char *str)
{
	unsigned int i, result = 0;

	for(i=0 ; i<10 ; i++) {
		if ( '0' <= str[i] && str[i] <= '9' ) {
			result *= 10;
			result += (str[i]-'0');
		}
		else {
			break;
		}
	}

	return result;
}

LibExport unsigned atouW(const wchar_t *str)
{
	unsigned int i, result = 0;

	for(i=0 ; i<10 ; i++) {
		if ( L'0' <= str[i] && str[i] <= L'9' ) {
			result *= 10;
			result += (str[i]-L'0');
		}
		else {
			break;
		}
	}

	return result;
}

// ディレクトリ名のみを抜き出す
// fullpathのディレクトリ名の部分をdirbufに書き出す。
// fullpathのポインタとdirbufのポインタが指している先が同じでもよい
// 成功すると dirbuf を返し、失敗するとNULLを返す
LibExport char *getDirectoryNameA(const char *fullpath, char *dirbuf, int dirbufsize)
{
	int len, i;
	char *buf;

	if ( fullpath && dirbuf ) {
		len = lstrlen(fullpath);
		buf = zalloc(len+1);

		if ( buf ) {
			lstrcpy( buf, fullpath );
			for(i=len ; i>0 && !isKanji1A(buf,i-1) && buf[i] != ':' && buf[i] != '\\' ; i--)
				;
			if ( i > 0 ) {
				buf[i+1] = 0;
			}
			else {
				buf[0] = 0;
			}

			if ( lstrlen(buf) < dirbufsize ) {
				lstrcpy(dirbuf, buf);
				safefree(buf);
				return dirbuf;
			}
			else {
				safefree(buf);
			}
		}
	}

	return NULL; // fullpath または dirbuf が NULL か、メモリが足りないなどの理由で失敗
}

LibExport wchar_t *getDirectoryNameW(const wchar_t *fullpath, wchar_t *dirbuf, int dirbufsize)
{
	int len, i;
	wchar_t *buf;

	if ( fullpath && dirbuf ) {
		len = lstrlenW(fullpath);
		buf = walloc(len+1);

		if ( buf ) {
			lstrcpyW( buf, fullpath );
			for(i=len ; i>0 && buf[i] != L':' && buf[i] != L'\\' ; i--)
				;
			if ( i > 0 ) {
				buf[i+1] = 0;
			}
			else {
				buf[0] = 0;
			}

			if ( lstrlenW(buf) < dirbufsize ) {
				lstrcpyW(dirbuf, buf);
				safefree(buf);
				return dirbuf;
			}
			else {
				safefree(buf);
			}
		}
	}

	return NULL; // fullpath または dirbuf が NULL か、メモリが足りないなどの理由で失敗
}

// 拡張子を取り除いた部分を抜き出す
// fullpathのディレクトリ名＋ファイル名の部分をdirbufに書き出す。
// fullpathのポインタとdirbufのポインタが指している先が同じでもよい
// 成功すると dirbuf を返し、失敗するとNULLを返す
LibExport char *getFileNameOnlyA(const char *fullpath, char *fnamebuf, int fnamebufsize)
{
	int len, i;
	char *buf;

	if ( fullpath && fnamebuf ) {
		len = lstrlen(fullpath);
		buf = zalloc(len+1);

		if ( buf ) {
			lstrcpy( buf, fullpath );
			for(i=len ; i>0 && buf[i] != ':' && buf[i] != '\\' && buf[i] != '.' ; i--)
				;
			if ( buf[i] == '.' ) {
				buf[i] = 0;
			}

			if ( lstrlen(buf) < fnamebufsize ) {
				lstrcpy(fnamebuf, buf);
				safefree(buf);
				return fnamebuf;
			}
			else {
				safefree(buf);
			}
		}
	}

	return NULL; // fullpath または fnamebuf が NULL か、メモリが足りないなどの理由で失敗
}

LibExport wchar_t *getFileNameOnlyW(const wchar_t *fullpath, wchar_t *fnamebuf, int fnamebufsize)
{
	int len, i;
	wchar_t *buf;

	if ( fullpath && fnamebuf ) {
		len = lstrlenW(fullpath);
		buf = walloc(len+1);

		if ( buf ) {
			lstrcpyW( buf, fullpath );
			for(i=len ; i>0 && buf[i] != L':' && buf[i] != L'\\' && buf[i] != L'.' ; i--)
				;
			if ( buf[i] == L'.' ) {
				buf[i] = 0;
			}

			if ( lstrlenW(buf) < fnamebufsize ) {
				lstrcpyW(fnamebuf, buf);
				safefree(buf);
				return fnamebuf;
			}
			else {
				safefree(buf);
			}
		}
	}

	return NULL; // fullpath または fnamebuf が NULL か、メモリが足りないなどの理由で失敗
}

LibExport char *lvGetItemStringA( HWND hListview, unsigned n, unsigned c )
{
	UINT bufsize = 256, lb;
	char *buf = NULL;

	while( 1 ) {
		buf = zalloc(bufsize);
		if ( buf ) {
			ListView_GetItemText( hListview, n, c, buf, bufsize );
			buf[bufsize-1] = 0;

			if ( (UINT)lstrlen(buf) == bufsize-1 ) {
				// バッファのサイズが足りなかった可能性がある
				free( buf ); buf = NULL;
				lb = bufsize;
				bufsize *= 2; // バッファサイズを2倍にしてやり直し
				if( lb > bufsize ) { // 桁数オーバーフロー(メモリ確保に失敗)
					return NULL;
				}
                continue;
			}
			else {
				// メモリを余分に確保してしまっているので、切りつめる
				char *tmp = (char *)realloc( buf, sizeof(char)*(lstrlen(buf)+1) );

				if ( tmp ) {
					buf = tmp;
				}
				return buf;
			}
		}
		else {
			return NULL; // メモリ確保に失敗
		}
	}
}

#define ListView_GetItemTextW(hwndLV, i, iSubItem_, pszText_, cchTextMax_) \
{ LV_ITEMW _ms_lvi;\
  _ms_lvi.iSubItem = iSubItem_;\
  _ms_lvi.cchTextMax = cchTextMax_;\
  _ms_lvi.pszText = pszText_;\
  SendMessageW((hwndLV), LVM_GETITEMTEXTW, (WPARAM)(i), (LPARAM)&_ms_lvi);\
}

LibExport wchar_t *lvGetItemStringW( HWND hListview, unsigned n, unsigned c )
{
	UINT bufsize = 256, lb;
	wchar_t *buf = NULL;

	while( 1 ) {
		buf = walloc(bufsize);
		if ( buf ) {
			LV_ITEMW _ms_lvi;
			_ms_lvi.iSubItem = c;
			_ms_lvi.cchTextMax = bufsize;
			_ms_lvi.pszText = buf;
			SendMessageW(hListview, LVM_GETITEMTEXTW, (WPARAM)n, (LPARAM)&_ms_lvi);

			buf[bufsize-1] = 0;

			if ( (UINT)lstrlenW(buf) == bufsize - 1 ) {
				// バッファのサイズが足りなかった可能性がある
				free( buf ); buf = NULL;
				lb = bufsize;
				bufsize *= 2; // バッファサイズを2倍にしてやり直し
				if( lb > bufsize ) { // 桁数オーバーフロー(メモリ確保に失敗)
					return NULL;
				}
                continue;
			}
			else {
				// メモリを余分に確保してしまっているので、切りつめる
				wchar_t *tmp = (wchar_t *)realloc( buf, sizeof(wchar_t)*(lstrlenW(buf)+1) );

				if ( tmp ) {
					buf = tmp;
				}
				return buf;
			}
		}
		else {
			return NULL; // メモリ確保に失敗
		}
	}
}

// SJIS文字列であることを考慮しつつ、strlwrする
LibExport char *sjislwr(char *str)
{
	if (str) {
		char *p = str;
		while(*p) {
			if (ISKANJI1M(*p)) {	// SJISマルチバイト１文字目だったら
				++p;				// 次の文字は強制スキップ
				if (*p == 0) {		// 突如として終端：強制終了
					break;
				}
			}
			else {
				// 処理系依存ですが、大文字→小文字変換
				if ('A' <= (unsigned char)*p && (unsigned char)*p <= 'Z') {
					*p += ('a' - 'A');
				}
			}
			++p;
		}
	}
	return str;
}

// SJIS文字列であることを考慮しつつ、struprする
LibExport char *sjisupr(char *str)
{
	if (str) {
		char *p = str;
		while(*p) {
			if (ISKANJI1M(*p)) {	// SJISマルチバイト１文字目だったら
				++p;				// 次の文字は強制スキップ
				if (*p == 0) {		// 突如として終端：強制終了
					break;
				}
			}
			else {
				// 処理系依存ですが、小文字→大文字変換
				if ('a' <= (unsigned char)*p && (unsigned char)*p <= 'z') {
					*p -= ('a' - 'A');
				}
			}
			++p;
		}
	}
	return str;
}

// SJIS文字列であることを考慮しつつ、strstrする
LibExport char *sjisstr( const char *str1, const char *str2 )
{
	if (str1 != NULL && str2 != NULL) {
		if (str2[0] == 0) {
			// str2に長さ0の文字列が与えられたら、str1を返す
			return (char *)str1;
		}

		size_t str1len = strlen(str1);
		size_t str2len = strlen(str2);
		size_t i = 0;

		while(str1len - i >= str2len) {
			if (0 == memcmp(&str1[i], str2, str2len)) {
				// 見つかった
				return (char *)&str1[i];
			}

			if (ISKANJI1M(str1[i])) {
				// さきほど比較した文字列の第１バイト目が、
				// マルチバイト文字としての第１バイト目だったら
				i += 2;
			}
			else {
				++i;
			}
		}
	}
	return NULL;	// 見つからなかった
}

// SJIS文字列であることを考慮しつつ、strstriする。
LibExport char *sjisstri( const char *str1, const char *str2 )
{
	char *p, *q, *r = NULL;
	UINT i = 0;

	if (str1 != NULL && str2 != NULL) {
		p = _strdup( str1 );
		if ( p ) {
			q = _strdup( str2 );
			if ( q ) {
				r = sjisstr(sjislwr(p), sjislwr(q));
				i = (UINT)(r - p);
				free( q );
			}
			free( p );
		}
		return r?(char *)(str1 + i):NULL;
	}
	else {
		return NULL;
	}
}

// case sensitiveでないstrstr
LibExport char *strstriA( const char *str1, const char *str2 )
{
	char *p, *q, *r = NULL;
	UINT i = 0;

	if (str1 != NULL && str2 != NULL) {
		p = _strdup( str1 );
		if ( p ) {
			q = _strdup( str2 );
			if ( q ) {
#pragma warning( disable : 4996 )
				r = strstr(_strlwr(p), _strlwr(q));
#pragma warning( default : 4996 )
				i = (UINT)(r - p);
				free( q );
			}
			free( p );
		}
		return r?(char *)(str1 + i):NULL;
	}
	else {
		return NULL;
	}
}

LibExport wchar_t *strstriW( const wchar_t *str1, const wchar_t *str2 )
{
	wchar_t *p, *q, *r = NULL;
	UINT i = 0;

	if (str1 != NULL && str2 != NULL) {
		p = _wcsdup( str1 );
		if ( p ) {
			q = _wcsdup( str2 );
			if ( q ) {
#pragma warning( disable : 4996 )
				r = wcsstr(_wcslwr(p), _wcslwr(q));
#pragma warning( default : 4996 )
				i = (UINT)(r - p);
				free( q );
			}
			free( p );
		}
		return r?(wchar_t *)(str1 + i):NULL;
	}
	else {
		return NULL;
	}
}

// 文字列str中のrep1をすべてrep2に置き換える
// 戻り値：変換後の文字列へのポインタ。使い終わったら解放(free)すること
LibExport char *replacestrA( const char *str, const char *rep1, const char *rep2 )
{
	wchar_t *vw = NULL;	// ワークエリア

	if ( str && rep1 && rep1[0] ) {
		if ( rep2 == NULL ) {
            rep2 = "";
		}

		try {
			// 検索対象文字列・検索文字列・置換文字列を、それぞれwidecharに変換する
			// まずは検索対象文字列
			vw = mb2wc(str);
			wstring w_str(vw);
			safefree(vw);

			// 次に検索文字列
			vw = mb2wc(rep1);
			wstring w_rep1(vw);
			safefree(vw);
			wstring::size_type w_rep1_length = w_rep1.length();

			// 最後に置換後文字列
			vw = mb2wc(rep2);
			wstring w_rep2(vw);
			safefree(vw);
			wstring::size_type w_rep2_length = w_rep2.length();

			// 文字列strの始めの方からrep1をサーチし、rep2に置き換えていく
			wstring::size_type p = 0;	// サーチ中の位置
			wstring::size_type rp;		// rep1が見つかった位置

			while(1) {
				rp = w_str.find(w_rep1, p);
				if ( rp == wstring::npos ) {
					break;
				}
				else {
					w_str.replace(rp, w_rep1_length, w_rep2);
					p = rp + w_rep2_length;
				}
			}

			// 置換後文字列はWideCharであるため、MultiByteに変換してから返却する
			// 返却値は、あとでfree()する必要あり
			return wc2mb(w_str.c_str());
		}
		catch(...) {
			safefree(vw);
			return NULL;
		}
	}
	else {
		return NULL;
	}
}

LibExport wchar_t *replacestrW( const wchar_t *str, const wchar_t *rep1, const wchar_t *rep2 )
{
	if ( str && rep1 && rep1[0] ) {
		if ( rep2 == NULL ) {
            rep2 = L"";
		}

		try {
			// 検索対象文字列・検索文字列・置換文字列を、それぞれwstringに代入する
			// まずは検索対象文字列
			wstring w_str(str);

			// 次に検索文字列
			wstring w_rep1(rep1);
			wstring::size_type w_rep1_length = w_rep1.length();

			// 最後に置換後文字列
			wstring w_rep2(rep2);
			wstring::size_type w_rep2_length = w_rep2.length();

			// 文字列strの始めの方からrep1をサーチし、rep2に置き換えていく
			wstring::size_type p = 0;	// サーチ中の位置
			wstring::size_type rp;		// rep1が見つかった位置

			while(1) {
				rp = w_str.find(w_rep1, p);
				if ( rp == wstring::npos ) {
					break;
				}
				else {
					w_str.replace(rp, w_rep1_length, w_rep2);
					p = rp + w_rep2_length;
				}
			}

			// 置換結果を_wcsdup(_strdup)して返す
			return _wcsdup(w_str.c_str());
		}
		catch(...) {
			return NULL;
		}
	}
	else {
		return NULL;
	}
}

	
// GetLastError()の戻り値を渡すと、エラーメッセージを文字列にして返却する(戻り値は解放しないこと)
LibExport char *getLastErrorStringMJPA(BOOL modeJP, DWORD errorcode)
{
    char *buf = NULL;
	static char *stbuf = NULL;

	safefree( stbuf );

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL, errorcode, modeJP ? MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&buf,
                  0, NULL);

    if( buf ) {
        stbuf = zalloc(lstrlen( buf ) + 1);
		if ( stbuf ) {
			int i, l = lstrlen(buf);
			for(i=0 ; i<l ; i++) { // コントロールコードがあったら、スペースに置き換えておく
				if ( 0 < buf[i] && buf[i] < ' ' ) {
					buf[i] = ' ';
				}
			}
            lstrcpy(stbuf, buf);
		}
        LocalFree(buf);
    }
	else {
        return "FormatMessage() error";
	}

	return stbuf ? stbuf : "calloc() error";
}

LibExport wchar_t *getLastErrorStringMJPW(BOOL modeJP, DWORD errorcode)
{
    wchar_t *buf = NULL;
	static wchar_t *stbuf = NULL;

	safefree( stbuf );

    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
                   NULL, errorcode, modeJP ? MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPWSTR)&buf,
                   0, NULL);

    if( buf ) {
        stbuf = walloc(lstrlenW( buf ) + 1);
		if ( stbuf ) {
			int i, l = lstrlenW(buf);
			for(i=0 ; i<l ; i++) { // コントロールコードがあったら、スペースに置き換えておく
				if ( 0 < buf[i] && buf[i] < L' ' ) {
					buf[i] = L' ';
				}
			}
            lstrcpyW(stbuf, buf);
		}
        LocalFree(buf);
    }
	else {
        return L"FormatMessage() error";
	}

	return stbuf ? stbuf : L"calloc() error";
}

typedef BOOL (WINAPI *SR_SET_RESTORE_POINT)(PRESTOREPOINTINFO, PSTATEMGRSTATUS);
typedef BOOL (WINAPI *SR_SET_RESTORE_POINTW)(PRESTOREPOINTINFOW, PSTATEMGRSTATUS);

// 復元ポイントを作成する
// 引数　：name = 作成する復元ポイントに付ける名前(MAX_DESCバイトまで)
// 戻り値：成功 ERROR_SUCCESS(0), 失敗 0以外
//   ※失敗時の値は、SRSetRestorePointがSTATEMGRSTATUSのnStatusに設定する値
//     ただし、SRSetRestorePoint以外(DLLのアタッチ等)での失敗は0xffffffff
LibExport UINT createRestorePointA( const char *name )
{
	SR_SET_RESTORE_POINT pfSRSetRestorePoint = NULL;
	HMODULE          hDLL = NULL;
	RESTOREPOINTINFO RstPt;
	STATEMGRSTATUS   MgrStat;
	UINT             result = 0;

	// 変数の初期化
	ZeroMemory( &RstPt, sizeof(RstPt) );
	ZeroMemory( &MgrStat, sizeof(MgrStat) );

	hDLL = ::LoadLibrary_System32("srclient.dll");
	if ( hDLL ) {
		pfSRSetRestorePoint = (SR_SET_RESTORE_POINT)::GetProcAddress(hDLL,"SRSetRestorePointA");
	}

	if ( pfSRSetRestorePoint ) {
		RstPt.dwEventType = BEGIN_SYSTEM_CHANGE;
		RstPt.dwRestorePtType = MODIFY_SETTINGS;
		lstrcpyn(RstPt.szDescription, name?name:"Restore Point", MAX_DESC-1);

		// 復元ポイントの作成（1回目の呼び出し）
		if ( pfSRSetRestorePoint(&RstPt, &MgrStat) ) {
			RstPt.dwEventType = END_SYSTEM_CHANGE;
			RstPt.llSequenceNumber = MgrStat.llSequenceNumber;

			// 復元ポイントの作成（2回目の呼び出し）- コミット
			//  ※ここでは、単純に復元ポイントを作るだけなので、何もせずに確定登録とする
			pfSRSetRestorePoint(&RstPt, &MgrStat);
		}

		// 失敗時の値は、SRSetRestorePointがSTATEMGRSTATUSのnStatusに設定する値
		// 成功の場合は、これで 0 が入ってきてくれる
		result = MgrStat.nStatus;
	}
	else {
		// その他の理由での失敗は、0xffffffff を返却
		result = 0xffffffff;
	}

	if ( hDLL ) {
		FreeLibrary( hDLL );
	}

	// 注意：成功時は0が返却されます
	return result;
}

LibExport UINT createRestorePointW( const wchar_t *name )
{
	SR_SET_RESTORE_POINTW pfSRSetRestorePoint = NULL;
	HMODULE          hDLL = NULL;
	RESTOREPOINTINFOW RstPt;
	STATEMGRSTATUS   MgrStat;
	UINT             result = 0;

	// 変数の初期化
	ZeroMemory( &RstPt, sizeof(RstPt) );
	ZeroMemory( &MgrStat, sizeof(MgrStat) );

	{ // Windows XP
		hDLL = ::LoadLibrary_System32W(L"srclient.dll");
		if ( hDLL ) {
			pfSRSetRestorePoint = (SR_SET_RESTORE_POINTW)::GetProcAddress(hDLL,"SRSetRestorePointW");
		}
	}

	if ( pfSRSetRestorePoint ) {
		RstPt.dwEventType = BEGIN_SYSTEM_CHANGE;
		RstPt.dwRestorePtType = MODIFY_SETTINGS;
		lstrcpynW(RstPt.szDescription, name?name:L"Restore Point", MAX_DESC-1);

		// 復元ポイントの作成（1回目の呼び出し）
		if ( pfSRSetRestorePoint(&RstPt, &MgrStat) ) {
			RstPt.dwEventType = END_SYSTEM_CHANGE;
			RstPt.llSequenceNumber = MgrStat.llSequenceNumber;

			// 復元ポイントの作成（2回目の呼び出し）- コミット
			//  ※ここでは、単純に復元ポイントを作るだけなので、何もせずに確定登録とする
			pfSRSetRestorePoint(&RstPt, &MgrStat);
		}

		// 失敗時の値は、SRSetRestorePointがSTATEMGRSTATUSのnStatusに設定する値
		// 成功の場合は、これで 0 が入ってきてくれる
		result = MgrStat.nStatus;
	}
	else {
		// その他の理由での失敗は、0xffffffff を返却
		result = 0xffffffff;
	}

	if ( hDLL ) {
		FreeLibrary( hDLL );
	}

	// 注意：成功時は0が返却されます
	return result;
}

LibExport int lvGetIconNumber( HWND hListView, int cur )
{
	LVITEM lvItem;

	ZeroMemory( &lvItem, sizeof(LVITEM) );
	lvItem.mask = LVIF_IMAGE;
	lvItem.iItem = cur;
	ListView_GetItem( hListView, &lvItem );

	return lvItem.iImage;
}

LibExport LPARAM lvGetLParam( HWND hListView, int cur )
{
	LVITEM lvItem;

	ZeroMemory( &lvItem, sizeof(LVITEM) );
	lvItem.mask = LVIF_PARAM;
	lvItem.iItem = cur;
	ListView_GetItem( hListView, &lvItem );

	return lvItem.lParam;
}

// ファイル名を指定して、ファイルサイズを取得する。ただし、ファイルサイズは2GBまで。
// ファイルが存在しない場合は -1 が返る
LibExport DWORD getFileSizeA( const char *fname )
{
	HANDLE hFile;
	DWORD dwFileSizeLow = (DWORD)-1;

	hFile = CreateFile( fname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
		                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if ( hFile ) {
		dwFileSizeLow = GetFileSize(hFile, NULL);
		CloseHandle(hFile);
	}
	return dwFileSizeLow;
}

LibExport DWORD getFileSizeW( const wchar_t *fname )
{
	HANDLE hFile;
	DWORD dwFileSizeLow = (DWORD)-1;

	hFile = CreateFileW( fname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
		                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if ( hFile ) {
		dwFileSizeLow = GetFileSize(hFile, NULL);
		CloseHandle(hFile);
	}
	return dwFileSizeLow;
}

// ファイル名を指定して、ファイルサイズを取得する。ただし、ファイルサイズの上限はQWORD.
// ファイルが存在しない場合は -1 が返る
LibExport UINT64 getFileSizeQA( const char *fname )
{
	HANDLE hFile;
	DWORD dwFileSizeLow = (DWORD)-1, dwFileSizeHigh = (DWORD)-1;

	hFile = CreateFile( fname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
		                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if ( hFile ) {
		dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
		if ( dwFileSizeLow == -1 ) {
			if ( GetLastError() != NO_ERROR ) {
				CloseHandle(hFile);
				return (UINT64)-1;
			}
		}
		CloseHandle(hFile);
	}
	return (UINT64)0x100000000 * (UINT64)dwFileSizeHigh + (UINT64)dwFileSizeLow;
}
LibExport UINT64 getFileSizeQW( const wchar_t *fname )
{
	HANDLE hFile;
	DWORD dwFileSizeLow = (DWORD)-1, dwFileSizeHigh = (DWORD)-1;

	hFile = CreateFileW( fname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
		                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if ( hFile ) {
		dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
		if ( dwFileSizeLow == -1 ) {
			if ( GetLastError() != NO_ERROR ) {
				CloseHandle(hFile);
				return (UINT64)-1;
			}
		}
		CloseHandle(hFile);
	}
	return (UINT64)0x100000000 * (UINT64)dwFileSizeHigh + (UINT64)dwFileSizeLow;
}

// Windowsのバージョンを、整数部×100+小数部で返す
LibExport WORD tf_getWinVer( void )
{
	OSVERSIONINFO verinfo;

	verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx( &verinfo );

	if ( verinfo.dwPlatformId != VER_PLATFORM_WIN32_NT ) {
		if (HIWORD(verinfo.dwBuildNumber)) {
			verinfo.dwMajorVersion = (DWORD)(HIWORD(verinfo.dwBuildNumber) >> 8);
			verinfo.dwMinorVersion = (DWORD)(HIWORD(verinfo.dwBuildNumber) & 0xff);
		}
		else { // Windows XPによってWindows 95に偽装されている
			verinfo.dwMajorVersion = 4;
			verinfo.dwMinorVersion = 0;
		}
	}

	return (WORD)(verinfo.dwMajorVersion*100 + verinfo.dwMinorVersion);
}

// WindowsのプラットフォームIDを返す
// NT系より先の未来があるかもしれないので、常にVER_PLATFORM_WIN32_NTを返すようなことはしない
LibExport DWORD tf_GetPlatform( void )
{
	OSVERSIONINFO verinfo;

	verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx( &verinfo );

	return verinfo.dwPlatformId;
}

#if _MSC_VER < 1500
#ifndef _WIN64
// WindowsがNT系であれば、TRUEを返す
LibExport BOOL tf_isNT( void )
{
	return (tf_GetPlatform() == VER_PLATFORM_WIN32_NT)?TRUE:FALSE;
}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
// ↑現在ではマクロ定義で「常に１」となる（本バージョンはWinXP以降の動作であり、必ずNT系となるので）

// dir + file を実行し、dir に格納する(ファイル名をダブルコーテーションで囲まないこと)
LibExport char *dir_add_fileA( char *dir, const char *fname )
{
	if ( dir && fname ) {
		// dirの終わりが\で終わっている場合は、\を追加しない
		dir_add_bsA(dir);
		lstrcat(dir, fname);
	}
	return dir;
}

LibExport wchar_t *dir_add_fileW( wchar_t *dir, const wchar_t *fname )
{
	if ( dir && fname ) {
		// dirの終わりが\で終わっている場合は、\を追加しない
		dir_add_bsW(dir);
		lstrcatW(dir, fname);
	}
	return dir;
}

// dir の後ろに \ が付いていない場合に \ を付加する(ファイル名をダブルコーテーションで囲まないこと)
LibExport char *dir_add_bsA( char *dir )
{
	if ( dir ) {
		// dirの終わりが\で終わっている場合は、\を追加しない
		int iLen = lstrlen( dir );
		if ( !(iLen > 0 && dir[iLen-1] == '\\' && !isKanji1A(dir, iLen-2)) ) {
			lstrcat(dir, "\\");
		}
		return dir;
	}
	return NULL;
}

LibExport wchar_t *dir_add_bsW( wchar_t *dir )
{
	if ( dir ) {
		// dirの終わりが\で終わっている場合は、\を追加しない
		int iLen = lstrlenW( dir );
		if ( !(iLen > 0 && dir[iLen-1] == L'\\') ) {
			lstrcatW(dir, L"\\");
		}
		return dir;
	}
	return NULL;
}

// マルチバイトからワイドキャラクタへの変換。(使用後はfreeで開放すること)
LibExport wchar_t *mb2wc( const char *mbstr )
{
	wchar_t *wcstr = NULL;

	if ( mbstr ) {
		int i = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, mbstr, -1, NULL, 0);
		if ( i != 0 ) {
			++i;
			wcstr = walloc(i);
			if ( wcstr ) {
				if ( 0 == MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, mbstr, -1, wcstr, i) ) {
					free( wcstr );
					return NULL;
				}
			}
		}
	}
	return wcstr;
}

// ワイドキャラクタからマルチバイトへの変換。(使用後はfreeで開放すること)
LibExport char *wc2mb( const wchar_t *wcstr )
{
	char *mbstr = NULL;

	if ( wcstr ) {
		int i = WideCharToMultiByte(GetACP(), 0, wcstr, -1, NULL, 0, NULL, NULL);
		if ( i != 0 ) {
			++i;
			mbstr = zalloc(i);
			if ( mbstr ) {
				if ( 0 == WideCharToMultiByte(GetACP(), 0, wcstr, -1, mbstr, i, NULL, NULL) ) {
					free( mbstr );
					return NULL;
				}
			}
		}
	}
	return mbstr;
}


// -------------------------------- MD5算出 --------------------------------
// 下記ソースコードは、オリジナルの MD5 の Cソースコードを参考に作られて
// います。
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
  ULONG i[2];                   /* number of _bits_ handled mod 2^64 */
  ULONG buf[4];                                    /* scratch buffer */
  unsigned char in[64];                              /* input buffer */
  unsigned char digest[16];     /* actual digest after MD5Final call */
} MD5_CTX;

void MD5Init( MD5_CTX *mdContext );
void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen );
void MD5Final( MD5_CTX *mdContext );
static void Transform( ULONG *buf, ULONG *in );

static unsigned char PADDING[64] = {
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* F, G and H are basic MD5 functions: selection, majority, parity */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z))) 

/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
  {(a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
   (a) = ROTATE_LEFT ((a), (s)); \
   (a) += (b); \
  }
#define GG(a, b, c, d, x, s, ac) \
  {(a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
   (a) = ROTATE_LEFT ((a), (s)); \
   (a) += (b); \
  }
#define HH(a, b, c, d, x, s, ac) \
  {(a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
   (a) = ROTATE_LEFT ((a), (s)); \
   (a) += (b); \
  }
#define II(a, b, c, d, x, s, ac) \
  {(a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
   (a) = ROTATE_LEFT ((a), (s)); \
   (a) += (b); \
  }

void MD5Init( MD5_CTX *mdContext )
{
  mdContext->i[0] = mdContext->i[1] = (ULONG)0;

  /* Load magic initialization constants.
   */
  mdContext->buf[0] = (ULONG)0x67452301;
  mdContext->buf[1] = (ULONG)0xefcdab89;
  mdContext->buf[2] = (ULONG)0x98badcfe;
  mdContext->buf[3] = (ULONG)0x10325476;
}

void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen )
{
  ULONG in[16];
  int mdi;
  unsigned int i, ii;

  /* compute number of bytes mod 64 */
  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

  /* update number of bits */
  if ((mdContext->i[0] + ((ULONG)inLen << 3)) < mdContext->i[0])
    mdContext->i[1]++;
  mdContext->i[0] += ((ULONG)inLen << 3);
  mdContext->i[1] += ((ULONG)inLen >> 29);

  while (inLen--) {
    /* add new character to buffer, increment mdi */
    mdContext->in[mdi++] = *inBuf++;

    /* transform if necessary */
    if (mdi == 0x40) {
      for (i = 0, ii = 0; i < 16; i++, ii += 4)
        in[i] = (((ULONG)mdContext->in[ii+3]) << 24) |
                (((ULONG)mdContext->in[ii+2]) << 16) |
                (((ULONG)mdContext->in[ii+1]) << 8) |
                ((ULONG)mdContext->in[ii]);
      Transform (mdContext->buf, in);
      mdi = 0;
    }
  }
}

void MD5Final( MD5_CTX *mdContext )
{
  ULONG in[16];
  int mdi;
  unsigned int i, ii;
  unsigned int padLen;

  /* save number of bits */
  in[14] = mdContext->i[0];
  in[15] = mdContext->i[1];

  /* compute number of bytes mod 64 */
  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

  /* pad out to 56 mod 64 */
  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
  MD5Update (mdContext, PADDING, padLen);

  /* append length in bits and transform */
  for (i = 0, ii = 0; i < 14; i++, ii += 4)
    in[i] = (((ULONG)mdContext->in[ii+3]) << 24) |
            (((ULONG)mdContext->in[ii+2]) << 16) |
            (((ULONG)mdContext->in[ii+1]) << 8) |
            ((ULONG)mdContext->in[ii]);
  Transform (mdContext->buf, in);

  /* store buffer in digest */
  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
    mdContext->digest[ii+1] =
      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
    mdContext->digest[ii+2] =
      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
    mdContext->digest[ii+3] =
      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
  }
}

/* Basic MD5 step. Transform buf based on in.
 */
static void Transform( ULONG *buf, ULONG *in )
{
  ULONG a = buf[0], b = buf[1], c = buf[2], d = buf[3];

  /* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
  FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */
  FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */
  FF ( c, d, a, b, in[ 2], S13,  606105819); /* 3 */
  FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */
  FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */
  FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */
  FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */
  FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */
  FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */
  FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */
  FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */
  FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */
  FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */
  FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */
  FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */
  FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */

  /* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
  GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */
  GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */
  GG ( c, d, a, b, in[11], S23,  643717713); /* 19 */
  GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */
  GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */
  GG ( d, a, b, c, in[10], S22,   38016083); /* 22 */
  GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */
  GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */
  GG ( a, b, c, d, in[ 9], S21,  568446438); /* 25 */
  GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */
  GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */
  GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */
  GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */
  GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */
  GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */
  GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */

  /* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
  HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */
  HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */
  HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */
  HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */
  HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */
  HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */
  HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */
  HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */
  HH ( a, b, c, d, in[13], S31,  681279174); /* 41 */
  HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */
  HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */
  HH ( b, c, d, a, in[ 6], S34,   76029189); /* 44 */
  HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */
  HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */
  HH ( c, d, a, b, in[15], S33,  530742520); /* 47 */
  HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */

  /* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
  II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */
  II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */
  II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */
  II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */
  II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */
  II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */
  II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */
  II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */
  II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */
  II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */
  II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */
  II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */
  II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */
  II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */
  II ( c, d, a, b, in[ 2], S43,  718787259); /* 63 */
  II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */

  buf[0] += a;
  buf[1] += b;
  buf[2] += c;
  buf[3] += d;
}
// -------------------------------- MD5算出[END] --------------------------------

// メモリ上のデータからMD5を算出する
// data  : データの格納されたメモリの先頭アドレス
// datalength : dataの長さ（バイト単位）
// md5   : char [33] 文字型配列。MD5の算出結果を文字列にして格納する
// 戻り値: 成功=1、失敗=0（失敗時はmd5の指すアドレスの中のデータは変えない）
LibExport BOOL md5dataA( const void *data, int datalength, char *md5 )
{
	MD5_CTX mdContext;

	if ( !data || !datalength || !md5 ) {
		return FALSE;
	}

	MD5Init( &mdContext );
	MD5Update(&mdContext, (unsigned char *)data, datalength);
	MD5Final( &mdContext );

	wsprintf(md5, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
		mdContext.digest[0],
		mdContext.digest[1],
		mdContext.digest[2],
		mdContext.digest[3],
		mdContext.digest[4],
		mdContext.digest[5],
		mdContext.digest[6],
		mdContext.digest[7],
		mdContext.digest[8],
		mdContext.digest[9],
		mdContext.digest[10],
		mdContext.digest[11],
		mdContext.digest[12],
		mdContext.digest[13],
		mdContext.digest[14],
		mdContext.digest[15]);

	return true;
}

LibExport BOOL md5dataW( const void *data, int datalength, wchar_t *md5 )
{
	MD5_CTX mdContext;

	if ( !data || !datalength || !md5 ) {
		return FALSE;
	}

	MD5Init( &mdContext );
	MD5Update(&mdContext, (unsigned char *)data, datalength);
	MD5Final( &mdContext );

	wsprintfW(md5, L"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
		mdContext.digest[0],
		mdContext.digest[1],
		mdContext.digest[2],
		mdContext.digest[3],
		mdContext.digest[4],
		mdContext.digest[5],
		mdContext.digest[6],
		mdContext.digest[7],
		mdContext.digest[8],
		mdContext.digest[9],
		mdContext.digest[10],
		mdContext.digest[11],
		mdContext.digest[12],
		mdContext.digest[13],
		mdContext.digest[14],
		mdContext.digest[15]);

	return true;
}

// ファイルからMD5を算出する
// fname : ファイル名
// md5   : char [33] 文字型配列。MD5の算出結果を文字列にして格納する
// 戻り値: 成功=1、失敗=0（失敗時はmd5の指すアドレスの中のデータは変えない）
LibExport BOOL md5fileA( const char *fname, char *md5, md5file_callback cbfunc )
{
	FILE *fp;
	MD5_CTX mdContext;
	unsigned int bytes;
	unsigned char data[1024];

	if ( !fname || !md5 ) {
		return FALSE;
	}

	if ( 0 != fopen_s(&fp, fname, "rb") ) {
		return FALSE;
	}

	fseek(fp, 0, SEEK_END);
	long fsize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	MD5Init( &mdContext );
	while ((bytes = (unsigned int)fread(data, 1, 1024, fp)) != 0) {
		MD5Update(&mdContext, data, bytes);
		if (cbfunc) {
			if (FALSE == cbfunc(ftell(fp), fsize)) {
				fclose(fp);
				return FALSE;
			}
		}
	}

	MD5Final( &mdContext );
	fclose(fp);

	wsprintf(md5, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
		mdContext.digest[0],
		mdContext.digest[1],
		mdContext.digest[2],
		mdContext.digest[3],
		mdContext.digest[4],
		mdContext.digest[5],
		mdContext.digest[6],
		mdContext.digest[7],
		mdContext.digest[8],
		mdContext.digest[9],
		mdContext.digest[10],
		mdContext.digest[11],
		mdContext.digest[12],
		mdContext.digest[13],
		mdContext.digest[14],
		mdContext.digest[15]);

	return TRUE;
}

LibExport BOOL md5fileW( const wchar_t *fname, wchar_t *md5, md5file_callback cbfunc )
{
	FILE *fp;
	MD5_CTX mdContext;
	unsigned int bytes;
	unsigned char data[1024];

	if ( !fname || !md5 ) {
		return FALSE;
	}

	if ( 0 != _wfopen_s(&fp, fname, L"rb") ) {
		return FALSE;
	}

	fseek(fp, 0, SEEK_END);
	long fsize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	MD5Init( &mdContext );
	while ((bytes = (unsigned int)fread(data, 1, 1024, fp)) != 0) {
		MD5Update(&mdContext, data, bytes);
		if (cbfunc) {
			if (FALSE == cbfunc(ftell(fp), fsize)) {
				fclose(fp);
				return FALSE;
			}
		}
	}

	MD5Final( &mdContext );
	fclose(fp);

	wsprintfW(md5, L"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
		mdContext.digest[0],
		mdContext.digest[1],
		mdContext.digest[2],
		mdContext.digest[3],
		mdContext.digest[4],
		mdContext.digest[5],
		mdContext.digest[6],
		mdContext.digest[7],
		mdContext.digest[8],
		mdContext.digest[9],
		mdContext.digest[10],
		mdContext.digest[11],
		mdContext.digest[12],
		mdContext.digest[13],
		mdContext.digest[14],
		mdContext.digest[15]);

	return TRUE;
}

// 自らのMD5値を取得・比較（ただし、比較元MD5が'x'32個なら比較しない
// fname    : チェック対象のファイル名(NULLのときは、自プログラム名を使用)
// root     : 最終正常起動日時を記録するためのレジストリのハイブ
// regkey   : 最終正常起動日時を記録するためのレジストリのキー
// lasttime : 前回正常起動日時を返す32バイト以上のエリア(NULLのときは無視)
//   なお、root == NULL の場合は、regkey をファイル名と見なして、そこへ記録する。
//   regkey == NULL の時は、記録を行わない。
// 戻り値 = 0 : MD5不一致、 1 : MD5一致、 2 : 未判明、 3 : 自プログラム名取得不可
int md5FileCheckA( const char *fname, HKEY root, const char *regkey, char *lasttime )
{
	// 改変チェック用
	const static char sz_exe_md5[16+32+2] = "XX_SZ_EXE_MD5_XXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
	const char *exename;
	char ownname[MAX_PATH*2];
	char datetime[32];
	UINT a, b;
	int  rc = 2;
	HKEY  hkey;

	// 前回最終正常起動日時を読み出し
	if ( regkey && lasttime ) {
		HKEY  hkey;

		if ( root ) {
			if ( ERROR_SUCCESS == RegOpenKeyEx(root, regkey, NULL, KEY_QUERY_VALUE, &hkey ) ) {
				DWORD dwSize = 32 * sizeof(char);

				RegQueryValueEx(hkey, "LastNormalBoot", NULL, NULL, (LPBYTE)lasttime, &dwSize);
				RegCloseKey( hkey );
			}
		}
		else {
            GetPrivateProfileString( "MD5Check", "LastNormalBoot", "None", lasttime, 32, regkey );
		}
	}

	// どのファイル名を使うか？
	if ( fname ) {
		exename = fname;
	}
	else {	// NULLのときは、自プログラム名を使用
		// 実行ファイル名の取得
		if ( !GetModuleFileName(NULL, ownname, _countof(ownname)) ) {
			return 3;
		}
		exename = ownname;
    }
	
	for(b=0,a=0 ; a<32 ; ++a) {
		if ( sz_exe_md5[16+a] != 'x' ) {
			b = 1;
			break;
		}
	}

	if ( b == 1 ) {
		char md5[33] = "error";
		unsigned char *fdata;
		FILE *fp;

		if ( 0 == fopen_s(&fp, exename, "rb") ) {
			fseek(fp, 0, SEEK_END);
			long fsize = ftell(fp);
			fseek(fp, 0, SEEK_SET);

			// メモリ確保
			fdata = (unsigned char *)zalloc(fsize);
			if ( fdata ) {
				// ファイル読みだし
				fread(fdata, fsize, 1, fp);
				// XX_SZ_EXE_MD5_XX より後ろの32文字のバイト列をxで埋めてからMD5の取得をする
				for(a=0 ; a<(UINT)(fsize/sizeof(char))-16 ; ++a) {
                    if ( fdata[a   ] == (unsigned char)sz_exe_md5[0] &&
						 fdata[a+ 1] == (unsigned char)sz_exe_md5[1] &&
						 fdata[a+ 2] == (unsigned char)sz_exe_md5[2] &&
						 fdata[a+ 3] == (unsigned char)sz_exe_md5[3] &&
						 fdata[a+ 4] == (unsigned char)sz_exe_md5[4] &&
						 fdata[a+ 5] == (unsigned char)sz_exe_md5[5] &&
						 fdata[a+ 6] == (unsigned char)sz_exe_md5[6] &&
						 fdata[a+ 7] == (unsigned char)sz_exe_md5[7] &&
						 fdata[a+ 8] == (unsigned char)sz_exe_md5[8] &&
						 fdata[a+ 9] == (unsigned char)sz_exe_md5[9] &&
						 fdata[a+10] == (unsigned char)sz_exe_md5[10] &&
						 fdata[a+11] == (unsigned char)sz_exe_md5[11] &&
						 fdata[a+12] == (unsigned char)sz_exe_md5[12] &&
						 fdata[a+13] == (unsigned char)sz_exe_md5[13] &&
						 fdata[a+14] == (unsigned char)sz_exe_md5[14] &&
						 fdata[a+15] == (unsigned char)sz_exe_md5[15] ) {

						for(b=0 ; b<32 ; ++b) {
                            fdata[a+16+b] = 'x';
						}

						if ( md5dataA(fdata, fsize, md5) ) {
							if ( lstrcmpi(md5, &sz_exe_md5[16]) != 0 ) {
								// MD5不一致
								rc = 0;
							}
							else {
								// MD5一致
                                rc = 1;

								// 現在日時を記録
								if ( regkey ) {
									SYSTEMTIME st;

									GetLocalTime(&st);
									wsprintf(datetime, "%5d/%2d/%2d %2d:%02d:%02d",
										st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
									if ( root ) {
										if ( ERROR_SUCCESS == RegOpenKeyEx(root, regkey, NULL, KEY_WRITE, &hkey ) ) {
											RegSetValueEx(hkey, "LastNormalBoot", NULL, REG_SZ, (LPBYTE)datetime, sizeof(char)*(lstrlen(datetime)+1));
											RegCloseKey( hkey );
										}
									}
									else {
                                        WritePrivateProfileString( "MD5Check", "LastNormalBoot", datetime, regkey );
									}
								}
							}
						}
						break;
					}
				}
				safefree(fdata);
			}
			fclose(fp);
		}
	}

	return rc;
}

int md5FileCheckW( const wchar_t *fname, HKEY root, const wchar_t *regkey, wchar_t *lasttime )
{
	// 改変チェック用
	const static wchar_t sz_exe_md5[16+32+2] = L"XX_SZ_EXE_MD5_XXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
	const wchar_t *exename;
	wchar_t ownname[MAX_PATH];
	wchar_t datetime[32];
	UINT a, b;
	int  rc = 2;
	HKEY  hkey;

	// 前回最終正常起動日時を読み出し
	if ( regkey && lasttime ) {
		HKEY  hkey;

		if ( root ) {
			if ( ERROR_SUCCESS == RegOpenKeyExW(root, regkey, NULL, KEY_QUERY_VALUE, &hkey ) ) {
				DWORD dwSize = 32 * sizeof(wchar_t);

				RegQueryValueExW(hkey, L"LastNormalBoot", NULL, NULL, (LPBYTE)lasttime, &dwSize);
				RegCloseKey( hkey );
			}
		}
		else {
            GetPrivateProfileStringW( L"MD5Check", L"LastNormalBoot", L"None", lasttime, 32, regkey );
		}
	}

	// どのファイル名を使うか？
	if ( fname ) {
		exename = fname;
	}
	else {	// NULLのときは、自プログラム名を使用
		// 実行ファイル名の取得
		if ( !GetModuleFileNameW(NULL, ownname, _countof(ownname)) ) {
			return 3;
		}
		exename = ownname;
    }
	
	for(b=0,a=0 ; a<32 ; ++a) {
		if ( sz_exe_md5[16+a] != L'x' ) {
			b = 1;
			break;
		}
	}

	if ( b == 1 ) {
		wchar_t md5[33] = L"error";
		wchar_t *fdata;
		FILE *fp;

		if ( 0 == _wfopen_s(&fp, exename, L"rb") ) {
			fseek(fp, 0, SEEK_END);
			long fsize = ftell(fp);
			fseek(fp, 0, SEEK_SET);

			// メモリ確保
			fdata = (wchar_t *)walloc(fsize);
			if ( fdata ) {
				// ファイル読みだし
				fread(fdata, fsize, 1, fp);
				// XX_SZ_EXE_MD5_XX より後ろの32文字のバイト列をxで埋めてからMD5の取得をする
				for(a=0 ; a<(UINT)(fsize/sizeof(wchar_t))-16 ; ++a) {
                    if ( fdata[a   ] == (wchar_t)sz_exe_md5[0] &&
						 fdata[a+ 1] == (wchar_t)sz_exe_md5[1] &&
						 fdata[a+ 2] == (wchar_t)sz_exe_md5[2] &&
						 fdata[a+ 3] == (wchar_t)sz_exe_md5[3] &&
						 fdata[a+ 4] == (wchar_t)sz_exe_md5[4] &&
						 fdata[a+ 5] == (wchar_t)sz_exe_md5[5] &&
						 fdata[a+ 6] == (wchar_t)sz_exe_md5[6] &&
						 fdata[a+ 7] == (wchar_t)sz_exe_md5[7] &&
						 fdata[a+ 8] == (wchar_t)sz_exe_md5[8] &&
						 fdata[a+ 9] == (wchar_t)sz_exe_md5[9] &&
						 fdata[a+10] == (wchar_t)sz_exe_md5[10] &&
						 fdata[a+11] == (wchar_t)sz_exe_md5[11] &&
						 fdata[a+12] == (wchar_t)sz_exe_md5[12] &&
						 fdata[a+13] == (wchar_t)sz_exe_md5[13] &&
						 fdata[a+14] == (wchar_t)sz_exe_md5[14] &&
						 fdata[a+15] == (wchar_t)sz_exe_md5[15] ) {

						for(b=0 ; b<32 ; ++b) {
                            fdata[a+16+b] = L'x';
						}

						if ( md5dataW(fdata, fsize, md5) ) {
							if ( lstrcmpiW(md5, &sz_exe_md5[16]) != 0 ) {
								// MD5不一致
								rc = 0;
							}
							else {
								// MD5一致
                                rc = 1;

								// 現在日時を記録
								if ( regkey ) {
									SYSTEMTIME st;

									GetLocalTime(&st);
									wsprintfW(datetime, L"%5d/%2d/%2d %2d:%02d:%02d",
										st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
									if ( root ) {
										if ( ERROR_SUCCESS == RegOpenKeyExW(root, regkey, NULL, KEY_WRITE, &hkey ) ) {
											RegSetValueExW(hkey, L"LastNormalBoot", NULL, REG_SZ, (LPBYTE)datetime, sizeof(wchar_t)*(lstrlenW(datetime)+1));
											RegCloseKey( hkey );
										}
									}
									else {
                                        WritePrivateProfileStringW( L"MD5Check", L"LastNormalBoot", datetime, regkey );
									}
								}
							}
						}
						break;
					}
				}
				safefree(fdata);
			}
			fclose(fp);
		}
	}

	return rc;
}

// WOW64下の32bitプロセスとして実行している場合、TRUEを返す。そうでない場合はFALSEを返す。
BOOL tf_IsWow64Process()
{
#ifndef _WIN64
	return tf_IsWow64ProcessHandle(GetCurrentProcess());
#else  // _WIN64
	return FALSE; // 現在のプロセスがx64ならば、WOW64配下で動くことは有り得ない
#endif // _WIN64
}

// 指定されたプロセスがWOW64下の32bitプロセスとして実行している場合、TRUEを返す。そうでない場合はFALSEを返す。
BOOL tf_IsWow64ProcessHandle(HANDLE hProcess)
{
	typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE hProcess, PBOOL Wow64Process);
	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
 
	if (NULL != fnIsWow64Process) {
		BOOL bIsWow64 = FALSE;

		if (fnIsWow64Process(hProcess, &bIsWow64)) {
			return bIsWow64;
		}
	}

	return FALSE;
}


// 現在のスレッドにおける、WOW64によるファイルリダイレクション(System32→SysWOW64)を無効化する。成功すると0以外の値が返る。
// 引数には、現在のリダイレクトするかどうかの状態を入れるための変数へのポインタを指定する。
BOOL tf_Wow64DisableWow64FsRedirection(PVOID *pOldValue)
{
	typedef BOOL (WINAPI *LPFN_WOW64DISABLEWOW64FSREDIRECTION) (PVOID*);
	LPFN_WOW64DISABLEWOW64FSREDIRECTION fnWow64DisableWow64FsRedirection =
		(LPFN_WOW64DISABLEWOW64FSREDIRECTION)GetProcAddress(GetModuleHandle("kernel32"), "Wow64DisableWow64FsRedirection");
 
	if (NULL != fnWow64DisableWow64FsRedirection) {
		return fnWow64DisableWow64FsRedirection(pOldValue);
	}

	return FALSE;
}

// 現在のスレッドにおける、WOW64によるファイルリダイレクション(System32→SysWOW64)を前の状態に戻す。成功すると0以外の値が返る。
// 引数には、現在のリダイレクトするかどうかの状態を入れるための変数を指定する。これは、Wow64DisableWow64FsRedirectionの
// 引数へ入れたときに得られた値となる。つまり、Wow64DisableWow64FsRedirection前の状態に復帰するということになる。
BOOL tf_Wow64RevertWow64FsRedirection(PVOID OldValue)
{
	typedef BOOL (WINAPI *LPFN_WOW64REVERTWOW64FSREDIRECTION) (PVOID);
	LPFN_WOW64REVERTWOW64FSREDIRECTION fnWow64RevertWow64FsRedirection =
		(LPFN_WOW64REVERTWOW64FSREDIRECTION)GetProcAddress(GetModuleHandle("kernel32"), "Wow64RevertWow64FsRedirection");
 
	if (NULL != fnWow64RevertWow64FsRedirection) {
		return fnWow64RevertWow64FsRedirection(OldValue);
	}

	return FALSE;
}

// カレントディレクトリをWindowsのSystem32フォルダに移してからDLLをLoadする
LibExport HMODULE LoadLibrary_System32W(const wchar_t* pwzFileName)
{
    static wchar_t wzSystem[MAX_PATH];
    wchar_t wzCurDir[MAX_PATH];
    HMODULE hMod = NULL;

    if(wzSystem[0] == L'\0') {
		if(GetSystemDirectoryW(wzSystem, _countof(wzSystem)) == 0) {
            return NULL; // 異常終了
		}
    }

    // 現在のカレントディレクトリを待避
	if(GetCurrentDirectoryW(_countof(wzCurDir), wzCurDir) == 0) {
        wzCurDir[0] = L'\0';
	}

    SetCurrentDirectoryW(wzSystem);		// System32ディレクトリへカレントディレクトリを移動
    hMod = LoadLibraryW(pwzFileName);		// 安全なDLL読み込み
    SetCurrentDirectoryW(wzCurDir);		// カレントディレクトリを元に戻す

	return hMod;
}

LibExport HMODULE LoadLibrary_System32A(const char *pszFileName)
{
    static char szSystem[MAX_PATH*2];
    char szCurDir[MAX_PATH*2];
    HMODULE hMod = NULL;

    if(szSystem[0] == L'\0') {
		if(GetSystemDirectoryA(szSystem, _countof(szSystem)) == 0) {
            return NULL; // 異常終了
		}
    }

    // 現在のカレントディレクトリを待避
	if(GetCurrentDirectoryA(_countof(szCurDir), szCurDir) == 0) {
        szCurDir[0] = L'\0';
	}

    SetCurrentDirectoryA(szSystem);		// System32ディレクトリへカレントディレクトリを移動
    hMod = LoadLibraryA(pszFileName);		// 安全なDLL読み込み
    SetCurrentDirectoryA(szCurDir);		// カレントディレクトリを元に戻す

	return hMod;
}

// 再帰的にフォルダ内のファイルを削除[Unicode版]
LibExport int emptyDirectoryW(LPCWSTR folder, FILETIME *bf_ft)
{
	HANDLE hFind;
	WIN32_FIND_DATAW wfd;
	int iResult = 1;
	wchar_t NowDir[MAX_PATH];

	// 現在のカレントディレクトリを待避し、指定されたディレクトリへカレントを移す
	if (0 == GetCurrentDirectoryW(_countof(NowDir), NowDir)) {
		return 0; // 1つ以上の失敗
	}
	if (0 == SetCurrentDirectoryW(folder)) {
		return 0; // 1つ以上の失敗
	}

	// ファイル・フォルダサーチ
	hFind = FindFirstFileW(L"*.*", &wfd);
	if (hFind == INVALID_HANDLE_VALUE) {
		return 0; // 1つ以上の失敗
	}
	do {
		if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			if (wfd.cFileName[0] == L'.') {
				// 特殊なディレクトリは無視
			}
			else {
				// 通常のディレクトリの場合は再帰呼出により中のファイルをすべて削除してから、フォルダ削除
				if (0 == emptyDirectoryW(wfd.cFileName, bf_ft)) {
					iResult = 0; // 1つ以上の失敗
				}
				else {
					// 中身が空になったのでフォルダ削除
					SetFileAttributesW(wfd.cFileName, FILE_ATTRIBUTE_NORMAL); // まずは属性の変更
					if (0 == RemoveDirectoryW(wfd.cFileName)){ // フォルダ削除
						iResult = 0; // フォルダ削除失敗
					}
				}
			}
		}
		else {
			// ファイル削除 … 日付指定されていないか、日付指定されている場合はその日付より過去だったら、削除
			if (bf_ft == NULL || CompareFileTime(&(wfd.ftLastWriteTime), bf_ft) < 0) {
				SetFileAttributesW(wfd.cFileName, FILE_ATTRIBUTE_NORMAL); // まずは属性の変更
				if (0 == DeleteFileW(wfd.cFileName)) { // ファイル削除
					iResult = 0; // 1つ以上の失敗
				}
			}
		}
	} while(FindNextFileW(hFind, &wfd));

	FindClose(hFind);

	// カレントディレクトリを元に戻す
	SetCurrentDirectoryW(NowDir);

	return iResult;
}

// 再帰的にフォルダ内のファイルを削除[ANSI版]
LibExport int emptyDirectoryA(LPCSTR folder, FILETIME *bf_ft)
{
	HANDLE hFind;
	WIN32_FIND_DATAA wfd;
	int iResult = 1;
	char NowDir[MAX_PATH];

	// 現在のカレントディレクトリを待避し、指定されたディレクトリへカレントを移す
	if (0 == GetCurrentDirectoryA(_countof(NowDir), NowDir)) {
		return 0; // 1つ以上の失敗
	}
	if (0 == SetCurrentDirectoryA(folder)) {
		return 0; // 1つ以上の失敗
	}

	// ファイル・フォルダサーチ
	hFind = FindFirstFileA("*.*", &wfd);
	if (hFind == INVALID_HANDLE_VALUE) {
		return 0; // 1つ以上の失敗
	}
	do {
		if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			if (wfd.cFileName[0] == '.') {
				// 特殊なディレクトリは無視
			}
			else {
				// 通常のディレクトリの場合は再帰呼出により中のファイルをすべて削除してから、フォルダ削除
				if (0 == emptyDirectoryA(wfd.cFileName, bf_ft)) {
					iResult = 0; // 1つ以上の失敗
				}
				else {
					// 中身が空になったのでフォルダ削除
					SetFileAttributesA(wfd.cFileName, FILE_ATTRIBUTE_NORMAL); // まずは属性の変更
					if (0 == RemoveDirectoryA(wfd.cFileName)){ // フォルダ削除
						iResult = 0; // フォルダ削除失敗
					}
				}
			}
		}
		else {
			// ファイル削除 … 日付指定されていないか、日付指定されている場合はその日付より過去だったら、削除
			if (bf_ft == NULL || CompareFileTime(&(wfd.ftLastWriteTime), bf_ft) < 0) {
				SetFileAttributesA(wfd.cFileName, FILE_ATTRIBUTE_NORMAL); // まずは属性の変更
				if (0 == DeleteFileA(wfd.cFileName)) { // ファイル削除
					iResult = 0; // 1つ以上の失敗
				}
			}
		}
	} while(FindNextFileA(hFind, &wfd));

	FindClose(hFind);

	// カレントディレクトリを元に戻す
	SetCurrentDirectoryA(NowDir);

	return iResult;
}


// OSのZipFolder機能を利用し、指定したフォルダ（フルパス）へ、zipファイルを展開する
// Windows XP以降で、zip展開機能が有効であること。Unicode版関数のみ提供
// あらかじめ CoInitialize() しておくこと!!
// 参照元サイト：EternalWindows ( http://eternalwindows.jp/installer/zip/zip01.html )

// ここから↓ Visual Studio 2005でコンパイルするには定義が不足しているので追加。
#if _MSC_VER < 1500
extern "C++"
{
    template<typename T> void** IID_PPV_ARGS_Helper(T** pp) 
    {
        static_cast<IUnknown*>(*pp);    // make sure everyone derives from IUnknown
        return reinterpret_cast<void**>(pp);
    }
}
#endif // _MSC_VER < 1500

#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
// ここまで↑

// IShellDispatchによるzipファイルの展開
BOOL Unzip_fldr(IShellDispatch *pShellDispatch, LPWSTR lpszZipPath, LPWSTR lpszOutPath)
{
	HRESULT     hr;
	VARIANT     varOutDir, varZip, varItem, varOptions;
	Folder      *pOutFolder, *pZipFile;
	FolderItems *pZipFileItems;
	
	VariantInit(&varOutDir);
	varOutDir.vt = VT_BSTR;
	varOutDir.bstrVal = SysAllocString(lpszOutPath);
	hr = pShellDispatch->NameSpace(varOutDir, &pOutFolder);
	VariantClear(&varOutDir);
	if (hr != S_OK)
		return FALSE;

	VariantInit(&varZip);
	varZip.vt = VT_BSTR;
	varZip.bstrVal = SysAllocString(lpszZipPath);
	hr = pShellDispatch->NameSpace(varZip, &pZipFile);
	VariantClear(&varZip);
	if (hr != S_OK) {
		pOutFolder->Release();
		return FALSE;
	}

	hr = pZipFile->Items(&pZipFileItems);
	if (hr != S_OK) {
		pZipFile->Release();
		pOutFolder->Release();
		return FALSE;
	}

	VariantInit(&varItem);
	varItem.vt = VT_DISPATCH;
	varItem.pdispVal = pZipFileItems;
	VariantInit(&varOptions);
	varOptions.vt = VT_I4;
	varOptions.lVal = 4;
	hr = pOutFolder->CopyHere(varItem, varOptions);
	if (hr != S_OK) {
		pZipFileItems->Release();
		pZipFile->Release();
		pOutFolder->Release();
		return FALSE;
	}

	pZipFileItems->Release();
	pZipFile->Release();
	pOutFolder->Release();

	return TRUE;
}

// Windows XP以降のOS機能を利用したzipファイル展開
//  zipfile : 展開したいzipファイル名。フルパスで指定すること。
//  outfolder : 出力先フォルダ名。フルパスで指定すること。
LibExport int Shell_UnZipW(LPWSTR zipfile, LPWSTR outfolder)
{
	HRESULT        hr;
	IShellDispatch *pShellDispatch;

	hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellDispatch));
	if (FAILED(hr)) {
		// 呼出し失敗
		return FALSE;
	}

	if (Unzip_fldr(pShellDispatch, zipfile, outfolder)) {
		// 展開成功（途中でキャンセルした場合もこちらになる様子）
		return TRUE;
	}
	else {
		// 展開失敗
		return FALSE;
	}
}

// ATMLチェックを行う
LibExport int checkAtmlA()
{
	int   rv = 0;

#if (ATML_ENABLED == 1)
	// 特定のレジストリキーが存在していたら、チェックNGとする
	HKEY  hkey;
	if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) || 
		 ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) || 
		 ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) ) {
		RegCloseKey( hkey );
		rv = 1; // チェックNG
	}
#endif

	return rv;
}

LibExport int checkAtmlW()
{
	int   rv = 0;

#if (ATML_ENABLED == 1)
	// 特定のレジストリキーが存在していたら、チェックNGとする
	HKEY  hkey;
	if ( ERROR_SUCCESS == RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) || 
		 ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) || 
		 ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Wow6432Node\\TrendMicro", NULL, KEY_QUERY_VALUE, &hkey ) ) {
		RegCloseKey( hkey );
		rv = 1; // チェックNG
	}
#endif

	return rv;
}
