#include "stdafx.h"
#include "Rnsf7.h"
#include "addctrl.h"
#include "symbol.h"
#include "function.h"
#include "resource.h"
#include "trnsunit.h"
#include "refresh.h"
#include "splash.h"
#include "commfunc.h"
#include "chkaccr.h"
#include "cpp_func.h"
#include <winerror.h>

// 96 DPI ピクセルを想定しているデザインをどれだけスケーリングするか
double scaleX;
double scaleY;

#pragma warning( disable : 4312 )
#define WORKAREA			13.0/14.0
#define LEFT_CTRLX			SCALEX(16)
#define RIGHT_CTRLX			SCALEX(580)
#define LV_MIN_HEIGHT		SCALEY(84)
#define LV_MID_HEIGHT		SCALEY(194)
#define LV_NORMAL_HEIGHT	SCALEY(304)
#define LVBT_RIGHT_CTRLX	SCALEX(520)
#define LV_BUTTONS_X        SCALEX(542)
#define LV_BUTTONS_WIDTH    SCALEX(70)
#define DIALOGWIDTH			SCALEX(630)

HINSTANCE hInst;					// プログラムのインスタンス

// ローカル関数
static BOOL registercontrol_o( HWND hCtrl, UINT i, UINT ctrl, UINT opt, UINT flag_opt, const char *key, const char *entry, const char *def_sz, UINT def_dw, const char *text, const char *id, UINT byte_min, UINT bit_max, UINT opt_u1, UINT opt_u2, void *opt_p1, void *opt_p2, LPARAM opt_lp, LPARAM lParam );	// コントロール登録
#define registercontrol(h,l)     registercontrol_o((h), ERRORVALUE, ctrl, opt, flag_opt, key, entry, def_sz, def_dw, text, id, byte_min, bit_max, opt_u1, opt_u2, opt_p1, opt_p2, opt_lp, (l) )
#define registercontrol_i(h,i,l) registercontrol_o((h), (i)       , ctrl, opt, flag_opt, key, entry, def_sz, def_dw, text, id, byte_min, bit_max, opt_u1, opt_u2, opt_p1, opt_p2, opt_lp, (l) )

// flagに基づいてtregに渡すオプションを選ぶマクロ
#define TREG_EXTYPE(X)	(((X) & SZ_EXPAND)?TREG_EXPAND_SZ : ((X) & MAYBE_EXPAND) ? TREG_MAYBE_SZ : TREG_NORMAL_SZ)

static void ready_for_restore( void );			// 「戻す」のための準備
static BOOL addTooltip( HWND hWnd_or_hCtrl, char *text ); // ツールチップへの追加。 text==NULL のとき初期化で、hWnd_or_hCtrlにはウィンドウハンドルを入れる
BOOL CALLBACK searchNormalSizeListView(HWND hCtrl, LPARAM snslv);	// ListViewサイズ拡張用
BOOL CALLBACK extNormalSizeListView(HWND hCtrl, LPARAM snslv);	// ListViewサイズ拡張用

// 共有グローバル変数
RCTRLS *rctrls;			// コントロールについて格納
UINT    nctrls;			// コントロールの個数
UINT    yctrls;			// 最後のコントロールの下端のy座標
UINT    dWidth, dHeight;	// ダイアログの高さと幅
UINT	gDialogWidthMin;	// ダイアログの横幅の最小値（スクロールバーの有無で変化する）
BOOL    bCannotWriteHKLM = 0;	// この環境で HKLM 配下の値にアクセスできなければ 1。そうでなければ 0。
HFONT   hBoldFont;

// コントロールタイプ
char *P_TEXT           = "TEXT";
char *P_CHECKBOX       = "CHECKBOX";
char *P_CHECKBOX3      = "CHECKBOX3";
char *P_EDITBOX        = "EDITBOX";
char *P_EDITBOXNUM     = "EDITBOXNUM";
char *P_ICON           = "ICON";
char *P_KEYLIST        = "KEYLIST";
char *P_LISTVIEW       = "LISTVIEW";
char *P_VALUELIST      = "VALUELIST";
char *P_BUTTON_NEW     = "BUTTON_NEW";
char *P_BUTTON_EDIT    = "BUTTON_EDIT";
char *P_BUTTON_DEL     = "BUTTON_DEL";
char *P_SPIN           = "SPIN";
char *P_BUTTON         = "BUTTON";
char *P_COLOR_BUTTON   = "COLOR_BUTTON";
char *P_BUTTON_FILE    = "BUTTON_FILE";
char *P_BUTTON_FOLDER  = "BUTTON_FOLDER";
char *P_BUTTON_DEFAULT = "BUTTON_DEFAULT";
char *P_COMBOBOX       = "COMBOBOX";
char *P_MULTIEDIT      = "MULTIEDIT";
char *P_CHECK_LIST     = "CHECK_LIST";
char *P_MIN_GOTO_BUTTON = "MIN_GOTO_BUTTON";
char *P_BUTTON_OK      = "BUTTON_OK";
char *P_BUTTON_CANCEL  = "BUTTON_CANCEL";
char *P_BUTTON_APPRY   = "BUTTON_APPRY";
char *P_BUTTON_RETRY   = "BUTTON_RETRY";
char *P_BUTTON_SAVE    = "BUTTON_SAVE";
char *P_BUTTON_LOAD    = "BUTTON_LOAD";
char *P_BUTTON_HELP    = "BUTTON_HELP";
char *P_OTHER          = "OTHER";

// チェック状態の音声用文字列
char *P_VOICE_CATEGORY = "カテゴリ名";
char *P_VOICE_UNCHECK  = "チェックなし";
char *P_VOICE_CHECK    = "チェック";
char *P_VOICE_NODET    = "半チェック";
char *P_VOICE_DISABLE  = "無効状態";

// リストビューのサイズ拡張用構造体
typedef struct {
	HWND hDlg;
    HWND hListView;
	int  iListViewTop;
	int  iDefHeight;
} SNSLV, *LSNSLV;

// 共有グローバル変数
HICON hIconCategory, hCBLIconCheck, hCBLIconUncheck, hCBLIconNoDet, hCBLIconDisable, hIconEmpty;
HICON hIconFolderBrowse, hIconFileBrowse, hIconCategoryOpen;
HICON hIconMail;
HICON hIconSelIcon, hIconInputText;
HIMAGELIST himlTreeSmall, himlCBLSmall, himlCBLState;

// デフォルトのRSCアイコン（共有）
HICON hDefaultRscIcon, hDefaultRscSmallIcon;

char *rscname, *g_item, *helpfile, *rndname;
UINT  contextid;

// モジュール内変数
static char initializing_flag = 0; // 初期化中（ダイアログの生成中は1。コントロールを操作してもisChangedが1にならない)
static HWND hCheckBoxList = NULL;; // チェックボックスリスト作成中
static HWND hGroupBox = NULL;

// 96 DPI ピクセルを想定しているデザインをどれだけスケーリングするか? の変数を初期化する
void InitScaling()
{
	HDC screen = GetDC(0);
	scaleX = GetDeviceCaps(screen, LOGPIXELSX) / 96.0;
	scaleY = GetDeviceCaps(screen, LOGPIXELSY) / 96.0;
	ReleaseDC(0, screen);
}

// もし key が HKLM 配下で、かつ、現在 HKLM へ書き込みアクセスできないならば、hCtrlを非活性にする
BYTE ifHKLMandSTDUSR_disable(HWND hCtrl, const char *key, UINT flag_opt)
{
	if (bCannotWriteHKLM &&  hCtrl) {
		if ((key && (0 == strncmp(key, "HKEY_LOCAL_MACHINE\\", 19) ||
		             0 == strncmp(key, "HKLM\\", 5) ||
		             0 == strncmp(key, "HKEY_CLASSES_ROOT\\", 18) ||
		             0 == strncmp(key, "HKCR\\", 5) ||
		             0 == strncmp(key, "HKEY_USERS\\", 11) ||
		             0 == strncmp(key, "HKU\\", 4)))
		    ||
			((flag_opt&CTRL_NEEDADMIN) == CTRL_NEEDADMIN)
		   ) {
			EnableWindow(hCtrl, FALSE);
			return 1;
		}
	}

	return 0;
}

HWND addctrl( HWND hSubDlg, UINT ctrl, UINT opt, UINT flag_opt, const char *key, const char *entry,
			  const char *def_sz, UINT def_dw, char *text, const char *id, UINT byte_min, UINT bit_max,
			  UINT opt_u1, UINT opt_u2, void *opt_p1, void *opt_p2, LPARAM opt_lp )
{
	HWND	hCtrl = NULL;	// これから作成するコントロールのハンドル
	HKEY	hKey;	// レジストリキーのハンドル
	static	UINT next_x = 0;// テキストの右に編集ボックスなどを配置したい場合
	static  UINT lastlv_btn_y = 0; // 最後に作ったListViewボタンのY座標
	static  HFONT hFont;	// 標準のフォント

	switch( ctrl ) {
		case AC_INIT: // 初期化（最初に必ず呼び出されなければならない）
			nctrls = 0;
			rctrls = NULL;
			next_x = 0;
			lastlv_btn_y = 0;
			hCheckBoxList = NULL;
			hGroupBox = NULL;
			searchID( NULL ); // ←戻り値は必ずエラーとなるので、戻り値はみない
			InitScaling();
			yctrls = SCALEY(8);
			dWidth = gDialogWidthMin = DIALOGWIDTH; // 本命の代入箇所は、もっと後ろ

			// 現在では、MS P ゴシックに固定
			// if ( rnsf7RegRead("NoDefFont", 0) == 0 ) {
			//	hFont = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
			// }
			// else {
			//	hFont = (HFONT)SendMessage(hSubDlg, WM_GETFONT, 0, 0);
			// }
			hFont = (HFONT)SendMessage(hSubDlg, WM_GETFONT, 0, 0);
			if (hBoldFont == NULL) {
				hBoldFont = CreateFont(SCALEY(12), 0,
									   0, 0, FW_BOLD | FW_NORMAL, 0, 0, 0,
									   SHIFTJIS_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
									   DEFAULT_QUALITY, VARIABLE_PITCH  | FF_DONTCARE,
									   "MS UI Gothic");
			}

			SendMessage(hSubDlg, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

			initializing_flag = 1; // ウィンドウ生成中を示すハンドル

			addTooltip( hSubDlg, NULL ); // 初期化。第１引数は、このウィンドウのハンドル
			init_chkaccr();	// アクセラレータキーチェックの初期化
			return NULL;

		case AC_FINISH: // 終了（最後に必ず呼び出されなければならない）
			next_x = 0;	// ここで一時的に利用させてもらうので、初期化
			hCheckBoxList = NULL; // チェックボックスリスト強制終了
			hGroupBox = NULL;	  // グループボックスも同様
			if ( initializing_flag == 0 ) return NULL;

			// [OK][キャンセル]などのボタンの追加
			switch( rnsf7RegRead("stdButtonMenu", 0) ) {
				case 1: // ダイアログ上部左側にメニューバーとして配置する
					// ボタンではなく、ダイアログ上部にメニューバーとして追加する
					SetMenu(hSubDlg, LoadMenu(hInst, (LPCSTR)IDR_DIALOGMENU));

					// 配置したメニューの分だけダイアログを下に伸ばす
					yctrls += GetSystemMetrics(SM_CYMENU) * 3 / 2;
					break;

				case 2: // ダイアログ上部右側にメニューバーとして配置する
					// ボタンではなく、ダイアログ上部にメニューバーとして追加する
					SetMenu(hSubDlg, LoadMenu(hInst, (LPCSTR)IDR_DIALOGMENU_R));

					// 配置したメニューの分だけダイアログを下に伸ばす
					yctrls += GetSystemMetrics(SM_CYMENU) * 3 / 2;
					break;

				case 3: // ダイアログ下部にボタンとして配置する（項目数が多い場合はスクロールが必要）[左寄せ]
					next_x =  SCALEX(LEFT_CTRLX);
					// そのまま下へ

				default: // ダイアログ下部にボタンとして配置する（項目数が多い場合はスクロールが必要）[右寄せ]
					if ( next_x == 0 ) {
						next_x =  SCALEX(90);
					}
					hCtrl = CreateWindow( WC_BUTTON, "OK", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | WS_DISABLED, next_x, yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDOK, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 0, 0, 0, 0, 0, 0, "OK", "IDOK", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "編集内容を保存し、このダイアログを閉じます");

					hCtrl = CreateWindow( WC_BUTTON, "キャンセル", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, next_x+SCALEX(73), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDCLOSE, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 1, 0, 0, 0, 0, 0, "キャンセル", "IDCANCEL", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "編集内容を保存せず、このダイアログを閉じます。\r\n編集内容は失われます([適用]を押していた場合は、それ以降の編集が失われます)");

					add_chkaccr( "適用(&A)" );
					hCtrl = CreateWindow( WC_BUTTON, "適用(&A)", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | WS_DISABLED, next_x+SCALEX(73*2), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDYES, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 2, 0, 0, 0, 0, 0, "適用(&A)", "IDYES", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "編集内容の保存だけを行い、このダイアログは閉じません");

					add_chkaccr( "戻す(&R)" );
					hCtrl = CreateWindow( WC_BUTTON, "戻す(&R)", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | WS_DISABLED, next_x+SCALEX(73*3), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDRETRY, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 3, 0, 0, 0, 0, 0, "戻す(&R)", "IDRETRY", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "このダイアログを開いたときの状態に戻します");

					add_chkaccr( "保存(&S)..." );
					hCtrl = CreateWindow( WC_BUTTON, "保存(&S)...", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, next_x+SCALEX(73*4), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDSAVE, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 5, 0, 0, 0, 0, 0, "保存(&S)", "IDSAVE", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "ダイアログの状態をファイルへ保存します");

					add_chkaccr( "読込(&L)..." );
					hCtrl = CreateWindow( WC_BUTTON, "読込(&L)...", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, next_x+SCALEX(73*5), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDLOAD, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 6, 0, 0, 0, 0, 0, "読込(&L)", "IDLOAD", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "ダイアログの状態をファイルから読み込みます");

					add_chkaccr( "ヘルプ(&H)" );
					hCtrl = CreateWindow( WC_BUTTON, "ヘルプ(&H)", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, next_x+SCALEX(73*6), yctrls+SCALEY(8), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDHELP, hInst, NULL);
					if ( hCtrl == NULL )
						return NULL;
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol_o( hCtrl, 0, AC_FINISH, 4, 0, 0, 0, 0, 0, "ヘルプ(&H)", "IDHELP", 0, 0, 0, 0, 0, 0, 0, 0);
					addTooltip(hCtrl, "このダイアログに関するヘルプを表示します");

					// 配置したボタンの分だけダイアログを下に伸ばす
					yctrls += SCALEY(34);
					break;
			}
			// 終了準備
			yctrls += (GetSystemMetrics(SM_CYEDGE)*2 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME)*2);
			ready_for_restore(); // [戻す]のための準備
			next_x = 0; // この変数を一時的に利用させてもらっているので初期化

			/* yctrls が、作業画面全体の(割合:設定値[WORKAREA])を超えていたら、右にスクロールバーを付けて、スクロールできるようにしてみる */
			{
				UINT uDlgMaxHeight;
				int  iDefHeight;
				SCROLLINFO si;

				//uDlgMaxHeight = 現在のhDlgが所属するモニタの高さ*WORKAREA
				HMONITOR hMon = MonitorFromWindow(hSubDlg, MONITOR_DEFAULTTOPRIMARY);
				MONITORINFO mi;
				mi.cbSize = sizeof(MONITORINFO);
				GetMonitorInfo(hMon, &mi);
				uDlgMaxHeight = (UINT)((double)(mi.rcMonitor.bottom - mi.rcMonitor.top)*WORKAREA);

				if ( uDlgMaxHeight < yctrls ) { // ダイアログサイズが画面の作業領域を超える場合は、制限をかける
					dHeight = uDlgMaxHeight;
				}

				// ●スクロールバーは必ず準備する
				dWidth = gDialogWidthMin = DIALOGWIDTH + GetSystemMetrics(SM_CXVSCROLL);
				SetWindowPos(hSubDlg, 0, 0, 0, gDialogWidthMin, (int)uDlgMaxHeight, SWP_NOMOVE | SWP_NOZORDER);
				ShowScrollBar(hSubDlg, SB_VERT, TRUE);
				si.cbSize = sizeof( SCROLLINFO );
				si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
				si.nMin = 0;
				si.nMax = yctrls;
				si.nPos = 0;
				si.nPage = dHeight;
				SetScrollInfo(hSubDlg, SB_VERT, &si, FALSE);

				if ( uDlgMaxHeight >= yctrls ) {	// yctrlsが、作業画面よりもある程度小さい
					// ただし、ダイアログのサイズが十分に大きければ、スクロールバーは無効にする
					EnableScrollBar(hSubDlg, SB_VERT, ESB_DISABLE_BOTH);

					if ( rnsf7RegRead("extListViewHeight", 0) ) {
						// リストビューサイズの拡張
						SNSLV	snslv;

						// これから拡大するダイアログの高さと、現在の高さとの差を求める
						// (この分だけリストビューの高さを拡大し、それより下のコントロールを下げる)
						iDefHeight = (int)uDlgMaxHeight - (int)yctrls;

						// 高さが LV_NORMAL_HEIGHT となっているリストビューをサーチ
						ZeroMemory(&snslv, sizeof(SNSLV));
						snslv.hDlg = hSubDlg;
						snslv.iDefHeight = iDefHeight;
						EnumChildWindows(hSubDlg, (WNDENUMPROC)searchNormalSizeListView, (LPARAM)&snslv);

						// 見つかったら、それよりも下にあるコントロールを uDefHeight だけ下に下げ、
						// 該当するリストビューを uDefHeight だけ拡大する
						if ( snslv.hListView ) {
                            EnumChildWindows(hSubDlg, (WNDENUMPROC)extNormalSizeListView, (LPARAM)&snslv);

							// ダイアログサイズの拡張
							yctrls = uDlgMaxHeight;
						}
					}
					dHeight = yctrls;
					gDialogWidthMin = DIALOGWIDTH;
					SetWindowPos(hSubDlg, 0, 0, 0, gDialogWidthMin, yctrls, SWP_NOMOVE | SWP_NOZORDER);
				}
			}
			initializing_flag = 0; // 現在初期化中フラグをオフにする

			if ( rnsf7RegRead("NoPreCheck", 0) == 0 ) {
				chk_chkaccr( hSubDlg ); // アクセラレータキーの重複チェック
			}
			return NULL;

		case AC_RESIZE: // 編集ダイアログをユーザがリサイズした
			{
				RECT rt;
				HWND hRetValue = NULL;

				GetWindowRect( hSubDlg, &rt );

				if ( opt == 0 ) { // リサイズ終了
					// ●高さのリサイズ処理
					if ( dHeight != rt.bottom - rt.top ) {
						dHeight = rt.bottom - rt.top;

						// ダイアログ右側のスクロールバーを調整
						if ( dHeight >= yctrls ) {
							// ただし、ダイアログのサイズが十分に大きければ、スクロールバーは無効にする
							EnableScrollBar(hSubDlg, SB_VERT, ESB_DISABLE_BOTH);
						}
						else {
							SCROLLINFO si;

							EnableScrollBar(hSubDlg, SB_VERT, ESB_ENABLE_BOTH);
							//SetWindowPos(hSubDlg, 0, 0, 0, dWidth, dHeight, SWP_NOMOVE | SWP_NOZORDER);
							ShowScrollBar(hSubDlg, SB_VERT, TRUE);
							si.cbSize = sizeof( SCROLLINFO );
							si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
							si.nMin = 0;
							si.nMax = yctrls;
							si.nPos = GetScrollPos(hSubDlg, SB_VERT);
							si.nPage = dHeight;
							SetScrollInfo(hSubDlg, SB_VERT, &si, TRUE);
						}

						// リサイズしたときに、[OK]ボタンなどが上部へ浮いてしまっていないか?
						if ( GetScrollPos(hSubDlg, SB_VERT) + dHeight > yctrls ) {
							hRetValue = (HWND)1; // 浮いているからなんとかしろと、呼び出し元に伝える
						}
					}

					// ●幅のリサイズ処理
					if (dWidth != rt.right - rt.left) {
						UINT lastWidth = dWidth;
						UINT diffWidth;
						RECT rc;
						POINT po1;
						UINT i;

						dWidth = rt.right - rt.left;
						diffWidth = dWidth - lastWidth;

						// 登録済みのほぼすべてのコントロールの再配置（リサイズと移動）を行う
						// (未登録のコントロールとOK等下部ボタンについては、何もしない）)
						for (i=0 ; i<nctrls ; ++i) {
							switch(rctrls[i].ctrl) {
								case CHECK_CTRL:
									if (rctrls[i].i != ERRORVALUE) {
										break;
									}
								case EDIT_CTRL:
								case COMBO_CTRL:
								case GOTO_BUTTON:
								case MULTI_EDIT:
								case CHKLIST_CTRL:
								case LIST_CTRL:
								//case COLOR_BUTTON:
								case TEXT_CTRL:
									// 幅のみを変化させるように調整（座標は変化させない）
									GetWindowRect(rctrls[i].hCtrl, &rc);
									po1.x = rc.left;  po1.y = rc.top;
									ScreenToClient(hSubDlg, &po1);
									MoveWindow(rctrls[i].hCtrl, po1.x, po1.y, rc.right-rc.left + diffWidth, rc.bottom-rc.top, TRUE);
									break;

								case LVC_BUTTON_NEW:
								case LVC_BUTTON_EDIT:
								case LVC_BUTTON_DEL:
								case REF_BUTTON_FILE:
								case REF_BUTTON_FOLDER:
								case TODEFAULT_BUTTON:
								case SPIN_CTRL:
								case MIN_GOTO_BUTTON:
									// 左隅座標のみを変化させるように調整（サイズは変化させない）
									GetWindowRect(rctrls[i].hCtrl, &rc);
									po1.x = rc.left;  po1.y = rc.top;
									ScreenToClient(hSubDlg, &po1);
									MoveWindow(rctrls[i].hCtrl, po1.x + diffWidth, po1.y, rc.right-rc.left, rc.bottom-rc.top, TRUE);
									break;
							}
						}

						InvalidateRect(hSubDlg, NULL, FALSE);
					}
				}
				return hRetValue;
			}

		case AC_DOWN: // 行空け
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			yctrls += SCALEY(4);
			return NULL;

		case TEXT_CTRL: // スタティックテキスト
			next_x = 0;
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			else {
				SIZE tsize = {0, 0};
				HDC hdc;

				if ( hCheckBoxList ) { // チェックボックスリスト作成中
					// カテゴリ名称の作成を行う
					ListCheck_Add( hCheckBoxList, 0, text );
				}
				else {
					if (text) {
						if (opt_u1 == 1) {
							// グループボックスの開始
							tsize.cx = 0;
							tsize.cy = SCALEY(14)*2;
							hCtrl = CreateWindow( WC_BUTTON, text, WS_CHILD|WS_VISIBLE|BS_GROUPBOX, LEFT_CTRLX/2, yctrls + (tsize.cy*opt+2)/2, RIGHT_CTRLX+LEFT_CTRLX/2+20, tsize.cy, hSubDlg, (HMENU)IDNO, hInst, NULL);

							hGroupBox = hCtrl;

							if (hCtrl) {
								// リサイズ用にコントロールを登録
								registercontrol(hCtrl, 0);
							}
						}
						else { // (opt_u1 == 0 or 2)
							// テキストを１行表示または複数行表示
							tsize.cx = 0;
							hdc = GetDC( hSubDlg );
							if ( hdc ) {
								SelectObject(hdc, hFont);
								add_chkaccr( text );
								GetTextExtentPoint32(hdc, text, lstrlen(text), &tsize);
								ReleaseDC( hSubDlg, hdc );
							}
							tsize.cy = SCALEY(14); // どうもそのままだとうまくいかないので上書き

							hCtrl = CreateWindow( WC_STATIC, text, WS_CHILD|WS_VISIBLE|SS_LEFT, next_x?next_x:LEFT_CTRLX, flag_opt>0?yctrls+SCALEY(7):yctrls+SCALEY(4), next_x?(RIGHT_CTRLX-next_x+LEFT_CTRLX):RIGHT_CTRLX, tsize.cy*opt, hSubDlg, (HMENU)IDNO, hInst, NULL);
						}
					}
					else {
						if (opt_u1 == 1) {
							// グループボックスの終了
							if (hGroupBox) {
								RECT rc;
								POINT po1;

								tsize.cx = 0;
								tsize.cy = SCALEY(14);

								// 高さのみを変化させるように調整（座標は変化させない）
								GetWindowRect(hGroupBox, &rc);
								po1.x = rc.left;  po1.y = rc.top;
								ScreenToClient(hSubDlg, &po1);
								MoveWindow(hGroupBox, po1.x, po1.y, rc.right-rc.left, yctrls - po1.y + (tsize.cy*opt+2) * 4 / 5, TRUE);

								hGroupBox = NULL;

								next_x = 0;
								yctrls += (tsize.cy*opt+2);
							}

							break;
						}
						else {
							// 水平線
							tsize.cy = 1;
							hCtrl = CreateWindow( WC_STATIC, "", WS_CHILD|WS_VISIBLE|SS_ETCHEDHORZ, next_x?next_x:LEFT_CTRLX, yctrls + (tsize.cy*opt+2)/2, next_x?(RIGHT_CTRLX-next_x+LEFT_CTRLX):RIGHT_CTRLX, tsize.cy, hSubDlg, (HMENU)IDNO, hInst, NULL);

							if (hCtrl) {
								// リサイズ用にコントロールを登録
								registercontrol(hCtrl, 0);
							}
						}
					}

					if ( hCtrl == NULL ) {
						next_x = 0;
						return NULL;
					}
					else {
						if ( flag_opt > 0 ) { // 第2引数が指定されていた場合は、次の編集ボックス等は、少なくともその座標で始める
							if ( flag_opt > (UINT)tsize.cx+SCALEY(2) )
								next_x += (SCALEY(flag_opt) + LEFT_CTRLX);
							else
								next_x += (tsize.cx + SCALEY(2) + LEFT_CTRLX);
							if ( (int)next_x >= RIGHT_CTRLX-SCALEY(1) ) {
								next_x = 0;
								yctrls += (tsize.cy*opt+SCALEY(2));
							}
						}
						else {
							next_x = 0;
							yctrls += (tsize.cy*opt+2);
						}
						SendMessage(hCtrl, WM_SETFONT, (WPARAM)(opt_u1 == 1 || opt_u1 == 2 ? hBoldFont : hFont), (LPARAM)FALSE);
					}
				}
			}
			break;

		case CHECK_CTRL: // チェックボックス
			//next_x = 0; // - たぶん、ここにあるのは間違いな気がする/**/
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない

			if ( hCheckBoxList ) { // チェックボックスリスト作成中
				hCtrl = hCheckBoxList;
				// チェックボックスリストへの追加は、この後ろの方で行う
			}
			else {
				add_chkaccr( text );
				// BS_AUTO3STATEの場合…本当の3state
				// BS_3STATEの場合…通常はON/OFFにしかならないが、初期状態によっては半チェックを許す場合。この場合、OpenSettingにて自力でチェック状態をコントロールする
				hCtrl = CreateWindow( WC_BUTTON, text, WS_CHILD|WS_VISIBLE|WS_TABSTOP| (opt==1?BS_AUTO3STATE:BS_3STATE), next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(4), next_x?(RIGHT_CTRLX-next_x+LEFT_CTRLX):RIGHT_CTRLX, SCALEY(16), hSubDlg, (HMENU)IDNO, hInst, NULL);
				next_x = 0;
			}

			if ( hCtrl == NULL )
				return NULL;
			else {
				int iCheckState = 0;

				if ( !hCheckBoxList ) { // チェックボックスリスト作成中でない場合
					yctrls += SCALEY(16);
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
				}

				// デフォルトの値をセット
				if ( opt == 1 ) { // 3stateの場合
					iCheckState = def_dw;
				}
				else {
					if ( def_dw ) {
						iCheckState = 1;
					}
				}

				// レジストリキーとエントリが有効なら、そこから値を読んでセット
				if ( key && entry ) {
					if ( NULL != (hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY )) ) {
						if ( opt == 0 || opt == 1 ) { // 数値・文字列の場合
							int value;

							if ( opt == 1 && tRegValueExist( hKey, entry ) == -1 ) { // 3stateで値が存在しなければグレイ
								iCheckState = value = 2;
							}
							else { // 2state
								if ( opt_p1 && opt_p2 ) {
									// (char *)opt_p2には、uncheck時にとる値が、(char *)opt_p1には、check時にとる値が格納されている…はず
									char *pvalue;

									pvalue = mtRegReadString( hKey, entry, NULL );
									if ( pvalue ) {
										if ( _stricmp(pvalue, (char *)opt_p1) == 0 ) {
											iCheckState = 1;
										}
										else if ( _stricmp(pvalue, (char *)opt_p2) == 0 ) {
											iCheckState = 0;
										}
										else {
											iCheckState = def_dw?1:0;
										}
										safefree(pvalue);
									}
								}
								else if ( (flag_opt & CHECK_SZ01) || (flag_opt & CHECK_SZYN) || (flag_opt & CHECK_SZTF) ) { // 文字列型
									char value[8]; // このブロックでの判定で使われる文字列は、最大で5文字まで

									if ( tRegReadString( hKey, entry, value, 7 ) ) {
										if ( atoi(value) != 0 || _stricmp(value, "TRUE") == 0  || _stricmp(value, "YES") == 0 ) {
											iCheckState = 1;
										}
										else if ( _stricmp(value, "0") == 0 || _stricmp(value, "FALSE") == 0  || _stricmp(value, "NO") == 0 ) {
											iCheckState = 0;
										}
										else {
											iCheckState = def_dw?1:0;
										}
									}
								}
								else { // 数値型
									// bit_maxにはuncheck時にとる値が、byte_minには、check時にとる値が、それぞれ格納されている↑
									value = tRegReadInteger( hKey, entry, def_dw?byte_min:bit_max );
									iCheckState = (value != bit_max)?1:0;
								}
							}
						}
						else if ( opt == 2 ) { // バイナリのビット指定の場合
							unsigned char *buf;
							int  i;
							UINT dw = def_dw;

							i = tRegValueExist(hKey, entry);
							if ( i > 0 && (signed)byte_min < i ) {
								buf = (unsigned char *)zalloc( i );
								if ( buf ) {
									tRegReadString(hKey, entry, (char *)buf, i);
									dw = ((buf[byte_min] >> bit_max) & 1);
									safefree(buf);
									dw = (dw != opt_u2);
								}
							}

							// opt_u2にはオフのときの値(0または1)が入っている。u1,u2には、1,0または0,1しか入れては行けないことになっているので、ここの値を見て、u1の値は決めつけする
							iCheckState = dw?1:0;
						}
						else if ( opt == 3 ) { // DWORD型のビット指定の場合
							UINT dw;

							if ( -1 != tRegValueExist(hKey, entry) ) {
								dw = (DWORD)tRegReadInteger( hKey, entry, 0 );
								dw = ((dw >> bit_max)&1);
							}
							else {
								dw = def_dw;
							}

							// opt_u2にはオフのときの値(0または1)が入っている。u1,u2には、1,0または0,1しか入れては行けないことになっているので、ここの値を見て、u1の値は決めつけする
							iCheckState = (dw != opt_u2)?1:0;
						}
						RegCloseKey( hKey );
					}
					else { // キー・エントリが存在しない場合、3stateでは、グレイにする
						if ( opt == 1 ) {
							iCheckState = 2;
						}
					}
				}

				if ( hCheckBoxList ) {
					UINT add_i = ListCheck_Add( hCheckBoxList, opt == 1 ? 3 : 2, text );

					registercontrol_i( hCtrl, add_i, 0 ); // コントロールをデータベースに登録
					ListCheck_Set( id, iCheckState );
				}
				else {
					switch( iCheckState ) {
						case 0:
							SendMessage(hCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
							break;
						case 1:
							SendMessage(hCtrl, BM_SETCHECK, BST_CHECKED, 0);
							break;
						case 2:
							SendMessage(hCtrl, BM_SETCHECK, BST_INDETERMINATE, 0);
							break;
					}

					registercontrol( hCtrl, 0 ); // コントロールをデータベースに登録
				}
			}
			break;

		case EDIT_CTRL: // 編集コントロール
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			if ( opt == 1 ) { // 数値
				char itbuf[16];

				if ( 0 != _ultoa_s(def_dw, itbuf, _countof(itbuf), 10) ) {
					// エラーの場合は、errで編集ボックスを作成
					lstrcpy(itbuf, "err");
				}
				hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, WC_EDIT, itbuf, WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER | ((flag_opt & EDIT_PASSWORD)?ES_PASSWORD:0) | ((flag_opt & EDIT_READONLY)?ES_READONLY:0), next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(4), ((flag_opt & EDIT_DEFAULT)?(RIGHT_CTRLX-SCALEX(60)):RIGHT_CTRLX)-(next_x?(next_x-LEFT_CTRLX):0), SCALEY(22), hSubDlg, (HMENU)IDNO, hInst, NULL);
			}
			else { // 文字列
				hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES, WC_EDIT, def_sz, WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL | ((flag_opt & EDIT_PASSWORD)?ES_PASSWORD:0) | ((flag_opt & EDIT_READONLY)?ES_READONLY:0), next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(4), ((flag_opt & (EDIT_DEFAULT | EDIT_FILENAME | EDIT_FOLDER))?(RIGHT_CTRLX-SCALEX(60)):RIGHT_CTRLX)-(next_x?(next_x-LEFT_CTRLX):0), SCALEY(22), hSubDlg, (HMENU)IDNO, hInst, NULL);
			}
			next_x = 0;
			if ( hCtrl == NULL ) // コントロールの生成に失敗したらエラー
				return NULL;
			else {
				yctrls += SCALEY(22);
				SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

				// レジストリキーとエントリが有効なら、そこから値を呼んでセット
				if ( key && entry ) {
					if ( NULL != (hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY )) ) {
						if ( opt == 1 ) { // 数値型編集ボックスを扱う場合
							DWORD type = tRegValueType(hKey, entry);

							if (type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) {
								// レジストリのデータ型が文字列だった場合
								char *value;

								value = mtRegReadString(hKey, entry, NULL);	
								if ( value ) {
									if ( text ) { // 単位変換の必要性
										char itbuf[16];

										if ( 0 == _ultoa_s(atou(value)/transunit(text), itbuf, _countof(itbuf), 10) ) {
											SetWindowText( hCtrl, itbuf );
										}
									}
									else {
										SetWindowText( hCtrl, value );
									}
									safefree(value);
								}
							}
							else {
								// レジストリのデータ型が数値だった場合
								char itbuf[16];

								if ( 0 == _ultoa_s(tRegReadInteger(hKey, entry, def_dw)/transunit(text), itbuf, _countof(itbuf), 10) ) {
									SetWindowText( hCtrl, itbuf );
								}
							}
						}
						else { // 文字列の場合
							if (tRegValueType(hKey, entry) == REG_DWORD) {
								// レジストリのデータ型が数値だった場合（単位変換せずにそのまま文字列にして代入）
								char itbuf[16];

								if ( 0 == _ultoa_s(tRegReadInteger(hKey, entry, def_dw), itbuf, _countof(itbuf), 10) ) {
									SetWindowText( hCtrl, itbuf );
								}
							}
							else {
								// レジストリのデータ型が文字列だった場合
								char *value;

								value = mtRegReadString(hKey, entry, NULL);
								if ( value ) {
									SetWindowText( hCtrl, value );
									safefree(value);
								}
							}
						}
						RegCloseKey( hKey );
					}
				}

				registercontrol( hCtrl, 0 ); // コントロールをデータベースに登録

				if ( opt == 1 ) { // 数値 - アップダウンコントロールの追加 - スピンコントロールにする
					hCtrl = CreateUpDownControl( WS_CHILD | WS_VISIBLE | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS, SCALEX(522), yctrls+SCALEY(8-24), SCALEX(50), SCALEY(50), hSubDlg, IDNO, hInst, hCtrl, 10000, 0, 5000);
					if ( hCtrl ) {
						char *spin_id;

						spin_id = zalloc( strlen(id) + 10 );
						if ( spin_id ) {
							lstrcpy( spin_id, id );
							lstrcat( spin_id, "_SPIN" );
							registercontrol_o( hCtrl, 0, SPIN_CTRL, 0, 0, 0, 0, 0, 0, 0, spin_id, byte_min, bit_max, opt_u1, opt_u2, 0, 0, 0, 0 );
							ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
							SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
						}
					}
				}
				else if ( flag_opt & (EDIT_FILENAME | EDIT_FOLDER) ) { // ファイル名,フォルダ名の場合 - [参照ボタン]の追加 (EDIT_BUTTON = (EDIT_FILENAME | EDIT_FOLDER)になっているので、EDIT_BUTTONもひっかかる)
					hCtrl = CreateWindow( WC_BUTTON, text, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, LV_BUTTONS_X, yctrls+SCALEY(4-21), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDNO, hInst, NULL);
					if ( hCtrl ) {
						char *button_id;
						add_chkaccr( text );
						button_id = zalloc( strlen(id) + 10 );
						if ( button_id ) {
							if ((flag_opt & EDIT_BUTTON) == EDIT_BUTTON) { // GOTOボタン
								wsprintf( button_id, ":%s_BUTTON", id );
								registercontrol_o( hCtrl, 0, MIN_GOTO_BUTTON, 0, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
								ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
							}
							else { // ファイル・フォルダ参照ボタン
								wsprintf( button_id, "%s_BROWSE", id );
								registercontrol_o( hCtrl, 0, (flag_opt&EDIT_FILENAME) ? REF_BUTTON_FILE : REF_BUTTON_FOLDER, 0, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
								ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
								addTooltip( hCtrl, (flag_opt & EDIT_FILENAME) ? "ファイルを一覧の中から選択し、左の編集ボックスへ入れます" : "フォルダを一覧の中から選択し、左の編集ボックスへ入れます" );
							}
							safefree(button_id);
							SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
						}
					}
				}

				// [既定値](デフォルトへ戻すボタン)
				// 数値のエディットボックスであれば、EDIT_DEFAULT の有無だけチェックする
				// 文字列のエディットボックスであれば、参照ボタンについても考慮する（参照ボタン優先）
				if ( (opt == 1 && (flag_opt & EDIT_DEFAULT) == EDIT_DEFAULT) || // ←数値　↓文字列
					 (flag_opt & (EDIT_FILENAME | EDIT_FOLDER | EDIT_DEFAULT)) == EDIT_DEFAULT ) {
					hCtrl = CreateWindow( WC_BUTTON, "既定値", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, LV_BUTTONS_X, yctrls+SCALEY(4-21), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDNO, hInst, NULL);
					if ( hCtrl ) {
						char *button_id;

						button_id = zalloc( strlen(id) + 10 );
						if ( button_id ) {
							wsprintf( button_id, "%s_DEFAULT", id );
							registercontrol_o( hCtrl, 0, TODEFAULT_BUTTON, opt, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
							ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
							safefree(button_id);
							SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
							addTooltip( hCtrl, "既定値(デフォルト)と認識されている値に戻します" );
						}
					}
				}
			}
			break;

		case ICON_BUTTON: // アイコンの変更ボタン
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			hCtrl = CreateWindow( WC_BUTTON, def_sz, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_ICON, next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(8), SCALEX(38), SCALEY(38), hSubDlg, (HMENU)IDNO, hInst, NULL);
			if ( hCtrl == NULL ) {
				return NULL;
			}
			else {
				HICON hIcon;
				char *iconfname;

				SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
				iconfname = _strdup( def_sz );
				addTooltip( hCtrl, "アイコンを一覧の中から選択します" );
						
				if ( key && entry ) {
					if ( NULL != (hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY )) ) {
						char *value;

						value = mtRegReadString(hKey, entry, NULL);
						if ( value ) {
							SetWindowText(hCtrl, value);
							safefree(iconfname);
							iconfname = value;
						}
						RegCloseKey( hKey );
					}
				}
				
				hIcon = LoadIconFromFile( hInst, iconfname );
				if ( hIcon )
					SendMessage(hCtrl, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);

				registercontrol(hCtrl, (LPARAM)hIcon); // コントロールをデータベースに登録

				hCtrl = CreateWindow( WC_STATIC, iconfname, WS_CHILD|WS_VISIBLE|SS_LEFT, next_x?(next_x+SCALEX(38)):SCALEX(62), yctrls+SCALEY(20), RIGHT_CTRLX, LEFT_CTRLX, hSubDlg, (HMENU)IDNO, hInst, NULL);
				if ( hCtrl ) {
					char *text_id = zalloc( strlen(id) + 10 );
					if ( text_id ) {
						SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
						wsprintf(text_id, "%s_TEXT", id);
						registercontrol_o(hCtrl, 0, TEXT_CTRL, 0, 0, 0, 0, 0, 0, iconfname, text_id, 0, 0, 0, 0, 0, 0, 0, 0);
						safefree(text_id);
					}
				}

				yctrls += SCALEY(42);
				safefree(iconfname);
			}
			next_x = 0;
			break;

		case CHKLIST_CTRL: // チェックボックスリスト
			if ( next_x > 0 ) {
				next_x = 0;
				yctrls += 14;
			}

			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない

			if ( id ) { // id != NULL だったら、チェックボックスリストの開始であるとみなす
				hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
					                   WS_TABSTOP | WS_CHILD | WS_VISIBLE | LVS_AUTOARRANGE | LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER /*| LVS_NOCOLUMNHEADER */  | /*((flag_opt&LV_MULTISELECT)?0:LVS_SINGLESEL)*/LVS_SINGLESEL | LVS_SHAREIMAGELISTS,
									   LEFT_CTRLX, yctrls+SCALEY(4), RIGHT_CTRLX, (flag_opt&LV_SMALL) ?LV_MIN_HEIGHT:
			                                                                      (flag_opt&LV_MIDDLE)?LV_MID_HEIGHT:LV_NORMAL_HEIGHT,
									   hSubDlg, (HMENU)IDNO, hInst, NULL);
				if ( hCtrl == NULL )
					return NULL;
				else {
					LV_COLUMN   lvColumn;

					// フォントの設定
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

					// アイコンイメージリスト（共有）の設定
					ListView_SetImageList(hCtrl, himlCBLSmall, LVSIL_SMALL);
					ListView_SetImageList(hCtrl, himlCBLState, LVSIL_STATE);

					{ //if ( ccpu32_GetComCtl32Ver() >= 470 ) {
						// comctl32.dllのバージョンが4.70以降なら、横一列全選択を付けられるようにする
						// (ハイライト時の見栄えの都合で)
						ListView_SetExtendedListViewStyleEx(hCtrl, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT );

						{ //if ( ccpu32_GetComCtl32Ver() >= 471 ) {
							// comctl32.dllのバージョンが4.71以降なら、infotipを付けられるようにする
							ListView_SetExtendedListViewStyleEx(hCtrl, LVS_EX_INFOTIP/*| LVS_EX_BORDERSELECT*/, LVS_EX_INFOTIP/*| LVS_EX_BORDERSELECT*/ );
						}
					}

					// 一応カラム設定
					lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
					lvColumn.fmt = LVCFMT_LEFT;
					lvColumn.pszText = "項目"; lvColumn.cx = RIGHT_CTRLX - SCALEY(80);
					ListView_InsertColumn(hCtrl, 0, &lvColumn);
					lvColumn.pszText = "チェック状態"; lvColumn.cx = SCALEY(80);
					ListView_InsertColumn(hCtrl, 1, &lvColumn);
					// 注意：上記「チェック状態」は、スクリーンリーダ用の対策である
					//      (視覚に障害を持つ方がチェック状対を把握できるよう、
					//       「チェックあり」「チェックなし」「半チェック」「カテゴリ」「無効状態」を
					//       読み上げられるように、日本語でこれらの文字を入れておく)
					//       実際に本プログラムがチェック状態として認識するのは、ListViewの各項目のlParamである

					// とりあえず全項目削除
					ListView_DeleteAllItems(hCtrl);

					registercontrol(hCtrl, 0); // コントロールをデータベースに登録

					// Y座標加算
					yctrls += ((flag_opt&LV_SMALL )?(LV_MIN_HEIGHT+SCALEY(2)):
					           (flag_opt&LV_MIDDLE)?(LV_MID_HEIGHT+SCALEY(2)):(LV_NORMAL_HEIGHT+SCALEY(2)));

					// チェックボックスリスト作成開始
					hCheckBoxList = hCtrl;
				}
			}
			else { // id == NULL だったら、チェックボックスリストの終了であると見なす
				if ( hCheckBoxList != NULL ) {
					// エラー終了しないようにするために、hCtrlに何かを入れておく。
					hCtrl = hCheckBoxList;
					// 1つ以上の項目が入っていたら、最初の項目にフォーカスを合わせておく
					if ( ListView_GetItemCount( hCheckBoxList ) > 0 ) {
                        ListView_SetItemState( hCheckBoxList, 0, LVIS_FOCUSED, LVIS_FOCUSED );
					}
					// チェックボックスリスト作成終了
					hCheckBoxList = NULL;
					// 項目カラムの自動修正
					// ListView_SetColumnWidth(hCheckBoxList, 0, LVSCW_AUTOSIZE); // 今のところ、作成時にサイズを直指定している
				}
				else {
					return NULL;
				}
			}
			next_x = 0;
			break;

		case LIST_CTRL: // リストビューコントロール (report view) - 値とデータの一覧表示
			if ( next_x > 0 ) {
				next_x = 0;
				yctrls += 14;
			}
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
								   WS_TABSTOP | WS_CHILD | WS_VISIBLE | LVS_AUTOARRANGE | LVS_REPORT | LVS_SHOWSELALWAYS | ((flag_opt&LV_SORTHEADER)?0:LVS_NOSORTHEADER) | ((flag_opt&LV_MULTISELECT)?0:LVS_SINGLESEL),
								   LEFT_CTRLX, yctrls+SCALEY(4), LVBT_RIGHT_CTRLX,(flag_opt&LV_SMALL) ?LV_MIN_HEIGHT:
			                                                                      (flag_opt&LV_MIDDLE)?LV_MID_HEIGHT:LV_NORMAL_HEIGHT,
								   hSubDlg, (HMENU)IDNO, hInst, NULL);
			if ( hCtrl == NULL )
				return NULL;
			else {
				MULTISTRING *mulstr;

				// フォントの設定
				SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

				{ //if ( ccpu32_GetComCtl32Ver() >= 471 ) { // comctl32.dllのバージョンが4.71以降なら、infotipを付けられるようにする
					SendMessage(hCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_INFOTIP, LVS_EX_INFOTIP);
				}

				if ( opt == 0 ) { // Value List
					HKEY      hKey;
					DWORD     i,n,vl,dl,new_i;
					LV_COLUMN lvColumn;

					lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
					lvColumn.fmt = LVCFMT_LEFT;
					lvColumn.pszText = (char *)def_sz; // 値の意味
					lvColumn.cx = SCALEX(150);	// 仮の値
					ListView_InsertColumn(hCtrl, 0, &lvColumn);
					lvColumn.pszText = (char *)text; // データの意味
					lvColumn.cx = SCALEX(405);	// 仮の値
					ListView_InsertColumn(hCtrl, 1, &lvColumn);

					ListView_DeleteAllItems( hCtrl );

					if ( NULL != (hKey = tRegOpenKey(NULL, key, TREG_OPEN_READONLY)) ) {
						RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &n, &vl, &dl, NULL, NULL);
						vl = (vl+1)*2;
						dl += 2;
						ListView_SetItemCount(hCtrl, n);
						if ( n > 0 ) {
							LVITEM lvitem;
							char *value, *data;
							DWORD vl2, dl2, type;

							value = zalloc( vl );
							if ( value ) {
								data = zalloc( dl );
								if ( data ) {
									for(i=0 ; i<n ; i++) {
										vl2 = vl;
										dl2 = dl;

										RegEnumValue(hKey, i, value, &vl2, NULL, &type, (LPBYTE)data, &dl2);

										lvitem.mask = LVIF_TEXT;
										lvitem.iItem = i;
										lvitem.iSubItem = 0;
										lvitem.pszText = value;
										new_i = ListView_InsertItem(hCtrl, &lvitem);
										if ( type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ ) {
											// 文字列系の型の場合は、そのまま代入
											ListView_SetItemText(hCtrl, new_i, 1, data);
										}
										else if ( type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN ) {
											// 数値系の型の場合は、DWORDに代入してから "(DWORD)n" の形で表示
											DWORD x = 0;
											char buf[20] = "(DWORD)err";

											memcpy(&x, data, sizeof(DWORD));
											if ( 0 == _ultoa_s(x, buf+7, _countof(buf)-7, 10) ) {
												ListView_SetItemText(hCtrl, new_i, 1, buf);
											}
										}
										else {
											// 不明な型の場合は何もしない
										}
									}

									safefree(data);
								}
								else {
									destroy_splash_window();
									MessageBox( hSubDlg, "メモリが足りません。一部のデータは失われているかもしれません。", "エラー", MB_OK | MB_ICONSTOP );
								}
								safefree(value);
							}
							else {
								destroy_splash_window();
								MessageBox( hSubDlg, "メモリが足りません。一部のデータは失われているかもしれません。", "エラー", MB_OK | MB_ICONSTOP );
							}

							// カラムサイズ調整
							ListView_SetColumnWidth(hCtrl, 0, LVSCW_AUTOSIZE);
							ListView_SetColumnWidth(hCtrl, 1, LVSCW_AUTOSIZE);

							// 1番目の項目にフォーカスをセット
							ListView_SetItemState(hCtrl, 0, LVIS_FOCUSED, LVIS_FOCUSED);
						}

						RegCloseKey( hKey );
					}
					else {
						ListView_SetItemCount(hCtrl, 0);
					}
					def_dw = 2; // カラムの個数を代入しておく（[戻す]のため)
				}
				else if ( opt == 1 ) { // KeyList or ただのlistview
					// entry:msz_btns, def_sz:values, text:means
					HKEY      hKey;
					UINT      i, j, n, m, len, new_i;
					char    **values_save = NULL, **means_save = NULL;
					LV_COLUMN lvColumn;
					char      *vs;

					lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
					lvColumn.fmt = LVCFMT_LEFT;
					for(i=n=0 ; NULL != (vs = getVariable_d_a(text,i)) ; i++,n++) {
						lvColumn.pszText = vs; // 値の意味
						lvColumn.cx = 150; // 仮の値
						ListView_InsertColumn(hCtrl, i, &lvColumn);
					}
					def_dw = n; // カラムの個数を代入しておく（[戻す]のため)

					ListView_DeleteAllItems( hCtrl );

					if ( key == NULL ) { // ただのlistview
						means_save = (char **)calloc(n+1, sizeof(char**));
						if ( means_save ) {
							values_save = NULL;
							for(i=0 ; i<n && NULL != (vs = getVariable_d_a(text,i)) ; i++) {
								means_save[i] = _strdup( vs );
							}
							means_save[i] = NULL;
						}
					}
					else { // キーリスト
						means_save = (char **)calloc(n+1, sizeof(char**));
						values_save = (char **)calloc(n+1, sizeof(char**));
						for(i=0 ; i<n && NULL != (vs = getVariable_d_a(def_sz,i)) ; i++) {
							values_save[i] = _strdup( vs );
							means_save[i] = _strdup( getVariable_d_a(text,i) );
						}

						if (NULL != (hKey = tRegOpenKey(NULL, key, TREG_OPEN_READONLY))) {
							RegQueryInfoKey(hKey, NULL, NULL, NULL, (LPDWORD)&m, &len, NULL, NULL, NULL, NULL, NULL, NULL);
							len = (len+1)*2;

							vs = zalloc( len );
							if ( vs ) {
								for( j=0 ; j<m ; j++ ) {
									LVITEM lvitem;
									HKEY   hKey2;
									DWORD len2 = len;

									RegEnumKeyEx( hKey, j, vs, &len2, NULL, NULL, NULL, NULL );

									if ( NULL != (hKey2 = tRegOpenKey( hKey, vs, 0 )) ) { // そもそも書込めないキーは開けても仕方がないので、書込みオープンとしている
										lvitem.mask = LVIF_TEXT;
										lvitem.iItem = j;
										lvitem.iSubItem = 0;
										lvitem.pszText = vs;
										new_i = ListView_InsertItem(hCtrl, &lvitem);

										for( i=1 ; values_save[i] ; i++ ) {
											// ↑ i=0 はキー名を表示するためにある
											DWORD  vtype;

											vtype = tRegValueType( hKey2, values_save[i] );
											if ( vtype == REG_SZ || vtype == REG_EXPAND_SZ || vtype == REG_MULTI_SZ ) {
												// 文字列系の型の場合は、そのまま代入
												char *value = mtRegReadString( hKey2, values_save[i], "");
												if ( value ) {
													ListView_SetItemText(hCtrl, new_i, i, value);
													safefree(value);
												}
												else {
													destroy_splash_window();
													MessageBox( hSubDlg, "メモリが足りません。一部のデータは失われているかもしれません。", "エラー", MB_OK | MB_ICONSTOP );
												}
											}
											else if ( vtype == REG_DWORD || vtype == REG_DWORD_BIG_ENDIAN ) {
												// 数値系の型の場合は、DWORDに代入してから "(DWORD)n" の形で表示
												char buf[20];

												wsprintf(buf, "(DWORD)%u", tRegReadInteger( hKey2, values_save[i], 0 ));
												ListView_SetItemText(hCtrl, new_i, i, buf);
											}
											else {
												// 不明な型の場合は何もしない
											}
										}
										RegCloseKey( hKey2 );
									}
								}
								safefree( vs );
							}
							else {
								destroy_splash_window();
								MessageBox( hSubDlg, "メモリが足りません。一部のデータは失われているかもしれません。", "エラー", MB_OK | MB_ICONSTOP );
							}
							RegCloseKey( hKey );

							if ( m > 0 ) {
								// アイテムの各項目の幅を調整
								for( i=0 ; values_save[i] ; i++ ) {
									ListView_SetColumnWidth(hCtrl, i, LVSCW_AUTOSIZE);
								}

								// 1番目の項目にフォーカスをセット
								ListView_SetItemState(hCtrl, 0, LVIS_FOCUSED, LVIS_FOCUSED);
							}
						}
					}

					// 保存のため
					def_sz = (char *)values_save;
					text = (char *)means_save;
				}

				mulstr = (MULTISTRING *)entry;
				registercontrol(hCtrl, 0); // コントロールをデータベースに登録

				// entry が MULTISTRINGへのポインタになっていて、それが「新規」「編集」「削除」になる
				hCtrl = CreateWindow( WC_BUTTON, mulstr->str1, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, LV_BUTTONS_X, yctrls+SCALEY(8+24*0), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDNO, hInst, NULL);
				if ( hCtrl ) { // ↑新規
					char *button_id;
					add_chkaccr( mulstr->str1 );

					button_id = zalloc( lstrlen(id) + 10 );
					if ( button_id ) {
						wsprintf( button_id, "%s_NEW", id );
						registercontrol_o( hCtrl, 0, LVC_BUTTON_NEW, 0, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
						ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
						SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
						addTooltip( hCtrl, "左のリストビューに、新しい項目を追加します" );

						hCtrl = CreateWindow( WC_BUTTON, mulstr->str2, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, LV_BUTTONS_X, yctrls+SCALEY(8+24*1), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDNO, hInst, NULL);
						if ( hCtrl ) { // ↑編集
							add_chkaccr( mulstr->str2 );
							wsprintf( button_id, "%s_EDIT", id );
							registercontrol_o( hCtrl, 0, LVC_BUTTON_EDIT, 0, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
							ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
							SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
							addTooltip( hCtrl, "左のリストビューで選択中の項目を編集します" );

							hCtrl = CreateWindow( WC_BUTTON, mulstr->str3, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, LV_BUTTONS_X, yctrls+SCALEY(8+24*2), LV_BUTTONS_WIDTH, SCALEY(20), hSubDlg, (HMENU)IDNO, hInst, NULL);
							if ( hCtrl ) { // ↑削除
								add_chkaccr( mulstr->str3 );
								wsprintf( button_id, "%s_DELETE", id );
								registercontrol_o( hCtrl, 0, LVC_BUTTON_DEL, 0, 0, 0, 0, 0, 0, 0, button_id, 0, 0, 0, 0, 0, 0, 0, 0 );
								ifHKLMandSTDUSR_disable( hCtrl, key, flag_opt );
								SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
								addTooltip( hCtrl, "左のリストビューで選択中の項目を削除します" );
							}
						}
						safefree( button_id );
					}
				}
				lastlv_btn_y = yctrls+SCALEY(8+24*3);

				// Y座標加算
				yctrls += ((flag_opt&LV_SMALL )?(LV_MIN_HEIGHT+SCALEY(2)):
				           (flag_opt&LV_MIDDLE)?(LV_MID_HEIGHT+SCALEY(2)):(LV_NORMAL_HEIGHT+SCALEY(2)));
			}
			break;

		case GOTO_BUTTON: // ラベルへジャンプするボタン
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			{
				int btn_x, btn_y, btn_w, btn_h;
				UINT ml_flag = (flag_opt & (LV_SMALL | LV_MIDDLE)); // 配置場所に関するフラグのみ取り出す

				add_chkaccr( text );

				if (lastlv_btn_y != 0 && (ml_flag == LV_SMALL || ml_flag == LV_MIDDLE)) {
					// リストビュー付随型ミニボタン
					btn_x = LV_BUTTONS_X;
					btn_y = lastlv_btn_y;
					btn_w = LV_BUTTONS_WIDTH;
					btn_h = (ml_flag == LV_SMALL) ? SCALEY(20) : SCALEY(50);

					lastlv_btn_y += ((ml_flag == LV_SMALL) ? SCALEY(24) : SCALEY(55));
				}
				else {
					// 通常型ボタン
					btn_x = next_x?next_x:LEFT_CTRLX;
					btn_y = yctrls+SCALEY(8);
					btn_w = LVBT_RIGHT_CTRLX-next_x;
					btn_h = SCALEY(20);
				}
				
				hCtrl = CreateWindow( WC_BUTTON, text, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON|BS_MULTILINE, btn_x, btn_y, btn_w, btn_h, hSubDlg, (HMENU)IDNO, hInst, NULL);

				next_x = 0;
				if ( hCtrl == NULL )
					return NULL;
				else {
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

					// コントロールをデータベースに登録
					if (lastlv_btn_y != 0 && (ml_flag == LV_SMALL || ml_flag == LV_MIDDLE)) {
						// リストビュー付随型ミニボタン
						registercontrol_o( hCtrl, 0, MIN_GOTO_BUTTON, 0, 0, 0, 0, 0, 0, 0, id, 0, 0, 0, 0, 0, 0, 0, 0 );
					}
					else {
						// 通常型ボタン
						registercontrol(hCtrl, 0);
						yctrls += SCALEY(24);
					}
				}
			}
			break;

		case COLOR_BUTTON: // 色選択ボタン
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			{
				char ptext[70];
				int x, y, w, h;
				HWND hColorSample;	// カラーサンプル用スタティックコントロール

				if ( key && entry ) {
					HKEY hKey;

					if ( NULL != ( hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY ) ) ) {
						UINT r = 0, g = 0, b = 0;

						if (flag_opt & CB_DWORD) {
							// 色番号は数値型(0xbbggrr)
							def_dw = tRegReadInteger(hKey, entry, def_dw);
						}
						else {
							// 色番号は文字列型 "rrr ggg bbb"
							if ( tRegReadString( hKey, entry, ptext, 70 ) ) {
								sscanf_s( ptext, "%d %d %d", &r, &g, &b );
								def_dw = (r&0xff) | ((g&0xff)<<8) | ((b&0xff)<<16);
							}
						}
						RegCloseKey( hKey );
					}
				}

				wsprintf( ptext, "赤:%d  緑:%d  青:%d", (def_dw&0xff), (def_dw&0xff00)>>8, (def_dw&0xff0000)>>16 );
				
				hCtrl = CreateWindow( WC_BUTTON, ptext?ptext:"", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, x=next_x?next_x:LEFT_CTRLX, y=yctrls+SCALEY(8), w=LVBT_RIGHT_CTRLX-next_x, h=SCALEY(24), hSubDlg, (HMENU)IDNO, hInst, NULL);
				if (hCtrl) {
					addTooltip( hCtrl, "色選択のダイアログを表示します" );
				}
				hColorSample = CreateWindowEx(WS_EX_STATICEDGE, WC_STATIC, "", WS_CHILD|WS_VISIBLE, x+w, y, 16, h, hSubDlg, (HMENU)IDNO, hInst, NULL);

				next_x = 0;
				if ( hCtrl == NULL )
					return NULL;
				else {
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					opt_u1 = def_dw;	 // 色番号
					opt_u2 = 0xffffffff; // 画面表示中の色番号（画面から表示要求があったときに書き換え）
					opt_p1 = 0;			 // 画面表示中の色のhBrush（0でなかったら、終了時にハンドルを解放するのを忘れずに！）
					registercontrol(hCtrl, (LPARAM)hColorSample); // コントロールをデータベースに登録
					yctrls += SCALEY(28);
				}
			}
			break;

		case MULTI_EDIT: // 複数行編集ボックス
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			{ // opt:n(行数) key:key entry:entry def_sz:def_sz id:id
				char *value_msz = _strdup(def_sz);

				if ( key && entry ) {
					HKEY hKey;

					if ( NULL != ( hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY ) ) ) {
						safefree( value_msz );
						if (tRegValueType(hKey, entry) == REG_DWORD) {
							// レジストリのデータ型が数値だった場合
							char itbuf[16];
							if ( 0 == _ultoa_s(tRegReadInteger(hKey, entry, def_dw), itbuf, _countof(itbuf), 10) ) {
								value_msz = _strdup(itbuf);
							}
						}
						else if ( flag_opt & (EDIT_SZ | SZ_EXPAND | MAYBE_EXPAND) ) { // 通常の文字列または環境文字列で指定された場合は、普通に読み込む
							value_msz = mtRegReadString(hKey, entry, NULL);
						}
						else { // 何も指定されなかった場合は、REG_MULTI_SZ であるとみなして読み込む
							value_msz = mtRegReadMultiString( hKey, entry );
						}
						RegCloseKey( hKey );
					}
				}
				hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES, WC_EDIT, value_msz, WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL /*| ((flag_opt & EDIT_PASSWORD)?ES_PASSWORD:0) Windowsの使用により、single line edit control でしかES_PASSWORDは使えない */ | ((flag_opt & EDIT_READONLY)?ES_READONLY:0),
					                    next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(4), next_x?(RIGHT_CTRLX-next_x+LEFT_CTRLX):RIGHT_CTRLX, SCALEY(15)*opt, hSubDlg, (HMENU)IDNO, hInst, NULL);
				next_x = 0;
				if ( hCtrl == NULL ) {
					return NULL;
				}
				else {
					SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);
					registercontrol(hCtrl, 0); // コントロールをデータベースに登録
					yctrls += (SCALEY(15)*opt+SCALEY(2));
				}

				safefree(value_msz);
			}
			break;

		case COMBO_CTRL: // コンボボックス
			if ( initializing_flag == 0 ) return NULL; // ダイアログの作成中以外はコントロールの追加を許可しない
			// text  :means(表示されるテキスト)
			// def_dw:cur(デフォルトカーソル位置)
			// def_sz:対応するレジストリエントリの値のリスト( opt == 0 のとき文字列, opt == 1 のとき数値 )
			{
				UINT i, n, cur;
				char *vs;

				cur = def_dw;
				hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, WC_COMBOBOX, "", WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST|WS_VSCROLL, next_x?next_x:LEFT_CTRLX, yctrls+SCALEY(4), next_x?(RIGHT_CTRLX-next_x+LEFT_CTRLX):RIGHT_CTRLX, SCALEY(200), hSubDlg, (HMENU)IDNO, hInst, NULL);
				next_x = 0;
				if ( hCtrl == NULL )
					return NULL;

				SendMessage(hCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE);

				// コンボボックスの項目を登録
				for(i=0 ; NULL != (vs = getVariable_d_a(text,i)) ; i++) {
					SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)vs);
				}
				n = i;

				if ( n <= cur ) // デフォルトのカーソル位置が項目数を超えていたら
					cur = 0;

				// デフォルトのカーソル位置を設定
				SendMessage(hCtrl, CB_SETCURSEL, (WPARAM)cur, 0);

				if ( key && entry ) {
					HKEY hKey;

					if ( opt == 0 ) { // レジストリエントリが文字列型
						char **regs;

						regs = (char **)calloc((n+1), sizeof(char *));

						if ( regs ) {
							for(i=0 ; i<n ; i++) {
								vs = getVariable_d_a(def_sz, i);
								regs[i] = vs?_strdup(vs):_strdup("");
							}
							regs[i] = NULL;

							// 保存のために
							def_sz = (char *)regs;

							// レジストリの読み出し
							if (NULL != (hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY ) )) {
								char *value;

								value = mtRegReadString(hKey, entry, regs[cur]);
								if ( value ) {
									for(i=0 ; i<n ; i++) {
										if ( _stricmp(regs[i], value) == 0 ) {
											SendMessage(hCtrl, CB_SETCURSEL, (WPARAM)i, 0);
											break;
										}
									}
									safefree(value);
								}
								RegCloseKey( hKey );
							}
						}
					}
					else if ( opt == 1 ) { // レジストリエントリが整数型
						UINT *regs, v;

						regs = (UINT *)calloc(n, sizeof(UINT));
						if ( regs ) {
							for(i=0 ; i<n ; i++) {
								v = 0;
								getVariable_a(def_sz, i, &v);
								regs[i] = v;
							}

							// 保存のために
							def_sz = (char *)regs;

							// レジストリの読み出し
							if (NULL != (hKey = tRegOpenKey( NULL, key, TREG_OPEN_READONLY ) )) {
								UINT value;

								value = tRegReadInteger(hKey, entry, regs[def_dw]);	
								for(i=0 ; i<n ; i++) {
									if ( regs[i] == value ) {
										SendMessage(hCtrl, CB_SETCURSEL, (WPARAM)i, 0);
										break;
									}
								}

								RegCloseKey( hKey );
							}
						}
					}
				}
				else
					def_sz = NULL;

				registercontrol(hCtrl, 0); // コントロールをデータベースに登録
				yctrls+=24;
			}
			break;

		default: // 不明
			return NULL;
	}

	return hCtrl;
}

// (同一アプリケーション内で)フォーカスが与えられたら、そのコントロールを完全に表示する
LRESULT CALLBACK focusproc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam)
{
	UINT i;

	// 該当するコントロールが何番目のコントロールかを探す
	for(i=0 ; i<nctrls ; i++) {
		if ( hWnd == rctrls[i].hCtrl ) {
			HWND ParentWindow = GetParent( hWnd );

			switch ( mes ) {
				case WM_KEYDOWN: // リストビューのための[DEL]キー等の取得のため
					{
						OSPCKDP op;

						op.iCtrl = i;
						op.retval = 1;
						op.ctrl = rctrls[i].ctrl;
						op.hCtrl = rctrls[i].hCtrl;

						SendMessage(ParentWindow, OSP_CTRL_KEYDOWN, wParam, (LPARAM)&op);

						if ( op.retval == 0 ) {
							return 0; // デフォルトのプロシージャを呼ばずにそのまま終了
						}
						// もし、何らかの理由でCallWindowProcを呼ばせたいのであれば、op.retvalは1になる
					}
					break;

				case WM_CHAR:
					{
						OSPCKDP op;

						op.iCtrl = i;
						op.retval = 1;
						op.ctrl = rctrls[i].ctrl;
						op.hCtrl = rctrls[i].hCtrl;

						SendMessage(ParentWindow, OSP_CTRL_CHAR, wParam, (LPARAM)&op);

						if ( op.retval == 0 ) {
							return 0; // デフォルトのプロシージャを呼ばずにそのまま終了
						}
						// もし、何らかの理由でCallWindowProcを呼ばせたいのであれば、op.retvalは1になる
					}
					break;

				case WM_SETFOCUS: // 子ウィンドウがフォーカスを受け取った
					if ( GetParent( (HWND)wParam ) == ParentWindow ) { // 外からのフォーカス受け取りには反応しない
						RECT rt;
						POINT pt;	// 子ウィンドウの位置を調べ、ダイアログ外にあるものだったら、ダイアログ内につれてくる

						GetWindowRect( hWnd, &rt );
						pt.y = rt.top; pt.x = rt.left;
						ScreenToClient( ParentWindow, &pt );
						SendMessage(ParentWindow, OSP_CTRL_GETFOCUS, (WPARAM)pt.y, (LPARAM)(rt.bottom-rt.top));
					}
					break;
					// 補足:WM_SETFOCUSを処理する既定のプロシージャは、親ウィンドウにフォーカスを与える動作をするので、それは既定のプロシージャにやらせるため、ここではbreak.

				case WM_DROPFILES: // 編集ボックスがファイルをドロップされた
					if ( IsWindowEnabled(hWnd) ) { // 編集ボックスは有効になっているか?
						int n; // ドロップされたファイルの数
						int i; // カウンタ
						int len; // 編集ボックス内にすでに存在する文字列のバイト数
						char fname[MAX_PATH*2];
						char *buf;

						n = DragQueryFile((HDROP)wParam, (UINT)-1, NULL, 0);
						for(i=0 ; i<n ; i++) {
							if (_countof(fname) > DragQueryFile((HDROP)wParam, i, fname, _countof(fname))) {
                                len = GetWindowTextLength( hWnd );
								if ( len > 0 ) { // すでに文字列が入っていた場合は、そこにスペースを加えてから追加
									buf = zalloc( len + lstrlen(fname) + 2 );
									if ( buf ) {
										GetWindowText( hWnd, buf, len+1 );
										lstrcat(buf, " ");
										lstrcat(buf, fname);
										SetWindowText(hWnd, buf);
										SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(IDNO, EN_CHANGE), (LPARAM)hWnd);
										safefree( buf );
									}
								}
								else { // まだ文字列が入っていない場合は、そのまま設定
                                    SetWindowText(hWnd, fname);
									SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(IDNO, EN_CHANGE), (LPARAM)hWnd);
								}
								break;
							}
						}
					}
					break;
			}

			// デフォルトのプロシージャをコール
			return (CallWindowProc(rctrls[i].orgproc, hWnd, mes, wParam, lParam));
		}
	}

	return 0; //ここにはこないはず
}

// コントロールをデータベースに追加する
static BOOL registercontrol_o( HWND hCtrl, UINT add_i, UINT ctrl, UINT opt, UINT flag_opt, const char *key, const char *entry, const char *def_sz, UINT def_dw, const char *text, const char *id, UINT byte_min, UINT bit_max, UINT opt_u1, UINT opt_u2, void *opt_p1, void *opt_p2, LPARAM opt_lp, LPARAM lParam )
{
	RCTRLS *new_rctrls;

	new_rctrls = (RCTRLS *)realloc( rctrls, sizeof(RCTRLS)*(nctrls+1) );

	if ( new_rctrls ) {
		rctrls = new_rctrls;

		rctrls[nctrls].hCtrl    = hCtrl;
		rctrls[nctrls].i        = add_i;
		rctrls[nctrls].ctrl     = ctrl;
		rctrls[nctrls].opt      = opt;
		rctrls[nctrls].flag_opt = flag_opt;
		rctrls[nctrls].key      = key?_strdup(key):NULL;
		rctrls[nctrls].entry    = entry?_strdup(entry):NULL;
		rctrls[nctrls].def_sz   = ((ctrl == LIST_CTRL && opt == 0) || (ctrl == EDIT_CTRL && opt == 0) || ctrl == MULTI_EDIT || ctrl == ICON_BUTTON)?_strdup(def_sz):(( ctrl == LIST_CTRL && opt == 1 ) || ( ctrl == COMBO_CTRL ))?def_sz:NULL;
		rctrls[nctrls].def_dw   = def_dw;
		rctrls[nctrls].text     = (char *)((ctrl == LIST_CTRL && opt == 1)?text:(text?_strdup(text):NULL));
		rctrls[nctrls].id       = id?_strdup(id):NULL;
		rctrls[nctrls].byte_min = byte_min;
		rctrls[nctrls].bit_max  = bit_max;

		rctrls[nctrls].opt_u1   = opt_u1;
		rctrls[nctrls].opt_u2   = opt_u2;
		rctrls[nctrls].opt_p1   = (ctrl == CHECK_CTRL)?(opt_p1?_strdup((char *)opt_p1):NULL):opt_p1;
		rctrls[nctrls].opt_p2   = (ctrl == CHECK_CTRL)?(opt_p2?_strdup((char *)opt_p2):NULL):opt_p2;
		rctrls[nctrls].opt_lp   = opt_lp;

		rctrls[nctrls].dfr		= 0;
		rctrls[nctrls].lParam   = lParam;
		rctrls[nctrls].orgproc  = (WNDPROC)GetWindowLongPtr(hCtrl, GWLP_WNDPROC); // 既定のメッセージプロシージャを保存
		rctrls[nctrls].stop		= ifHKLMandSTDUSR_disable(hCtrl, key, flag_opt); // もし key が HKLM 配下で、かつ、現在 HKLM へ書き込みアクセスできないならば、hCtrlを非活性にすると共に、レジストリ書き込みも停止
		rctrls[nctrls].changed  = 0;

		if ( id ) {
			if ( rnsf7RegRead("NoPreCheck", 0) == 0 ) {
				if ( id[0] == 0 ) {
					destroy_splash_window();
					MessageBox( GetParent(hCtrl), "ID文字列として空文字列が指定されました。\n[保存][読込]ボタンがうまく動作しないかもしれません。", "R-Scriptコントロールの生成", MB_OK | MB_ICONEXCLAMATION );
				}
				else if ( ERRORVALUE != searchID( id ) ) { // searchIDの中ではnctrls が使われているが、この変数はまだインクリメントされていないので、ここで登録中のidは検出されない
					char *s;

					s = zalloc( strlen(id) + 100 );
					if ( s ) {
						lstrcpy( s, id );
						lstrcat( s, "\n\nこのID文字列が重複して指定されました。\n[保存][読込]ボタンがうまく動作しないかもしれません。" );
						destroy_splash_window();
						MessageBox( GetParent(hCtrl), s, "R-Scriptコントロールの生成", MB_OK | MB_ICONEXCLAMATION );
						safefree(s);
					}
				}
			}
		}

		SetWindowLongPtr(hCtrl, GWLP_WNDPROC, (LONG_PTR)focusproc); // 子ウィンドウがフォーカスを受け取ったら、親ウィンドウに通知を出すプロシージャ

		nctrls++;
		return TRUE;
	}
	else {
		return FALSE;
	}
}

// ツールチップへの追加。 text==NULL のとき初期化で、hWnd_or_hCtrlにはウィンドウハンドルを入れる
static BOOL addTooltip( HWND hWnd_or_hCtrl, char *text )
{
	static TOOLINFO ti;		// ツールチップのための構造体
	static HWND hTooltip;	// ツールチップのためのハンドル

	if ( initializing_flag ) { // ウィンドウ生成中の場合にのみ動作する
		if ( text == NULL ) { // 初期化。hWnd_or_hCtrlはウィンドウハンドルとなる
			if (NULL == (hTooltip = CreateWindow(TOOLTIPS_CLASS, "", TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd_or_hCtrl, NULL, hInst, NULL))) {
				return FALSE;
			}

			// ツールチップのサイズを、ダイアログの4/5に制限し、改行を可能にする
			{ //if ( ccpu32_GetComCtl32Ver() >= 470 ) {
				RECT rc;

				GetClientRect( hWnd_or_hCtrl, &rc );
				SendMessage( hTooltip, TTM_SETMAXTIPWIDTH, 0, rc.right*5/4 );  
			}

			ZeroMemory(&ti, sizeof(ti));
			ti.cbSize = sizeof(TOOLINFO);
			ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;// uIDはツールチップを表示するウィンドウを識別するハンドル / サブクラス化もお任せ
			ti.hwnd = hWnd_or_hCtrl;	// ツールチップを持つウィンドウ
			
			return TRUE;
		}
		else { // 通常の呼び出し（ツールチップ追加）。hWnd_or_hCtrlはコントロールハンドルとなる
			if ( hTooltip ) {
		        ti.uId = (UINT_PTR)hWnd_or_hCtrl;
				ti.lpszText = text;
				return (BOOL)SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
			}
			else {
				return FALSE;
			}
		}
	}
	else {
		return FALSE;
	}
}

// コントロールのデータベースを削除する
BOOL free_controls( HWND hWnd, int ok )
{
	UINT i;
	BOOL rv = 0;
	LONG lasterr;
	BOOL bRegErrMes = rnsf7RegRead("regErrorMessage", 0);

	if ( rctrls ) {
		for( i=0 ; i<nctrls ; i++ ) {
			if ( ok != 0 ) { // 中身を見て、レジストリに書き込む
				HKEY hKey;

				if ( rctrls[i].key && rctrls[i].entry && rctrls[i].changed && rctrls[i].stop == 0 && rctrls[i].id && IsDisableControl(rctrls[i].id) ) {
					if ( NULL != ( hKey = tRegOpenKey(NULL, rctrls[i].key, TREG_OPEN_CREATE)) ) {
						switch( rctrls[i].ctrl ) {
							case CHECK_CTRL:
								{
									UINT value = 0;
									switch ( GetCheckBox(rctrls[i].id) ) {
										case 1: //(BST_CHECKED)
											value = 1;
											break;
										case 0: //(BST_UNCHECKED)
											value = 0;
											break;
										case 2: //(BST_INDETERMINATE)
											value = 2;
											break;
										// ERRORVALUEは無視
									}
									
									switch( rctrls[i].opt ) {
										case 1: // 3state (グレイならばエントリ削除)
											if ( value == 2 ) {
												lasterr = RegDeleteValue(hKey, rctrls[i].entry);
												if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(CHECK_CTRL1)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
												break;
											}
											// そのまま下へ
										case 0: // ふつうにON/OFF (DWORD, SZ, EXPANDSZ)
											if ((rctrls[i].flag_opt & DELETE_DEFAULT) && rctrls[i].def_dw == value ) {
												// デフォルトとして指定した値と同じだったら削除
												lasterr = RegDeleteValue(hKey, rctrls[i].entry);
												if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(CHECK_CTRL0)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
											else {
												tRegClearLastError();

												if ( rctrls[i].opt_p1 && rctrls[i].opt_p2 ) {
													tRegWriteString(hKey, rctrls[i].entry, (char *)(value?rctrls[i].opt_p1:rctrls[i].opt_p2), TREG_EXTYPE(rctrls[i].flag_opt));
												}
												else if ( rctrls[i].flag_opt & CHECK_SZ01 ) {
													tRegWriteString(hKey, rctrls[i].entry, value?"1":"0", TREG_EXTYPE(rctrls[i].flag_opt));
												}
												else if ( rctrls[i].flag_opt & CHECK_SZYN ) {
													tRegWriteString(hKey, rctrls[i].entry, value?"yes":"no", TREG_EXTYPE(rctrls[i].flag_opt));
												}
												else if ( rctrls[i].flag_opt & CHECK_SZTF ) {
													tRegWriteString(hKey, rctrls[i].entry, value?"true":"false", TREG_EXTYPE(rctrls[i].flag_opt));
												}
												else {
													tRegWriteInteger(hKey, rctrls[i].entry, value?rctrls[i].byte_min:rctrls[i].bit_max);
												}

												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(CHECK_CTRL)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
											break;

										case 2: // BINARYの特定のバイトの特定のビット
											{
												unsigned char *buf;
												int m;

												m = tRegValueExist(hKey, rctrls[i].entry);
												if ( m < 0 ) {
													m = rctrls[i].byte_min+1;
													buf = (unsigned char *)calloc( 1, m );
												}
												else if ( (signed)rctrls[i].byte_min >= m ) {
													m = rctrls[i].byte_min+1;
													buf = (unsigned char *)calloc( 1, m );
													tRegReadString(hKey, rctrls[i].entry, (char *)buf, m);
												}
												else {
													buf = (unsigned char *)calloc( 1, m );
													tRegReadString(hKey, rctrls[i].entry, (char *)buf, m);
												}

												if ( value != rctrls[i].opt_u2 ) { // opt_u2にはオフのときの値(0または1)が入っている。u1,u2には、1,0または0,1しか入れては行けないことになっているので、ここの値を見て、u1の値は決めつけする
													buf[rctrls[i].byte_min] |= (1 << rctrls[i].bit_max);
												}
												else {
													buf[rctrls[i].byte_min] &= (~(1 << rctrls[i].bit_max));
												}

												if (!tRegWriteBinary(hKey, rctrls[i].entry, (char *)buf, m)) {
													lasterr = tRegGetLastError();
													if (lasterr != ERROR_SUCCESS && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(CHECK_CTRL2)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
												}
												safefree(buf);
											}
											break;

										case 3: // DWORDの特定のバイトの特定のビット
											{
												DWORD dw;
												
												dw = (DWORD)tRegReadInteger(hKey, rctrls[i].entry, 0);

												if ( value != rctrls[i].opt_u2 ) { // opt_u2にはオフのときの値(0または1)が入っている。u1,u2には、1,0または0,1しか入れては行けないことになっているので、ここの値を見て、u1の値は決めつけする
													dw |= (1 << rctrls[i].bit_max);
												}
												else {
													dw &= (~(1 << rctrls[i].bit_max));
												}

												if (!tRegWriteInteger(hKey, rctrls[i].entry, dw)) {
													lasterr = tRegGetLastError();
													if (lasterr != ERROR_SUCCESS && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(CHECK_CTRL3)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
												}
											}
											break;
									}
								}
								break;

							case EDIT_CTRL:
								{
									UINT length;
									char *value;

									length = GetWindowTextLength( rctrls[i].hCtrl );
									if ( NULL != (value = zalloc( length+1 )) ) {
										GetWindowText(rctrls[i].hCtrl, value, length+1);

										if ( rctrls[i].opt == 0 ) { // 文字列
											if ( (rctrls[i].flag_opt & DELETE_DEFAULT) && 0 == strcmp(rctrls[i].def_sz,value) ) {
												lasterr = RegDeleteValue(hKey, rctrls[i].entry);
												if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRL0)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
											else {
												if (!tRegWriteString(hKey, rctrls[i].entry, value, TREG_EXTYPE(rctrls[i].flag_opt))) {
													lasterr = tRegGetLastError();
													if (lasterr != ERROR_SUCCESS && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRL)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
												}
											}
										}
										else { // 数値
											if ( (rctrls[i].flag_opt & DELETE_DEFAULT) && rctrls[i].def_dw == atou(value) ) {
												lasterr = RegDeleteValue(hKey, rctrls[i].entry);
												if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRLn)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
											else {
												if ( rctrls[i].flag_opt & EDIT_SZ ) {
													char *v = "err";
													char itbuf[16];

													if ( rctrls[i].text ) { // 単位変換の必要性
														if ( 0 == _ultoa_s(atou(value) * transunit(rctrls[i].text), itbuf, _countof(itbuf), 10) ) {
															v = itbuf;
														}
													}
													else {
														v = value;
													}

													if (!tRegWriteString(hKey, rctrls[i].entry, v, TREG_EXTYPE(rctrls[i].flag_opt))) {
														lasterr = tRegGetLastError();
														if (lasterr != ERROR_SUCCESS && bRegErrMes) {
															dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRLs)", "レジストリキー'", rctrls[i].key,
																			 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																			 getLastErrorString(lasterr));
														}
													}
												}
												else if ( rctrls[i].flag_opt & EDIT_BINARY ) {
													DWORD dw = (DWORD)atou(value) * transunit(rctrls[i].text);
													tRegWriteBinary(hKey, rctrls[i].entry, (char *)&dw, 4);
													lasterr = tRegGetLastError();
													if (lasterr != ERROR_SUCCESS && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRLb)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
												}
												else {
													tRegWriteInteger(hKey, rctrls[i].entry, atou(value) * transunit(rctrls[i].text));
													lasterr = tRegGetLastError();
													if (lasterr != ERROR_SUCCESS && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(EDIT_CTRLo)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
												}
											}
										}

										safefree(value);
									}
								}
								break;

							case ICON_BUTTON:
								{
									UINT length;
									char *value;

									length = GetWindowTextLength( rctrls[i].hCtrl );
									if ( NULL != (value = zalloc( length+1 )) ) {
										GetWindowText(rctrls[i].hCtrl, value, length+1);
										if ( (rctrls[i].flag_opt & DELETE_DEFAULT) && 0 == strcmp(value, rctrls[i].def_sz) ) {
											lasterr = RegDeleteValue( hKey, rctrls[i].entry );
											if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
												dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(ICON_BUTTON)", "レジストリキー'", rctrls[i].key,
																 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																 getLastErrorString(lasterr));
											}
										}
										else {
											if (!tRegWriteString(hKey, rctrls[i].entry, value, TREG_EXTYPE(rctrls[i].flag_opt))) {
												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(ICON_BUTTON2)", "レジストリキー'", rctrls[i].key,
																	 "'のエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
										}
										safefree(value);
									}
								}
								break;

							case LIST_CTRL:
								if ( rctrls[i].opt == 0 ) { // Value List
									char **del_values; // szまたはexpandsz型でlistにないものは削除
									DWORD k,n,vl,num_del_value;
									char *value, *lv0data, *data;
									DWORD vl2, type;

									RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &n, &vl, NULL, NULL, NULL);
									vl = (vl+1)*2;

									del_values = (char **)calloc(n, sizeof(char *));
									if ( del_values ) {
										value = zalloc( vl );
										if ( value ) {
											num_del_value = 0; // del_values の個数
											for(k=0 ; k<n ; k++) {
												vl2 = vl;

												RegEnumValue(hKey, k, value, &vl2, NULL, &type, NULL, NULL);
												{
													int i2,n2;

													n2 = ListView_GetItemCount( rctrls[i].hCtrl );
													for(i2=0 ; i2<n2 ; i2++) {
														lv0data = lvGetItemString( rctrls[i].hCtrl, i2, 0 );
														if ( lv0data ) {
															if ( 0 == strcmp(lv0data, value) ) {
																safefree(lv0data);
																break;
															}
															safefree(lv0data);
														}
													}
													if ( i2 == n2 ) {
														del_values[num_del_value++] = _strdup( value );
													}
												}
											}

											for(k=0 ; k<num_del_value ; k++) {
												if ( del_values[k] ) {
													lasterr = RegDeleteValue( hKey, del_values[k] );
													if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL)", "レジストリキー'", rctrls[i].key,
																		 "'のエントリ'",del_values[k],"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
													safefree( del_values[k] );
												}
											}

											safefree( value );
										}
										else {
											destroy_splash_window();
											MessageBox(NULL, "保存のためのメモリが足りません。いくつかのデータは失われます。", "エラー", MB_OK | MB_ICONSTOP);
										}
										safefree( del_values );
									}
									else {
										destroy_splash_window();
										MessageBox(NULL, "保存のためのメモリが足りません。いくつかのデータは失われます。", "エラー", MB_OK | MB_ICONSTOP);
									}

									// 値の書き込み
									n = ListView_GetItemCount( rctrls[i].hCtrl );
									for(k=0 ; k<n ; k++) {
										value = lvGetItemString( rctrls[i].hCtrl, k, 0 );
										if ( value ) {
											data = lvGetItemString( rctrls[i].hCtrl, k, 1 );
											if ( data ) {
												// 値の書き込み
												// どんな型で書き込むのかを確定する方法：
												// ・コントロールがLV_DWORDで作られていて、"\(DWORD\)[0-9]+"なら数値
												//    - REG_DWORD で書き込む。
												// ・上記以外なら文字列
												//    - コントロールがSZ_EXPANDでつくられているのなら、REG_EXPAND_SZで書き込む
												//    - すでに値が存在し、REG_EXPAND_SZならば、それらの型で書き込む
												//    - 上記以外なら、REG_SZ型で書き込む
												
												if ( (rctrls[i].flag_opt&LV_DWORD) && cpp_regex_match(data, "\\(DWORD\\)[0-9]+", NULL) == TRUE ) {
													if (!tRegWriteInteger(hKey, value, atou(data+7))) {
														lasterr = tRegGetLastError();
														if (lasterr != ERROR_SUCCESS && bRegErrMes) {
															dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL2)", "レジストリキー'", rctrls[i].key,
																			 "'のエントリ'",value,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																			 getLastErrorString(lasterr));
														}
													}
												}
												else {
													if (!tRegWriteString(hKey, value, data, TREG_EXTYPE(rctrls[i].flag_opt))) {
														lasterr = tRegGetLastError();
														if (lasterr != ERROR_SUCCESS && bRegErrMes) {
															dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL3)", "レジストリキー'", rctrls[i].key,
																			 "'のエントリ'",value,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																			 getLastErrorString(lasterr));
														}
													}
												}

												safefree( data );
											}
											else {
												destroy_splash_window();
												MessageBox(NULL, "メモリが足りません。いくつかのデータは失われます。", "エラー", MB_OK | MB_ICONSTOP);
											}
											safefree( value );
										}
										else {
											destroy_splash_window();
											MessageBox(NULL, "メモリが足りません。いくつかのデータは失われます。", "エラー", MB_OK | MB_ICONSTOP);
										}
									}
								}
								else if ( rctrls[i].opt == 1 ) { // Key List
									// entry:msz_btns, def_sz:values, text:means
									char **del_keys; // リストにないキーは削除する
									char *keyname, **values;
									DWORD n, j, l, num_del_keys;

									// レジストリキー内のサブキーの数を数え、メモリ確保
									RegQueryInfoKey(hKey, NULL, NULL, NULL, &n, &j, NULL, NULL, NULL, NULL, NULL, NULL);
									j = (j+1)*2;
									del_keys = (char **)calloc(n, sizeof(char *));
									if ( del_keys ) {
										keyname = zalloc( l = j+1 );
										if ( keyname ) {
											HKEY   hKey2;

											// リストビュー内のアイテムと、サブキーの名称を比較。サブキーにしかない名称については削除を行う。
											for(j=num_del_keys=0 ; j<n ; j++) {
												UINT i2, n2;
												char *lv0data;

												DWORD l2 = l;
												RegEnumKeyEx(hKey, j, keyname, &l2, NULL, NULL, NULL, NULL);
												n2 = ListView_GetItemCount( rctrls[i].hCtrl );
												for(i2=0 ; i2<n2 ; i2++) {
													lv0data = lvGetItemString( rctrls[i].hCtrl, i2, 0 );
													if ( lv0data ) {
														if ( 0 == strcmp(lv0data, keyname) ) {
															safefree( lv0data );
															break; // リストに存在していたサブキー→削除しない
														}
														safefree( lv0data );
													}
												}
												if ( i2 == n2 ) { // リストに存在していないサブキー→削除する
													del_keys[num_del_keys++] = _strdup( keyname );
												}
											}

											// 削除候補列挙完了。削除を行う。
											for(j=0 ; j<num_del_keys ; j++) {
												if ( NULL != (hKey2 = tRegOpenKey( hKey, del_keys[j], 0 )) ) { // 書込オープンができたキーのみ、削除を行う。書込オープンができないのならば、そもそも削除する権利はない
													RegCloseKey( hKey2 );

													lasterr = RegDeleteKey(hKey, del_keys[j]);
													if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
														dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL4)", "レジストリキー'", rctrls[i].key,
																		 "'のサブキー'",del_keys[j],"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																		 getLastErrorString(lasterr));
													}
													safefree( del_keys[j] );
												}
											}

											safefree( keyname );
										}
										safefree( del_keys );
									}

									values = (char **)rctrls[i].def_sz;
									n = ListView_GetItemCount( rctrls[i].hCtrl );
									for(j=0 ; j<n ; j++) {
										char *lv0data;
										HKEY hSubKey;

										lv0data = lvGetItemString( rctrls[i].hCtrl, j, 0 );
										if ( lv0data ) {
											if ( NULL != (hSubKey = tRegOpenKey( hKey, lv0data, TREG_OPEN_CREATE )) ) {
												for(l=1 ; values[l] ; l++) {
													safefree(lv0data);
													lv0data = lvGetItemString( rctrls[i].hCtrl, j, l );
													if ( lv0data ) {
														if ( lv0data[0] == 0 && (rctrls[i].flag_opt&LV_DELETE_NOVALUE) ) {
															lasterr = RegDeleteValue( hSubKey,  values[l] );
															if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
																dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL5)", "レジストリキー'", rctrls[i].key,
																				 "'のサブキーのエントリ'",values[l],"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
																				 getLastErrorString(lasterr));
															}
														}
														else {
															// 値の書き込み
															// どんな型で書き込むのかを確定する方法：
															// ・コントロールがLV_DWORDで作られていて、"\(DWORD\)[0-9]+"なら数値
															//    - REG_DWORD で書き込む。
															// ・上記以外なら文字列
															//    - コントロールがSZ_EXPANDでつくられているのなら、REG_EXPAND_SZで書き込む
															//    - コントロールがMAYBE_EXPANDで作られているなら、書き込もうとしている値の中に%が2つ以上含まれているなら、REG_EXPAND_SZで書き込む
															//    - 上記以外なら、REG_SZ型で書き込む
															
															if ( (rctrls[i].flag_opt&LV_DWORD) && cpp_regex_match(lv0data, "\\(DWORD\\)[0-9]+", NULL) == TRUE ) {
																if (!tRegWriteInteger(hSubKey, values[l], atou(lv0data+7))) {
																	lasterr = tRegGetLastError();
																	if (lasterr != ERROR_SUCCESS && bRegErrMes) {
																		dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL6)", "レジストリキー'", rctrls[i].key,
																						 "'のサブキーのエントリ'",values[l],"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																						 getLastErrorString(lasterr));
																	}
																}
															}
															else {
																if (!tRegWriteString(hSubKey, values[l], lv0data, TREG_EXTYPE(rctrls[i].flag_opt))) {
																	lasterr = tRegGetLastError();
																	if (lasterr != ERROR_SUCCESS && bRegErrMes) {
																		dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL7)", "レジストリキー'", rctrls[i].key,
																						 "'のサブキーのエントリ'",values[l],"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																						 getLastErrorString(lasterr));
																	}
																}
															}
														}
													}
												}
												tRegCloseKey( hSubKey );
											}
											else {
												if (bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(LIST_CTRL0)", "レジストリキー'", rctrls[i].key, "\\", lv0data,
																	 "'を書き込みアクセスで開こうとしてエラーになりました。\nAPIが報告した原因：", getLastErrorString(tRegGetLastError()));
												}

												rv = 1; // レジストリへの書き込みオープンに失敗した
											}
											safefree(lv0data);
										}
									}
								}
								break;

							case MULTI_EDIT:
								{
									char *value_msz;
									int   cl;

									cl = GetWindowTextLength( rctrls[i].hCtrl )+1;
									value_msz = zalloc( cl );
									GetWindowText( rctrls[i].hCtrl, value_msz, cl );
									if ( (rctrls[i].flag_opt & DELETE_DEFAULT) && 0 == strcmp(value_msz, rctrls[i].def_sz) ) {
										lasterr = RegDeleteValue( hKey, rctrls[i].entry );
										if (lasterr != ERROR_SUCCESS && lasterr != ERROR_FILE_NOT_FOUND && bRegErrMes) {
											dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(MULTI_EDIT)", "レジストリキー'", rctrls[i].key,
															 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
															 getLastErrorString(lasterr));
										}
									}
									else {
										if ( rctrls[i].flag_opt & (EDIT_SZ|SZ_EXPAND|MAYBE_EXPAND) ) {
											if (!tRegWriteString( hKey, rctrls[i].entry, value_msz, TREG_EXTYPE(rctrls[i].flag_opt) )) {
												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(MULTI_EDITs)", "レジストリキー'", rctrls[i].key,
																	 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
										}
										else {
											if (!tRegWriteMultiString( hKey, rctrls[i].entry, value_msz)) {
												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(MULTI_EDITo)", "レジストリキー'", rctrls[i].key,
																	 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
										}
									}
									safefree( value_msz );
								}
								break;

							case COMBO_CTRL:
								{
									int cur = (int)SendMessage(rctrls[i].hCtrl, CB_GETCURSEL, 0, 0);
									if ( (rctrls[i].flag_opt & DELETE_DEFAULT) && rctrls[i].def_dw == cur ) {
										lasterr = RegDeleteValue( hKey, rctrls[i].entry );
										if (lasterr != ERROR_SUCCESS && bRegErrMes) {
											dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(COMBO_CTRL)", "レジストリキー'", rctrls[i].key,
															 "'のエントリ'",rctrls[i].entry,"'を削除しようとしてエラーになりました。\nAPIが報告した原因：",
															 getLastErrorString(lasterr));
										}
									}
									else {
										if ( rctrls[i].opt == 0 ) { // 文字列
											char **values = (char **)rctrls[i].def_sz;
											if (!tRegWriteString( hKey, rctrls[i].entry, values[cur], TREG_EXTYPE(rctrls[i].flag_opt) )) {
												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(COMBO_CTRL0)", "レジストリキー'", rctrls[i].key,
																	 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
										}
										else if ( rctrls[i].opt == 1 ) { // 数値
											int *values = (int *)rctrls[i].def_sz;
											if (!tRegWriteInteger( hKey, rctrls[i].entry, values[cur] )) {
												lasterr = tRegGetLastError();
												if (lasterr != ERROR_SUCCESS && bRegErrMes) {
													dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(COMBO_CTRL1)", "レジストリキー'", rctrls[i].key,
																	 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
																	 getLastErrorString(lasterr));
												}
											}
										}
									}
								}
								break;

							case COLOR_BUTTON:
								if (rctrls[i].flag_opt & CB_DWORD) {
									if (!tRegWriteInteger(hKey, rctrls[i].entry, rctrls[i].opt_u1)) {
										lasterr = tRegGetLastError();
										if (lasterr != ERROR_SUCCESS && bRegErrMes) {
											dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(COLOR_BUTTONn)", "レジストリキー'", rctrls[i].key,
															 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
															 getLastErrorString(lasterr));
										}
									}
								}
								else {
									char ptext[70];

									wsprintf(ptext, "%d %d %d", (rctrls[i].opt_u1&0xff), (rctrls[i].opt_u1&0xff00)>>8, (rctrls[i].opt_u1&0xff0000)>>16);
									if (!tRegWriteString( hKey, rctrls[i].entry, ptext, TREG_NORMAL_SZ )) {
										lasterr = tRegGetLastError();
										if (lasterr != ERROR_SUCCESS && bRegErrMes) {
											dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー(COLOR_BUTTONs)", "レジストリキー'", rctrls[i].key,
															 "'のサブキーのエントリ'",rctrls[i].entry,"'への書き込みを行おうとしてエラーになりました。\nAPIが報告した原因：",
															 getLastErrorString(lasterr));
										}
									}
								}
								if (rctrls[i].opt_p1) { // 画面表示中のブラシがあったら削除
									DeleteObject(rctrls[i].opt_p1);
								}
								break;

						}
						RegCloseKey( hKey );
					}
					else {
						if (bRegErrMes) {
							dispErrorMessage(hWnd, MB_OK | MB_ICONSTOP, "レジストリへの書き込み中エラー", "レジストリキー'", rctrls[i].key,
								             "'を書き込みアクセスで開こうとしてエラーになりました。\nAPIが報告した原因：", getLastErrorString(tRegGetLastError()), NULL, NULL);
						}
						rv = 1; // レジストリへの書き込みオープンに失敗した
					}
				}
			}
			rctrls[i].stop = 0;
			rctrls[i].changed = 0;

			// [適用] でなかった場合（つまり[OK][キャンセル]ボタンだった場合）：いろいろ削除
			if ( ok != 2 ) { // 各項目のバッファを削除
				safefree( rctrls[i].key );
				safefree( rctrls[i].entry );

				if ( rctrls[i].def_sz ) {
					if ( (rctrls[i].ctrl == LIST_CTRL && rctrls[i].opt == 1) && (rctrls[i].ctrl == COMBO_CTRL) ) { // keylistまたは、ただのlistviewだったら
						char **values;

						for( values = (char **)rctrls[i].def_sz ; *values ; values++ ) {
							safefree( *values );
						}
					}

					safefree( rctrls[i].def_sz );
				}

				if ( rctrls[i].text ) {
					if ( rctrls[i].ctrl == LIST_CTRL && rctrls[i].opt == 1 ) { // keylistだったら
						char **means;

						for( means = (char **)rctrls[i].text ; *means ; means++ ) {
							safefree( *means );
						}
					}

					safefree( rctrls[i].text );
				}

				if ( rctrls[i].id ) {
					safefree( rctrls[i].id );
				}

				if ( rctrls[i].opt_p1 ) {
					if ( rctrls[i].ctrl == CHECK_CTRL ) { // チェックボックスコントロールだったら
                        safefree( rctrls[i].opt_p1 );
					}
				}

				if ( rctrls[i].opt_p2 ) {
					if ( rctrls[i].ctrl == CHECK_CTRL ) { // チェックボックスコントロールだったら
                        safefree( rctrls[i].opt_p2 );
					}
				}

				// アイコンボタン削除
				if ( rctrls[i].ctrl == ICON_BUTTON ) {
					if ( rctrls[i].lParam ) { // アイコンハンドルの解放
						DestroyWindow( rctrls[i].hCtrl ); // 先にボタンを破棄
						rctrls[i].hCtrl = NULL;
						DestroyIcon( (HICON)rctrls[i].lParam );
						rctrls[i].lParam = 0;
					}
				}

				// [戻す]のためのバックアップデータを削除
				if ( rctrls[i].dfr ) {
					if ( rctrls[i].ctrl == EDIT_CTRL || rctrls[i].ctrl == MULTI_EDIT || rctrls[i].ctrl == ICON_BUTTON || rctrls[i].ctrl == TEXT_CTRL || rctrls[i].ctrl == GOTO_BUTTON ) {
                        safefree( (char *)(rctrls[i].dfr) );
					}
					else if ( rctrls[i].ctrl == LIST_CTRL ) {
						LPRESTOREDATA_LISTVIEW rdlv = (LPRESTOREDATA_LISTVIEW)rctrls[i].dfr;
						UINT x, y;

						for(y=0 ; y<rdlv->nItems ; y++) {
							for(x=0 ; x<rdlv->nColumns ; x++) {
								safefree(rdlv->data[y*rdlv->nColumns+x]);
							}
						}
						safefree(rdlv);
					}
					rctrls[i].dfr = 0;
				}

				SetWindowLongPtr(rctrls[i].hCtrl, GWLP_WNDPROC, (LONG_PTR)rctrls[i].orgproc); // メッセージプロシージャを元に戻す
			}
		}

		if ( ok != 2 ) { // [適用]ボタンでなかったら（つまり、[OK]ボタンだったら）
			safefree( rctrls );
			nctrls = 0;
		}
	}

	return rv;
}

// [戻す]ボタンを押したときのための準備
static void ready_for_restore( void )
{
	UINT i;

	if ( rctrls ) {
		for( i=0 ; i<nctrls ; i++ ) {
			if (rctrls[i].id) {
				if ( rctrls[i].ctrl == CHECK_CTRL ) {
					rctrls[i].dfr = (LPARAM)GetCheckBox( rctrls[i].id );
				}

				else if ( rctrls[i].ctrl == EDIT_CTRL || rctrls[i].ctrl == MULTI_EDIT ||
						  rctrls[i].ctrl == ICON_BUTTON || rctrls[i].ctrl == GOTO_BUTTON) {

					rctrls[i].dfr = (LPARAM)GetEditBox( rctrls[i].id );
				}

				else if ( rctrls[i].ctrl == LIST_CTRL ) {
					LPRESTOREDATA_LISTVIEW rdlv;
					UINT x, y;

					rdlv = (LPRESTOREDATA_LISTVIEW)zalloc( sizeof(RESTOREDATA_LISTVIEW) );

					if ( rdlv ) {
						rdlv->nColumns = rctrls[i].def_dw;
						rdlv->nItems = ListView_GetItemCount( rctrls[i].hCtrl );
						rdlv->data = (char **)calloc(rdlv->nColumns * rdlv->nItems, sizeof(char *));

						for(y=0 ; y<rdlv->nItems ; y++) {
							for(x=0 ; x<rdlv->nColumns ; x++) {
								rdlv->data[rdlv->nColumns*y+x] = ListView_GetText(rctrls[i].id, y, x);
							}
						}
					}
					rctrls[i].dfr = (LPARAM)rdlv;
				}
				else if ( rctrls[i].ctrl == COMBO_CTRL ) {
					rctrls[i].dfr = (LPARAM)GetComboBoxCursor( rctrls[i].id );
				}

				// 有効化・無効化の状態、stopを保存
				rctrls[i].o_enabled = (BYTE)IsDisableControl(rctrls[i].id) | (rctrls[i].stop ? 2 : 0);
			}
		}
	}
}

// コントロールのデータベースを開いたときの状態に戻す（IDRETRYから呼ばれる）
void  restore_controls( void )
{
	UINT i;

	if ( rctrls ) {
		for( i=0 ; i<nctrls ; i++ ) {
			if (rctrls[i].id) {
				if ( rctrls[i].ctrl == CHECK_CTRL ) {
					SetCheckBox( rctrls[i].id, (UINT)rctrls[i].dfr );
					if ( rctrls[i].text ) {
						SetTextCtrl( rctrls[i].id, rctrls[i].text );
					}
				}

				else if ( rctrls[i].ctrl == EDIT_CTRL || rctrls[i].ctrl == MULTI_EDIT ) {
					if ( rctrls[i].dfr ) {
						SetEditBox( rctrls[i].id, (char *)rctrls[i].dfr );
					}
				}

				else if ( rctrls[i].ctrl == GOTO_BUTTON ) {
					if ( rctrls[i].dfr ) {
						SetTextCtrl( rctrls[i].id, (char *)rctrls[i].dfr );
					}
				}

				else if ( rctrls[i].ctrl == ICON_BUTTON ) {
					if ( rctrls[i].dfr ) {
						SetIconBox( rctrls[i].id, (char *)rctrls[i].dfr );
					}
				}

				else if ( rctrls[i].ctrl == LIST_CTRL ) {
					LPRESTOREDATA_LISTVIEW rdlv = (LPRESTOREDATA_LISTVIEW)rctrls[i].dfr;
					UINT x, y;

					if ( rdlv ) {
						ListView_DeleteAllItems( rctrls[i].hCtrl ); // リストビューのすべてのアイテムを削除

						for(y=0 ; y<rdlv->nItems ; y++) {
							if ( rdlv->data[y*rdlv->nColumns] ) {
								ListView_Add( rctrls[i].id, rdlv->data[y*rdlv->nColumns] );
							}
							for(x=1; x<rdlv->nColumns ; x++) {
								if ( rdlv->data[y*rdlv->nColumns+x] ) {
									ListView_SetText(rctrls[i].id, y, x, rdlv->data[y*rdlv->nColumns+x]);
								}
							}
						}
						ListView_SetItemState(rctrls[i].hCtrl, 0, LVIS_FOCUSED, LVIS_FOCUSED);
					}
				}
				else if ( rctrls[i].ctrl == COMBO_CTRL ) {
					SetComboBoxCursor( rctrls[i].id, (UINT)rctrls[i].dfr );
				}
				else if ( rctrls[i].ctrl == COLOR_BUTTON ) {
					SetColorButton( rctrls[i].id, rctrls[i].def_dw );
				}

				if ( rctrls[i].ctrl != AC_FINISH ) {
					// [OK]〜[Help]ボタン以外の有効化・無効化の状態も復帰
					DisableControl( rctrls[i].id, (rctrls[i].o_enabled&1)?TRUE:FALSE );
					rctrls[i].stop = (rctrls[i].o_enabled&2) ? 1 : 0;
				}
			}
		}
	}
}

// ダイアログの状態をファイルへ書き込む
BOOL saveDialogStatus( HWND hWnd, const char *fname )
{
	UINT i;			// カウンタ
	HANDLE hFile;	// ファイルハンドル
	DWORD tmp, it;	// 4バイト書き込み用変数
	BYTE  bt;		// 1バイト書き込み用変数
	char *rscfname;	// rscnameのファイル名のみの部分

	hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if ( hFile == INVALID_HANDLE_VALUE ) {
		destroy_splash_window();
		MessageBox( hWnd, "指定されたファイルを開けません。", "ダイアログ状態をファイルへ書き込み", MB_OK | MB_ICONSTOP );
		return FALSE;
	}

	// ヘッダの書き込み(DIALOGHEADERSIZE bytes)
	WriteFile( hFile, DIALOGHEADER, DIALOGHEADERSIZE, &tmp, NULL );

	// rscファイル名を書き込み
	rscfname = rscname;
	// もし、rscnameの右側に\\があったら、その次にrscfnameに指させる。
	for(i=0 ; rscname[i] ; i++) {
		if (rscname[i] == '\\' && !isKanji1(rscname,i-1)) {
			rscfname = rscname + i + 1;
		}
	}
	it = lstrlen(rscfname)+1;
	WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
	WriteFile( hFile, rscfname, it, &tmp, NULL );

	if ( rctrls ) {
		for( i=0 ; i<nctrls ; i++ ) {
			switch ( rctrls[i].ctrl ) { // 必要なコントロールについてのみ書き込む
				case CHECK_CTRL:
				case EDIT_CTRL:
				case MULTI_EDIT:
				case ICON_BUTTON:
				//case TEXT_CTRL: // テキストコントロールはアイコンボタンのみのためであるが、ここでは利用しない
				case GOTO_BUTTON:
				case LIST_CTRL:
				case COMBO_CTRL:
				case COLOR_BUTTON:
					if (rctrls[i].id) {
						// IDの書き込み(内容バイト数[4bytes]+内容(うしろに\0含む))
						it = lstrlen(rctrls[i].id)+1;
						WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
						WriteFile( hFile, rctrls[i].id, it, &tmp, NULL );

						// コントロールの種類を書き込み
						it = rctrls[i].ctrl; // このitの値は、次のswitchでも使う
						WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );

						// 有効・無効状態を書き込み
						bt = (BYTE)IsDisableControl(rctrls[i].id) | ( rctrls[i].stop ? 2 : 0 );
						WriteFile( hFile, (LPCVOID)&bt, sizeof(bt), &tmp, NULL );
					}
					else {
						continue;
					}
					break;

				default: // ここでcontinueしておかないと、変数itの値が古いままになって、次のswitch()で不具合を起こすので
					continue;
			}

			switch( it ) {
				case CHECK_CTRL:
					// チェックボックスだった場合
					bt = (BYTE)GetCheckBox( rctrls[i].id ) + 3;  // 過去のバージョンのミスにより、0,1,2 は欠番
					WriteFile( hFile, (LPCVOID)&bt, sizeof(bt), &tmp, NULL );
					// そのまま下へ ( 過去のバージョンでは、こうなっていなかった )
				case EDIT_CTRL:
				case MULTI_EDIT:
				case ICON_BUTTON:
				//case TEXT_CTRL: // テキストコントロールはアイコンボタンのみのためであるが、ここでは利用しない
				case GOTO_BUTTON:
					{	// 文字列メインのコントロール
						char *pbuf;

						pbuf = GetEditBox( rctrls[i].id );
						if ( pbuf ) {
							it = lstrlen( pbuf ) + 1;
							WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
							WriteFile( hFile, pbuf, it, &tmp, NULL );
							safefree( pbuf );
						}
						else {
							it = 19; // "-メモリ不足で失敗-" のバイト数
							WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
							WriteFile( hFile, "-メモリ不足で失敗-", it, &tmp, NULL );
							destroy_splash_window();
							MessageBox( hWnd, "メモリ不足により、書き込みに失敗した項目があります。ファイルは不完全なものとなります。\n書き込みを継続します。", "ダイアログの状態を保存", MB_OK | MB_ICONEXCLAMATION );
						}
					}
					break;

				case LIST_CTRL:
					{
						UINT x, y, mx, my;
						char *pbuf;

						mx = rctrls[i].def_dw;
						WriteFile( hFile, (LPCVOID)&mx, sizeof(mx), &tmp, NULL );
						my = ListView_GetItemCount( rctrls[i].hCtrl );
						WriteFile( hFile, (LPCVOID)&my, sizeof(my), &tmp, NULL );

						for(y=0 ; y<my ; y++) {
							for(x=0 ; x<mx ; x++) {
								pbuf = ListView_GetText( rctrls[i].id, y, x );
								if ( pbuf ) {
									it = lstrlen(pbuf)+1;
									WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
									WriteFile( hFile, pbuf, it, &tmp, NULL );
									safefree( pbuf );
								}
								else {
									it = 19; // "-メモリ不足で失敗-" のバイト数
									WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
									WriteFile( hFile, "-メモリ不足で失敗-", it, &tmp, NULL );
									destroy_splash_window();
									MessageBox( hWnd, "メモリ不足により、書き込みに失敗した項目があります。ファイルは不完全なものとなります。\n書き込みを継続します。", "ダイアログの状態を保存", MB_OK | MB_ICONEXCLAMATION );
								}
							}
						}
					}
					break;

				case COMBO_CTRL:
					// コンボボックス
					it = GetComboBoxCursor( rctrls[i].id );
					WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
					break;

				case COLOR_BUTTON:
					// 色選択ボタン
					it = GetColorButton( rctrls[i].id );
					WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
					break;
			}
		}
	}

	CloseHandle( hFile );
	return TRUE;
}

// ダイアログの状態をファイルから読み出し
UINT loadDialogStatus( HWND hWnd, const char *fname )
{
	UINT   no;		// カウンタ
	HANDLE hFile;	// ファイルハンドル
	DWORD  tmp, it;	// 4バイト読み込み用変数
	DWORD  ctrl;	// コントロールの種類
	BYTE   bt;		// 1バイト読み込み用変数
	char *pbuf;		// 読込バッファ用
	char *rscfname;	// rscnameのファイル名のみの部分
	UINT   rv = 0;	// 戻り値
	BOOL bflag;		// 読み込み失敗感知フラグ

	hFile = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if ( hFile == INVALID_HANDLE_VALUE ) {
		destroy_splash_window();
		MessageBox( hWnd, "指定されたファイルを開けません。", "ダイアログ状態をファイルから読み込み", MB_OK | MB_ICONSTOP );
		return FALSE;
	}

	// ヘッダのチェック(DIALOGHEADERSIZE bytes)
    pbuf = zalloc( DIALOGHEADERSIZE+1 );
	if ( !pbuf ) {
		destroy_splash_window();
		MessageBox( hWnd, "動作を完了させるためのメモリが不足しています。", "ダイアログ状態をファイルから読み込み", MB_OK | MB_ICONSTOP );
		CloseHandle( hFile );
		return FALSE;
	}
	bflag = ReadFile( hFile, pbuf, DIALOGHEADERSIZE, &tmp, NULL );
	if ( bflag == 0 || (bflag != 0 && tmp == 0) ) pbuf[0] = 0;
	pbuf[DIALOGHEADERSIZE-1] = 0;
	pbuf[DIALOGHEADERIGNR] = '-'; // 上位互換性のための読み飛ばし

	if ( strcmp(pbuf, DIALOGHEADER) != 0 ) {
		CloseHandle( hFile );
		destroy_splash_window();
		MessageBox( hWnd, "指定されたファイルは状態が保存されたファイルではないか、対応していないバージョンです。", "ダイアログ状態をファイルから読み込み", MB_OK | MB_ICONSTOP );
		return FALSE;
	}
	safefree( pbuf );

	// rscファイル名を読み込み、rscnameのファイル名部分と同じかどうかチェックする
	rscfname = rscname;
	// もし、rscnameの右側に\\があったら、その次にrscfnameに指させる。
	for(no=0 ; rscname[no] ; no++) {
		if (rscname[no] == '\\' && !isKanji1(rscname,no-1)) {
			rscfname = rscname + no + 1;
		}
	}
	bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
	if ( bflag == 0 || (bflag != 0 && tmp == 0) ) it = 1;
	
	pbuf = zalloc( it );
	if ( pbuf ) {
		bflag = ReadFile(hFile, pbuf, it, &tmp, NULL);
		if ( bflag == 0 || (bflag != 0 && tmp == 0) ) pbuf[0] = 0;

		pbuf[it-1] = 0;

		if ( strcmp(pbuf, rscfname) != 0 ) {
			destroy_splash_window();
			if ( IDYES != MessageBox( hWnd, "指定されたファイルは、現在開かれているダイアログ用として保存されたものではないかもしれません。\n該当しない項目が存在すると、その項目は読み飛ばされます。\n読み込みを強行しますか?", pbuf, MB_YESNO | MB_ICONQUESTION ) ) {
				safefree( pbuf );
				CloseHandle( hFile );
				return FALSE;
			}
		}
		safefree( pbuf );
	}
	else {
		CloseHandle( hFile );
		destroy_splash_window();
		MessageBox( hWnd, "ダイアログ状態読み込みのために必要なメモリを確保できませんでした。", "ダイアログ状態をファイルから読み込み", MB_OK | MB_ICONSTOP );
		return FALSE;
	}

	it = lstrlen(rscfname)+1;
	WriteFile( hFile, (LPCVOID)&it, sizeof(it), &tmp, NULL );
	WriteFile( hFile, rscfname, it, &tmp, NULL );
	pbuf = NULL;

	if ( rctrls ) {
		while( 1 ) {
			char *id;

			rv = 1;
			// IDを読み込み
			bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
			if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

			rv = 2; // 以降でbreakする場合、読み込んだけと中途半端
			
			id = zalloc( it );
			if ( id  ) {
				bflag = ReadFile(hFile, id, it, &tmp, NULL);
				if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

				id[it-1] = 0;
				// IDに対応する番号検索:仮にIDが存在しなく(no==nctrls)てもここでは無視し、代入時にスキップする
				for(no=0 ; no<nctrls ; no++) {
					if ( rctrls[no].id && _stricmp(rctrls[no].id, id) == 0 ) {
						ActiveControl( rctrls[no].id );
						break;
					}
				}
				safefree( id );
				if ( no < nctrls ) {
					id = rctrls[no].id;
				}
			}
			else {
				SetFilePointer(hFile, it, NULL, FILE_CURRENT);
			}

			// コントロールの種類
			bflag = ReadFile(hFile, (LPVOID)&ctrl, sizeof(ctrl), &tmp, NULL);
			if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

			// [OK]〜[Help]ボタン以外の有効化・無効化の状態も復帰
			bflag = ReadFile(hFile, (LPVOID)&bt, sizeof(bt), &tmp, NULL);
			if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;
			if ( it != AC_FINISH ) {
				if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
					// 有効・無効状態を読み込み
					DisableControl( rctrls[no].id, (bt&1) ? TRUE: FALSE );
					rctrls[no].stop = (bt&2) ? 1 : 0;
				}
			}

			switch( ctrl ) {
				case CHECK_CTRL:
					// チェックボックス
					bflag = ReadFile(hFile, (LPVOID)&bt, sizeof(bt), &tmp, NULL);
					if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

					if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
						if ( bt < 3 )
							SetCheckBox(id, (UINT)bt);
						else if ( bt < 6 )
							SetCheckBox(id, (UINT)bt-3);
					}
					if ( bt < 3 )
						break; // 過去のバージョンの互換(0〜2は、文字列を設定していなかった)
					// そのまま下へ
				case EDIT_CTRL:
				case MULTI_EDIT:
				//case TEXT_CTRL:	// 太古のβ版では有効だったが、現在では使われないどころか異常終了するのでコメントアウト
				case GOTO_BUTTON:
					bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
					if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

					pbuf = zalloc( it );
					if ( pbuf ) {
						bflag = ReadFile(hFile, pbuf, it, &tmp, NULL);
						if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

						pbuf[it-1] = 0;

						if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
							if ( rctrls[no].ctrl == EDIT_CTRL || rctrls[no].ctrl == MULTI_EDIT )
								SetEditBox( id, pbuf );
							else
								SetTextCtrl( id, pbuf );
						}

						safefree( pbuf );
					}
					else {
						SetFilePointer(hFile, it, NULL, FILE_CURRENT);
					}
					break;

				case ICON_BUTTON:
					bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
					if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

					pbuf = zalloc( it );
					if ( pbuf ) {
						bflag = ReadFile(hFile, pbuf, it, &tmp, NULL);
						if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

						pbuf[it-1] = 0;

						if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
							SetIconBox( id, pbuf );
						}

						safefree( pbuf );
					}
					else {
						SetFilePointer(hFile, it, NULL, FILE_CURRENT);
					}
					break;

				case LIST_CTRL:
					{
						UINT x, y, mx, my;

						bflag = ReadFile( hFile, (LPVOID)&mx, sizeof(mx), &tmp, NULL );
						if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

						bflag = ReadFile( hFile, (LPVOID)&my, sizeof(my), &tmp, NULL );
						if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

						if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
							ListView_DeleteAllItems( rctrls[no].hCtrl );
						}

						for(y=0 ; y<my ; y++) {
							// pbufのメモリ確保とファイルからの読込
							bflag = ReadFile( hFile, (LPVOID)&it, sizeof(it), &tmp, NULL );
							if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

							pbuf = zalloc( it );
							if ( pbuf ) {
								bflag = ReadFile( hFile, pbuf, it, &tmp, NULL );
								if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

								if ( no < nctrls ) {
									ListView_Add( id, pbuf );
								}
								safefree( pbuf );
							}
							else {
								SetFilePointer(hFile, it, NULL, FILE_CURRENT);
							}

							for(x=1; x<mx ; x++) {
								// pbufのメモリ確保とファイルからの読込
								bflag = ReadFile( hFile, (LPVOID)&it, sizeof(it), &tmp, NULL );
								if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

								pbuf = zalloc( it );
								if ( pbuf ) {
									bflag = ReadFile( hFile, pbuf, it, &tmp, NULL );
									if ( no < nctrls ) {
										ListView_SetText(id, y, x, pbuf);
									}
									safefree( pbuf );
								}
								else {
									SetFilePointer(hFile, it, NULL, FILE_CURRENT);
								}
							}
						}
						if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
							ListView_SetItemState(rctrls[no].hCtrl, 0, LVIS_FOCUSED, LVIS_FOCUSED);
						}
					}
					break;

				case COMBO_CTRL:
					bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
					if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

					if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
						SetComboBoxCursor(id, (UINT)it);
					}
					break;

				case COLOR_BUTTON:
					bflag = ReadFile(hFile, (LPVOID)&it, sizeof(it), &tmp, NULL);
					if ( bflag == 0 || (bflag != 0 && tmp == 0) ) break;

					if ( no < nctrls && rctrls[no].ctrl == ctrl ) {
						SetColorButton(id, (UINT)it);
					}
					break;
			}
		}
	}

	CloseHandle( hFile );
	if ( rv == 2 ) {
		destroy_splash_window();
		MessageBox( hWnd, "ファイルからダイアログの状態を読み込みましたが、ファイルの内容が中途半端だったため、途中まで読み込まれました。\nファイルの内容が壊れている場合、ダイアログの内容も破壊されているかもしれませんので、この場合は[OK]は押さずに、ただちに[キャンセル]を押して下さい。", "ダイアログの状態を読み込み", MB_OK | MB_ICONEXCLAMATION );
	}
	return rv;
}

// 各標準ボタンの有効化/無効化
BOOL stdButtonStatus( HWND hDlg, int ctrlID, BOOL status )
{
	HMENU hMenu;
	BOOL bLastStatus = -1;

	bLastStatus = IsWindowEnabled(GetDlgItem(hDlg, ctrlID));
	hMenu = GetMenu( hDlg );
	switch( status ) {
		case TRUE:
			EnableWindow( GetDlgItem(hDlg, ctrlID), TRUE );
			if ( hMenu ) {
				bLastStatus = EnableMenuItem(hMenu, ctrlID, MF_BYCOMMAND | MF_ENABLED);
				if ( bLastStatus == MF_ENABLED ) {
					bLastStatus = TRUE;
				}
				else {
					bLastStatus = FALSE;
					DrawMenuBar( hDlg ); // メニューに変化が生じたのであれば再描画（必ず）
				}
			}
			break;

		case FALSE:
			EnableWindow( GetDlgItem(hDlg, ctrlID), FALSE );
			if ( hMenu ) {
				bLastStatus = EnableMenuItem(hMenu, ctrlID, MF_BYCOMMAND | MF_GRAYED); 
				if ( bLastStatus == MF_ENABLED ) {
					bLastStatus = TRUE;
					DrawMenuBar( hDlg ); // メニューに変化が生じたのであれば再描画（必ず）
				}
				else {
					bLastStatus = FALSE;
				}
			}
			break;

		// status = TRUE, FALSE 以外だった場合は、何もしない
		// ただし、メニュー状態は返す
		default:
			if ( hMenu ) {
				bLastStatus = EnableMenuItem(hMenu, ctrlID, MF_BYCOMMAND | MF_GRAYED); 
				EnableMenuItem(hMenu, ctrlID, MF_BYCOMMAND | bLastStatus); 
				if ( bLastStatus == MF_ENABLED ) {
					bLastStatus = TRUE;
				}
				else {
					bLastStatus = FALSE;
				}
			}
			break;
	}

	return bLastStatus;
}

// 各標準ボタンの有効化/無効化
void stdButtonsStatus( HWND hDlg, BOOL sOK, BOOL sCancel, BOOL sAppry, BOOL sRetry, BOOL sSave, BOOL sLoad, BOOL sHelp )
{
	stdButtonStatus( hDlg, IDOK, sOK );
	stdButtonStatus( hDlg, IDCLOSE, sCancel );
	stdButtonStatus( hDlg, IDYES, sAppry );
	stdButtonStatus( hDlg, IDRETRY, sRetry );
	stdButtonStatus( hDlg, IDSAVE, sSave );
	stdButtonStatus( hDlg, IDLOAD, sLoad );
	stdButtonStatus( hDlg, IDHELP, sHelp );
}

// コントロールの変更が行われたら、OKボタンなどを有効にする
static void ac_ctrlChange( int ctrl_no )
{
	rctrls[ctrl_no].changed = 1;
	if ( !(rctrls[ctrl_no].flag_opt & CTRL_NOEFFECT ) ) {
		stdButtonsStatus( GetParent(rctrls[ctrl_no].hCtrl), TRUE, -1, TRUE, TRUE, -1, -1, -1 );
	}
}

// idからチェックボックスの状態を得る
UINT GetCheckBox( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL ) {
			if ( rctrls[i].i == ERRORVALUE ) { // 普通のチェックボックスだった場合
				switch ( SendMessage(rctrls[i].hCtrl, BM_GETCHECK, 0, 0) ) {
					case BST_CHECKED   : return 1;
					case BST_UNCHECKED : return 0;
					default            : return 2;
				}
			}
			else { // チェックボックスリスト中のチェックボックスだった場合
				return ListCheck_Get( rctrls[i].id );
			}
		}
	}

	return ERRORVALUE;
}

// idから編集ボックス/アイコンボックス/テキスト/チェックボックス/ボタン内の文字列を取得する
char *GetEditBox( const char *id )
{
	UINT i, l;
	char *p;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == EDIT_CTRL || rctrls[i].ctrl == ICON_BUTTON || rctrls[i].ctrl == MULTI_EDIT || rctrls[i].ctrl == CHECK_CTRL || rctrls[i].ctrl == GOTO_BUTTON) {
			if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
				// チェックボックスリスト中のチェックボックスだった場合
				return lvGetItemString( rctrls[i].hCtrl, rctrls[i].i, 0 );
			}
			else {
				l = GetWindowTextLength( rctrls[i].hCtrl );
				if (l >= 0) {
					p = zalloc( l+1 );
					if ( p ) {
						GetWindowText(rctrls[i].hCtrl, p, l+1);
					}
					return p;
				}
			}
		}
	}

	return _strdup("");
}

// idのチェックボックスの状態を設定
BOOL SetCheckBox( const char *id, UINT check )
{
	UINT i;
	
	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL ) {
			if ( rctrls[i].i == ERRORVALUE ) { // 普通のチェックボックスだった場合
				if ( initializing_flag == 0 ) {
					ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
				}

				SendMessage(rctrls[i].hCtrl, BM_SETCHECK, check==0?BST_UNCHECKED:
														  check==1?BST_CHECKED:
																   BST_INDETERMINATE, 0);
			}
			else { // チェックボックスリスト中のチェックボックスだった場合
				ListCheck_Set( rctrls[i].id, check );
			}
			return TRUE;
		}
	}

	return ERRORVALUE;
}

// idの編集ボックスの内容を設定
BOOL SetEditBox( const char *id, const char *text )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == MULTI_EDIT || rctrls[i].ctrl == EDIT_CTRL) {
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			return (SetWindowText(rctrls[i].hCtrl, text) != 0)?1:0;
		}
	}

	return ERRORVALUE;
}

// idのアイコンボックスの内容を設定
BOOL SetIconBox( const char *id, const char *text )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == ICON_BUTTON ) {
            HICON hIcon;

			// 旧アイコンを解放
			hIcon = (HICON)SendMessage(rctrls[i].hCtrl, BM_GETIMAGE, IMAGE_ICON, 0);
			if (hIcon) {
				DestroyIcon(hIcon);
			}

			// 新アイコン（と文字列）を設定
			SetWindowText(rctrls[i].hCtrl, text);
			if (text[0]) {
				hIcon = LoadIconFromFile(hInst, text);
			}
			else {
				hIcon = NULL;
			}
			SendMessage(rctrls[i].hCtrl, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);

			if ( initializing_flag == 0 ) {
				// 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
				ac_ctrlChange(i);
			}
			return (SetWindowText(rctrls[i+1].hCtrl, text) != 0)?1:0;
		}
	}

	return ERRORVALUE;
}

// チェックボックス、ボタン、テキストの文字列を設定
BOOL SetTextCtrl( const char *id, char *text )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( (rctrls[i].ctrl == CHECK_CTRL || rctrls[i].ctrl == GOTO_BUTTON) ) {
			// 注意：編集コントロールの変更ではないので、ac_ctrlChange() は呼ばれない

			if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
				// チェックボックスリスト中のチェックボックスだった場合
				ListView_SetItemText( rctrls[i].hCtrl, rctrls[i].i, 0, text );
				return 1;
			}
			else {
				return (SetWindowText(rctrls[i].hCtrl, text) != 0)?1:0;
			}
		}
	}

	return ERRORVALUE;
}

// idのコントロールを有効化・無効化（グレイアウト） flag:TRUE=有効 FALSE=無効
BOOL DisableControl( const char *id, UINT flag )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		ac_ctrlChange(i); // Enable() をしたときも、書き込みが行われるように配慮

		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			// チェックボックスリスト中のチェックボックスだった場合
			ListCheck_Disable( id, flag );
		}
		else {
			EnableWindow(rctrls[i].hCtrl, flag);

			if ( rctrls[i].ctrl == ICON_BUTTON ) { // アイコンボタンだったら、その次のスタティックコントロールもグレイアウト
				if ( rctrls[i+1].ctrl == TEXT_CTRL) {
					EnableWindow(rctrls[i+1].hCtrl, flag);
				}
			}
			else if ( rctrls[i].ctrl == EDIT_CTRL ) { // 編集ボックスで、その後が参照ボタン・デフォルトへ戻すボタンだったら、それもグレイアウト
				if ( rctrls[i+1].ctrl == REF_BUTTON_FILE || rctrls[i+1].ctrl == REF_BUTTON_FOLDER || rctrls[i+1].ctrl == TODEFAULT_BUTTON ) {
					EnableWindow(rctrls[i+1].hCtrl, flag);
				}
			}
			else if ( rctrls[i].ctrl == LIST_CTRL ) { // リストビューだったら、その次の3つのボタンもグレイアウト
				if ( rctrls[i+1].ctrl == LVC_BUTTON_NEW ) {
					EnableWindow(rctrls[i+1].hCtrl, flag);
					if ( rctrls[i+1].ctrl == LVC_BUTTON_EDIT ) {
						EnableWindow(rctrls[i+2].hCtrl, flag);
						if ( rctrls[i+1].ctrl == LVC_BUTTON_DEL ) {
							EnableWindow(rctrls[i+3].hCtrl, flag);
						}
					}
				}
			}
		}
		return TRUE;
	}

	return ERRORVALUE;
}

// idの有効/無効状態を取得 戻り値:TRUE=有効 FALSE=無効
EXTERN BOOL IsDisableControl( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			// チェックボックスリスト中のチェックボックスだった場合
			return ListCheck_IsDisable( id );
		}
		else {
			return IsWindowEnabled(rctrls[i].hCtrl) ? 1 : 0;
		}
	}

	return ERRORVALUE;
}


// idのコントロールを一時停止(1回だけレジストリへの自動書き込みを抑制する)
BOOL StopControl( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		rctrls[i].stop = 1;
		return TRUE;
	}

	return ERRORVALUE;
}

// idのコントロールの一時停止を解除し、変更があったように内部データを改鋳する
BOOL ActiveControl( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		rctrls[i].stop = 0;
		ac_ctrlChange(i);
		return TRUE;
	}

	return ERRORVALUE;
}

// idのコントロールにフォーカスをあわせる
BOOL SetFocusControl( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( NULL == SetFocus( rctrls[i].hCtrl ) ) {
			return FALSE;
		}
		else {
			if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
				// チェックボックスリスト中のチェックボックスだった場合
				ListView_SetItemState( rctrls[i].hCtrl, rctrls[i].i, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED );
				ListView_EnsureVisible( rctrls[i].hCtrl, rctrls[i].i, FALSE );
			}
			return TRUE;
		}
	}

	return ERRORVALUE;
}

// ------------------------------------------------------------------------------------------
// リストビューの操作関数
// ------------------------------------------------------------------------------------------

// リストビュー・チェックボックスリストのアイテムの数を得る
UINT ListView_GetNum( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			return (UINT)ListView_GetItemCount( rctrls[i].hCtrl );
		}
	}

	return ERRORVALUE;
}

// リストビュー・チェックボックスリストの新しいカーソル位置を設定する
UINT ListView_SetCursor( const char *id, UINT n )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			ListView_SetItemState(rctrls[i].hCtrl, n, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
			if (GetLVCursor(rctrls[i].hCtrl) == n) {
                ListView_EnsureVisible( rctrls[i].hCtrl, n, TRUE );
				return 1;
			}
			else {
                return 0;
			}
		}
	}

	return ERRORVALUE;
}

// リストビュー・チェックボックスリストの、現在カーソルの置かれている行の番号を返す
// （カーソルが置かれていないと0xffffffff。複数のカーソルがあると、最初のカーソル位置を返す）
UINT ListView_GetCursor( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			return (UINT)GetLVCursor(rctrls[i].hCtrl);
		}
	}

	return ERRORVALUE;
}

// リストビューのn行i桁に文字列をセットする
BOOL ListView_SetText( const char *id, UINT n, UINT c, const char *text )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL ) {
			if ( c == 0 ) { // セットの前に c == 0 だったら、他の第１項目と重複がないかをチェックする
				UINT j;
				int  m = ListView_GetItemCount(rctrls[i].hCtrl);
				char *pbuf = NULL;

				for(j=0 ; j<m ; j++) {
					if ( n != j ) {
						pbuf = lvGetItemString( rctrls[i].hCtrl, j, 0 );
						if ( pbuf ) {
							if ( strcmp(pbuf, text) == 0 ) { // 重複
								safefree( pbuf );
								return FALSE;
							}
							safefree( pbuf );
						}
					}
				}

			}
			ListView_SetItemText( rctrls[i].hCtrl, n, c, (char *)text );
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			return TRUE;
		}
	}

	return ERRORVALUE;
}

// リストビューに項目を追加する（追加を指示するだけで、設定はSetTextで）
BOOL ListView_Add( const char *id, const char *text )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL ) {
			LVITEM lvitem;
			int j, m = ListView_GetItemCount(rctrls[i].hCtrl);
			char *pbuf = NULL;

			for(j=0 ; j<m ; j++) {// セットの前に、他の第１項目と重複がないかをチェックする
				pbuf = lvGetItemString( rctrls[i].hCtrl, j, 0 );
				if ( pbuf ) {
					if ( strcmp(pbuf, text) == 0 ) { // 重複
						safefree( pbuf );
						return FALSE;
					}
					safefree( pbuf );
				}
			}

			lvitem.mask = LVIF_TEXT;
			lvitem.iItem = ListView_GetItemCount(rctrls[i].hCtrl); //最後に追加
			lvitem.iSubItem = 0;
			lvitem.pszText = (char *)text;

			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			return ( -1 != ListView_InsertItem( rctrls[i].hCtrl, &lvitem ) );
		}
	}

	return ERRORVALUE;
}

// リストビュー・チェックボックスリストのi行目が反転状態になっているか?
UINT ListView_isSelected( const char *id, UINT n )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			if ( (UINT)ListView_GetItemCount( rctrls[i].hCtrl ) <= n ) {
				return ERRORVALUE;
			}
			else {
				return (LVIS_SELECTED == ListView_GetItemState(rctrls[i].hCtrl, n, LVIS_SELECTED)) ? 1 : 0;
			}
		}
	}

	return ERRORVALUE;
}

// リストビューのi行目の項目を削除する
BOOL ListView_Del( const char *id, UINT n )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL ) {
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			return ListView_DeleteItem( rctrls[i].hCtrl, n );
		}
	}

	return ERRORVALUE;
}

// リストビュー・チェックボックスリストのcカラム目から、文字列textを検索し、見つかったら項目番号を返す。
// 見つからなければERRORVALUE
UINT ListView_Search( const char *id, UINT c, const char *text )
{
	UINT i, n, m;
	char *pbuf = NULL;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			m = ListView_GetItemCount(rctrls[i].hCtrl);
			for (n=0 ; n<m ; n++) {
				pbuf = lvGetItemString( rctrls[i].hCtrl, n, c );
				if ( pbuf ) {
					if ( _stricmp(pbuf, text) == 0 ) {
						safefree( pbuf );
						return n;
					}
					safefree( pbuf );
				}
			}
		}
	}

	return ERRORVALUE;
}

// リストビュー・チェックボックスリストのn行c桁の文字列を得る（戻り値は、あとでfreeすること）
char *ListView_GetText( const char *id, UINT n, UINT c )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == LIST_CTRL || rctrls[i].ctrl == CHKLIST_CTRL ) {
			if ( rctrls[i].id && _stricmp(rctrls[i].id, id) == 0 ) {
				return lvGetItemString( rctrls[i].hCtrl, n, c );
			}
		}
	}

	return _strdup( "" );
}

// ------------------------------------------------------------------------------------------
// 複数行編集ボックス関連
// ------------------------------------------------------------------------------------------

// 複数行編集ボックスの行数を得る
UINT GetMultiEditLineCount( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == MULTI_EDIT ) {
			return (UINT)SendMessage( rctrls[i].hCtrl, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL );
		}
	}

	return ERRORVALUE;
}

// 複数行編集ボックスのn行目を得る
char *GetMultiEditLine( const char *id, UINT n )
{
	UINT i, l;
	char *p, *r;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == MULTI_EDIT ) {
			l = GetWindowTextLength( rctrls[i].hCtrl ) + 1;
			if ( l < 5 ) {
				l = 5;
			}
			p = (char *)calloc( l+1, 1 );
			if ( p ) {
				// (EM_GETLINE)
				// MSDN Library : Before sending the message, set the first word of this buffer to the size, in TCHARs, of the buffer.
				//                EM_GETLINEメッセージを送る前に、バッファの最初の2バイト(WORD)に、バッファのサイズ(TCHAR単位)を入れること。
				// REMARK : The copied line does not contain a terminating null character. 
				//          コピーされる文字列には、最後のNULL文字は含まれない。
				*((int *)p) = l; // 本当は short でいいんだけどね…
				i = (int)SendMessage( rctrls[i].hCtrl, EM_GETLINE, (WPARAM)n, (LPARAM)p );
				p[i] = 0;
				r = _strdup( p );
				safefree( p );
				return r;
			}
		}
	}

	return _strdup("");
}

// 複数行編集ボックスの内容をチェックする
// 戻り値：
//  ビット1(1) … 最終行以外に空行が入っている
//  ビット2(2) … 行の内容が重複している箇所がある
// EM_GETLINEの特殊さについては、↑GetMultiEditLine()のコメントに転記した MSDN ライブラリのヘルプ参照
unsigned checkMultiEdit( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == MULTI_EDIT ) {
			UINT l, ip, ir, t, rv = 0;
			char *p, *r;
			// まずは行数を取得
			UINT uLine = (UINT)SendMessage( rctrls[i].hCtrl, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL );

			// 各行の内容を得るためのバッファを確保
			l = GetWindowTextLength( rctrls[i].hCtrl ) + 1;
			if ( l < 5 ) {
				l = 5;
			}
			p = (char *)calloc( l+1, 1 ); // 比較元行バッファ確保
			r = (char *)calloc( l+1, 1 ); // 比較先行バッファ確保
			if ( p && r ) {
				// 比較元ループ（比較元ループは最終行以外で）
				for(ip=0 ; ip<uLine-1 && ((rv&3)!=3) ; ++ip) {
					// 比較元行取得
					*((int *)p) = l; // 本当は short でいいんだけどね…
					t = (int)SendMessage( rctrls[i].hCtrl, EM_GETLINE, (WPARAM)ip, (LPARAM)p );
					p[t] = 0;

					// 比較しながら空行判定
					if (t == 0) { // 空行だったら、rv の ビット1 を立てる
						rv |= 1;
					}

					// 比較先ループ（比較元の行の次の行から比較を始めればよい）
					for(ir=ip+1 ; ir<uLine && ((rv&2)!=2) ; ++ir) {
						// 比較元行取得
						*((int *)r) = l; // 本当は short でいいんだけどね…
						t = (int)SendMessage( rctrls[i].hCtrl, EM_GETLINE, (WPARAM)ir, (LPARAM)r );
						r[t] = 0;

						// 比較元行と比較先行を比較して、一致していたら rv の ビット2 を立てる
						if (lstrcmp(p, r) == 0) {
							rv |= 2;
							// 空行判定の方もあるので、ループは強制終了させない
						}
					}
				}
			}
			else {
				rv = ERRORVALUE;
			}
			safefree( p );
			safefree( r );

			return rv;
		}
	}

	return ERRORVALUE;
}

// 複数行編集ボックスから、文字列textを検索し、見つかったら行番号を返す。
// 見つからなければERRORVALUE
// EM_GETLINEの特殊さについては、↑GetMultiEditLine()のコメントに転記した MSDN ライブラリのヘルプ参照
UINT MultiEdit_Search( const char *id, const char *text )
{
	UINT i, rv = ERRORVALUE;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == MULTI_EDIT ) {
			// まずは行数を取得
			int  l;
			char *p;
			UINT u, t, uLine = (UINT)SendMessage( rctrls[i].hCtrl, EM_GETLINECOUNT, (WPARAM)NULL, (LPARAM)NULL );

			// 各行の内容を得るためのバッファを確保
			l = GetWindowTextLength( rctrls[i].hCtrl ) + 1;
			if ( l < 5 ) {
				l = 5;
			}
			p = (char *)calloc( l+1, 1 ); // サーチ対象行バッファ確保
			if (p) {
				for(u=0 ; u<uLine ; ++u) {
					// サーチ対象行取得
					*((int *)p) = l; // 本当は short でいいんだけどね…
					t = (int)SendMessage( rctrls[i].hCtrl, EM_GETLINE, (WPARAM)u, (LPARAM)p );
					p[t] = 0;
					if (_stricmp(p, text) == 0) {
						// 一致！
						rv = u;
						break;
					}
				}
				safefree(p);
			}
		}
	}

	return rv;
}

// ------------------------------------------------------------------------------------------
// コンボボックス関連
// ------------------------------------------------------------------------------------------

// コンボボックスのカーソル位置を得る
UINT GetComboBoxCursor( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == COMBO_CTRL ) {
			return (UINT)SendMessage(rctrls[i].hCtrl,CB_GETCURSEL, 0, 0);
		}
	}

	return ERRORVALUE;
}

// コンボボックスのカーソル位置を設定
UINT SetComboBoxCursor( const char *id, UINT n )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == COMBO_CTRL ) {
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			return (UINT)SendMessage(rctrls[i].hCtrl, CB_SETCURSEL,(WPARAM)n,0);
		}
	}

	return ERRORVALUE;
}

// ------------------------------------------------------------------------------------------

// ダイアログを開いてから、または、[適用]を押してから変更されたか
UINT isChanged( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		return (UINT)rctrls[i].changed;
	}

	return ERRORVALUE;
}

// idのコントロールが何者だかを調べる
char *getControlType( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		switch(rctrls[i].ctrl) {
			case TEXT_CTRL:
				return P_TEXT; // これはアイコンテキストのため
			case CHECK_CTRL:
				return (rctrls[i].opt == 1)?P_CHECKBOX3:P_CHECKBOX;
			case EDIT_CTRL:
				return (rctrls[i].opt == 1)?P_EDITBOXNUM:P_EDITBOX;
			case ICON_BUTTON:
				return P_ICON;
			case LIST_CTRL:
				return (rctrls[i].opt == 1)?(rctrls[i].key?P_KEYLIST:P_LISTVIEW):P_VALUELIST;
			case LVC_BUTTON_NEW:
				return P_BUTTON_NEW;
			case LVC_BUTTON_EDIT:
				return P_BUTTON_EDIT;
			case LVC_BUTTON_DEL:
				return P_BUTTON_DEL;
			case SPIN_CTRL:
				return P_SPIN;
			case GOTO_BUTTON:
				return P_BUTTON;
			case COLOR_BUTTON:
				return P_COLOR_BUTTON;
			case REF_BUTTON_FILE:
				return P_BUTTON_FILE;
			case REF_BUTTON_FOLDER:
				return P_BUTTON_FOLDER;
			case TODEFAULT_BUTTON:
				return P_BUTTON_DEFAULT;
			case COMBO_CTRL:
				return P_COMBOBOX;
			case MULTI_EDIT:
				return P_MULTIEDIT;
			case CHKLIST_CTRL:
				return P_CHECK_LIST;
			case MIN_GOTO_BUTTON:
				return P_MIN_GOTO_BUTTON;
			case AC_FINISH:
				switch ( rctrls[i].opt ) {
					case 0:
						return P_BUTTON_OK;
					case 1:
						return P_BUTTON_CANCEL;
					case 2:
						return P_BUTTON_APPRY;
					case 3:
						return P_BUTTON_RETRY;
					case 5:
						return P_BUTTON_SAVE;
					case 6:
						return P_BUTTON_LOAD;
					case 4:
						return P_BUTTON_HELP;
				}
				// そのまま下へ
			default:
				return P_OTHER;
		}
	}

	return "";
}

// idのコントロールが何番目だかを調べる（idが存在しなければ 0xffffffff を返す）
UINT searchID( const char *id )
{
	UINT i;
	static UINT uCacheNum = ERRORVALUE;

	if ( id == NULL ) { // キャッシュ初期化
		uCacheNum = ERRORVALUE;
		return ERRORVALUE;
	}

	if ( uCacheNum != ERRORVALUE && rctrls[uCacheNum].id && strcmp(rctrls[uCacheNum].id, id) == 0 ) {
		return uCacheNum;
	}

	for(i=0 ; i<nctrls ; i++) {
		if ( uCacheNum != i && rctrls[i].id && strcmp(rctrls[i].id, id) == 0 ) {
			return uCacheNum = i;
		}
	}

	return ERRORVALUE;
}

// hCtrlのコントロールが何番目だかを調べる（idが存在しなければ 0xffffffff を返す）
UINT searchHandle( HWND hCtrl )
{
	UINT i;

	for(i=0 ; i<nctrls ; i++) {
		if ( rctrls[i].hCtrl == hCtrl ) {
			return i;
		}
	}

	return ERRORVALUE;
}

UINT GetColorButton( const char *id )
{
	UINT i;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == COLOR_BUTTON ) {
			return (UINT)rctrls[i].opt_u1;
		}
	}

	return ERRORVALUE;
}

UINT SetColorButton( const char *id, UINT rgb )
{
	UINT i;
	char s[70];

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == COLOR_BUTTON ) {
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}
			rctrls[i].opt_u1 = (rgb & 0xffffff);
			wsprintf( s, "赤:%d  緑:%d  青:%d", (rgb&0xff), (rgb&0xff00)>>8, (rgb&0xff0000)>>16);
			return (SetWindowText( rctrls[i].hCtrl, s ) != 0) ? 1 : 0;
		}
	}

	return ERRORVALUE;
}

// ------------------------------------------------------------------------------------------
// チェックボックスリスト関連
// 
// チェック状態等のステータスは、lParamの各ビットで制御する
//  lParam(0-1ビット) = type :0=カテゴリ 2=2state 3=3state
//  lParam(2-3ビット) = state:0=非チェック状態 1=チェック状態 2=半チェック
//                      (第2カラム目の日本語表記よりも、こちらを優先する)
//  lParam(4ビット)   = disable=0:無効 1:有効
// ------------------------------------------------------------------------------------------

// 現在のlParamに合わせて、アイコンと第２カラムの文字列を設定する
static BOOL ListCheck_SetIcon( HWND hCheckBoxList, UINT i, LPARAM newLParam )
{
	union  CBL_FLAG fCbl;
	LVITEM lvitem;
	char  *pVoice = "";

	fCbl.u = newLParam;

	ZeroMemory(&lvitem, sizeof(lvitem));
	lvitem.mask = LVIF_IMAGE | LVIF_PARAM;
	lvitem.stateMask = LVIS_STATEIMAGEMASK;

	if ( fCbl.b.type == 2 || fCbl.b.type == 3 ) { // 2stateまたは3stateのチェックボックス
		if ( fCbl.b.disable == FALSE ) { // 無効化状態だったら
			lvitem.iImage = CBL_ICON_DISABLE;
			pVoice = P_VOICE_DISABLE;
		}
		else {
			switch( fCbl.b.state ) {
				case 0:
                    lvitem.iImage = CBL_ICON_UNCHECK;
					pVoice = P_VOICE_UNCHECK;
					break;

				case 1:
                    lvitem.iImage = CBL_ICON_CHECK;
					pVoice = P_VOICE_CHECK;
					break;

				default:
                    lvitem.iImage = CBL_ICON_NODET;
					pVoice = P_VOICE_NODET;
					break;
			}
		}
	}
	else { // カテゴリ
		lvitem.iImage = CBL_ICON_CATEGORY;
		pVoice = P_VOICE_CATEGORY;
	}
	
	lvitem.iItem = i;
	lvitem.iSubItem = 0;
	lvitem.lParam = fCbl.u;
	if ( ListView_SetItem(hCheckBoxList, &lvitem) ) {
		ListView_SetItemText(hCheckBoxList, i, 1, pVoice);
		return TRUE;
	}

	return FALSE;
}

// チェックボックスリストへの項目追加(type:0=カテゴリ 2=2state 3=3state, 戻り値=リストビュー内の通番)
UINT ListCheck_Add( HWND hCheckBoxList, UINT type, char *text )
{
	UINT   newNo;
	union CBL_FLAG fCbl;
	LVITEM lvitem;

	if ( hCheckBoxList && text ) {
		fCbl.u = 0; // 初期化
		fCbl.b.type = type;
		fCbl.b.disable = TRUE;

		ZeroMemory(&lvitem, sizeof(lvitem));
		lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
		lvitem.iImage = type == 0 ? CBL_ICON_CATEGORY : CBL_ICON_UNCHECK;
		lvitem.state  = INDEXTOSTATEIMAGEMASK((type == 0 ? CBL_ICON_CATEGORY : CBL_ICON_UNCHECK)+1);
		lvitem.stateMask = LVIS_STATEIMAGEMASK;
		lvitem.iItem = ListView_GetItemCount( hCheckBoxList );
		lvitem.iSubItem = 0;
		lvitem.pszText = text;
		lvitem.lParam = fCbl.u;
		if ( -1 != (newNo = ListView_InsertItem(hCheckBoxList, &lvitem)) ) {
			ListView_SetItemText(hCheckBoxList, newNo, 1, type == 0 ? P_VOICE_CATEGORY : P_VOICE_UNCHECK);
			return newNo;
		}
	}

	return ERRORVALUE;
}

// チェックボックスリストへ追加済みデータへのチェック状態変更
BOOL ListCheck_Set( const char *id, UINT state )
{
	UINT i;
	union CBL_FLAG fCbl;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			if ( initializing_flag == 0 ) {
				ac_ctrlChange(i); // 初期化中でなければ、コントロールの内部からの変更も、書き込みの対象とする
			}

			fCbl.u = lvGetLParam( rctrls[i].hCtrl, rctrls[i].i );
			if ( (state != 2 && fCbl.b.type == 2) || fCbl.b.type == 3 ) {
				fCbl.b.state = state;
				return ListCheck_SetIcon( rctrls[i].hCtrl, rctrls[i].i, fCbl.u );
			}
		}
	}

	return FALSE;
}

// チェックボックスリストへ追加済みデータからのチェック状態取得
UINT ListCheck_Get( const char *id )
{
	UINT i;
	union CBL_FLAG fCbl;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			fCbl.u = lvGetLParam( rctrls[i].hCtrl, rctrls[i].i );
			return fCbl.b.state;
		}
	}

	return ERRORVALUE;
}

// チェックボックスリストの項目を無効化する(fDisable:TRUE=有効 FALSE=無効)
BOOL ListCheck_Disable( const char *id, BOOL fDisable )
{
	UINT i;
	union CBL_FLAG fCbl;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			fCbl.u = lvGetLParam( rctrls[i].hCtrl, rctrls[i].i );
			if ( fCbl.b.type == 2 || fCbl.b.type == 3 ) {
				fCbl.b.disable = fDisable;
				return ListCheck_SetIcon( rctrls[i].hCtrl, rctrls[i].i, fCbl.u );
			}
		}
	}

	return FALSE;
}

// チェックボックスリストの項目を有効/無効状態を調べる(戻り値:TRUE=有効 FALSE=無効)
BOOL ListCheck_IsDisable( const char *id )
{
	UINT i;
	union CBL_FLAG fCbl;

	if ( ERRORVALUE != ( i = searchID( id ) ) ) {
		if ( rctrls[i].ctrl == CHECK_CTRL && rctrls[i].i != ERRORVALUE ) {
			fCbl.u = lvGetLParam( rctrls[i].hCtrl, rctrls[i].i );
			return fCbl.b.disable;
		}
	}

	return FALSE;
}

// チェックボックスリストの項目のチェック状態を切り替える
// state: 0 = OFF, 1=ON, 2=半チェック
// state: -1 = {チェック [→半チェック] → チェック無し → … }
BOOL ListCheck_Change( HWND hCheckBoxList, int cur, int state )
{
	union CBL_FLAG fCbl;

	// 注意：ここでac_ctrlChange(i);の発行は行わない。
	//       呼び出し側で発行すること。

	fCbl.u = lvGetLParam( hCheckBoxList, cur );

	if ( state == -1 ) {
		if ( fCbl.b.disable == TRUE && (fCbl.b.type == 2 || fCbl.b.type == 3) ) {
			switch ( fCbl.b.state ) {
				case 0:
					fCbl.b.state = 1; // チェック
					break;

				case 2:
					fCbl.b.state = 0; // 非チェック
					break;

				case 1:
					if ( fCbl.b.type == 2 ) { // 半チェックになれない場合
						fCbl.b.state = 0; // 非チェック
					}
					else { // 半チェックになれる場合
						fCbl.b.state = 2; // 半チェック
					}
					break;
			}
			return ListCheck_SetIcon( hCheckBoxList, cur, fCbl.u );
		}
	}
	else if ( state == 0 || state == 1 ) {
		if ( fCbl.b.disable == TRUE && (fCbl.b.type == 2 || fCbl.b.type == 3) ) {
			fCbl.b.state = state;
			return ListCheck_SetIcon( hCheckBoxList, cur, fCbl.u );
		}
	}
	else if ( state == 2 ) {
		if ( fCbl.b.disable == TRUE && fCbl.b.type == 3 ) {
			fCbl.b.state = 2;
			return ListCheck_SetIcon( hCheckBoxList, cur, fCbl.u );
		}
	}

	return FALSE;
}

// ------------------------------------------------------------------------------------------
// 共有イメージリスト・アイコンの準備と破棄
// ------------------------------------------------------------------------------------------
// アイコンハンドル／共有イメージリスト準備
void createImageLists(void)
{
	// アイコンの準備
	hIconCategory     = (HICON)LoadImage(hInst, (LPCTSTR)IDI_CATEGORY, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
	hCBLIconCheck     = (HICON)LoadImage(hInst, (LPCTSTR)IDI_CHECK, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
	hCBLIconUncheck   = (HICON)LoadImage(hInst, (LPCTSTR)IDI_UNCHECK, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
	hCBLIconNoDet     = (HICON)LoadImage(hInst, (LPCTSTR)IDI_NODET, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
	hCBLIconDisable   = (HICON)LoadImage(hInst, (LPCTSTR)IDI_DISABLECHECK, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
	hIconCategoryOpen = (HICON)LoadImage(hInst, (LPCTSTR)IDI_CATEGORYOPEN, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconFileBrowse   = (HICON)LoadImage(hInst, (LPCTSTR)IDI_FILE_BROWSE, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconFolderBrowse = (HICON)LoadImage(hInst, (LPCTSTR)IDI_FOLDER_BROWSE, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconEmpty        = (HICON)LoadImage(hInst, (LPCTSTR)IDI_EMPTY, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconMail         = (HICON)LoadImage(hInst, (LPCTSTR)IDI_MAIL, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconSelIcon      = (HICON)LoadImage(hInst, (LPCTSTR)IDI_SELICON, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);
	hIconInputText    = (HICON)LoadImage(hInst, (LPCTSTR)IDI_INPUTTEXT, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);

	// デフォルトのRSCアイコンもここで準備
	hDefaultRscIcon = (HICON)LoadImage(hInst, (LPCSTR)232, IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR | LR_SHARED);
	hDefaultRscSmallIcon = (HICON)LoadImage(hInst, (LPCSTR)232, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR | LR_SHARED);

	// チェックボックスリスト用アイコンリストの作成（ここで作成するアイコンは、チェック状態5種類を表すもの）
	himlCBLSmall = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 5, 0);
	ImageList_AddIcon(himlCBLSmall, hIconEmpty);
	ImageList_AddIcon(himlCBLSmall, hCBLIconUncheck);
	ImageList_AddIcon(himlCBLSmall, hCBLIconCheck);
	ImageList_AddIcon(himlCBLSmall, hCBLIconNoDet);
	ImageList_AddIcon(himlCBLSmall, hCBLIconDisable);

	// チェックボックスリスト用ステータス状態の作成
	himlCBLState = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 2, 0);
	ImageList_AddIcon(himlCBLState, hIconCategory);
	ImageList_AddIcon(himlCBLState, hIconEmpty);

	// カテゴリリスト用のアイコンリストの作成
	himlTreeSmall = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 4, 0);
	ImageList_AddIcon(himlTreeSmall, hIconCategory);
	ImageList_AddIcon(himlTreeSmall, hIconFolderBrowse);
	ImageList_AddIcon(himlTreeSmall, hIconFileBrowse);
	ImageList_AddIcon(himlTreeSmall, hIconCategoryOpen);
}

// 共有イメージリスト破棄
void destroyImageLists(void)
{
	ImageList_Destroy( himlTreeSmall );
	ImageList_Destroy( himlCBLState );
	ImageList_Destroy( himlCBLSmall );

	// アイコンハンドルの削除は、初回ロード時にSHAREDで読むようにしたので必要なくなりました。
}
// ------------------------------------------------------------------------------------------

// 高さが LV_NORMAL_HEIGHT となっているリストビューをサーチ
BOOL CALLBACK searchNormalSizeListView(HWND hChild, LPARAM snslv)
{
	RECT rt;
	POINT pt;
	char szClassName[MAX_PATH*2];

	if ( GetParent( hChild ) == ((LSNSLV)snslv)->hDlg ) { // 孫ウィンドウは探さない
		// クラス名がWC_LISTVIEWであることを調べる
		if ( 0 != GetClassName(hChild, szClassName, _countof(szClassName)) ) {
			if ( strcmp(szClassName, WC_LISTVIEW) == 0 ) {
				GetWindowRect(hChild, &rt);
				if ( rt.bottom-rt.top == LV_NORMAL_HEIGHT ) {
					pt.x = rt.left; pt.y = rt.top;
					ScreenToClient(((LSNSLV)snslv)->hDlg, &pt);
					((LSNSLV)snslv)->iListViewTop = pt.y;
					((LSNSLV)snslv)->hListView = hChild;

					// 目的のリストビューが見つかったので、検索中断
					return FALSE;
				}
			}
		}
	}

	// 目的のリストビューではなかったので、検索継続
	return TRUE;
}

// 見つかったら、それよりも下にあるコントロールを uDefHeight だけ下に下げ、
// 該当するリストビューを uDefHeight だけ拡大する
BOOL CALLBACK extNormalSizeListView(HWND hChild, LPARAM snslv)
{
	RECT rt;
	POINT pt;

	if ( GetParent( hChild ) == ((LSNSLV)snslv)->hDlg ) { // 孫ウィンドウは探さない
		GetWindowRect(hChild, &rt);
		pt.x = rt.left; pt.y = rt.top;
		ScreenToClient(((LSNSLV)snslv)->hDlg, &pt);

		if ( hChild == ((LSNSLV)snslv)->hListView ) {
			SetWindowPos(hChild, 0, 0, 0, rt.right-rt.left, rt.bottom-rt.top + ((LSNSLV)snslv)->iDefHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
		}
		else if ( pt.y > ((LSNSLV)snslv)->iListViewTop+LV_NORMAL_HEIGHT ) {
			SetWindowPos(hChild, 0, pt.x, pt.y + ((LSNSLV)snslv)->iDefHeight, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
		}
	}
	return TRUE;
}
