#include "stdafx.h"
#include "resource.h"

static HINSTANCE hInst;
static LRESULT CALLBACK DlgProc_winxplayer( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
static char *fname, *value;

static char *szTitle = "互換モードの設定";

static char *sfname, *s_unknown;
static bool bWin95, bWin98SE, bWinNT4SP5, bWin2k, bWinXPSP2, bWinSrv2003SP1,
            bWinXPSP3, bWinVista, bWinVistaSP1, bWinVistaSP2, bWinSrv2008SP1, bWin7RTM,
            bw256, bw16bit, bw640, bwnoime, bwnotheme,
            bHiDpiAware, bDisableDwm, bDisableNX, bEnableNX, bRunAsAdmin;

static WORD winver;

BOOL APIENTRY DllMain( HINSTANCE hInstance, DWORD what, LPVOID )
{
	switch (what) {
		case DLL_PROCESS_ATTACH:
            hInst = hInstance;
			break;

		case DLL_PROCESS_DETACH:
			safefree(sfname);
			safefree(s_unknown);
			break;
	}
    return TRUE;
}

static int args_typecheck( struct ARGS *args, char *types ) // 引数のチェック
{
	struct ARGS *p;

	p = args;

	if (p == NULL) {
		if (types == NULL || types[0] == 0)
			return 1; // OK
		else
			return 0; // NG
	}

	do {
		switch ( p->type ) {
			case UFCT_ARG_INT:
				if (*types != 'i')
					return 0; // NG
				break;

			case UFCT_ARG_STRING:
				if (*types != 's')
					return 0; // NG
				break;

			case UFCT_ARG_INTS:
				if (*types != 'a')
					return 0; // NG
				break;

			case UFCT_ARG_STRINGS:
				if (*types != 'r')
					return 0; // NG
				break;
		}
		
		types++;
	} while( (p = p->next) != NULL );

	if ( *types == 0 ) // argsが終端に達したとき、typeも終端に達したか?
		return 1; // OK
	else
		return 0; // NG
}

DllExport UINT editdialog( HWND hWnd, struct ARGS *args )
{
	if ( args_typecheck( args, "ss" ) ) {
		fname = ARG1.text;
		value = ARG2.text;
		return (UINT)DialogBox(hInst, (LPCTSTR)IDD_DIALOG1, hWnd, (DLGPROC)DlgProc_winxplayer);
	}

	return 0;
}

DllExport HGLOBAL getfilename( HWND hWnd, struct ARGS *args )
{
	HGLOBAL hMem = 0;
	char *buf;

	if ( sfname && args_typecheck( args, "" ) ) {
		if ( NULL != (hMem = GlobalAlloc( GMEM_MOVEABLE, lstrlen(sfname)+1 )) ) {
			if ( NULL != (buf = (char *)GlobalLock( hMem ) ) ) {
				lstrcpy(buf, sfname);
				GlobalUnlock( hMem );
			}
		}
	}

	return hMem;
}


DllExport HGLOBAL getvalues( HWND hWnd, struct ARGS *args )
{
	HGLOBAL hMem = 0;
	char *buf;

	if ( s_unknown && args_typecheck( args, "" ) ) {
		char *valueb = zalloc(lstrlen(s_unknown)+100);

		if (valueb) {
			if ( bWin95 )
				lstrcat( valueb, "WIN95 " );
			else if ( bWin98SE )
				lstrcat( valueb, "WIN98 " );
			else if ( bWinNT4SP5 )
				lstrcat( valueb, "NT4SP5 " );
			else if ( bWin2k )
				lstrcat( valueb, "WIN2000 " );
			else if ( bWinXPSP2 )
				lstrcat( valueb, "WINXPSP2 " );
			else if ( bWinSrv2003SP1 )
				lstrcat( valueb, "WINSRV03SP1 " );
			else if ( bWinXPSP3 )
				lstrcat( valueb, "WINXPSP3 " );
			else if ( bWinVista )
				lstrcat( valueb, "VISTARTM " );
			else if ( bWinVistaSP1 )
				lstrcat( valueb, "VISTASP1 " );
			else if ( bWinVistaSP2 )
				lstrcat( valueb, "VISTASP2 " );
			else if ( bWinSrv2008SP1 )
				lstrcat( valueb, "WINSRV08SP1 " );
			else if ( bWin7RTM )
				lstrcat( valueb, "WIN7RTM " );

			if ( bw256 )
				lstrcat( valueb, "256COLOR " );
			if ( bw16bit )
				lstrcat( valueb, "16BITCOLOR " );
			if ( bw640 )
				lstrcat( valueb, "640X480 " );
			if ( bwnotheme )
				lstrcat( valueb, "DISABLETHEMES " );
			if ( bwnoime )
				lstrcat( valueb, "DISABLECICERO " );
			if ( bHiDpiAware )
				lstrcat( valueb, "HIGHDPIAWARE " );
			if ( bDisableDwm )
				lstrcat( valueb, "DISABLEDWM " );
			if ( bDisableNX )
				lstrcat( valueb, "DisableNXShowUI " );
			if ( bEnableNX )
				lstrcat( valueb, "EnableNXShowUI " );
			if ( bRunAsAdmin )
				lstrcat( valueb, "RUNASADMIN " );

			// 不明文字列の付加
			lstrcat(valueb, s_unknown);

			if ( NULL != (hMem = GlobalAlloc( GMEM_MOVEABLE, lstrlen(valueb)+1 )) ) {
				if ( NULL != (buf = (char *)GlobalLock( hMem ) ) ) {
					lstrcpy(buf, valueb);
					GlobalUnlock( hMem );
				}
			}

			free(valueb);
		}
	}

	return hMem;
}

// ウィンドウ用ダイアログプロシージャ
static LRESULT CALLBACK DlgProc_winxplayer( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			if ( fname ) {
				SetDlgItemText(hDlg, IDC_EDIT_FILENAME, fname);
			}

			if ( GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_FILENAME)) <= 0 ) {
				EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
			}

			{
				winver = tf_getWinVer();

				// コンボボックスの準備（前バージョン共通）
				// [0]使用しない
				SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"使用しない");
				// [1]Windows 95
				SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows 95互換(注意事項あり：ヘルプ参照)");
				// [2]Windows 98/Me
				SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows 98 Second Edition互換");
				// [3]Windows NT 4.0 SP5
				SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows NT 4.0 SP5互換");
				// デフォルトの選択肢=0
				SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 0, 0);
#if _MSC_VER < 1500
#ifndef _WIN64
				if (winver <= 500) { // Windows 2000以下
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_DisableNXShowUI), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_EnableNXShowUI), FALSE);
				}
#endif /* _WIN64 */
#endif // _MSC_VER < 1500
				if (500 < winver) { // Windows XP以上
					// [4]Windows 2000
					SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows 2000互換");

					if (502 < winver) { // Windows Server 2003より上
						// [5]Windows XP SP2
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows XP SP2互換");
						// [6]Windows Server 2003 SP1
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows Server 2003 SP1互換");

						if (600 < winver) { // Windows 7以上
							// [7]Windows XP SP3
							SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows XP SP3互換");
							// [8]Windows Vista
							SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows Vista互換");
							// [9]Windows Vista SP1
							SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows Vista SP1互換");
							// [10]Windows Vista SP2
							SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows Vista SP2互換");
							// [11]Windows Server 2008 SP1
							SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows Server 2008 SP1互換");

							if (601 < winver) { // Windows 8以上
								// [12]Windows 7
								SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_ADDSTRING, 0, (LPARAM)"Windows 7互換");
							}
						}
					}
				}
				if (winver <= 502) { // Windows Server 2003以下
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_HIGHDPIAWARE), FALSE);	// 高DPI設定では画面のスケーリングを無効にする
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_DISABLEDWM), FALSE);	// デスクトップコンポジション（メモリ内で画面構成後に出力）無効
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_RUNASADMIN), FALSE);	// 管理者として実行
				}
				if (winver < 602) { // Win8未満
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_16BITCOLOR), FALSE);	// 16ビット（65536）カラー
				}
				if (winver >= 602) { // Win8以上
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_NOTHEME), FALSE);		// 視覚テーマ無効
					EnableWindow(GetDlgItem(hDlg, IDC_CHECK_DISABLEDWM), FALSE);	// デスクトップコンポジション（メモリ内で画面構成後に出力）無効
				}

				// value の内容を解析。不明なモノは文字列のまま残す
				char *pbuf = _strdup(value);
				if ( pbuf == NULL ) {
					MessageBox(hDlg, "メモリが足りないため、互換モードの文字列の解析ができません。", szTitle, MB_OK | MB_ICONSTOP);
					EndDialog(hDlg, FALSE);
					return TRUE;
				}

				char *pszUnknown = zalloc(lstrlen(pbuf)+1); // 不明な文字列を溜め込んでおくための領域
				if ( pszUnknown == NULL ) {
					MessageBox(hDlg, "メモリが足りないため、不明文字列の解析ができません。", szTitle, MB_OK | MB_ICONSTOP);
					EndDialog(hDlg, FALSE);
					return TRUE;
				}

				// スペースをデリミタとするトークンの列を解析
				char *context = NULL, *p;
				p = strtok_s(pbuf, " ", &context);
				while(p) {
					if ( lstrcmpi(p, "WIN95") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 1, 0);
					else if ( lstrcmpi(p, "WIN98") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 2, 0);
					else if ( lstrcmpi(p, "NT4SP5") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 3, 0);
					else if ( lstrcmpi(p, "WIN2000") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 4, 0); // Windows XP以降
					else if ( lstrcmpi(p, "WINXPSP2") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 5, 0); // Windows Vista以降
					else if ( lstrcmpi(p, "WINSRV03SP1") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 6, 0); // Windows Vista以降
					else if ( lstrcmpi(p, "WINXPSP3") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 7, 0); // Windows 7以降
					else if ( lstrcmpi(p, "VISTARTM") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 8, 0); // Windows 7以降
					else if ( lstrcmpi(p, "VISTASP1") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 9, 0); // Windows 7以降
					else if ( lstrcmpi(p, "VISTASP2") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 10, 0); // Windows 7以降
					else if ( lstrcmpi(p, "WINSRV08SP1") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 11, 0); // Windows 7以降
					else if ( lstrcmpi(p, "WIN7RTM") == 0 )
						SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_SETCURSEL, 12, 0); // Windows 8以降
					else if ( lstrcmpi(p, "256COLOR") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_256COLOR, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "16BITCOLOR") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_16BITCOLOR, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "640X480") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_640X480, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "DISABLETHEMES") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_NOTHEME, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "DISABLECICERO") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_NOIME, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "HIGHDPIAWARE") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_HIGHDPIAWARE, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "DISABLEDWM") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_DISABLEDWM, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "DisableNXShowUI") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_DisableNXShowUI, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "EnableNXShowUI") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_EnableNXShowUI, BM_SETCHECK, BST_CHECKED, NULL );
					else if ( lstrcmpi(p, "RUNASADMIN") == 0 )
						SendDlgItemMessage( hDlg, IDC_CHECK_RUNASADMIN, BM_SETCHECK, BST_CHECKED, NULL );
					else {
						// 不明な互換文字列は蓄積
						lstrcat(pszUnknown, p);
						lstrcat(pszUnknown, " ");
					}

					// 次のトークンを捜索
					p = strtok_s(NULL, " ", &context);
				}

				// 不明な互換文字列をまとめる
				SetDlgItemText(hDlg, IDC_EDIT_UNKNOWN, pszUnknown);

				free(pszUnknown);
				free(pbuf);
			}
			return TRUE;

		case WM_COMMAND:
			switch ( LOWORD(wParam) ) {
				case IDOK:
					if ( GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_FILENAME)) <= 0 ) {
						MessageBox(hDlg, "ファイル名を入力して下さい。", "互換モード設定", MB_OK | MB_ICONSTOP);
					}
					else {
						int iCur = (int)SendDlgItemMessage(hDlg, IDC_COMBO_OSVER, CB_GETCURSEL, 0, 0);

						bWin95 = bWin98SE = bWinNT4SP5 = bWin2k = bWinXPSP2 = bWinSrv2003SP1 =
						         bWinXPSP3 = bWinVista = bWinVistaSP1 = bWinVistaSP2 = bWinSrv2008SP1 = bWin7RTM = 0;

						switch(iCur) {
							case 1:
								bWin95 = 1;
								break;
							case 2:
								bWin98SE = 1;
								break;
							case 3:
								bWinNT4SP5 = 1;
								break;
							case 4:
								bWin2k = 1;
								break;
							case 5:
								bWinXPSP2 = 1;
								break;
							case 6:
								bWinSrv2003SP1 = 1;
								break;
							case 7:
								bWinXPSP3 = 1;
								break;
							case 8:
								bWinVista = 1;
								break;
							case 9:
								bWinVistaSP1 = 1;
								break;
							case 10:
								bWinVistaSP2 = 1;
								break;
							case 11:
								bWinSrv2008SP1 = 1;
								break;
							case 12:
								bWin7RTM = 1;
								break;
						}

						bw256       = (SendDlgItemMessage( hDlg, IDC_CHECK_256COLOR, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bw16bit     = (SendDlgItemMessage( hDlg, IDC_CHECK_16BITCOLOR, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bw640       = (SendDlgItemMessage( hDlg, IDC_CHECK_640X480, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bwnotheme   = (SendDlgItemMessage( hDlg, IDC_CHECK_NOTHEME, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bwnoime     = (SendDlgItemMessage( hDlg, IDC_CHECK_NOIME, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bHiDpiAware = (SendDlgItemMessage( hDlg, IDC_CHECK_HIGHDPIAWARE, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bDisableDwm = (SendDlgItemMessage( hDlg, IDC_CHECK_DISABLEDWM, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bDisableNX  = (SendDlgItemMessage( hDlg, IDC_CHECK_DisableNXShowUI, BM_GETCHECK, 0, NULL ) == BST_CHECKED); 
						bEnableNX   = (SendDlgItemMessage( hDlg, IDC_CHECK_EnableNXShowUI, BM_GETCHECK, 0, NULL ) == BST_CHECKED);
						bRunAsAdmin = (SendDlgItemMessage( hDlg, IDC_CHECK_RUNASADMIN, BM_GETCHECK, 0, NULL ) == BST_CHECKED);

						// ファイル名フルパスの編集ボックスからの文字列の読み取り
						safefree(sfname);
						int len = GetWindowTextLength( GetDlgItem(hDlg, IDC_EDIT_FILENAME) )+1;
						sfname = zalloc(len);
						if ( sfname ) {
							GetDlgItemText(hDlg, IDC_EDIT_FILENAME, sfname, len);
						}
						else {
							MessageBox(hDlg, "メモリ不足のため、ファイル名を格納できません。", szTitle, MB_OK | MB_ICONSTOP);
						}

						// 不明文字列のまとめ
						safefree(s_unknown);
						len = GetWindowTextLength( GetDlgItem(hDlg, IDC_EDIT_UNKNOWN) )+1;
						s_unknown = zalloc(len);
						if ( s_unknown ) {
							GetDlgItemText(hDlg, IDC_EDIT_UNKNOWN, s_unknown, len);
						}
						else {
							MessageBox(hDlg, "メモリ不足のため、その他文字列の取得ができません。", szTitle, MB_OK | MB_ICONSTOP);
						}

						EndDialog(hDlg, TRUE);
					}
					return TRUE;

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

				case IDC_BUTTON_BROWSE:
					{
						OPENFILENAME ofn;
						char fname[MAX_PATH*2]="";

						GetDlgItemText(hDlg, IDC_EDIT_FILENAME, fname, _countof(fname));

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

						if (GetOpenFileName(&ofn)) {
							SetDlgItemText(hDlg, IDC_EDIT_FILENAME, fname);
						}
					}			
					SetFocus(GetDlgItem(hDlg,IDC_EDIT_FILENAME));
					EnableWindow(GetDlgItem(hDlg, IDOK), GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_FILENAME)) > 0? TRUE : FALSE);
					return TRUE;

				case IDC_EDIT_FILENAME:
					if ( HIWORD(wParam) == EN_CHANGE ) {
						EnableWindow(GetDlgItem(hDlg, IDOK), GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_FILENAME)) > 0? TRUE : FALSE  );
					}
					return TRUE;

				case IDC_COMBO_OSVER:
					if ( HIWORD(wParam) != CBN_SELCHANGE ) {
						return TRUE;
					}
				case IDC_CHECK_256COLOR:
				case IDC_CHECK_16BITCOLOR:
				case IDC_CHECK_640X480:
				case IDC_CHECK_NOIME:
				case IDC_CHECK_NOTHEME:
				case IDC_CHECK_HIGHDPIAWARE:
				case IDC_CHECK_DISABLEDWM:
				case IDC_CHECK_DisableNXShowUI:
				case IDC_CHECK_EnableNXShowUI:
				case IDC_CHECK_RUNASADMIN:
					EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
					return TRUE;
			}
			break;
	}
    return FALSE;
}
