#define	STRICT
#include	<windows.h>
#include	<windowsx.h>
#include	<string.h>
#include	<tchar.h>
#include	<commctrl.h>
#include	"resource.h"
#include	"import.h"
#include	"convert.h"

HINSTANCE	hInst ;
HWND		hMainWnd = NULL ;
HWND		hCmdBar ;
HWND		hEdtKey ;
HWND		hLbxKey ;
HWND		hLbxVal ;
HWND		hCbxRoot ;
HWND		hBtnLeft ;
HWND		hBtnRight ;
HWND		hBtnEdit ;
HWND		hBtnDelete ;
HWND		hBtnTop ;

DWORD		DllVersion = 0 ;

const	TCHAR	szWinName[] = TEXT("RegEdit") ;
#define		TitleName	szWinName
const	TCHAR	Version[] = TEXT("0.11") ;
const	TCHAR	szNoName[] = TEXT("<No Name>") ;
const	TCHAR	szUnknown[] = TEXT("<Unknown>") ;

static	LPCTSTR	RootStr[] = {
//	TEXT("LocalMachine"), TEXT("CurrentUser"), TEXT("Users"), TEXT("ClassesRoot"),
	TEXT("LMachine"), TEXT("CUser"), TEXT("Users"), TEXT("CRoot"),
} ;
static	HKEY	RootKey[] = {
	HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, HKEY_USERS, HKEY_CLASSES_ROOT,
} ;
const	DWORD	RootNum = sizeof RootStr / sizeof RootStr[0] ;

HKEY	hKeyRoot = INVALID_HANDLE_VALUE ;
TCHAR	RegSubKey[ 256 ] = TEXT("") ;
TCHAR	ClassName[ 256 ] = TEXT("") ;

TCHAR	KeyName[ MAX_PATH ] = TEXT("") ;
TCHAR	ValueName[ MAX_PATH ] ;
DWORD	ValueType = 0 ;
BYTE	ValueData[ 2048 ] ;
DWORD	ValueSize = 0 ;

TCHAR	Buffer[ 1024 ] ;
TCHAR	MessageBuf[ 256 ] ;

static TBBUTTON tbSTDButton[] = {
	{ 0, 0,            TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0, 0, -1},
//	{ 2, IDM_EDIT,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
//	{ 0, 0,            TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0, 0, -1},
	{ 5, IDM_NEW_SZ,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
	{ 7, IDM_NEW_MSZ,  TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
	{ 6, IDM_NEW_DW,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
//	{ 8, IDM_NEW_KEY,  TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
//	{ 0, 0,            TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0, 0, -1},
//	{ 3, IDM_DELETE,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
//	{ 9, IDM_DEL_KEY,  TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0, -1},
} ;

static	BOOL	init_application( void ) ;
static	BOOL	init_instance( int nCmdShow ) ;
static	void	MainWnd_OnCreate( HWND hWnd, WPARAM wParam, LPARAM lParam ) ;
LRESULT CALLBACK	MainWndFunc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) ;
BOOL CALLBACK	AboutDlgFunc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;

BOOL	ListupKeys( LPCTSTR KeyName ) ;
void	GetValueStr( LPTSTR buf, DWORD size ) ;
BOOL	NewValue( DWORD type ) ;
BOOL	EditValue( LPCTSTR name ) ;
BOOL	DeleteValue( LPCTSTR name ) ;
BOOL	NewKey( void ) ;
BOOL	DeleteKey( LPCTSTR keyname ) ;
BOOL CALLBACK	InputBoxDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;
BOOL CALLBACK	NewKeyDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;
static	BOOL	ExportKey( LPCTSTR keyname ) ;

int WINAPI
#ifdef	_WIN32_WCE
WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst,
		 LPTSTR lpszArgs, int nWinMode )
#else	/* _WIN32_WCE */
WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst,
		 LPSTR lpszArgs, int nWinMode )
#endif	/* _WIN32_WCE */
{
	MSG			msg ;
	HACCEL		hAccl ;

	hInst = hThisInst ;

#ifdef	_WIN32_WCE
	InitCommonControls();
#endif	/* _WIN32_WCE */

	init_convert() ;

	/* コマンドラインに指定されたファイルをインポートする */
	if ( *lpszArgs ) {
		if ( import_reg( lpszArgs ) ) {
			MessageBox( NULL, TEXT("Done."), szWinName, MB_OK|MB_ICONINFORMATION ) ;
		} else {
			MessageBox( NULL, TEXT("Failed."), szWinName, MB_OK|MB_ICONSTOP ) ;
		}
		goto ExitMain ;
	}

	if ( !init_application() ) {
		goto ExitMain ;
	}

	if ( !init_instance( nWinMode ) ) {
		goto ExitMain ;
	}

#ifdef	_WIN32_WCE
	hAccl = LoadAccelerators( hInst,
							  MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#else	/* _WIN32_WCE */
	hAccl = LoadAccelerators( GetModuleHandle(NULL),
							  MAKEINTRESOURCE(IDR_ACCELERATOR1) ) ;
#endif	/* _WIN32_WCE */

	while ( GetMessage( &msg, NULL, 0, 0 ) ) {
		if ( !TranslateAccelerator( hMainWnd, hAccl, &msg ) ) {
			TranslateMessage( &msg ) ;
		}
		DispatchMessage( &msg ) ;
	}

ExitMain:
	release_convert() ;
	return TRUE ;
}

static	BOOL
init_application( void )
{
	WNDCLASS	wcl ;

	/* メインウィンドウクラスを登録する */
	wcl.hInstance = hInst ;
	wcl.lpszClassName = szWinName ;
	wcl.lpfnWndProc = MainWndFunc ;
	wcl.style = CS_HREDRAW|CS_VREDRAW ;
	wcl.hIcon   = NULL ;
	wcl.hCursor = NULL ;
#ifdef	_WIN32_WCE
	wcl.lpszMenuName = 0 ;
#else	/* _WIN32_WCE */
	wcl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1) ;
#endif	/* _WIN32_WCE */
	wcl.cbClsExtra = 0 ;
	wcl.cbWndExtra = 0 ;
	wcl.hbrBackground = GetStockObject( WHITE_BRUSH ) ;
	if ( !RegisterClass( &wcl ) ) {
		return FALSE ;
	}
	return TRUE ;
}

static	BOOL
init_instance( int nCmdShow )
{
	const	DWORD	x0 = 0 ;
	DWORD			y0 = 0, i, x, y, w, h ;

	/* メインウィンドウを作成する */
	hMainWnd = CreateWindowEx( 0, szWinName,
						TitleName,
						WS_VISIBLE,
#ifdef	_WIN32_WCE
						0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
#else	/* _WIN32_WCE */
						0, 0, 480, 240,
#endif	/* _WIN32_WCE */
						NULL,
						NULL,
						hInst,
						NULL ) ;
	if ( !hMainWnd ) {
		return FALSE;
	}

#ifdef	_WIN32_WCE
	/* コマンドバーを作成する */
	hCmdBar = CommandBar_Create( hInst, hMainWnd, 1 ) ;
	/* メニューをつける */
	CommandBar_InsertMenubar( hCmdBar, hInst, IDR_MENU1, 0 ) ;
	/*  */
	CommandBar_AddBitmap( hCmdBar, hInst, IDB_BITMAP1,
						  16, 16, 16 ) ;
	CommandBar_AddButtons( hCmdBar, sizeof(tbSTDButton) / sizeof(TBBUTTON),
						   tbSTDButton ) ;
	/* 終了ボタンをつける */
	CommandBar_AddAdornments( hCmdBar, CMDBAR_HELP, 0 ) ;
	y0 = CommandBar_Height( hCmdBar ) ;
#endif	/* _WIN32_WCE */

	hCbxRoot = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("COMBOBOX"), TEXT(""),
							CBS_DROPDOWNLIST|WS_VSCROLL|WS_TABSTOP|WS_CHILD|WS_VISIBLE,
							2+x0, 2+y0, 64, 80,
							hMainWnd, (HMENU)IDC_CBX_ROOT, hInst, NULL ) ;
	hBtnTop = CreateWindowEx( 0, TEXT("BUTTON"), TEXT("|<"),
							WS_CHILD|WS_VISIBLE,
							3+x0, 27+y0, 24, 20,
							hMainWnd, (HMENU)IDM_TOP, hInst, NULL ) ;
	hBtnLeft = CreateWindowEx( 0, TEXT("BUTTON"), TEXT("<<"),
							WS_CHILD|WS_VISIBLE,
							36+x0, 27+y0, 27, 20,
							hMainWnd, (HMENU)IDM_LEFT, hInst, NULL ) ;
	hBtnRight = CreateWindowEx( 0, TEXT("BUTTON"), TEXT(">>"),
							WS_CHILD|WS_VISIBLE,
							66+x0, 27+y0, 27, 20,
							hMainWnd, (HMENU)IDM_RIGHT, hInst, NULL ) ;
	hBtnEdit = CreateWindowEx( 0, TEXT("BUTTON"), TEXT("Edit"),
							WS_CHILD|WS_VISIBLE,
							156+x0, 27+y0, 33, 20,
							hMainWnd, (HMENU)IDM_EDIT, hInst, NULL ) ;
	hBtnDelete = CreateWindowEx( 0, TEXT("BUTTON"), TEXT("Del"),
							WS_CHILD|WS_VISIBLE,
							198+x0, 27+y0, 27, 20,
							hMainWnd, (HMENU)IDM_DELETE, hInst, NULL ) ;
	w = GetSystemMetrics( SM_CXSCREEN ) ;
	if ( w < 480 ) {
		x = 68 + x0 ;
		w -= x + 2 ;
		hEdtKey = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("STATIC"), TEXT(""),
								WS_CHILD|WS_VISIBLE,
								x, 3+y0, w, 20,
								hMainWnd, (HMENU)IDC_EDT_KEY, hInst, NULL ) ;
		x = 2 + x0 ;
		w = GetSystemMetrics( SM_CXSCREEN ) - 4 ;
		y = 50 + y0 ;
		hLbxKey = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
								LBS_NOINTEGRALHEIGHT|WS_VSCROLL|WS_TABSTOP|WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_SORT,
								x, y, w, 104,
								hMainWnd, (HMENU)IDC_LBX_KEY, hInst, NULL ) ;
		y += 104 + 2 ;
		h = GetSystemMetrics( SM_CYSCREEN ) - 24 - y ;
		hLbxVal = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
								LBS_NOINTEGRALHEIGHT|WS_VSCROLL|WS_TABSTOP|WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_SORT,
								x, y, w, h,
								hMainWnd, (HMENU)IDC_LBX_VALUE, hInst, NULL ) ;
	} else {
		x = 68 + x0 ;
		w -= x + 2 ;
		hEdtKey = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("STATIC"), TEXT(""),
								WS_CHILD|WS_VISIBLE,
								x, 3+y0, w, 20,
								hMainWnd, (HMENU)IDC_EDT_KEY, hInst, NULL ) ;
		x = 2 + x0 ;
		w = (GetSystemMetrics( SM_CXSCREEN ) - 4) / 2 ;
		y = 50 + y0 ;
		h = GetSystemMetrics( SM_CYSCREEN ) - 24 - y - 2 ;
		hLbxKey = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
								LBS_NOINTEGRALHEIGHT|WS_VSCROLL|WS_TABSTOP|WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_SORT,
								x, y, w, h,
								hMainWnd, (HMENU)IDC_LBX_KEY, hInst, NULL ) ;
		x += w + 2 ;
		hLbxVal = CreateWindowEx( WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
								LBS_NOINTEGRALHEIGHT|WS_VSCROLL|WS_TABSTOP|WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_SORT,
								x, y, w, h,
								hMainWnd, (HMENU)IDC_LBX_VALUE, hInst, NULL ) ;
	}

	for ( i = 0 ; i < RootNum ; i ++ ) {
		SendMessage( hCbxRoot, CB_ADDSTRING, 0, (LPARAM)RootStr[i] ) ;
	}

	/* メインウィンドウを表示する */
	ShowWindow( hMainWnd, nCmdShow ) ;
	UpdateWindow( hMainWnd ) ;

	return TRUE ;
}

LRESULT CALLBACK
MainWndFunc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	BOOL		rc ;
	LPTSTR		ptr ;
	HWND		hCtrl ;
	DWORD		i, cmd, type ;

	switch ( message ) {
	case WM_DESTROY:
		PostQuitMessage( 0 ) ;
		break ;
	case WM_COMMAND:
		cmd = GET_WM_COMMAND_ID( wParam, lParam ) ;
		switch ( cmd ) {
		case IDC_CBX_ROOT:
			if ( HIWORD( wParam ) == LBN_SELCHANGE ) {
				i = SendMessage( hCbxRoot, CB_GETCURSEL, 0, 0 ) ;
				if ( i == CB_ERR ) {
					break ;
				}
				hKeyRoot = RootKey[ i ] ;
				PostMessage( hWnd, WM_COMMAND, IDM_TOP, 0 ) ;
			}
			break ;
		case IDC_LBX_KEY:
			if ( HIWORD( wParam ) == LBN_DBLCLK) {
				PostMessage( hWnd, WM_COMMAND, IDM_RIGHT, 0 ) ;
			}
			break ;
		case IDC_LBX_VALUE:
			if ( HIWORD( wParam ) == LBN_DBLCLK ) {
				PostMessage( hWnd, WM_COMMAND, IDM_EDIT, 0 ) ;
			}
			break ;
		case IDM_TOP:
			*RegSubKey = 0 ;
			*KeyName = 0 ;
			ListupKeys( KeyName ) ;
			SetWindowText( hEdtKey, RegSubKey ) ;
			break ;
		case IDM_LEFT:
			if ( !*RegSubKey ) {
				MessageBeep( MB_ICONHAND ) ;
				break ;
			}
			ptr = _tcsrchr( RegSubKey, L'\\' ) ;
			if ( ptr == NULL ) {
				*RegSubKey = 0 ;
				*KeyName = 0 ;
			} else {
				*ptr = 0 ;
				ptr = _tcsrchr( RegSubKey, L'\\' ) ;
				if ( ptr == NULL ) {
					_tcscpy( KeyName, RegSubKey ) ;
					*RegSubKey = 0 ;
				} else {
					_tcscpy( KeyName, ptr + 1 ) ;
					*ptr = 0 ;
				}
			}
			ListupKeys( KeyName ) ;
			SetWindowText( hEdtKey, RegSubKey ) ;
			SetFocus( hLbxKey ) ;
			return FALSE ;
		case IDM_RIGHT:
			i = SendMessage( hLbxKey, LB_GETCURSEL, 0, 0 ) ;
			if ( i == LB_ERR ) {
				MessageBeep( MB_ICONHAND ) ;
				break ;
			} else if ( i == 0 ) {
				PostMessage( hWnd, WM_COMMAND, IDM_LEFT, 0 ) ;
				break ;
			}
			SendMessage( hLbxKey, LB_GETTEXT, i, (LPARAM) KeyName ) ;
			if ( ListupKeys( KeyName ) ) {
				SetWindowText( hEdtKey, RegSubKey ) ;
			}
			SetFocus( hLbxKey ) ;
			return FALSE ;
		case IDM_EDIT:
		case IDM_DELETE:
			i = SendMessage( hLbxVal, LB_GETCURSEL, 0, 0 ) ;
			if ( i == LB_ERR ) {
				MessageBeep( MB_ICONHAND ) ;
				break ;
			}
			SendMessage( hLbxVal, LB_GETTEXT, i, (LPARAM) KeyName ) ;
			ptr = _tcsstr( KeyName, TEXT(" : ") ) ;
			if ( ptr ) {
				*ptr = 0 ;
			}
			if ( cmd == IDM_EDIT ) {
				rc = EditValue( KeyName ) ;
			} else if ( cmd == IDM_DELETE ) {
				rc = DeleteValue( KeyName ) ;
			} else {
				rc = FALSE ;
			}
			if ( rc ) {
				ListupKeys( TEXT("") ) ;
			}
			SetFocus( hLbxVal ) ;
			break ;
		case IDM_ENTER:
			hCtrl = GetFocus() ;
			if ( hCtrl == hLbxVal ) {
				SendMessage( hWnd, WM_COMMAND, IDM_EDIT, 0 ) ;
			} else if ( hCtrl == hLbxKey ) {
				SendMessage( hWnd, WM_COMMAND, IDM_RIGHT, 0 ) ;
			}
			break ;
		case IDM_NEW_KEY:
			if ( NewKey() ) {
				ListupKeys( KeyName ) ;
				SetWindowText( hEdtKey, RegSubKey ) ;
			}
			SetFocus( hLbxKey ) ;
			break ;
		case IDM_DEL_KEY:
			i = SendMessage( hLbxKey, LB_GETCURSEL, 0, 0 ) ;
			if ( i == LB_ERR || i == 0 ) {
				MessageBeep( MB_ICONHAND ) ;
				break ;
			}
			SendMessage( hLbxKey, LB_GETTEXT, i, (LPARAM) KeyName ) ;
			if ( DeleteKey( KeyName ) ) {
				*KeyName = 0 ;
				ListupKeys( TEXT("") ) ;
			}
			SetFocus( hLbxKey ) ;
			break ;
		case IDM_IMPORT:
			if ( !ImportDlg( hWnd, Buffer ) ) {
				break ;
			} else if ( import_reg( Buffer ) ) {
				ListupKeys( TEXT("") ) ;
			} else {
				MessageBeep( MB_ICONHAND ) ;
			}
			break ;
		case IDM_EXPORT:
			i = SendMessage( hLbxKey, LB_GETCURSEL, 0, 0 ) ;
			if ( i == LB_ERR ) {
				MessageBeep( MB_ICONHAND ) ;
				break ;
			} else if ( i == 0 ) {
				KeyName[0] = 0 ;
			} else {
				SendMessage( hLbxKey, LB_GETTEXT, i, (LPARAM) KeyName ) ;
			}
			if ( !ExportKey( KeyName ) ) {
				MessageBeep( MB_ICONHAND ) ;
			}
			break ;
		case IDM_EXIT:
			SendMessage( hWnd, WM_CLOSE, 0, 0 ) ;
			break ;
		default:
			if ( cmd == IDM_NEW_DW ) {
				type = REG_DWORD ;
			} else if ( cmd == IDM_NEW_SZ ) {
				type = REG_SZ ;
			} else if ( cmd == IDM_NEW_MSZ ) {
				type = REG_MULTI_SZ ;
			} else if ( cmd == IDM_NEW_BIN ) {
				type = REG_BINARY ;
			} else {
				break ;
			}
			if ( NewValue( type ) ) {
				ListupKeys( TEXT("") ) ;
			}
			SetFocus( hLbxVal ) ;
			break ;
		}
		break ;
	case WM_HELP:
		/* Aboutダイアログを表示する */
		DialogBox( hInst, MAKEINTRESOURCE(IDD_DLG_ABOUT), hWnd, AboutDlgFunc ) ;
		break ;
	case WM_CLOSE:
		DestroyWindow( hWnd ) ;
		break;
	default:
		return DefWindowProc( hWnd, message, wParam, lParam ) ;
	}
	return 0 ;
}

BOOL
ListupKeys( LPCTSTR KeyName )
{
	DWORD	i, rc ;
	HKEY	hKey ;
	LONG	lret ;
	TCHAR	tchClassName[ MAX_PATH ] ;
	DWORD	dwcClassLen ;
	TCHAR	subkey[ MAX_PATH ] ;
	DWORD	dwcSubKeys, dwcMaxSubKey, dwcMaxClass, dwcValues ;
	DWORD	dwcMaxValueName, dwcMaxValueData, dwcSecDesc ;
	FILETIME	ftLastWriteTime ;

	if ( hKeyRoot == INVALID_HANDLE_VALUE ) {
		return FALSE ;
	}
	_tcscpy( subkey, RegSubKey ) ;
	if ( *subkey && *KeyName ) {
		_tcscat( subkey, TEXT("\\") ) ;
	}
	_tcscat( subkey, KeyName ) ;
	lret = RegOpenKeyEx( hKeyRoot, subkey, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		MessageBox( hMainWnd, TEXT("can't open the key"), szWinName, MB_OK ) ;
		return FALSE ;
	}
	dwcClassLen = MAX_PATH ;
	memset( tchClassName, 0, sizeof tchClassName ) ;
	RegQueryInfoKey( hKey,
					 tchClassName,
					 &dwcClassLen,
					 NULL,
					 &dwcSubKeys,
					 &dwcMaxSubKey,
					 &dwcMaxClass,
					 &dwcValues,
					 &dwcMaxValueName,
					 &dwcMaxValueData,
					 &dwcSecDesc,
					 &ftLastWriteTime ) ;

	SendMessage( hLbxKey, LB_RESETCONTENT, 0, 0 ) ;
	SendMessage( hLbxKey, LB_ADDSTRING, 0,
				(LONG) (*subkey ? TEXT("(Parent)") : TEXT("(Root)")) ) ;
	i = 0 ;
	do {
		DWORD	cbName = MAX_PATH ;
		TCHAR	keyName[ MAX_PATH ] ;

		memset( keyName, 0, sizeof keyName ) ;
		rc = RegEnumKeyEx( hKey, i ++, keyName, &cbName,
						   NULL, NULL, NULL, NULL ) ;
		if ( rc == (DWORD) ERROR_SUCCESS ) {
			SendMessage( hLbxKey, LB_ADDSTRING, 0, (LONG) keyName ) ;
		}
	} while ( rc == ERROR_SUCCESS ) ;
	SendMessage( hLbxVal, LB_RESETCONTENT, 0, 0 ) ;

	if ( dwcValues ) {
		for ( i = 0 ; i < dwcValues ; i ++ ) {
			DWORD	dwcValueName = MAX_PATH ;

			ValueSize = sizeof ValueData ;
			memset( ValueName, 0, sizeof ValueName ) ;
			memset( ValueData, 0, sizeof ValueData ) ;
			rc = RegEnumValue( hKey, i, ValueName, &dwcValueName,
							   NULL, &ValueType, ValueData, &ValueSize ) ;
			if ( rc != (DWORD) ERROR_SUCCESS && rc != ERROR_INSUFFICIENT_BUFFER ) {
				wsprintf( MessageBuf, TEXT( "based index = %d, rc = %d, ValueLen = %d\r\nError = %d" ),
						  i, rc, dwcValueName, GetLastError() );
				MessageBox( hMainWnd, MessageBuf, TEXT( "Debug" ), MB_OK );
				continue ;
			}
			GetValueStr( Buffer, sizeof Buffer / sizeof Buffer[0] ) ;
			SendMessage( hLbxVal, LB_ADDSTRING, 0, (LONG) Buffer ) ;
		}
	}
	RegCloseKey( hKey ) ;
	_tcscpy( RegSubKey, subkey ) ;
	return TRUE ;
}

BOOL
GetTypeStr( LPCTSTR *ptr )
{
	switch ( ValueType ) {
	case REG_BINARY:
		*ptr = TEXT("Binary") ;
		return TRUE ;
	case REG_DWORD:
		*ptr = TEXT("DWord") ;
		return TRUE ;
	case REG_SZ:
		*ptr = TEXT("SZ") ;
		return TRUE ;
	case REG_MULTI_SZ:
		*ptr = TEXT("Multi-SZ") ;
		return TRUE ;
	}
	return FALSE ;
}

BOOL
AppendStr( LPTSTR *dst, LPDWORD size, LPCTSTR src )
{
	DWORD	len, len2 ;

	len = _tcslen( src ) ;
	len2 = *size ;
	if ( len2 < len ) {
		if ( !len2 -- ) {
			return FALSE ;
		}
		if ( len2 ) {
			memcpy( *dst, src, len2 * sizeof (TCHAR) ) ;
		}
		*dst += len2 ;
		**dst = 0 ;
		*size = 0 ;
		return FALSE ;
	}
	_tcscpy( *dst, src ) ;
	*dst += len ;
	*size -= len ;
	return TRUE ;
}

void
GetBriefValueData( LPTSTR buf, DWORD size )
{
	TCHAR	tmpbuf[ 20 ] ;
	LPBYTE	src = ValueData ;

	if ( !size -- ) {
		return ;
	}
	*buf = 0 ;
	/* 値の内容があるかチェックする */
	if ( !ValueSize ) {
		return ;
	}
	if ( size > 30 ) {
		size = 30 ;
	}
	/* 値の内容をコピーする */
	switch ( ValueType ) {
	case REG_DWORD:
		wsprintf( tmpbuf, TEXT("%d"), *(LPDWORD)ValueData ) ;
		if ( !AppendStr( &buf, &size, tmpbuf ) ) {
			return ;
		}
		break ;
	case REG_SZ:
	case REG_MULTI_SZ:
		if ( !AppendStr( &buf, &size, (LPCTSTR) src ) ) {
			break ;
		}
		break ;
	default:
		do {
			wsprintf( tmpbuf, TEXT("%02X "), 0xFF & *src++ ) ;
			if ( !AppendStr( &buf, &size, tmpbuf ) ) {
				break ;
			}
		} while ( -- ValueSize ) ;
		break ;
	}
	*buf = 0 ;
}

void
GetValueStr( LPTSTR buf, DWORD size )
{
	LPCTSTR	ptr ;

	if ( !size -- ) {
		return ;
	}
	/* 値の名称をコピーする */
	ptr = *ValueName ? ValueName : szNoName ;
	if ( !AppendStr( &buf, &size, ptr ) ) {
		return ;
	}
	if ( !AppendStr( &buf, &size, TEXT(" : ") ) ) {
		return ;
	}
	/* 値の型をコピーする */
	if ( !GetTypeStr( &ptr ) ) {
		ptr = szUnknown ;
	}
	if ( !AppendStr( &buf, &size, ptr ) ) {
		return ;
	}
	if ( !AppendStr( &buf, &size, TEXT(" : ") ) ) {
		return ;
	}
	GetBriefValueData( buf, size ) ;
}

BOOL
GetValueData( LPTSTR buf, DWORD size )
{
	LPCTSTR	ptr ;
	DWORD	count ;
	TCHAR	tmpbuf[ 20 ], c ;
	LPBYTE	src = ValueData ;

	if ( !size -- ) {
		return FALSE ;
	}
	*buf = 0 ;
	/* 値の内容があるかチェックする */
	if ( !ValueSize ) {
		return FALSE ;
	}
	/* 値の内容をコピーする */
	switch ( ValueType ) {
	case REG_DWORD:
		wsprintf( tmpbuf, TEXT("%d"), *(LPDWORD)ValueData ) ;
		if ( !AppendStr( &buf, &size, tmpbuf ) ) {
			return FALSE ;
		}
		break ;
	case REG_SZ:
		if ( !AppendStr( &buf, &size, (LPCTSTR) src ) ) {
			return FALSE ;
		}
		break ;
	case REG_MULTI_SZ:
		ptr = (LPCTSTR) src ;
		count = ValueSize / sizeof (TCHAR) ;
		while ( *ptr ) {
			while ( c = *ptr++ ) {
				if ( !size -- ) {
					return FALSE ;
				}
				*buf++ = c ;
			}
			if ( !AppendStr( &buf, &size, TEXT("\r\n" ) ) ) {
				return FALSE ;
			}
		}
		break ;
	default:
		do {
			wsprintf( tmpbuf, TEXT("%02X "), 0xFF & *src++ ) ;
			if ( !AppendStr( &buf, &size, tmpbuf ) ) {
				return FALSE ;
			}
		} while ( -- ValueSize ) ;
		break ;
	}
	*buf = 0 ;
	return TRUE ;
}

BOOL
CheckValueData( LPCTSTR src, DWORD size )
{
	TCHAR	c, last ;
	DWORD	count, len ;

	switch ( ValueType ) {
	case REG_DWORD:
		break ;
	case REG_SZ:
		len = (_tcslen( src ) + 1) * sizeof (TCHAR) ;
		if ( len >= sizeof ValueData ) {
			return FALSE ;
		}
		break ;
	case REG_MULTI_SZ:
		last = L'A' ;
		len = 0 ;
		count = _tcslen( src ) ;
		do {
			c = *src++ ;
			if ( c == L'\r' ) {
				continue ;
			} else if ( c == L'\n' ) {
				c = 0 ;
			}
			if ( !c && !last ) {
				return FALSE ;
			}
			last = c ;
			len ++ ;
		} while ( -- count ) ;
		if ( c ) {
			len ++ ;
		}
		len ++ ;
		len *= sizeof (TCHAR) ;
		if ( len >= sizeof ValueData ) {
			return FALSE ;
		}
		break ;
	default:
		return FALSE ;
	}
	return TRUE ;
}

BOOL
PutValueData( LPCTSTR src, DWORD size )
{
	TCHAR	c ;
	LPTSTR	dst ;
	DWORD	count ;

	switch ( ValueType ) {
	case REG_DWORD:
		*((LPDWORD) ValueData) = _ttol( src ) ;
		ValueSize = sizeof (DWORD) ;
		break ;
	case REG_SZ:
		_tcscpy( (LPTSTR) ValueData, src ) ;
		ValueSize = (_tcslen( src ) + 1) * sizeof (TCHAR) ;
		break ;
	case REG_MULTI_SZ:
		ValueSize = 0 ;
		dst = (LPTSTR) ValueData ;
		count = _tcslen( src ) ;
		do {
			c = *src++ ;
			if ( c == L'\r' ) {
				continue ;
			} else if ( c == L'\n' ) {
				c = 0 ;
			}
			*dst++ = c ;
			ValueSize ++ ;
		} while ( -- count ) ;
		if ( c ) {
			*dst++ = 0 ;
			ValueSize ++ ;
		}
		*dst++ = 0 ;
		ValueSize ++ ;
		ValueSize *= sizeof (TCHAR) ;
		break ;
	default:
		MessageBeep( MB_ICONHAND ) ;
		return FALSE ;
	}
	return TRUE ;
}

BOOL
NewValue( DWORD type )
{
	HKEY	hKey ;
	LONG	lret ;

	if ( hKeyRoot == INVALID_HANDLE_VALUE ) {
		MessageBeep( MB_ICONHAND ) ;
		return FALSE ;
	}
	ValueType = type ;
	*ValueName = 0 ;
	*Buffer = 0 ;
	if ( ValueType == REG_MULTI_SZ ) {
		if ( !DialogBox( (HANDLE) hInst,
						  MAKEINTRESOURCE(IDD_DLG_MULTI),
						  hMainWnd, (DLGPROC) InputBoxDlgProc ) ) {
			return FALSE ;
		}
	} else {
		if ( !DialogBox( (HANDLE) hInst,
						  MAKEINTRESOURCE(IDD_DLG_SINGLE),
						  hMainWnd, (DLGPROC) InputBoxDlgProc ) ) {
			return FALSE ;
		}
	}
	if ( !PutValueData( Buffer, sizeof Buffer / sizeof Buffer[0] ) ) {
		return FALSE ;
	}
	lret = RegOpenKeyEx( hKeyRoot, RegSubKey, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		MessageBox( hMainWnd, TEXT("can't open the key"), szWinName, MB_OK ) ;
		return FALSE ;
	}
	lret = RegSetValueEx( hKey, ValueName, 0, ValueType, ValueData, ValueSize ) ;
	if ( lret != ERROR_SUCCESS ) {
		RegCloseKey( hKey ) ;
		MessageBox( hMainWnd, TEXT("can't write the value"), ValueName, MB_OK ) ;
		return FALSE ;
	}
	RegCloseKey( hKey ) ;
	return TRUE ;
}

BOOL
EditValue( LPCTSTR name )
{
	HKEY	hKey ;
	LONG	lret ;
	LPTSTR	ptr = (LPTSTR) Buffer ;

	_tcscpy( ValueName, name ) ;
	lret = RegOpenKeyEx( hKeyRoot, RegSubKey, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		wsprintf( Buffer, TEXT("can't open the key : %d"), GetLastError() ) ;
		MessageBox( hMainWnd, Buffer, szWinName, MB_OK ) ;
		return FALSE ;
	}
	ValueSize = sizeof ValueData ;
	memset( ValueData, 0, sizeof ValueData ) ;
	lret = RegQueryValueEx( hKey, ValueName, NULL, &ValueType, ValueData, &ValueSize ) ;
	if ( lret != ERROR_SUCCESS ) {
		RegCloseKey( hKey ) ;
		MessageBox( hMainWnd, TEXT("can't read the value"), ValueName, MB_OK ) ;
		return FALSE ;
	}
	RegCloseKey( hKey ) ;
	if ( !GetValueData( Buffer, sizeof Buffer / sizeof Buffer[0] ) ) {
		MessageBox( hMainWnd, TEXT("registry data too large"), ValueName, MB_OK ) ;
		return FALSE ;
	}
	if ( ValueType == REG_MULTI_SZ ) {
		if ( !DialogBox( (HANDLE) hInst,
						  MAKEINTRESOURCE(IDD_DLG_MULTI),
						  hMainWnd, (DLGPROC) InputBoxDlgProc ) ) {
			return FALSE ;
		}
	} else {
		if ( !DialogBox( (HANDLE) hInst,
						  MAKEINTRESOURCE(IDD_DLG_SINGLE),
						  hMainWnd, (DLGPROC) InputBoxDlgProc ) ) {
			return FALSE ;
		}
	}
	if ( !PutValueData( Buffer, sizeof Buffer / sizeof Buffer[0] ) ) {
		return FALSE ;
	}
	lret = RegOpenKeyEx( hKeyRoot, RegSubKey, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		wsprintf( Buffer, TEXT("can't open the key : %d"), GetLastError() ) ;
		MessageBox( hMainWnd, Buffer, szWinName, MB_OK ) ;
		return FALSE ;
	}
	lret = RegSetValueEx( hKey, ValueName, 0, ValueType, ValueData, ValueSize ) ;
	if ( lret != ERROR_SUCCESS ) {
		RegCloseKey( hKey ) ;
		MessageBox( hMainWnd, TEXT("can't write the value"), ValueName, MB_OK ) ;
		return FALSE ;
	}
	RegCloseKey( hKey ) ;
	return TRUE ;
}

BOOL
DeleteValue( LPCTSTR name )
{
	HKEY	hKey ;
	LONG	lret ;

	_tcscpy( ValueName, name ) ;
	lret = RegOpenKeyEx( hKeyRoot, RegSubKey, 0,
#ifdef	_WIN32_WCE
						0,
#else	/* _WIN32_WCE */
						KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						&hKey ) ;
	if ( lret != ERROR_SUCCESS ) {
		wsprintf( Buffer, TEXT("can't open the key : %d"), GetLastError() ) ;
		MessageBox( hMainWnd, Buffer, szWinName, MB_OK ) ;
		return FALSE ;
	}
	wsprintf( Buffer, TEXT("Delete Value : %s"), ValueName ) ;
	if ( MessageBox( hMainWnd, TEXT("Are you sure?"), Buffer, MB_YESNO ) != IDYES ) {
		RegCloseKey( hKey ) ;
		return FALSE ;
	}
	RegDeleteValue( hKey, ValueName ) ;
	RegCloseKey( hKey ) ;
	return TRUE ;
}

BOOL
NewKey( void )
{
	HKEY	hKey ;
	LONG	lret ;
	DWORD	disposition ;
	TCHAR	subkey[ MAX_PATH ] ;

	if ( hKeyRoot == INVALID_HANDLE_VALUE ) {
		MessageBeep( MB_ICONHAND ) ;
		return FALSE ;
	}
	if ( !DialogBox( (HANDLE) hInst,
					  MAKEINTRESOURCE(IDD_DLG_KEY),
					  hMainWnd, (DLGPROC) NewKeyDlgProc ) ) {
		return FALSE ;
	}
	/* Keyの名前を作成する */
	_tcscpy( subkey, RegSubKey ) ;
	if ( *subkey && *KeyName ) {
		_tcscat( subkey, TEXT("\\") ) ;
	}
	_tcscat( subkey, KeyName ) ;
	/* Keyを作成する */
	lret = RegCreateKeyEx( hKeyRoot, subkey, 0, ClassName, 0, 0, NULL, &hKey, &disposition ) ;
	if ( lret != ERROR_SUCCESS ) {
		MessageBox( hMainWnd, TEXT("can't create the key"), szWinName, MB_OK ) ;
		return FALSE ;
	}
	RegCloseKey( hKey ) ;
	return TRUE ;
}

BOOL
DeleteKey( LPCTSTR keyname )
{
	TCHAR	subkey[ MAX_PATH ] ;

	if ( hKeyRoot == INVALID_HANDLE_VALUE ) {
		return FALSE ;
	}
	/* Keyの名前を作成する */
	_tcscpy( subkey, RegSubKey ) ;
	if ( *subkey && *keyname ) {
		_tcscat( subkey, TEXT("\\") ) ;
	}
	_tcscat( subkey, keyname ) ;
	if ( MessageBox( hMainWnd, TEXT("Are you sure you want to delete this key?"), TEXT("Confirm Key Delete"), MB_YESNO ) != IDYES ) {
		return FALSE ;
	}
	return RegDeleteKey( hKeyRoot, subkey ) == ERROR_SUCCESS ;
}

BOOL CALLBACK
InputBoxDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	LPTSTR		ptr ;
	HWND		hWnd ;
	LONG		tmp ;

	switch ( message ) {
	case WM_INITDIALOG:
		/* 値の名前を設定する */
		hWnd = GetDlgItem( hDlg, IDC_EDT_NAME ) ;
		if ( *ValueName ) {
			SetWindowText( hWnd, ValueName ) ;
			tmp = GetWindowLong( hWnd, GWL_STYLE ) ;
			SetWindowLong( hWnd, GWL_STYLE, tmp | WS_DISABLED ) ;
		}
		/* 値の内容を設定する */
		hWnd = GetDlgItem( hDlg, IDC_EDT_DATA ) ;
		SetWindowText( hWnd, Buffer ) ;
		/* 値の型を設定する */
		if ( !GetTypeStr( &ptr ) ) {
			ptr = TEXT("Unknown") ;
		}
		wsprintf( Buffer, TEXT("%s Editor"), ptr ) ;
		SetWindowText( hDlg, Buffer ) ;
		/* 初期フォーカスを決定する */
		hWnd = GetDlgItem( hDlg, *ValueName ? IDC_EDT_DATA : IDC_EDT_NAME ) ;
		SendMessage( hWnd, EM_SETSEL, (WPARAM) 0, (LPARAM) -1 ) ;
		SetFocus( hWnd ) ;
		return FALSE ;

	case WM_COMMAND:
		switch ( LOWORD( wParam ) ) {
		case IDCANCEL:
			EndDialog( hDlg, FALSE ) ;
			return TRUE ;
		case IDOK:
			if ( !*ValueName ) {
				hWnd = GetDlgItem( hDlg, IDC_EDT_NAME ) ;
				GetWindowText( hWnd, ValueName, sizeof ValueName / sizeof (TCHAR) ) ;
				if ( !*ValueName ) {
					SetFocus( hWnd ) ;
					MessageBeep( MB_ICONHAND ) ;
					return TRUE ;
				}
			}
			hWnd = GetDlgItem( hDlg, IDC_EDT_DATA ) ;
			GetWindowText( hWnd, (LPTSTR) Buffer, sizeof Buffer / sizeof (TCHAR) ) ;
			if ( !CheckValueData( Buffer, sizeof Buffer / sizeof (TCHAR) ) ) {
				SetFocus( hWnd ) ;
				MessageBeep( MB_ICONHAND ) ;
				return TRUE ;
			}
			EndDialog( hDlg, TRUE ) ;
			return TRUE ;
		}
	}
	return FALSE ;
}

BOOL CALLBACK
NewKeyDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	HWND		hWnd ;

	switch ( message ) {
	case WM_INITDIALOG:
		hWnd = GetDlgItem( hDlg, IDC_EDT_KEY ) ;
		SetFocus( hWnd ) ;
		return FALSE ;

	case WM_COMMAND:
		switch ( LOWORD( wParam ) ) {
		case IDCANCEL:
			EndDialog( hDlg, FALSE ) ;
			return TRUE ;
		case IDOK:
			*KeyName = 0 ;
			hWnd = GetDlgItem( hDlg, IDC_EDT_KEY ) ;
			GetWindowText( hWnd, KeyName, sizeof KeyName / sizeof (TCHAR) ) ;
			if ( !*KeyName ) {
				SetFocus( hWnd ) ;
				MessageBeep( MB_ICONHAND ) ;
				return TRUE ;
			}
			*ClassName = 0 ;
			hWnd = GetDlgItem( hDlg, IDC_EDT_CLASS ) ;
			GetWindowText( hWnd, ClassName, sizeof ClassName / sizeof (TCHAR) ) ;
			EndDialog( hDlg, TRUE ) ;
			return TRUE ;
		}
	}
	return FALSE ;
}

BOOL CALLBACK
AboutDlgFunc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch ( message ) {
	case WM_INITDIALOG:
		/* バージョン情報を初期化する */
		wsprintf( MessageBuf, TEXT("%s Ver %s  for WindowsCE"),
				  szWinName, Version ) ;
		SetDlgItemText( hDlg, IDC_VERSION, MessageBuf ) ;
		/* DLLバージョン */
		if ( DllVersion ) {
			wsprintf( MessageBuf, TEXT("KCTRL.DLL Ver %d.%02d"),
					  DllVersion / 100, DllVersion % 100 ) ;
		} else {
			*MessageBuf = 0 ;
		}
		SetDlgItemText( hDlg, IDC_DLLVERSION, MessageBuf ) ;
		return TRUE ;
	case WM_COMMAND:
		switch ( GET_WM_COMMAND_ID( wParam, lParam ) ) {
		case IDOK:
		case IDCANCEL:
			EndDialog( hDlg, TRUE ) ;
			return TRUE ;
		}
		break ;
	}
	return FALSE ;
}

static	BOOL
ExportKey( LPCTSTR keyname )
{
	TCHAR	subkey[ MAX_PATH ] ;

	if ( hKeyRoot == INVALID_HANDLE_VALUE ) {
		return FALSE ;
	}
	_tcscpy( subkey, RegSubKey ) ;
	if ( *subkey && *keyname ) {
		_tcscat( subkey, TEXT("\\") ) ;
	}
	_tcscat( subkey, keyname ) ;
	return export_reg( hKeyRoot, subkey ) ;
}
