// regclass.cpp : Rnsfおよびすっきりシリーズ用レジストリクラス/一般ライブラリ
/*

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

　これは、REGCLASS.LIB を生成するためのソースプログラムです。
　C++でレジストリを容易に扱うためのクラスライブラリと、C言語でレジストリを容易に
　扱うためのライブラリです。

*/

#include "stdafx.h"

#define OWN__REGCLASS__

#include "regclass.h"

#define zalloc(n)     ((char *)calloc((n),sizeof(char)))
#define walloc(n)     ((wchar_t *)calloc((n),sizeof(wchar_t)))

static bool modeJP = 1, useMessage = 1;
static bool bDisableReflectionKey = false;
static LONG tRegLastError = ERROR_SUCCESS; // 最後に発生したレジストリ系Windows APIのエラーコード（作者デバッグ用のため、すべてで取得できるわけではない）

// ライブラリのバージョンの取得
LibExport DWORD tRegGetVersion(void)
{
	return REGCLASS_VERSIONNUMBER;
}

// 英語モードへの切り替え
LibExport VOID  tRegEnglishMode(BOOL flag)
{
	modeJP = flag ? false : true;
}

// ノーメッセージモードへの切り替え
LibExport VOID  tRegNoMessageMode(BOOL flag)
{
	useMessage = flag ? false : true;
}

// このライブラリで開くレジストリについて、レジストリのリフレクションを行わない
LibExport VOID  tRegDisableReflectionKeyMode(BOOL flag)
{
	bDisableReflectionKey = flag ? true : false;
}

// 指定したキーのハンドルについて、レジストリのリフレクションを行わない
LibExport LONG  tRegDisableReflectionKey(HKEY hBase)
{
	typedef LONG (WINAPI *LPFN_REGDISABLEREFLECTIONKEY) (HKEY);
	LPFN_REGDISABLEREFLECTIONKEY fnRegDisableReflectionKey =
		(LPFN_REGDISABLEREFLECTIONKEY)GetProcAddress(GetModuleHandle("Advapi32"), "RegDisableReflectionKey");

	if (fnRegDisableReflectionKey) {
		return fnRegDisableReflectionKey(hBase);
	}

	return ERROR_BAD_ENVIRONMENT;
}

// 最後に発生したレジストリ系Windows APIのエラーコード（作者デバッグ用のため、すべてで取得できるわけではない）
LibExport LONG  tRegGetLastError(void)
{
	return tRegLastError;
}

// tRegGetLastErrorが返す値を初期化する
LibExport VOID  tRegClearLastError(void)
{
	tRegLastError = ERROR_SUCCESS;
}

// デストラクタ
REGA::~REGA()
{
	if ( hkey ) {
	    CloseKey();
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"レジストリを自動クローズしました。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::~REGA().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
}

REGW::~REGW()
{
	if ( hkey ) {
	    CloseKey();
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"レジストリを自動クローズしました。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::~REGW().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
}

// キーのオープン/作成 <クラス>
bool REGA::OpenKey(HKEY root, const char *subkey, DWORD flag)
{ // root:開かれているキー subkey:これから開くキー flag:TREG_OPEN_CREATE=存在しなければ作成, TREG_OPEN_READONLY=読み込みのみモード
    if ( hkey ) {
		CloseKey();
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"レジストリキーを多重オープンしようとしたので保護しました(REGA::OpenKey())。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::OpenKey().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}

	hkey = tRegOpenKey(root, subkey, flag);

	return hkey?true:false;
}

bool REGW::OpenKey(HKEY root, const wchar_t *subkey, DWORD flag)
{ // root:開かれているキー subkey:これから開くキー flag:TREG_OPEN_CREATE=存在しなければ作成, TREG_OPEN_READONLY=読み込みのみモード
    if ( hkey ) {
		CloseKey();
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"レジストリキーを多重オープンしようとしたので保護しました(REGW::OpenKey())。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::OpenKey().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}

	hkey = tRegOpenKeyW(root, subkey, flag);

	return hkey?true:false;
}

// レジストリキーを開く
LibExport HKEY tRegOpenKeyA(HKEY root, const char *subkey, DWORD flag)
{ // root:開かれているキー subkey:これから開くキー flag:0=書き込み可能なモードで呼び出し TREG_OPEN_CREATE=存在しなければ作成, TREG_OPEN_READONLY=読み込みのみモード
	DWORD wh;
	HKEY  hkey;

	tRegLastError = ERROR_SUCCESS;

	if ( subkey ) {
		if (root == NULL) {
			hkey = tRegHiveKeyA( subkey );
			if ( hkey ) {
				return hkey;
			}
			else {
				if (0 == strncmp(subkey, "HKEY_CLASSES_ROOT\\", 18)) {
					root = HKEY_CLASSES_ROOT;
					subkey += 18;
				}
				else if (0 == strncmp(subkey, "HKCR\\", 5)) {
					root = HKEY_CLASSES_ROOT;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_CURRENT_USER\\", 18)) {
					root = HKEY_CURRENT_USER;
					subkey += 18;
				}
				else if (0 == strncmp(subkey, "HKCU\\", 5)) {
					root = HKEY_CURRENT_USER;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_LOCAL_MACHINE\\", 19)) {
					root = HKEY_LOCAL_MACHINE;
					subkey += 19;
				}
				else if (0 == strncmp(subkey, "HKLM\\", 5)) {
					root = HKEY_LOCAL_MACHINE;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_USERS\\", 11)) {
					root = HKEY_USERS;
					subkey += 11;
				}
				else if (0 == strncmp(subkey, "HKEY_CURRENT_CONFIG\\", 20)) {
					root = HKEY_CURRENT_CONFIG;
					subkey += 20;
				}
				else if (0 == strncmp(subkey, "HKCC\\", 5)) {
					root = HKEY_CURRENT_CONFIG;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_DYN_DATA\\", 14)) {
					root = HKEY_DYN_DATA;
					subkey += 14;
				}
				else if (0 == strncmp(subkey, "HKDD\\", 5)) {
					root = HKEY_DYN_DATA;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_PERFORMANCE_DATA\\", 22)) {
					root = HKEY_PERFORMANCE_DATA;
					subkey += 22;
				}
				else if (0 == strncmp(subkey, "HKPD\\", 5)) {
					root = HKEY_PERFORMANCE_DATA;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_PERFORMANCE_TEXT\\", 22)) {
					root = HKEY_PERFORMANCE_TEXT;
					subkey += 22;
				}
				else if ( 0 == strncmp(subkey, "HKPT\\", 5)) {
					root = HKEY_PERFORMANCE_TEXT;
					subkey += 5;
				}
				else if (0 == strncmp(subkey, "HKEY_PERFORMANCE_NLSTEXT\\", 25)) {
					root = HKEY_PERFORMANCE_NLSTEXT;
					subkey += 25;
				}
				else if (0 == strncmp(subkey, "HKPN\\", 5)) {
					root = HKEY_PERFORMANCE_NLSTEXT;
					subkey += 5;
				}
				else {
					return NULL;
				}
			}
		}

		if (ERROR_SUCCESS == (tRegLastError = RegOpenKeyEx(root, subkey, 0, (flag & TREG_OPEN_READONLY) ? KEY_READ : KEY_ALL_ACCESS, &hkey))) {
			if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);
			return hkey;
		}

		if ((flag & TREG_OPEN_CREATE) && ERROR_SUCCESS == (tRegLastError = RegCreateKeyEx(root, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &wh))) {
			if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);
			return hkey;
		}
	}

	return NULL;
}

LibExport HKEY tRegOpenKeyW(HKEY root, const wchar_t *subkey, DWORD flag)
{ // root:開かれているキー subkey:これから開くキー flag:0=書き込み可能なモードで呼び出し TREG_OPEN_CREATE=存在しなければ作成, TREG_OPEN_READONLY=読み込みのみモード
	DWORD wh;
	HKEY  hkey;

	tRegLastError = ERROR_SUCCESS;

	if ( subkey ) {
		if (root == NULL) {
			hkey = tRegHiveKeyW( subkey );
			if ( hkey ) {
				return hkey;
			}
			else {
				if (0 == wcsncmp(subkey, L"HKEY_CLASSES_ROOT\\", 18)) {
					root = HKEY_CLASSES_ROOT;
					subkey += 18;
				}
				else if (0 == wcsncmp(subkey, L"HKCR\\", 5)) {
					root = HKEY_CLASSES_ROOT;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_CURRENT_USER\\", 18)) {
					root = HKEY_CURRENT_USER;
					subkey += 18;
				}
				else if (0 == wcsncmp(subkey, L"HKCU\\", 5)) {
					root = HKEY_CURRENT_USER;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_LOCAL_MACHINE\\", 19)) {
					root = HKEY_LOCAL_MACHINE;
					subkey += 19;
				}
				else if (0 == wcsncmp(subkey, L"HKLM\\", 5)) {
					root = HKEY_LOCAL_MACHINE;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_USERS\\", 11)) {
					root = HKEY_USERS;
					subkey += 11;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_CURRENT_CONFIG\\", 20)) {
					root = HKEY_CURRENT_CONFIG;
					subkey += 20;
				}
				else if (0 == wcsncmp(subkey, L"HKCC\\", 5)) {
					root = HKEY_CURRENT_CONFIG;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_DYN_DATA\\", 14)) {
					root = HKEY_DYN_DATA;
					subkey += 14;
				}
				else if (0 == wcsncmp(subkey, L"HKDD\\", 5)) {
					root = HKEY_DYN_DATA;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_PERFORMANCE_DATA\\", 22)) {
					root = HKEY_PERFORMANCE_DATA;
					subkey += 22;
				}
				else if (0 == wcsncmp(subkey, L"HKPD\\", 5)) {
					root = HKEY_PERFORMANCE_DATA;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_PERFORMANCE_TEXT\\", 22)) {
					root = HKEY_PERFORMANCE_TEXT;
					subkey += 22;
				}
				else if ( 0 == wcsncmp(subkey, L"HKPT\\", 5)) {
					root = HKEY_PERFORMANCE_TEXT;
					subkey += 5;
				}
				else if (0 == wcsncmp(subkey, L"HKEY_PERFORMANCE_NLSTEXT\\", 25)) {
					root = HKEY_PERFORMANCE_NLSTEXT;
					subkey += 25;
				}
				else if (0 == wcsncmp(subkey, L"HKPN\\", 5)) {
					root = HKEY_PERFORMANCE_NLSTEXT;
					subkey += 5;
				}
				else {
					return NULL;
				}
			}
		}

		if (ERROR_SUCCESS == (tRegLastError = RegOpenKeyExW(root, subkey, 0, (flag & TREG_OPEN_READONLY) ? KEY_READ : KEY_ALL_ACCESS, &hkey))) {
			if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);
			return hkey;
		}

		if ((flag & TREG_OPEN_CREATE) && ERROR_SUCCESS == (tRegLastError = RegCreateKeyExW(root, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &wh))) {
			if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);
			return hkey;
		}
	}

	return NULL;
}

// 与えられたサブキーのオープン/作成 <クラス>
bool REGA::OpenSubKey(HKEY root, const char *subkey, const char *subsubkey, DWORD flag)
{
    if ( hkey ) {
		CloseKey();
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"レジストリキーを多重オープンしようとしたので保護しました(REGA::OpenSubKey)。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::OpenSubKey().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}

	hkey = tRegOpenSubKey(root, subkey, subsubkey, flag);

	return hkey?true:false;
}

bool REGW::OpenSubKey(HKEY root, const wchar_t *subkey, const wchar_t *subsubkey, DWORD flag)
{
    if ( hkey ) {
		CloseKey();
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"レジストリキーを多重オープンしようとしたので保護しました(REGW::OpenSubKey)。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::OpenSubKey().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}

	hkey = tRegOpenSubKeyW(root, subkey, subsubkey, flag);

	return hkey?true:false;
}

// 与えられたサブキーのオープン/作成
LibExport HKEY tRegOpenSubKeyA(HKEY root, const char *subkey, const char *subsubkey, DWORD flag)
{
	char *keyname;
	HKEY hkey = NULL;

	// 引数がNULLだった場合の各種対策
	if ( subkey == NULL && subsubkey != NULL ) {
		return tRegOpenKey(root, subsubkey, flag);
	}
	else if ( subkey != NULL && subsubkey == NULL ) {
		return tRegOpenKey(root, subkey, flag);
	}
	else if ( subkey == NULL && subsubkey == NULL ) {
		return NULL;
	}

	keyname = zalloc(lstrlen(subkey) + lstrlen(subsubkey) + 2); // subkeyに\\がついていないことも考慮して+2

	if ( keyname ) { // set_new_handler(0) 対策
		lstrcpy(keyname, subkey);
		if (keyname[lstrlen(subkey)-1] != '\\') {
			lstrcat(keyname, "\\");
		}
		lstrcat(keyname, subsubkey);

		hkey = tRegOpenKey(root, keyname, flag);
		free(keyname);
	}

	return hkey;
}

LibExport HKEY tRegOpenSubKeyW(HKEY root, const wchar_t *subkey, const wchar_t *subsubkey, DWORD flag)
{
	wchar_t *keyname;
	HKEY hkey = NULL;

	// 引数がNULLだった場合の各種対策
	if ( subkey == NULL && subsubkey != NULL ) {
		return tRegOpenKeyW(root, subsubkey, flag);
	}
	else if ( subkey != NULL && subsubkey == NULL ) {
		return tRegOpenKeyW(root, subkey, flag);
	}
	else if ( subkey == NULL && subsubkey == NULL ) {
		return NULL;
	}

	keyname = walloc(lstrlenW(subkey) + lstrlenW(subsubkey) + 2); // subkeyに\\がついていないことも考慮して+2

	if ( keyname ) { // set_new_handler(0) 対策
		lstrcpyW(keyname, subkey);
		if (keyname[lstrlenW(subkey)-1] != L'\\') {
			lstrcatW(keyname, L"\\");
		}
		lstrcatW(keyname, subsubkey);

		hkey = tRegOpenKeyW(root, keyname, flag);
		free(keyname);
	}

	return hkey;
}


// 値が存在したらサイズを返し、存在しなかったら-1を返す
LibExport int  tRegValueExistA(HKEY hkey, const char *ValueName)
{ // hkey:レジストリキー ValueName:存在を確認したい値の名前 
	int size = -1;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に ValueExistA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ValueExistA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return -1;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,NULL,NULL,(unsigned long *)&size))) {
		return size;
	}
	else {
		return -1;
	}
}

LibExport int  tRegValueExistW(HKEY hkey, const wchar_t *ValueName)
{ // hkey:レジストリキー ValueName:存在を確認したい値の名前 
	int size = -1;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ValueExistW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ValueExistW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return -1;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,NULL,NULL,(unsigned long *)&size))) {
		return size;
	}
	else {
		return -1;
	}
}

// 値が存在したらサイズを返し、存在しなかったら0を返す
LibExport DWORD tRegValueSizeA(HKEY hkey, const char *ValueName)
{ // hkey:レジストリキー ValueName:サイズを知りたい値の名前 
	DWORD size = 0;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に ValueSizeA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ValueSizeA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,NULL,NULL,&size))) {
		return size;
	}
	else {
		return 0;
	}
}

LibExport DWORD tRegValueSizeW(HKEY hkey, const wchar_t *ValueName)
{ // hkey:レジストリキー ValueName:サイズを知りたい値の名前 
	DWORD size = 0;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ValueSizeW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ValueSizeW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,NULL,NULL,&size))) {
		return size;
	}
	else {
		return 0;
	}
}

// 値の型を返す (値が存在したら型が返り、存在しないと 0 が返る)
LibExport DWORD tRegValueTypeA(HKEY hkey, const char *ValueName)
{
	DWORD type = 0;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に ValueTypeA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ValueTypeA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return (DWORD)-1;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,&type,NULL,NULL))) {
		return type;
	}
	else {
		return 0;
	}
}

LibExport DWORD tRegValueTypeW(HKEY hkey, const wchar_t *ValueName)
{
	DWORD type = 0;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ValueTypeW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ValueTypeW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return (DWORD)-1;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,&type,NULL,NULL))) {
		return type;
	}
	else {
		return 0;
	}
}

// 文字列の読み込み
LibExport BOOL tRegReadStringA(HKEY hkey, const char *ValueName, char *Value, int size)
{
	tRegLastError = ERROR_SUCCESS;

	if (ValueName == NULL || Value == NULL) {
		return FALSE;
	}

	Value[0] = 0;
	if (hkey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に ReadStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ReadStringA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,NULL,(LPBYTE)Value,(LPDWORD)&size)))?TRUE:FALSE;
}

LibExport BOOL tRegReadStringW(HKEY hkey, const wchar_t *ValueName, wchar_t *Value, int size)
{
	tRegLastError = ERROR_SUCCESS;

	if (ValueName == NULL || Value == NULL) {
		return FALSE;
	}

	Value[0] = 0;
	if (hkey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ReadStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ReadStringW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	size *= sizeof(wchar_t);

	return (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,NULL,(LPBYTE)Value,(LPDWORD)&size)))?TRUE:FALSE;
}

// 整数値か？
static BOOL isNumberA( const char *str )
{
	if ( str && (str[0] == '-' || str[0] == '+' || ('0' <= str[0] && str[0] <= '9')) ) {
		for(int i=1 ; str[i] ; i++) {
			if ( !('0' <= str[i] && str[i] <= '9') ) {
				return FALSE;
			}
		}
		return TRUE;
	}
	return FALSE;
}

static BOOL isNumberW( const wchar_t *str )
{
	if ( str && (str[0] == L'-' || str[0] == L'+' || (L'0' <= str[0] && str[0] <= L'9')) ) {
		for(int i=1 ; str[i] ; i++) {
			if ( !(L'0' <= str[i] && str[i] <= L'9') ) {
				return FALSE;
			}
		}
		return TRUE;
	}
	return FALSE;
}

// 数値の読み込み
LibExport DWORD tRegReadIntegerA(HKEY hkey, const char *ValueName, DWORD Def)
{
    DWORD Integer = Def, size = 0, type = 0;
	char *data;

/*
REG_DWORD  → そのまま数値として取得
REG_QWORD　→ はじめの４バイトを数値として取得
REG_DWORD_BIG_ENDIAN　→ リトルエンディアンに変換後、数値として取得

REG_BINARY → 4バイト以内の部分を数値として取得
　　　　　　　(実際にこの挙動に依存している箇所があるため)

REG_SZ, REG_MULTI_SZ → ニューメリックチェック(その文字列が数値として妥当か
REG_EXPAND_SZ 　　　　　の判定)を行い、数値と見なされれば数値扱いにし、
　　　　　　　　　　　　そうでなければデフォルト値を採用。

その他のレジストリ型 → デフォルト値を採用。
*/
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に ReadIntegerA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ReadIntegerA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
	else {
		// 必要なバイト数はあらかじめ調べる
		if ( ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey, ValueName, NULL, &type, NULL, (LPDWORD)&size))) {
			size++;
			data = zalloc(size);

			if ( data ) {
				if ( ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey, ValueName, NULL, &type, (LPBYTE)data, (LPDWORD)&size))) {
					switch( type ) {
						case REG_DWORD: // == REG_DWORD_LITTLE_ENDIAN
						case REG_BINARY:
						case REG_QWORD: // == REG_QWORD_LITTLE_ENDIAN
							CopyMemory(&Integer, data, 4);
							break;

						case REG_DWORD_BIG_ENDIAN:
							{
								char tmp;

								tmp = data[3];
								data[3] = data[0];
								data[0] = tmp;
								tmp = data[2];
								data[2] = data[1];
								data[1] = tmp;

								CopyMemory(&Integer, data, 4);
							}
							break;

						case REG_SZ:
						case REG_MULTI_SZ:
						case REG_EXPAND_SZ:
							if ( isNumberA( data ) ) {
								Integer = atoi( data );
							}
							break;
					}
				}
				free( data );
			}
		}
	}

	return Integer;
}

LibExport DWORD tRegReadIntegerW(HKEY hkey, const wchar_t *ValueName, DWORD Def)
{
    DWORD Integer = Def, size = 0, type = 0;
	wchar_t *data;

	tRegLastError = ERROR_SUCCESS;

/*
REG_DWORD  → そのまま数値として取得
REG_QWORD　→ はじめの４バイトを数値として取得
REG_DWORD_BIG_ENDIAN　→ リトルエンディアンに変換後、数値として取得

REG_BINARY → 4バイト以内の部分を数値として取得
　　　　　　　(実際にこの挙動に依存している箇所があるため)

REG_SZ, REG_MULTI_SZ → ニューメリックチェック(その文字列が数値として妥当か
REG_EXPAND_SZ 　　　　　の判定)を行い、数値と見なされれば数値扱いにし、
　　　　　　　　　　　　そうでなければデフォルト値を採用。

その他のレジストリ型 → デフォルト値を採用。
*/

	if (hkey == NULL) {
		if( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ReadIntegerW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ReadIntegerW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
	else {
		// 必要なバイト数はあらかじめ調べる
		if ( ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey, ValueName, NULL, &type, NULL, &size))) {
			size++;
			data = (wchar_t *)calloc(size, 1);

			if ( data ) {
				if ( ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE)data, &size))) {
					switch( type ) {
						case REG_DWORD: // == REG_DWORD_LITTLE_ENDIAN
						case REG_BINARY:
						case REG_QWORD: // == REG_QWORD_LITTLE_ENDIAN
							CopyMemory(&Integer, data, 4);
							break;

						case REG_DWORD_BIG_ENDIAN:
							{
								wchar_t tmp;

								tmp = data[3];
								data[3] = data[0];
								data[0] = tmp;
								tmp = data[2];
								data[2] = data[1];
								data[1] = tmp;

								CopyMemory(&Integer, data, 4);
							}
							break;

						case REG_SZ:
						case REG_MULTI_SZ:
						case REG_EXPAND_SZ:
							if ( isNumberW( data ) ) {
								Integer = _wtoi( data );
							}
							break;
					}
				}
				free( data );
			}
		}
	}

	return Integer;
}

// 文字列の書き込み
LibExport BOOL tRegWriteStringA(HKEY hkey, const char *ValueName, const char *Value, char rws_expand_flag)
{
	DWORD			flag = REG_SZ, flag2 = 0;
	int				i = 0, n = 0;

	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteStringA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	if (rws_expand_flag == TREG_EXPAND_SZ) { // (=1) 明確に展開文字列
		flag = REG_EXPAND_SZ;
	}
	else if (rws_expand_flag == TREG_MAYBE_SZ) { // (=2) ひょっとすると展開文字列
		for(i=n=0 ; Value[i] ; i++) {
			if(Value[i] == '%') {
				n++;
			}
		}
		if (n >= 2)
			flag = REG_EXPAND_SZ;
	}
	else if (rws_expand_flag == TREG_NORMAL_SZ) { // (=3) 明確に通常文字列
		;
	}
	else { // TREG_SZ(=0) 無指定時は、レジストリ側が展開文字列だったら、展開文字列
		if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,&flag2,NULL,NULL))) {
			if (flag2 == REG_EXPAND_SZ) {
				flag = REG_EXPAND_SZ;
			}
		}
	}

#ifndef _WIN64
	// Windows95 / NT4 では、デフォルトエントリは展開文字列にできない
	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 { // WinXPによる偽装であると思われる
			verinfo.dwMajorVersion = 5;
			verinfo.dwMinorVersion = 1;
		}
	}
	if (ValueName[0] == 0 && verinfo.dwMajorVersion == 4 && verinfo.dwMinorVersion == 0) {
		flag = REG_SZ;
	}
#endif /* _WIN64 */

	return (ERROR_SUCCESS == (tRegLastError = RegSetValueEx(hkey,ValueName,NULL,flag,(const unsigned char *)Value,lstrlen(Value)+1)));
}

LibExport BOOL tRegWriteStringW(HKEY hkey, const wchar_t *ValueName, const wchar_t *Value, char rws_expand_flag)
{
	DWORD			flag = REG_SZ, flag2 = 0;
	int				i = 0, n = 0;
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteStringW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	if (rws_expand_flag == TREG_EXPAND_SZ) { // (=1) 明確に展開文字列
		flag = REG_EXPAND_SZ;
	}
	else if (rws_expand_flag == TREG_MAYBE_SZ) { // (=2) ひょっとすると展開文字列
		for(i=n=0 ; Value[i] ; i++) {
			if(Value[i] == L'%') {
				n++;
			}
		}
		if (n >= 2)
			flag = REG_EXPAND_SZ;
	}
	else if (rws_expand_flag == TREG_NORMAL_SZ) { // (=3) 明確に通常文字列
		;
	}
	else { // TREG_SZ(=0) 無指定時は、レジストリ側が展開文字列だったら、展開文字列
		if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,&flag2,NULL,NULL))) {
			if (flag2 == REG_EXPAND_SZ) {
				flag = REG_EXPAND_SZ;
			}
		}
	}

#ifndef _WIN64
	// Windows95 / NT4 では、デフォルトエントリは展開文字列にできない
	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 { // WinXPによる偽装であると思われる
			verinfo.dwMajorVersion = 5;
			verinfo.dwMinorVersion = 1;
		}
	}
	if (ValueName[0] == 0 && verinfo.dwMajorVersion == 4 && verinfo.dwMinorVersion == 0) {
		flag = REG_SZ;
	}
#endif /* _WIN64 */

	return (ERROR_SUCCESS == (tRegLastError = RegSetValueExW(hkey,ValueName,NULL,flag,(const unsigned char *)Value,sizeof(wchar_t)*(lstrlenW(Value)+1))));
}

// 数値の書き込み
LibExport BOOL tRegWriteIntegerA(HKEY hkey,const char *ValueName, DWORD Integer)
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteIntegerA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteIntegerA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegSetValueEx(hkey,ValueName,NULL,REG_DWORD,(LPBYTE)&Integer,sizeof(DWORD))))?TRUE:FALSE;
}

LibExport BOOL tRegWriteIntegerW(HKEY hkey,const wchar_t *ValueName, DWORD Integer)
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteIntegerW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteIntegerW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegSetValueExW(hkey,ValueName,NULL,REG_DWORD,(LPBYTE)&Integer,sizeof(DWORD))))?TRUE:FALSE;
}

// バイナリデータの書き込み
LibExport BOOL tRegWriteBinaryA(HKEY hkey, const char *ValueName, const char *Value, int size)
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteBinaryA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteBinaryA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegSetValueEx(hkey,ValueName,NULL,REG_BINARY,(const unsigned char *)Value,size)))?TRUE:FALSE;
}

LibExport BOOL tRegWriteBinaryW(HKEY hkey, const wchar_t *ValueName, const char *Value, int size)
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteBinaryW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteBinaryW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegSetValueExW(hkey,ValueName,NULL,REG_BINARY,(const unsigned char *)Value,size)))?TRUE:FALSE;
}

// 開かれているキーの下のキーを削除 <クラス>
bool REGA::DeleteKey(const char *subkey) const
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に REGA::DeleteKey が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::DeleteKey().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegDeleteKey(hkey, subkey)));
}

bool REGW::DeleteKey(const wchar_t *subkey) const
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に REGW::DeleteKey が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::DeleteKey().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegDeleteKeyW(hkey, subkey)));
}

// 開かれているキーの下のキーを削除(さらに下のキーも全て削除) <クラス>
bool REGA::DeleteSubKey(const char *subkey) const
{
	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に REGA::DeleteSubKey が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::DeleteSubKey().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return tRegDeleteSubKeyA(hkey, subkey) ? true : false;
}

bool REGW::DeleteSubKey(const wchar_t *subkey) const
{
	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に REGW::DeleteSubKeyW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::DeleteSubKey().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return tRegDeleteSubKeyW(hkey, subkey) ? true : false;
}

// 開かれているキーの下の値を削除 <クラス>
bool REGA::DeleteValue(const char *valuename) const
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に REGA::DeleteValue が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::DeleteValue().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegDeleteValue(hkey, valuename)));
}

bool REGW::DeleteValue(const wchar_t *valuename) const
{
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に REGW::DeleteValue が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::DeleteValue().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return false;
	}
	return (ERROR_SUCCESS == (tRegLastError = RegDeleteValueW(hkey, valuename)));
}

// レジストリのクローズ <クラス>
bool REGA::CloseKey(void)
{
	tRegLastError = ERROR_SUCCESS;

	if ( hkey ) {
		tRegLastError = RegCloseKey(hkey);
		hkey = NULL;
		return (tRegLastError == ERROR_SUCCESS);
	}
	else {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"レジストリを多重クローズしようとしたので保護しました(REGA::CloseKey)。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in REGA::CloseKey().","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
	return false;
}

bool REGW::CloseKey(void)
{
	tRegLastError = ERROR_SUCCESS;

	if ( hkey ) {
		tRegLastError = RegCloseKey(hkey);
		hkey = NULL;
		return (tRegLastError == ERROR_SUCCESS);
	}
	else {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"レジストリを多重クローズしようとしたので保護しました(REGW::CloseKey)。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in REGW::CloseKey().",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
	}
	return false;
}

// レジストリから文字列を読み込み、そのままエディットボックスへ
LibExport BOOL tRegReadStringForEditboxA(HKEY hkey, const char *ValueName, HWND hDlg, int nIDDlgItem, const char *Def)
{
	int n;
	char *str = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に ReadStringForEditboxA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ReadStringForEditboxA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = tRegValueExist(hkey, ValueName);

	if (n <= 0) {
		SetDlgItemText(hDlg, nIDDlgItem, Def);
		return FALSE;
	}
	else {
		str = zalloc(n);
		if ( str ) { // set_new_handler(0) 対策
			tRegReadStringA(hkey, ValueName, str, n);
			SetDlgItemText(hDlg, nIDDlgItem, str);
			free(str);
			return TRUE;
		}
		else {
			return FALSE;
		}
	}
}

LibExport BOOL tRegReadStringForEditboxW(HKEY hkey, const wchar_t *ValueName, HWND hDlg, int nIDDlgItem, const wchar_t *Def)
{
	int n;
	wchar_t *str = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ReadStringForEditboxW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ReadStringForEditboxW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = tRegValueExistW(hkey, ValueName);

	if (n <= 0) {
		SetDlgItemTextW(hDlg, nIDDlgItem, Def);
		return FALSE;
	}
	else {
		str = walloc(n+1);
		if ( str ) { // set_new_handler(0) 対策
			tRegReadStringW(hkey, ValueName, str, n);
			SetDlgItemTextW(hDlg, nIDDlgItem, str);
			free(str);
			return TRUE;
		}
		else {
			return FALSE;
		}
	}
}

// レジストリから数値を読みとり、そのままエディットボックスへ
LibExport BOOL tRegReadIntegerForEditboxA(HKEY hkey, const char *ValueName, HWND hDlg, int nIDDlgItem, DWORD Def, BOOL bSigned)
{
    DWORD n;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に ReadIntegerForEditboxA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ReadIntegerForEditboxA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = tRegReadIntegerA(hkey, ValueName, Def);
	return SetDlgItemInt(hDlg, nIDDlgItem, n, bSigned);
}

LibExport BOOL tRegReadIntegerForEditboxW(HKEY hkey, const wchar_t *ValueName, HWND hDlg, int nIDDlgItem, DWORD Def, BOOL bSigned)
{
    DWORD n;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に ReadIntegerForEditboxW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ReadIntegerForEditboxW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = tRegReadIntegerW(hkey, ValueName, Def);
	return SetDlgItemInt(hDlg, nIDDlgItem, n, bSigned);
}

// エディットボックスから文字列の書き込み（デフォルト対応）
LibExport BOOL tRegWriteStringFromEditboxDefA(HKEY hkey, const char *ValueName, HWND hDlg, int nIDDlgItem, const char *Def)
{
	char *s = 0;
	int  n;
	BOOL result = FALSE;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteStringFromEditBoxA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteStringFromEditBoxA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = GetWindowTextLength(GetDlgItem(hDlg, nIDDlgItem))+1;
	s = zalloc(n);
	if ( s ) { // set_new_handler(0) 対策
		s[0] = 0;
		GetDlgItemText(hDlg, nIDDlgItem, s, n);
		result = tRegWriteStringA(hkey, ValueName, s[0]?s:Def, 0);
		free(s);
	}

	return result;
}

LibExport BOOL tRegWriteStringFromEditboxDefW(HKEY hkey, const wchar_t *ValueName, HWND hDlg, int nIDDlgItem, const wchar_t *Def)
{
	wchar_t *s = 0;
	int  n;
	BOOL result = FALSE;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteStringFromEditBoxW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteStringFromEditBoxW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = GetWindowTextLengthW(GetDlgItem(hDlg, nIDDlgItem))+1;
	s = walloc(n);
	if ( s ) { // set_new_handler(0) 対策
		s[0] = 0;
		GetDlgItemTextW(hDlg, nIDDlgItem, s, n);
		result = tRegWriteStringW(hkey, ValueName, s[0]?s:Def, 0);
		free(s);
	}

	return result;
}

// エディットボックスから文字列を読みとり、そのままレジストリへ
LibExport BOOL tRegWriteStringFromEditboxA(HKEY hkey, const char *ValueName, HWND hDlg, int nIDDlgItem, char rws_expand_flag)
{
	int n;
	BOOL result = FALSE;
	char *str = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteStringFromEditboxA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteStringFromEditboxA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = GetWindowTextLength(GetDlgItem(hDlg, nIDDlgItem))+1;
	str = zalloc(n);
	if ( str ) { // set_new_handler(0) 対策
		str[0] = 0;
		GetDlgItemText(hDlg, nIDDlgItem, str, n);
		result = tRegWriteStringA(hkey, ValueName, str, rws_expand_flag);
		free(str);
	}

	return result;
}

LibExport BOOL tRegWriteStringFromEditboxW(HKEY hkey, const wchar_t *ValueName, HWND hDlg, int nIDDlgItem, char rws_expand_flag)
{
	int n;
	BOOL result = FALSE;
	wchar_t *str = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteStringFromEditboxW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteStringFromEditboxW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	n = GetWindowTextLengthW(GetDlgItem(hDlg, nIDDlgItem))+1;
	str = walloc(n);
	if ( str ) { // set_new_handler(0) 対策
		str[0] = 0;
		GetDlgItemTextW(hDlg, nIDDlgItem, str, n);
		result = tRegWriteStringW(hkey, ValueName, str, rws_expand_flag);
		free(str);
	}

	return result;
}

// エディットボックスから数値を読みとり、そのままレジストリへ
LibExport BOOL tRegWriteIntegerFromEditboxA(HKEY hkey, const char *ValueName, HWND hDlg, int nIDDlgItem)
{
	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に WriteIntegerFromEditboxA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteIntegerFromEditboxA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	return tRegWriteIntegerA(hkey, ValueName, GetDlgItemInt(hDlg, nIDDlgItem, NULL, 0));
}

LibExport BOOL tRegWriteIntegerFromEditboxW(HKEY hkey, const wchar_t *ValueName, HWND hDlg, int nIDDlgItem)
{
	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に WriteIntegerFromEditboxW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteIntegerFromEditboxW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	return tRegWriteIntegerW(hkey, ValueName, GetDlgItemInt(hDlg, nIDDlgItem, NULL, 0));
}

// (new)ReadString 補助関数
static char *aux_ReadStringA(HKEY hkey, const char *ValueName, const char *Def, int *lpn)
{
	int size = 0;
	char *p = 0;
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL,modeJP?"開かれていないキーを対象に (new)RegReadStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in (new)ReadString.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		size = 0;
	}
	else {
        size = tRegValueExist(hkey, ValueName);
	}

	if ( size <= 0 ) {
		if ( Def ) {
			if ( lpn ) {
				*lpn = lstrlen( Def ) + 1;
			}
			return _strdup(Def);
		}
		else {
			return NULL;
		}
	}

	p = zalloc( size+1 );
	if (p && ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hkey,ValueName,NULL,NULL,(unsigned char *)p,(unsigned long *)&size))) {
		size /= sizeof(char);
		
		if ( lpn ) {
			*lpn = size + 1;
		}
		p[size] = 0;
		return p;
	}
	else
		return NULL;
}

static wchar_t *aux_ReadStringW(HKEY hkey, const wchar_t *ValueName, const wchar_t *Def, int *lpn)
{
	int size = 0;
	wchar_t *p = 0;
	tRegLastError = ERROR_SUCCESS;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に (new)RegReadStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in (new)ReadString.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		}
		size = 0;
	}
	else {
        size = tRegValueExistW(hkey, ValueName);
	}

	if ( size <= 0 ) {
		if ( Def ) {
			if ( lpn ) {
				*lpn = lstrlenW( Def ) + 1;
			}
			return _wcsdup(Def);
		}
		else {
			return NULL;
		}
	}

	p = walloc( size+1 );
	if (p && ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hkey,ValueName,NULL,NULL,(unsigned char *)p,(unsigned long *)&size))) {
		size /= sizeof(wchar_t);
		
		if ( lpn ) {
			*lpn = size + 1;
		}
		p[size] = 0;
		return p;
	}
	else
		return NULL;
}

// メモリの準備とレジストリから文字列のリード。戻り値はあとで delete[] すること！ <クラス>
char* REGA::new_ReadString(const char *ValueName, const char *Def) const
{
	int n = 0;
	char *p = 0, *r = 0;

	p = aux_ReadStringA(hkey, ValueName, Def, &n);
	if ( p ) {
		r = new char [ n ];
		if ( r ) { // set_new_handler(0) 対策
			memcpy(r, p, n*sizeof(char));
		}
		free( p );
		return r;
	}
	return NULL;
}

wchar_t* REGW::new_ReadString(const wchar_t *ValueName, const wchar_t *Def) const
{
	int n = 0;
	wchar_t *p = 0, *r = 0;

	p = aux_ReadStringW(hkey, ValueName, Def, &n);
	if ( p ) {
		r = new wchar_t [ n ];
		if ( r ) { // set_new_handler(0) 対策
			memcpy(r, p, n*sizeof(wchar_t));
		}
		free( p );
		return r;
	}
	return NULL;
}

// メモリの確保と文字列の読み込み - あとでfreeすること
LibExport char *mtRegReadStringA(HKEY hkey, const char *ValueName, const char *Def)
{
	return aux_ReadStringA(hkey, ValueName, Def, NULL);
}

LibExport wchar_t *mtRegReadStringW(HKEY hkey, const wchar_t *ValueName, const wchar_t *Def)
{
	return aux_ReadStringW(hkey, ValueName, Def, NULL);
}

// REG_MULTI_SZからデータを読み込み、\0を\r\nに変換してvalueに入れる
LibExport BOOL tRegReadMultiStringA(HKEY hkey, const char *ValueName, char *value, int size)
{
	int i, j;
	char *data;
	DWORD type = 0;
	bool last_is_nl = 0;

	if (ValueName == NULL || value == NULL || size == 0)
		return FALSE;

	value[0] = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL, modeJP?"開かれていないキーを対象に ReadMultiStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in ReadMultiStringA.","Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	data = mtRegReadString(hkey, ValueName, 0);

	if ( data == NULL ) { // 値が存在しなかった場合
		return FALSE;
	}

	type = tRegValueType(hkey, ValueName);
	if ( type == REG_SZ || type == REG_EXPAND_SZ ) { // REG_MULTI_SZではなかった場合
		if ( lstrlen(data) < size ) {
			lstrcpy(value, data);
			free( data );
			return TRUE;
		}
		else {
			free( data );
			return FALSE;
		}
	}
	else if ( type == REG_MULTI_SZ ) { // REG_MULTI_SZ だった場合 \0→\r\n に変換したり
		for(i=j=0 ; j<size ; i++,j++) {
			if ( data[i] == '\0' ) {
				if ( last_is_nl ) {
					value[j] = 0;
					break;
				}
				else {
					value[j] = '\r';
					value[++j] = '\n';
					last_is_nl = 1;
				}
			}
			else {
				value[j] = data[i];
				last_is_nl = 0;
			}
		}

		free( data );

		if (j == size) {
			value[0] = 0;
			return FALSE;
		}

		return TRUE;
	}

	return FALSE; // エラー
}

LibExport BOOL tRegReadMultiStringW(HKEY hkey, const wchar_t *ValueName, wchar_t *value, int size)
{
	int i, j;
	wchar_t *data;
	DWORD type = 0;
	bool last_is_nl = 0;

	if (ValueName == NULL || value == NULL || size == 0)
		return FALSE;

	value[0] = 0;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL, modeJP?L"開かれていないキーを対象に ReadMultiStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in ReadMultiStringW.",L"Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	data = mtRegReadStringW(hkey, ValueName, 0);

	if ( data == NULL ) { // 値が存在しなかった場合
		return FALSE;
	}

	type = tRegValueTypeW(hkey, ValueName);
	if ( type == REG_SZ || type == REG_EXPAND_SZ ) { // REG_MULTI_SZではなかった場合
		if ( lstrlenW(data) < size ) {
			lstrcpyW(value, data);
			free( data );
			return TRUE;
		}
		else {
			free( data );
			return FALSE;
		}
	}
	else if ( type == REG_MULTI_SZ ) { // REG_MULTI_SZ だった場合 \0→\r\n に変換したり
		for(i=j=0 ; j<size ; i++,j++) {
			if ( data[i] == L'\0' ) {
				if ( last_is_nl ) {
					value[j] = 0;
					break;
				}
				else {
					value[j] = L'\r';
					value[++j] = L'\n';
					last_is_nl = 1;
				}
			}
			else {
				value[j] = data[i];
				last_is_nl = 0;
			}
		}

		free( data );

		if (j == size) {
			value[0] = 0;
			return FALSE;
		}

		return TRUE;
	}

	return FALSE; // エラー
}

// \r\nを\0に変換し、REG_MULTI_SZへデータを入れる
LibExport BOOL tRegWriteMultiStringA(HKEY hkey, const char *ValueName, const char *value)
{
	char *data = 0;
	int  i, j;
	bool last_is_cr = 0;
	tRegLastError = ERROR_SUCCESS;

	if (ValueName == NULL || value == NULL)
		return FALSE;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBox(NULL, modeJP?"開かれていないキーを対象に WriteMultiStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in WriteMultiStringA.","Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	data = zalloc(lstrlen(value)+2);

	if ( data ) { // set_new_handler(0) 対策
		for(i=j=0 ; value[i] ; i++,j++) {
			if ( value[i] == '\r' ) {
				if ( last_is_cr ) {
					i++;
					j--;
				}
				else {
					data[j] = 0;
					i++;
					if ( value[i] == 0 )
						break;
					last_is_cr = 1;
				}
			}
			else {
				data[j] = value[i];
				last_is_cr = 0;
			}
		}

		data[j] = 0;
		if ( !last_is_cr )
			data[++j] = 0;

		tRegLastError = RegSetValueEx(hkey,ValueName,NULL,REG_MULTI_SZ,(const unsigned char *)data, j+1);
		free(data);

		return (tRegLastError == ERROR_SUCCESS)?TRUE:FALSE;
	}
	else { // メモリ不足等
		return FALSE;
	}
}

LibExport BOOL tRegWriteMultiStringW(HKEY hkey, const wchar_t *ValueName, const wchar_t *value)
{
	wchar_t *data = 0;
	int  i, j;
	bool last_is_cr = 0;
	tRegLastError = ERROR_SUCCESS;

	if (ValueName == NULL || value == NULL)
		return FALSE;

	if (hkey == NULL) {
		if ( useMessage ) {
			MessageBoxW(NULL, modeJP?L"開かれていないキーを対象に WriteMultiStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in WriteMultiStringW.",L"Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return FALSE;
	}

	data = walloc(lstrlenW(value)+2);

	if ( data ) { // set_new_handler(0) 対策
		for(i=j=0 ; value[i] ; i++,j++) {
			if ( value[i] == L'\r' ) {
				if ( last_is_cr ) {
					i++;
					j--;
				}
				else {
					data[j] = 0;
					i++;
					if ( value[i] == 0 )
						break;
					last_is_cr = 1;
				}
			}
			else {
				data[j] = value[i];
				last_is_cr = 0;
			}
		}

		data[j] = 0;
		if ( !last_is_cr )
			data[++j] = 0;

		tRegLastError = RegSetValueExW(hkey,ValueName,NULL,REG_MULTI_SZ,(const unsigned char *)data, j+1);
		free(data);

		return (tRegLastError == ERROR_SUCCESS)?TRUE:FALSE;
	}
	else { // メモリ不足等
		return FALSE;
	}
}

// (new)ReadMultiString補助関数
static char *aux_ReadMultiStringA(HKEY hkey, const char *ValueName, int *lpn)
{
	char *p = 0;
	DWORD type = 0, l, i, j, n;
	tRegLastError = ERROR_SUCCESS;

	if ( hkey == NULL ) {
		if ( useMessage ) {
			MessageBox(NULL, modeJP?"開かれていないキーを対象に (new)ReadMultiStringA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in (new)ReadMultiStringA.","Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return NULL;
	}

	if ( ValueName == NULL || ERROR_SUCCESS != (tRegLastError = RegQueryValueEx(hkey, ValueName, 0, &type, NULL, &l))) {
		return NULL;
	}

	if ( type == REG_SZ || type == REG_EXPAND_SZ ) { // REG_MULTI_SZではなかった場合
		return aux_ReadStringA( hkey, ValueName, 0, lpn );
	}
	else if ( type == REG_MULTI_SZ ) { // REG_MULTI_SZだった場合 - まずは \0 の数を数え、\0を\r\nに変換した後のサイズを調べる
		p = (char *)calloc( l, 1 );
		if ( p ) {
			RegQueryValueEx(hkey, ValueName, 0, &type, (LPBYTE)p, &l);
			l /= sizeof(char);

			for(i=j=0; i<l ; i++) {
				if ( p[i] == '\0' )
					j++;
			}

			n = i+j; // \0を\r\nに変換した後のサイズは i+j-1. 最後に\0を足してi+j.
			free( p );

			p = zalloc( n );
			if ( p ) {
				tRegReadMultiStringA(hkey, ValueName, p, n);
				if ( lpn ) {
					*lpn = n;
				}
				return p;
			}
		}
	}

	return NULL; // メモリ不足またはエラー
}

static wchar_t *aux_ReadMultiStringW(HKEY hkey, const wchar_t *ValueName, int *lpn)
{
	wchar_t *p = 0;
	DWORD type = 0, l, i, j, n;
	tRegLastError = ERROR_SUCCESS;

	if ( hkey == NULL ) {
		if ( useMessage ) {
			MessageBoxW(NULL, modeJP?L"開かれていないキーを対象に (new)ReadMultiStringW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in (new)ReadMultiStringW.",L"Registry Class",MB_OK | MB_ICONEXCLAMATION);
		}
		return NULL;
	}

	if ( ValueName == NULL || ERROR_SUCCESS != (tRegLastError = RegQueryValueExW(hkey, ValueName, 0, &type, NULL, &l))) {
		return NULL;
	}

	if ( type == REG_SZ || type == REG_EXPAND_SZ ) { // REG_MULTI_SZではなかった場合
		return aux_ReadStringW( hkey, ValueName, 0, lpn );
	}
	else if ( type == REG_MULTI_SZ ) { // REG_MULTI_SZだった場合 - まずは \0 の数を数え、\0を\r\nに変換した後のサイズを調べる
		p = (wchar_t *)calloc( l, 1 );
		if ( p ) {
			RegQueryValueExW(hkey, ValueName, 0, &type, (LPBYTE)p, &l);
			l /= sizeof(wchar_t);

			for(i=j=0; i<l ; i++) {
				if ( p[i] == L'\0' )
					j++;
			}

			n = i+j; // \0を\r\nに変換した後のサイズは i+j-1. 最後に\0を足してi+j.
			free( p );

			p = walloc( n );
			if ( p ) {
				tRegReadMultiStringW(hkey, ValueName, p, n);
				if ( lpn ) {
					*lpn = n;
				}
				return p;
			}
		}
	}

	return NULL; // メモリ不足またはエラー
}


// REG_MULTI_SZからデータを読み込み、\0を\r\nに変換して、領域を確保して返却(あとでdelete[]すること) <クラス>
char* REGA::new_ReadMultiString(const char *ValueName) const
{
	char *p = 0, *r = 0;
	int  n = 0;
	
	p = aux_ReadMultiStringA(hkey, ValueName, &n);

	if ( p ) {
        r = new char [ n ];
		if ( r ) { // set_new_handler(0) 対策
            memcpy(r, p, n*sizeof(char));
		}
		free( p );
		return r;
	}
	return NULL;
}

wchar_t* REGW::new_ReadMultiString(const wchar_t *ValueName) const
{
	wchar_t *p = 0, *r = 0;
	int  n = 0;
	
	p = aux_ReadMultiStringW(hkey, ValueName, &n);

	if ( p ) {
        r = new wchar_t [ n ];
		if ( r ) { // set_new_handler(0) 対策
            memcpy(r, p, n*sizeof(wchar_t));
		}
		free( p );
		return r;
	}
	return NULL;
}

// REG_MULTI_SZからデータを読み込み、\0を\r\nに変換して、領域を確保して返却(あとでfreeすること)
LibExport char *mtRegReadMultiStringA(HKEY hkey, const char *ValueName)
{
	return aux_ReadMultiStringA(hkey, ValueName, NULL);
}

LibExport wchar_t *mtRegReadMultiStringW(HKEY hkey, const wchar_t *ValueName)
{
	return aux_ReadMultiStringW(hkey, ValueName, NULL);
}

// hkSource\\source から hkDest\\dest へ、値をコピーし、hkSource\\source 下のすべての値を削除する
LibExport BOOL tRegMoveValuesA(HKEY hkSource, const char *source, HKEY hkDest, const char *dest)
{
	REG   reg1, reg2;
	DWORD n = 0,vn = 0,vl = 0,vtype = 0, maxValueNameLen = 0, maxValueLen = 0;
	char  *valuename = 0, *valuedata = 0;
	BOOL  bflag = FALSE;

	if (reg1.OpenKey(hkSource, source, true)) {
		RegQueryInfoKey(reg1.GetHKey(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueNameLen, &maxValueLen, NULL, NULL);
		maxValueNameLen += 5;
		valuename = zalloc(maxValueNameLen);
		if ( valuename ) { // set_new_handler(0) 対策
			maxValueLen += 5;
			valuedata = zalloc(maxValueLen);
			if ( valuedata ) { // set_new_handler(0) 対策
				if (reg2.OpenKey(hkDest, dest, true)) {
					// 値をコピーする
					n = 0;
					while( (vn = maxValueNameLen, vl = maxValueLen), ERROR_NO_MORE_ITEMS != RegEnumValue(reg1.GetHKey(),n,valuename,&vn,0,&vtype,(unsigned char *)valuedata,&vl) ) {
						RegSetValueEx(reg2.GetHKey(), valuename,0,vtype,(unsigned char *)valuedata,vl);
						n++;
					}

					// コピー元の値を削除する
					n = 0;
					while( (vn = maxValueNameLen, vl = maxValueLen), ERROR_NO_MORE_ITEMS != RegEnumValue(reg2.GetHKey(),n,valuename,&vn,0,&vtype,(unsigned char *)valuedata,&vl) ) {
						reg1.DeleteValue(valuename);
						n++;
					}

					reg2.CloseKey();
					bflag = TRUE;
				}
				free(valuedata);
			}
			free(valuename);
		}
		reg1.CloseKey();
	}

	return bflag;
}

// hkSource\\source から hkDest\\dest へ、値をコピーし、hkSource\\source 下のすべての値を削除する
LibExport BOOL tRegMoveValuesW(HKEY hkSource, const wchar_t *source, HKEY hkDest, const wchar_t *dest)
{
	REGW    reg1, reg2;
	DWORD   n = 0,vn = 0,vl = 0,vtype = 0, maxValueNameLen = 0, maxValueLen = 0;
	wchar_t *valuename = 0;
	char    *valuedata = 0;
	BOOL    bflag = FALSE;

	if (reg1.OpenKey(hkSource, source, true)) {
		RegQueryInfoKeyW(reg1.GetHKey(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueNameLen, &maxValueLen, NULL, NULL);
		maxValueNameLen += 5;
		valuename = walloc(maxValueNameLen);
		if ( valuename ) { // set_new_handler(0) 対策
			maxValueLen += 5;
			valuedata = zalloc(maxValueLen);
			if ( valuedata ) { // set_new_handler(0) 対策
				if (reg2.OpenKey(hkDest, dest, true)) {
					// 値をコピーする
					n = 0;
					while( (vn = maxValueNameLen, vl = maxValueLen), ERROR_NO_MORE_ITEMS != RegEnumValueW(reg1.GetHKey(),n,valuename,&vn,0,&vtype,(unsigned char *)valuedata,&vl) ) {
						RegSetValueExW(reg2.GetHKey(), valuename, 0, vtype, (unsigned char *)valuedata, vl);
						n++;
					}

					// コピー元の値を削除する
					n = 0;
					while( (vn = maxValueNameLen, vl = maxValueLen), ERROR_NO_MORE_ITEMS != RegEnumValueW(reg2.GetHKey(),n,valuename,&vn,0,&vtype,(unsigned char *)valuedata,&vl) ) {
						reg1.DeleteValue(valuename);
						n++;
					}

					reg2.CloseKey();
					bflag = TRUE;
				}
				free(valuedata);
			}
			free(valuename);
		}
		reg1.CloseKey();
	}

	return bflag;
}

// iniファイル中のセクションの数を数える
LibExport DWORD tiniNumSectionA( const char *inifile )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	char *lpBuf = 0;

	if ( inifile == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileSectionNames( lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSectionNames()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			for(i=n=0 ; !(lpBuf[i] == '\0' && lpBuf[i+1] == '\0') ; i++) {
				if ( lpBuf[i+1] == '\0' ) {
					n++;
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return n;
}

LibExport DWORD tiniNumSectionW( const wchar_t *inifile )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	wchar_t *lpBuf = 0;

	if ( inifile == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileSectionNamesW( lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSectionNames()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			for(i=n=0 ; !(lpBuf[i] == L'\0' && lpBuf[i+1] == L'\0') ; i++) {
				if ( lpBuf[i+1] == L'\0' ) {
					n++;
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return n;
}


// iniファイルのセクション中のキーの数を数える
LibExport DWORD tiniNumKeyA( const char *inifile, const char *section )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	char *lpBuf = 0;

	if ( inifile == NULL || section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileString( section, NULL, "", lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			for(i=n=0 ; !(lpBuf[i] == '\0' && lpBuf[i+1] == '\0') ; i++) {
				if ( lpBuf[i+1] == '\0' ) {
					n++;
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return n;
}

LibExport DWORD tiniNumKeyW( const wchar_t *inifile, const wchar_t *section )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	wchar_t *lpBuf = 0;

	if ( inifile == NULL || section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileStringW( section, NULL, L"", lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			for(i=n=0 ; !(lpBuf[i] == L'\0' && lpBuf[i+1] == L'\0') ; i++) {
				if ( lpBuf[i+1] == L'\0' ) {
					n++;
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return n;
}

// iniファイルから文字列を読み込む(使い終わったらfreeすること)
LibExport char *mtiniReadStringA( const char *inifile, const char *section, const char *key, const char *def )
{
	DWORD dwSize = 1024, dwr = 0;
	char *lpBuf = NULL;

	if ( section == NULL || key == NULL || def == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileString( section, key, def, lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 1 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-1 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できたので、サイズを調整する
			char *tmp = (char *)realloc(lpBuf, sizeof(char) * (lstrlen(lpBuf)+1));

			if ( tmp ) {
				lpBuf = tmp;
			}
			break;
		}
	}

	if ( lpBuf == NULL ) { // 取得に失敗していた場合
        lpBuf = _strdup( def );
	}

	return lpBuf;
}

LibExport wchar_t *mtiniReadStringW( const wchar_t *inifile, const wchar_t *section, const wchar_t *key, const wchar_t *def )
{
	DWORD dwSize = 1024, dwr = 0;
	wchar_t *lpBuf = NULL;

	if ( section == NULL || key == NULL || def == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileStringW( section, key, def, lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 1 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-1 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できたので、サイズを調整する
			wchar_t *tmp = (wchar_t *)realloc(lpBuf, sizeof(wchar_t) * (lstrlenW(lpBuf)+1));

			if ( tmp ) {
				lpBuf = tmp;
			}
			break;
		}
	}

	if ( lpBuf == NULL ) { // 取得に失敗していた場合
        lpBuf = _wcsdup( def );
	}

	return lpBuf;
}

// iniファイルからセクションを列挙(使い終わったらfreeすること)
LibExport char *mtiniEnumSectionA( const char *inifile, DWORD num )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	char *lpBuf = NULL, *retp = NULL;

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileSectionNames( lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSectionNames()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			if ( num == 0 ) {
				retp = _strdup( lpBuf );
			}
			else {
				for(i=n=0 ; !(lpBuf[i] == '\0' && lpBuf[i+1] == '\0') ; i++) {
					if ( lpBuf[i+1] == '\0' ) {
						if ( ++n == num ) {
							retp = _strdup( &lpBuf[i+2] );
							break;
						}
					}
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return retp;
}

LibExport wchar_t *mtiniEnumSectionW( const wchar_t *inifile, DWORD num )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	wchar_t *lpBuf = NULL, *retp = NULL;

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileSectionNamesW( lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSectionNames()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			if ( num == 0 ) {
				retp = _wcsdup( lpBuf );
			}
			else {
				for(i=n=0 ; !(lpBuf[i] == L'\0' && lpBuf[i+1] == L'\0') ; i++) {
					if ( lpBuf[i+1] == L'\0' ) {
						if ( ++n == num ) {
							retp = _wcsdup( &lpBuf[i+2] );
							break;
						}
					}
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return retp;
}

// iniファイルのセクションからキーを列挙(使い終わったらfreeすること)
LibExport char *mtiniEnumKeyA( const char *inifile, const char *section, DWORD num )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	char *lpBuf = NULL, *retp = NULL;

	if ( section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileString( section, NULL, "", lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			if ( num == 0 ) {
				retp = _strdup( lpBuf );
			}
			else {
				for(i=n=0 ; !(lpBuf[i] == '\0' && lpBuf[i+1] == '\0') ; i++) {
					if ( lpBuf[i+1] == '\0' ) {
						if ( ++n == num ) {
							retp = _strdup( &lpBuf[i+2] );
							break;
						}
					}
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return retp;
}

LibExport wchar_t *mtiniEnumKeyW( const wchar_t *inifile, const wchar_t *section, DWORD num )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	wchar_t *lpBuf = NULL, *retp = NULL;

	if ( section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileStringW( section, NULL, L"", lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileString()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			// lpBufの中をカウントする
			DWORD i;

			if ( num == 0 ) {
				retp = _wcsdup( lpBuf );
			}
			else {
				for(i=n=0 ; !(lpBuf[i] == L'\0' && lpBuf[i+1] == L'\0') ; i++) {
					if ( lpBuf[i+1] == L'\0' ) {
						if ( ++n == num ) {
							retp = _wcsdup( &lpBuf[i+2] );
							break;
						}
					}
				}
			}

			free( lpBuf ); lpBuf = NULL;
			break;
		}
	}

	return retp;
}

// ハイブ(最上位レジストリキー)の名前を、ハイブのハンドルへ変換
LibExport HKEY  tRegHiveKeyA(const char *hive)
{
	if ( hive ) {
		if (0 == _strcmpi(hive, "HKEY_CLASSES_ROOT") || 0 == _strcmpi(hive, "HKCR")) {
			return HKEY_CLASSES_ROOT;
		}
		else if (0 == _strcmpi(hive, "HKEY_CURRENT_USER") || 0 == _strcmpi(hive, "HKCU")) {
			return HKEY_CURRENT_USER;
		}
		else if (0 == _strcmpi(hive, "HKEY_LOCAL_MACHINE") || 0 == _strcmpi(hive, "HKLM")) {
			return HKEY_LOCAL_MACHINE;
		}
		else if (0 == _strcmpi(hive, "HKEY_USERS")) {
			return HKEY_USERS;
		}
		else if (0 == _strcmpi(hive, "HKEY_CURRENT_CONFIG") || 0 == _strcmpi(hive, "HKCC")) {
			return HKEY_CURRENT_CONFIG;
		}
		else if (0 == _strcmpi(hive, "HKEY_DYN_DATA") || 0 == _strcmpi(hive, "HKDD")) {
			return HKEY_DYN_DATA;
		}
		else if (0 == _strcmpi(hive, "HKEY_PERFORMANCE_DATA") || 0 == _strcmpi(hive, "HKPD")) {
			return HKEY_PERFORMANCE_DATA;
		}
		else if (0 == _strcmpi(hive, "HKEY_PERFORMANCE_TEXT") || 0 == _strcmpi(hive, "HKPT")) {
			return HKEY_PERFORMANCE_TEXT;
		}
		else if (0 == _strcmpi(hive, "HKEY_PERFORMANCE_NLSTEXT") || 0 == _strcmpi(hive, "HKPN")) {
			return HKEY_PERFORMANCE_NLSTEXT;
		}
	}

	return NULL;
}

LibExport HKEY  tRegHiveKeyW(const wchar_t *hive)
{
	if ( hive ) {
		if (0 == _wcsicmp(hive, L"HKEY_CLASSES_ROOT") || 0 == _wcsicmp(hive, L"HKCR")) {
			return HKEY_CLASSES_ROOT;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_CURRENT_USER") || 0 == _wcsicmp(hive, L"HKCU")) {
			return HKEY_CURRENT_USER;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_LOCAL_MACHINE") || 0 == _wcsicmp(hive, L"HKLM")) {
			return HKEY_LOCAL_MACHINE;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_USERS")) {
			return HKEY_USERS;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_CURRENT_CONFIG") || 0 == _wcsicmp(hive, L"HKCC")) {
			return HKEY_CURRENT_CONFIG;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_DYN_DATA") || 0 == _wcsicmp(hive, L"HKDD")) {
			return HKEY_DYN_DATA;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_PERFORMANCE_DATA") || 0 == _wcsicmp(hive, L"HKPD")) {
			return HKEY_PERFORMANCE_DATA;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_PERFORMANCE_TEXT") || 0 == _wcsicmp(hive, L"HKPT")) {
			return HKEY_PERFORMANCE_TEXT;
		}
		else if (0 == _wcsicmp(hive, L"HKEY_PERFORMANCE_NLSTEXT") || 0 == _wcsicmp(hive, L"HKPN")) {
			return HKEY_PERFORMANCE_NLSTEXT;
		}
	}

	return NULL;
}

// サブキーの削除(その下にあるサブキーすべて削除)
LibExport BOOL  tRegDeleteSubKeyA(HKEY hkey, const char *subkey)
{
	DWORD sk = 0, sklen = 0, i, buflen = 0;
	HKEY hsubkey;
	char **subkeys = 0, *subkeyname = 0;
	tRegLastError = ERROR_SUCCESS;

	if (ERROR_SUCCESS == (tRegLastError = RegOpenKeyEx(hkey, subkey, 0, KEY_ALL_ACCESS, &hsubkey))) {
		if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);

		RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &sk, &sklen, NULL, NULL, NULL, NULL, NULL, NULL);
		if ( sk > 0 ) { // サブキーが一つでもあれば、それらを削除してから
			subkeys = (char **)malloc( sk*sizeof(char *) );
			if ( subkeys ) {
				buflen = (sklen+1)*2;
				subkeyname = zalloc( buflen );
				if ( subkeyname ) {
					for(i=0 ; i<sk ; i++) {
						buflen = (sklen+1)*2;
						RegEnumKeyEx(hsubkey, i, subkeyname, &buflen, NULL, NULL, NULL, NULL);
						subkeys[i] = _strdup( subkeyname );
					}
					free( subkeyname );

					for(i=0 ; i<sk ; i++) {
						if ( subkeys[i] ) {
							tRegDeleteSubKey( hsubkey, subkeys[i] );
							free( subkeys[i] );
						}
					}
				}
				free( subkeys );
			}
		}
		RegCloseKey( hsubkey );
	}
	else {
		return FALSE;
	}

	return (tRegLastError = RegDeleteKeyA(hkey, subkey)) == ERROR_SUCCESS ? TRUE : FALSE ;
}

LibExport BOOL  tRegDeleteSubKeyW(HKEY hkey, const wchar_t *subkey)
{
	DWORD sk = 0, sklen = 0, i, buflen = 0;
	HKEY hsubkey;
	wchar_t **subkeys = 0, *subkeyname = 0;
	tRegLastError = ERROR_SUCCESS;

	if (ERROR_SUCCESS == (tRegLastError = RegOpenKeyExW(hkey, subkey, 0, KEY_ALL_ACCESS, &hsubkey))) {
		if (bDisableReflectionKey) tRegDisableReflectionKey(hkey);

		RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &sk, &sklen, NULL, NULL, NULL, NULL, NULL, NULL);
		if ( sk > 0 ) { // サブキーが一つでもあれば、それらを削除してから
			subkeys = (wchar_t **)malloc( sk*sizeof(wchar_t *) );
			if ( subkeys ) {
				buflen = (sklen+1)*2;
				subkeyname = walloc( buflen );
				if ( subkeyname ) {
					for(i=0 ; i<sk ; i++) {
						buflen = (sklen+1)*2;
						RegEnumKeyExW(hsubkey, i, subkeyname, &buflen, NULL, NULL, NULL, NULL);
						subkeys[i] = _wcsdup( subkeyname );
					}
					free( subkeyname );

					for(i=0 ; i<sk ; i++) {
						if ( subkeys[i] ) {
							tRegDeleteSubKeyW( hsubkey, subkeys[i] );
							free( subkeys[i] );
						}
					}
				}
				free( subkeys );
			}
		}
		RegCloseKey( hsubkey );
	}
	else {
		return FALSE;
	}

	return (tRegLastError = RegDeleteKeyW(hkey, subkey)) == ERROR_SUCCESS ? TRUE : FALSE ;
}

// 複数行文字列をレジストリから読み込む
LibExport BOOL  tRegReadMultiStringDirectA(HKEY hKey, const char *entry, char *buf, LPDWORD psize)
{
	DWORD size = 0;
	DWORD type = 0;
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に RegReadMultiStringDirectA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in RegReadMultiStringDirect.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	if ( psize == NULL || entry == NULL || buf == NULL ) {
        return FALSE;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hKey, entry, NULL, &type, NULL, &size))) {
		switch( type ) {
			case REG_SZ:
			case REG_EXPAND_SZ:
				if ( *psize > size/sizeof(char) ) {
                    ZeroMemory(buf, *psize);
					return (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hKey, entry, NULL, NULL, (LPBYTE)buf, psize))) ? TRUE : FALSE;
				}
				break;

			case REG_MULTI_SZ:
				if ( *psize >= size/sizeof(char) ) {
					return (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hKey, entry, NULL, NULL, (LPBYTE)buf, psize))) ? TRUE : FALSE;
				}
				break;
		}
	}
	return FALSE;
}

LibExport BOOL  tRegReadMultiStringDirectW(HKEY hKey, const wchar_t *entry, wchar_t *buf, LPDWORD psize)
{
	DWORD size = 0;
	DWORD type = 0;
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に RegReadMultiStringDirectW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in RegReadMultiStringDirectW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	if ( psize == NULL || entry == NULL || buf == NULL ) {
        return FALSE;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hKey, entry, NULL, &type, NULL, &size))) {
		switch( type ) {
			case REG_SZ:
			case REG_EXPAND_SZ:
				if ( *psize > size/sizeof(wchar_t) ) {
                    ZeroMemory(buf, *psize);
					return (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hKey, entry, NULL, NULL, (LPBYTE)buf, psize))) ? TRUE : FALSE;
				}
				break;

			case REG_MULTI_SZ:
				if ( *psize >= size/sizeof(wchar_t) ) {
					return (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hKey, entry, NULL, NULL, (LPBYTE)buf, psize))) ? TRUE : FALSE;
				}
				break;
		}
	}
	return FALSE;
}

// 複数行文字列をレジストリから読み込む (あとでfreeすること)
LibExport char *mtRegReadMultiStringDirectA(HKEY hKey, const char *entry, LPDWORD psize)
{
	DWORD size = tRegValueSize(hKey, entry);
	char *buf = 0;

	if ( size == 0 || psize == NULL ) {
		return NULL;
	}
	buf = (char *)malloc( ++size );
	*psize = size;
	if ( buf ) {
		if ( TRUE == tRegReadMultiStringDirectA(hKey, entry, buf, psize) ) {
			return buf;
		}
		free( buf );
	}
	return NULL;
}

LibExport wchar_t *mtRegReadMultiStringDirectW(HKEY hKey, const wchar_t *entry, LPDWORD psize)
{
	DWORD size = tRegValueSizeW(hKey, entry);
	wchar_t *buf = 0;

	if ( size == 0 || psize == NULL ) {
		return NULL;
	}
	buf = walloc( ++size );
	*psize = size * sizeof(wchar_t);
	if ( buf ) {
		if ( TRUE == tRegReadMultiStringDirectW(hKey, entry, buf, psize) ) {
			return buf;
		}
		free( buf );
	}
	return NULL;
}

// 複数行文字列をレジストリから読み込む (あとでdelete[]すること)
char* REGA::new_ReadMultiStringDirect(const char *entry, LPDWORD psize) const
{
	DWORD size = tRegValueSizeA(hkey, entry);
	char *buf = 0;

	if ( size == 0 || psize == NULL ) {
		return NULL;
	}
	++size;
	buf = new char [ size ];
	if ( buf ) {
		*psize = size;
		if ( TRUE == tRegReadMultiStringDirectA(hkey, entry, buf, psize) ) {
			return buf;
		}
		free(buf);
	}
	return NULL;
}

wchar_t* REGW::new_ReadMultiStringDirect(const wchar_t *entry, LPDWORD psize) const
{
	DWORD size = tRegValueSizeW(hkey, entry);
	wchar_t *buf = 0;

	if ( size == 0 || psize == NULL ) {
		return NULL;
	}
	++size;
	buf = new wchar_t [ size ];
	if ( buf ) {
		*psize = size * sizeof(wchar_t);
		if ( TRUE == tRegReadMultiStringDirectW(hkey, entry, buf, psize) ) {
			return buf;
		}
		free(buf);
	}
	return NULL;
}

// 複数行文字列をレジストリへ書き込む
LibExport BOOL  tRegWriteMultiStringDirectA(HKEY hKey, const char *entry, const char *buf, DWORD bufsize)
{
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に RegWriteMultiStringDirectA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in RegWriteMultiStringDirectA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	return (ERROR_SUCCESS == (tRegLastError = RegSetValueEx(hKey, entry, NULL, REG_MULTI_SZ, (const BYTE *)buf, bufsize*sizeof(char))));
}

LibExport BOOL  tRegWriteMultiStringDirectW(HKEY hKey, const wchar_t *entry, const wchar_t *buf, DWORD bufsize)
{
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に RegWriteMultiStringDirectW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in RegWriteMultiStringDirectW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	return (ERROR_SUCCESS == (tRegLastError = RegSetValueExW(hKey, entry, NULL, REG_MULTI_SZ, (const BYTE *)buf, bufsize*sizeof(wchar_t))));
}
/**/
// iniファイルのセクションを丸ごと読み込む
LibExport BOOL tiniReadSectionA( const char *inifile, const char *section, char *buf, DWORD bufsize )
{
	DWORD n;

	if ( inifile == NULL || section == NULL || buf == NULL || bufsize == 0 ) {
		return FALSE;
	}

	n = GetPrivateProfileSection( section, buf, bufsize, inifile );
	if ( n == 0 || n == bufsize-2 ) {
        return FALSE;
	}
	else {
		return TRUE;
	}
}

LibExport BOOL tiniReadSectionW( const wchar_t *inifile, const wchar_t *section, wchar_t *buf, DWORD bufsize )
{
	DWORD n;

	if ( inifile == NULL || section == NULL || buf == NULL || bufsize == 0 ) {
		return FALSE;
	}

	n = GetPrivateProfileSectionW( section, buf, bufsize, inifile );
	if ( n == 0 || n == bufsize-2 ) {
        return FALSE;
	}
	else {
		return TRUE;
	}
}

// iniファイルのセクションを丸ごと読み込む(使い終わったらfreeすること)
LibExport char *mtiniReadSectionA( const char *inifile, const char *section )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	char *lpBuf = NULL, *retp = NULL;

	if ( inifile == NULL || section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = zalloc(dwSize)) ) {
		dwr = GetPrivateProfileSection( section, lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSection()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			n = 0;
			while( !(lpBuf[n] == 0 && lpBuf[n+1] == 0) ) {
				n++;
			}
			n += 2;

			retp = (char *)realloc(lpBuf, n*sizeof(char));
			if ( !retp ) {
				retp = lpBuf;
			}
			break;
		}
	}

	return retp;
}

LibExport wchar_t *mtiniReadSectionW( const wchar_t *inifile, const wchar_t *section )
{
	DWORD dwSize = 1024, dwr = 0, n = 0;
	wchar_t *lpBuf = NULL, *retp = NULL;

	if ( inifile == NULL || section == NULL ) {
		return NULL;
	}

	while( NULL != (lpBuf = walloc(dwSize)) ) {
		dwr = GetPrivateProfileSectionW( section, lpBuf, dwSize, inifile );
		if ( dwr == dwSize - 2 ) { // GetPrivateProfileSection()の仕様により、メモリオーバーの際には dwSize-2 が返される
			// いったん解放して、サイズを2倍にしてリトライ
			free( lpBuf );
			dwSize *= 2;
			if ( dwSize < dwr ) { // かけた結果、小さくなってしまったらオーバーフロー
				lpBuf = NULL;
				break;
			}
		}
		else { // 正しく取得できた
			n = 0;
			while( !(lpBuf[n] == 0 && lpBuf[n+1] == 0) ) {
				n++;
			}
			n += 2;

			retp = (wchar_t *)realloc(lpBuf, n*sizeof(wchar_t));
			if ( !retp ) {
				retp = lpBuf;
			}
			break;
		}
	}

	return retp;
}

// iniファイルのセクションを丸ごと書き込む
LibExport BOOL tiniWriteSectionA( const char *inifile, const char *section, const char *buf )
{
	if ( inifile == NULL || section == NULL || buf == NULL ) {
		return FALSE;
	}

	return (WritePrivateProfileSection( section, buf, inifile ) != 0) ? TRUE : FALSE;
}

LibExport BOOL tiniWriteSectionW( const wchar_t *inifile, const wchar_t *section, const wchar_t *buf )
{
	if ( inifile == NULL || section == NULL || buf == NULL ) {
		return FALSE;
	}

	return (WritePrivateProfileSectionW( section, buf, inifile ) != 0) ? TRUE : FALSE;
}

// 複数行文字列(行が\0で区切られ終端が\0\0)の行数を調べる
// mszsize には msz のサイズを指定するが、ここを 0 にすると、単純に \0\0 を終端と見なす
LibExport DWORD numMultiStringA(const char *msz, DWORD mszsize)
{
	DWORD n = 0, i;

	if ( msz && mszsize != 1 ) {
		for(i=0 ; mszsize == 0 || i<mszsize ; i++) {
			if ( msz[i] == '\0' ) {
                n++;

				if ( mszsize == 0 ) {
					if ( msz[i+1] == '\0' ) {
						return n;
					}
				}
			}
		}
		n--;
	}

	return n;
}

LibExport DWORD numMultiStringW(const wchar_t *msz, DWORD mszsize)
{
	DWORD n = 0, i;

	if ( msz && mszsize != 1 ) {
		for(i=0 ; mszsize == 0 || i<mszsize ; i++) {
			if ( msz[i] == L'\0' ) {
                n++;

				if ( mszsize == 0 ) {
					if ( msz[i+1] == L'\0' ) {
						return n;
					}
				}
			}
		}
		n--;
	}

	return n;
}

// レジストリエントリの名前変更
LibExport BOOL  tRegRenValueA(HKEY hKey, const char *oldname, const char *newname)
{
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に RenValueA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in RenValueA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if ( tRegCopyValueA(hKey, oldname, newname) ) {
		if ( ERROR_SUCCESS == (tRegLastError = RegDeleteValue(hKey, oldname))) {
			return TRUE;
		}
	}

	return FALSE;
}

LibExport BOOL  tRegRenValueW(HKEY hKey, const wchar_t *oldname, const wchar_t *newname)
{
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBoxW(NULL,modeJP?L"開かれていないキーを対象に RenValueW が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":L"An error has occurred in RenValueW.",L"Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if ( tRegCopyValueW(hKey, oldname, newname) ) {
		if ( ERROR_SUCCESS == (tRegLastError = RegDeleteValueW(hKey, oldname))) {
			return TRUE;
		}
	}

	return FALSE;
}

// レジストリエントリのコピー
LibExport BOOL  tRegCopyValueA(HKEY hKey, const char *srcname, const char *destname)
{
	DWORD type = 0;
	DWORD size = 0;
	char *buf = 0;
	BOOL  rv = FALSE;
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に CopyValueA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in CopyValueA.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if ( srcname == NULL || destname == NULL ) {
		return 0;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hKey,srcname,NULL,&type,NULL,&size))) {
		buf = zalloc(size);
		if ( buf ) {
			if (ERROR_SUCCESS == (tRegLastError = RegQueryValueEx(hKey,srcname,NULL,NULL,(LPBYTE)buf,&size))) {
				if ( ERROR_SUCCESS == (tRegLastError = RegSetValueEx(hKey, destname, NULL, type, (CONST BYTE *)buf, size))) {
                    rv = TRUE;
				}
			}
			free( buf );
		}
	}

	return rv;
}

LibExport BOOL  tRegCopyValueW(HKEY hKey, const wchar_t *srcname, const wchar_t *destname)
{
	DWORD type = 0;
	DWORD size = 0;
	char  *buf = 0;
	BOOL  rv = FALSE;
	tRegLastError = ERROR_SUCCESS;

	if (hKey == NULL) {
		MessageBox(NULL,modeJP?"開かれていないキーを対象に CopyValueA が行われようとしたので保護します。\nこのメッセージが表示されたら、現在編集している/していたダイアログの名前を、メッセージの内容と共に正確に作者まで報告して下さい。":"An error has occurred in CopyValueW.","Registory Class",MB_OK | MB_ICONEXCLAMATION);
		return 0;
	}

	if ( srcname == NULL || destname == NULL ) {
		return 0;
	}

	if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hKey,srcname,NULL,&type,NULL,&size))) {
		buf = zalloc(size);
		if ( buf ) {
			if (ERROR_SUCCESS == (tRegLastError = RegQueryValueExW(hKey,srcname,NULL,NULL,(LPBYTE)buf,&size))) {
				if ( ERROR_SUCCESS == (tRegLastError = RegSetValueExW(hKey, destname, NULL, type, (CONST BYTE *)buf, size))) {
                    rv = TRUE;
				}
			}
			free( buf );
		}
	}

	return rv;
}

// GetPrivateProfileStringの仕様により、文字列が " や ' で囲まれていると、それが取り除かれてしまうので、' で囲っておく。
BOOL writePrivateProfileStringCTA( const char *lpAppName, const char *lpKeyName, const char *lpString, const char *lpFileName )
{
	if ( lpString[0] == '"' || lpString[0] == '\'' ) {
		char *lpString2 = zalloc(lstrlen(lpString)+3);
		BOOL bRes = FALSE;

		if ( lpString2 ) {
			lpString2[0] = '\'';
			lstrcat( lpString2, lpString );
			lstrcat( lpString2, "'" );

			bRes = WritePrivateProfileString( lpAppName, lpKeyName, lpString2, lpFileName );
			free( lpString2 );
		}

		return bRes;
	}
	else {
		return WritePrivateProfileString( lpAppName, lpKeyName, lpString, lpFileName );
	}
}

BOOL writePrivateProfileStringCTW( const wchar_t *lpAppName, const wchar_t *lpKeyName, const wchar_t *lpString, const wchar_t *lpFileName )
{
	if ( lpString[0] == L'"' || lpString[0] == L'\'' ) {
		wchar_t *lpString2 = walloc(lstrlenW(lpString)+3);
		BOOL bRes = FALSE;

		if ( lpString2 ) {
			lpString2[0] = L'\'';
			lstrcatW( lpString2, lpString );
			lstrcatW( lpString2, L"'" );

			bRes = WritePrivateProfileStringW( lpAppName, lpKeyName, lpString2, lpFileName );
			free( lpString2 );
		}

		return bRes;
	}
	else {
		return WritePrivateProfileStringW( lpAppName, lpKeyName, lpString, lpFileName );
	}
}

static const BYTE unicode_ini_default[] = {0xFF,0xFE,0x0D,0x00,0x0A,0x00}; // "<BOM><cr><lf>"

LibExport BOOL CreateUnicodeIniA(const char *inifile)
{
	// iniファイルが存在していない場合、Unicode版iniを先行作成
	FILE *fp;
	
	if (0 == fopen_s(&fp, inifile, "rb")) {
		fclose(fp); // iniファイルが存在した
		return TRUE;
	}
	else {
		if (0 == fopen_s(&fp, inifile, "wb")) {
			fwrite(unicode_ini_default, sizeof(unicode_ini_default), 1, fp);
			fclose(fp);
			return TRUE;
		}
		return FALSE;
	}
}

LibExport BOOL CreateUnicodeIniW(const wchar_t *inifile)
{
	// iniファイルが存在していない場合、Unicode版iniを先行作成
	FILE *fp;
	
	
	if (0 == _wfopen_s(&fp, inifile, L"rb")) {
		fclose(fp); // iniファイルが存在した
		return TRUE;
	}
	else {
		if (0 == _wfopen_s(&fp, inifile, L"wb")) {
			fwrite(unicode_ini_default, sizeof(unicode_ini_default), 1, fp);
			fclose(fp);
			return TRUE;
		}
		return FALSE;
	}
}

// 将来的には使えなくなるかもしれない関数 NtRenameKey (Ntdll.dll) を、とりあえず呼び出すための関数
LibExport LONG tRegRenameKeyW( HKEY hKey, const wchar_t *lpWSubKeyName, const wchar_t *lpWNewName )
{
	typedef LONG (WINAPI *LPFN_REGRENAMEKEY) (HKEY, LPCWSTR, LPCWSTR);
	LPFN_REGRENAMEKEY fnRegRenameKey =
		(LPFN_REGRENAMEKEY)GetProcAddress(GetModuleHandle("advapi32.dll"), "RegRenameKey");

	if (fnRegRenameKey) {
		return fnRegRenameKey(hKey, lpWSubKeyName, lpWNewName);
	}

	return ERROR_BAD_ENVIRONMENT;
}

LibExport LONG tRegRenameKeyA( HKEY hKey, const char *lpSubKeyName, const char *lpNewName )
{
	int iLength;
	LPWSTR lpWSubKeyName, lpWNewName;
	LONG lStatus = ERROR_BAD_ENVIRONMENT;
	
	// lpSubKeyName（変更前サブキー名称）をUnicode変換
	iLength = MultiByteToWideChar(CP_ACP, 0, lpSubKeyName, -1, NULL, 0) + 1;
	lpWSubKeyName = (LPWSTR)calloc(iLength, sizeof(WCHAR));
	if (lpWSubKeyName) {
		if (0 < MultiByteToWideChar(CP_ACP, 0, lpSubKeyName, -1, lpWSubKeyName, iLength)) {

			// lpNewName（変更後サブキー名称）をUnicode変換
			iLength = MultiByteToWideChar(CP_ACP, 0, lpNewName, -1, NULL, 0) + 1;
			lpWNewName = (LPWSTR)calloc(iLength, sizeof(WCHAR));
			if (lpWNewName) {
				if (0 < MultiByteToWideChar(CP_ACP, 0, lpNewName, -1, lpWNewName, iLength)) {
					lStatus = tRegRenameKeyW(hKey, lpWSubKeyName, lpWNewName);
				}
				free(lpWNewName);
			}
			else {
				lStatus = ERROR_NOT_ENOUGH_MEMORY;
			}
		}
		free(lpWSubKeyName);
	}
	else {
		lStatus = ERROR_NOT_ENOUGH_MEMORY;
	}

	return lStatus;
}

