reactos/rosapps/applications/sysutils/fontsub/fontsub.cpp

1603 lines
44 KiB
C++

// FontSub by Katayama Hirofumi MZ
//
// To the extent possible under law, the person who associated CC0 with
// FontSub has waived all copyright and related or neighboring rights
// to FontSub.
//
// You should have received a copy of the CC0 legalcode along with this
// work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <tchar.h>
#include <vector> // for std::vector
#include <set> // for std::set
#include <string> // for std::basic_string
#include <algorithm> // for std::sort
#include <cstdio>
#include <cstring>
#include <cassert>
#include "resource.h"
#define NAME_COLUMN_WIDTH 250
#define SUB_COLUMN_WIDTH 250
#define MAX_STRING 120
#ifndef _countof
#define _countof(array) (sizeof(array) / sizeof(array[0]))
#endif
typedef std::wstring STRING;
struct ITEM
{
STRING m_Name, m_Substitute;
BYTE m_CharSet1, m_CharSet2;
ITEM(const STRING& Name, const STRING& Substitute,
BYTE CharSet1, BYTE CharSet2)
: m_Name(Name), m_Substitute(Substitute),
m_CharSet1(CharSet1), m_CharSet2(CharSet2) { }
};
/* global variables */
HINSTANCE g_hInstance = NULL;
HWND g_hMainWnd = NULL;
HICON g_hIcon = NULL;
HWND g_hListView = NULL;
BOOL g_bModified = FALSE;
BOOL g_bNeedsReboot = FALSE;
INT g_iItem = 0;
LPCWSTR g_pszClassName = L"ReactOS Font Substitutes Editor";
LPCWSTR g_pszFileHeader = L"Windows Registry Editor Version 5.00";
WCHAR g_szTitle[MAX_STRING];
WCHAR g_szNameHead[MAX_STRING];
WCHAR g_szSubstituteHead[MAX_STRING];
INT g_iSortColumn = 0;
BOOL g_bSortAscendant = TRUE;
LPCWSTR g_pszKey =
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
typedef std::set<STRING> FONTNAMESET;
typedef std::vector<ITEM> ITEMVECTOR;
FONTNAMESET g_Names;
ITEMVECTOR g_Items;
STRING g_strFontName;
STRING g_strSubstitute;
BYTE g_CharSet1 = DEFAULT_CHARSET;
BYTE g_CharSet2 = DEFAULT_CHARSET;
typedef struct CHARSET_ENTRY
{
BYTE CharSet;
LPCWSTR DisplayName;
} CHARSET_ENTRY;
CHARSET_ENTRY g_CharSetList[] =
{
{ DEFAULT_CHARSET, L"DEFAULT_CHARSET (1)" },
{ ANSI_CHARSET, L"ANSI_CHARSET (0)" },
{ SYMBOL_CHARSET, L"SYMBOL_CHARSET (2)" },
{ SHIFTJIS_CHARSET, L"SHIFTJIS_CHARSET (128)" },
{ HANGUL_CHARSET, L"HANGUL_CHARSET (129)" },
{ GB2312_CHARSET, L"GB2312_CHARSET (134)" },
{ CHINESEBIG5_CHARSET, L"CHINESEBIG5_CHARSET (136)" },
{ OEM_CHARSET, L"OEM_CHARSET (255)" },
{ JOHAB_CHARSET, L"JOHAB_CHARSET (130)" },
{ HEBREW_CHARSET, L"HEBREW_CHARSET (177)" },
{ ARABIC_CHARSET, L"ARABIC_CHARSET (178)" },
{ GREEK_CHARSET, L"GREEK_CHARSET (161)" },
{ TURKISH_CHARSET, L"TURKISH_CHARSET (162)" },
{ VIETNAMESE_CHARSET, L"VIETNAMESE_CHARSET (163)" },
{ THAI_CHARSET, L"THAI_CHARSET (222)" },
{ EASTEUROPE_CHARSET, L"EASTEUROPE_CHARSET (238)" },
{ RUSSIAN_CHARSET, L"RUSSIAN_CHARSET (204)" },
{ MAC_CHARSET, L"MAC_CHARSET (77)" },
{ BALTIC_CHARSET, L"BALTIC_CHARSET (186)" }
};
const WCHAR g_LongestName[] = L"CHINESEBIG5_CHARSET (136)";
static void trim(STRING& str)
{
static const WCHAR Spaces[] = L" \t\r\n";
size_t i = str.find_first_not_of(Spaces);
size_t j = str.find_last_not_of(Spaces);
if (i == STRING::npos || j == STRING::npos)
{
str.clear();
}
else
{
str = str.substr(i, j - i + 1);
}
}
static int CALLBACK
EnumFontFamExProc(const ENUMLOGFONTW *pelf,
const NEWTEXTMETRICW *pntm,
int FontType,
LPARAM lParam)
{
switch (pelf->elfFullName[0])
{
case UNICODE_NULL: case L'@':
break;
default:
g_Names.insert((const WCHAR *)pelf->elfFullName);
}
switch (pelf->elfLogFont.lfFaceName[0])
{
case UNICODE_NULL: case L'@':
break;
default:
g_Names.insert(pelf->elfLogFont.lfFaceName);
}
return 1;
}
BOOL DoLoadNames(void)
{
g_Names.clear();
LOGFONTW lf;
ZeroMemory(&lf, sizeof(lf));
lf.lfCharSet = DEFAULT_CHARSET;
HDC hDC = CreateCompatibleDC(NULL);
EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontFamExProc, 0, 0);
DeleteDC(hDC);
return !g_Names.empty();
}
inline bool ItemCompareByNameAscend(const ITEM& Item1, const ITEM& Item2)
{
return Item1.m_Name < Item2.m_Name;
}
inline bool ItemCompareByNameDescend(const ITEM& Item1, const ITEM& Item2)
{
return Item1.m_Name > Item2.m_Name;
}
inline bool ItemCompareBySubAscend(const ITEM& Item1, const ITEM& Item2)
{
return Item1.m_Substitute < Item2.m_Substitute;
}
inline bool ItemCompareBySubDescend(const ITEM& Item1, const ITEM& Item2)
{
return Item1.m_Substitute > Item2.m_Substitute;
}
void DoSort(INT iColumn, BOOL bAscendant = TRUE)
{
LV_COLUMN Column;
ZeroMemory(&Column, sizeof(Column));
Column.mask = LVCF_IMAGE | LVCF_SUBITEM;
Column.iImage = 2;
Column.iSubItem = 0;
ListView_SetColumn(g_hListView, 0, &Column);
Column.iSubItem = 1;
ListView_SetColumn(g_hListView, 1, &Column);
switch (iColumn)
{
case 0:
Column.iSubItem = 0;
if (bAscendant)
{
std::sort(g_Items.begin(), g_Items.end(),
ItemCompareByNameAscend);
Column.iImage = 0;
ListView_SetColumn(g_hListView, 0, &Column);
}
else
{
std::sort(g_Items.begin(), g_Items.end(),
ItemCompareByNameDescend);
Column.iImage = 1;
ListView_SetColumn(g_hListView, 0, &Column);
}
break;
case 1:
Column.iSubItem = 1;
if (bAscendant)
{
std::sort(g_Items.begin(), g_Items.end(),
ItemCompareBySubAscend);
Column.iImage = 0;
ListView_SetColumn(g_hListView, 1, &Column);
}
else
{
std::sort(g_Items.begin(), g_Items.end(),
ItemCompareBySubDescend);
Column.iImage = 1;
ListView_SetColumn(g_hListView, 1, &Column);
}
break;
}
g_iSortColumn = iColumn;
g_bSortAscendant = bAscendant;
InvalidateRect(g_hListView, NULL, TRUE);
}
void LV_AddItems(HWND hwnd)
{
ListView_DeleteAllItems(hwnd);
LV_ITEM Item;
ZeroMemory(&Item, sizeof(Item));
Item.mask = LVIF_PARAM;
const INT Count = INT(g_Items.size());
for (INT i = 0; i < Count; ++i)
{
Item.iItem = i;
Item.iSubItem = 0;
Item.lParam = i;
ListView_InsertItem(hwnd, &Item);
Item.iItem = i;
Item.iSubItem = 1;
Item.lParam = i;
ListView_InsertItem(hwnd, &Item);
}
}
BOOL DoLoadItems(void)
{
ITEMVECTOR Items;
HKEY hKey = NULL;
RegOpenKeyExW(HKEY_LOCAL_MACHINE, g_pszKey, 0, KEY_READ, &hKey);
if (hKey == NULL)
return FALSE;
WCHAR szName[MAX_STRING], szValue[MAX_STRING];
DWORD cbName, cbValue;
for (DWORD dwIndex = 0; ; ++dwIndex)
{
cbName = sizeof(szName);
cbValue = sizeof(szValue);
LONG Error = RegEnumValueW(hKey, dwIndex, szName, &cbName,
NULL, NULL, (LPBYTE)szValue, &cbValue);
if (Error != ERROR_SUCCESS)
break;
BYTE CharSet1 = DEFAULT_CHARSET, CharSet2 = DEFAULT_CHARSET;
LPWSTR pch;
pch = wcsrchr(szName, L',');
if (pch)
{
*pch = 0;
CharSet1 = (BYTE)_wtoi(pch + 1);
}
pch = wcsrchr(szValue, L',');
if (pch)
{
*pch = 0;
CharSet2 = (BYTE)_wtoi(pch + 1);
}
ITEM Item(szName, szValue, CharSet1, CharSet2);
trim(Item.m_Name);
trim(Item.m_Substitute);
Items.push_back(Item);
}
RegCloseKey(hKey);
g_Items = Items;
LV_AddItems(g_hListView);
DoSort(0, TRUE);
g_bModified = FALSE;
g_bNeedsReboot = FALSE;
return !g_Items.empty();
}
BOOL DoLoad(void)
{
return DoLoadNames() && DoLoadItems();
}
void LV_InvalidateRow(HWND hwnd, INT iRow = -1)
{
if (iRow == -1)
iRow = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
if (iRow == -1)
return;
RECT Rect;
LPRECT GccIsWhining = &Rect;
ListView_GetItemRect(hwnd, iRow, GccIsWhining, LVIR_BOUNDS);
InvalidateRect(hwnd, &Rect, FALSE);
}
BOOL LV_Init(HWND hwnd)
{
ListView_SetExtendedListViewStyle(hwnd,
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
HIMAGELIST hImageList;
hImageList = ImageList_Create(12, 12, ILC_COLOR8 | ILC_MASK, 2, 2);
HBITMAP hbm;
hbm = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(2), IMAGE_BITMAP,
12, 12, LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
assert(hbm);
ImageList_AddMasked(hImageList, hbm, RGB(192, 192, 192));
DeleteObject(hbm);
hbm = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(3), IMAGE_BITMAP,
12, 12, LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
assert(hbm);
ImageList_AddMasked(hImageList, hbm, RGB(192, 192, 192));
DeleteObject(hbm);
hbm = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(4), IMAGE_BITMAP,
12, 12, LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
assert(hbm);
ImageList_AddMasked(hImageList, hbm, RGB(192, 192, 192));
DeleteObject(hbm);
ListView_SetImageList(hwnd, hImageList, LVSIL_SMALL);
LV_COLUMNW Column;
ZeroMemory(&Column, sizeof(Column));
Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH | LVCF_IMAGE;
Column.fmt = LVCFMT_LEFT;
Column.cx = NAME_COLUMN_WIDTH;
Column.pszText = g_szNameHead;
Column.iSubItem = 0;
Column.iImage = 0;
ListView_InsertColumn(hwnd, 0, &Column);
Column.cx = SUB_COLUMN_WIDTH;
Column.pszText = g_szSubstituteHead;
Column.iSubItem = 1;
Column.iImage = 2;
ListView_InsertColumn(hwnd, 1, &Column);
UINT State = LVIS_SELECTED | LVIS_FOCUSED;
ListView_SetItemState(hwnd, 0, State, State);
return TRUE;
}
BOOL EditDlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
COMBOBOXEXITEMW Item;
ZeroMemory(&Item, sizeof(Item));
Item.mask = CBEIF_TEXT;
FONTNAMESET::iterator it, end = g_Names.end();
for (it = g_Names.begin(); it != end; ++it)
{
Item.pszText = const_cast<LPWSTR>(it->c_str());
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb2));
SendDlgItemMessageW(hwnd, cmb2, CBEM_INSERTITEM, 0, (LPARAM)&Item);
}
SetDlgItemTextW(hwnd, edt1, g_strFontName.c_str());
SetDlgItemTextW(hwnd, cmb2, g_strSubstitute.c_str());
const INT Count = _countof(g_CharSetList);
for (INT i = 0; i < Count; ++i)
{
Item.pszText = const_cast<LPWSTR>(g_CharSetList[i].DisplayName);
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb3));
SendDlgItemMessageW(hwnd, cmb3, CBEM_INSERTITEM, 0, (LPARAM)&Item);
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb4));
SendDlgItemMessageW(hwnd, cmb4, CBEM_INSERTITEM, 0, (LPARAM)&Item);
}
SendDlgItemMessageW(hwnd, cmb3, CB_SETCURSEL, 0, 0);
SendDlgItemMessageW(hwnd, cmb4, CB_SETCURSEL, 0, 0);
for (INT i = 0; i < Count; ++i)
{
if (g_CharSet1 == g_CharSetList[i].CharSet)
{
SendDlgItemMessageW(hwnd, cmb3, CB_SETCURSEL, i, 0);
}
if (g_CharSet2 == g_CharSetList[i].CharSet)
{
SendDlgItemMessageW(hwnd, cmb4, CB_SETCURSEL, i, 0);
}
}
SIZE siz;
HDC hDC = CreateCompatibleDC(NULL);
SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
GetTextExtentPoint32W(hDC, g_LongestName, lstrlenW(g_LongestName), &siz);
DeleteDC(hDC);
SendDlgItemMessageW(hwnd, cmb3, CB_SETHORIZONTALEXTENT, siz.cx + 16, 0);
SendDlgItemMessageW(hwnd, cmb4, CB_SETHORIZONTALEXTENT, siz.cx + 16, 0);
EnableWindow(GetDlgItem(hwnd, cmb3), FALSE);
return TRUE;
}
void LV_OnDelete(HWND hwnd, INT iRow = -1)
{
if (iRow == -1)
iRow = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
if (iRow == -1)
return;
UINT State = LVIS_SELECTED | LVIS_FOCUSED;
ListView_SetItemState(g_hListView, iRow, State, State);
WCHAR sz[MAX_STRING];
LoadStringW(g_hInstance, IDS_QUERYDELETE, sz, _countof(sz));
if (IDYES != MessageBoxW(g_hMainWnd, sz, g_szTitle,
MB_ICONINFORMATION | MB_YESNO))
{
return;
}
ListView_DeleteItem(hwnd, iRow);
g_Items.erase(g_Items.begin() + iRow);
g_bModified = TRUE;
ListView_SetItemState(g_hListView, iRow, State, State);
InvalidateRect(hwnd, NULL, TRUE);
}
void EditDlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
WCHAR szValue[MAX_STRING];
STRING str;
INT i;
switch (id)
{
case IDOK:
GetDlgItemTextW(hwnd, cmb2, szValue, _countof(szValue));
str = szValue;
trim(str);
if (str.empty())
{
WCHAR sz[MAX_STRING];
SendDlgItemMessageW(hwnd, cmb2, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
SetFocus(GetDlgItem(hwnd, cmb2));
LoadStringW(g_hInstance, IDS_ENTERNAME2, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
g_Items[g_iItem].m_CharSet2 = DEFAULT_CHARSET;
i = SendDlgItemMessageW(hwnd, cmb4, CB_GETCURSEL, 0, 0);
if (i != CB_ERR)
{
g_Items[g_iItem].m_CharSet2 = g_CharSetList[i].CharSet;
}
g_Items[g_iItem].m_Substitute = str;
g_bModified = TRUE;
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
case psh1:
LV_OnDelete(g_hListView, g_iItem);
EndDialog(hwnd, psh1);
break;
}
}
INT_PTR CALLBACK
EditDlg_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, EditDlg_OnInitDialog);
HANDLE_MSG(hwnd, WM_COMMAND, EditDlg_OnCommand);
}
return 0;
}
void LV_OnDblClk(HWND hwnd)
{
g_iItem = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
if (g_iItem == -1)
return;
g_strFontName = g_Items[g_iItem].m_Name;
g_strSubstitute = g_Items[g_iItem].m_Substitute;
g_CharSet1 = g_Items[g_iItem].m_CharSet1;
g_CharSet2 = g_Items[g_iItem].m_CharSet2;
DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_EDIT), g_hMainWnd,
EditDlg_DlgProc);
InvalidateRect(g_hListView, NULL, TRUE);
}
BOOL MainWnd_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_VSCROLL |
LVS_SINGLESEL | LVS_REPORT | LVS_OWNERDRAWFIXED;
DWORD dwExStyle = WS_EX_CLIENTEDGE;
g_hListView = CreateWindowEx(dwExStyle, WC_LISTVIEW, NULL, dwStyle,
0, 0, 0, 0,
hwnd, (HMENU)1, g_hInstance, NULL);
if (g_hListView == NULL)
return FALSE;
if (!LV_Init(g_hListView))
return FALSE;
if (!DoLoad())
return FALSE;
UINT State = LVIS_SELECTED | LVIS_FOCUSED;
ListView_SetItemState(g_hListView, 0, State, State);
SetFocus(g_hListView);
return TRUE;
}
BOOL AddDlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
COMBOBOXEXITEMW Item;
ZeroMemory(&Item, sizeof(Item));
Item.iItem = -1;
Item.mask = CBEIF_TEXT;
FONTNAMESET::iterator it, end = g_Names.end();
for (it = g_Names.begin(); it != end; ++it)
{
Item.pszText = const_cast<LPWSTR>(it->c_str());
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb1));
SendDlgItemMessageW(hwnd, cmb1, CBEM_INSERTITEM, 0, (LPARAM)&Item);
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb2));
SendDlgItemMessageW(hwnd, cmb2, CBEM_INSERTITEM, 0, (LPARAM)&Item);
}
WCHAR szEnterName[MAX_STRING];
LoadStringW(g_hInstance, IDS_ENTERNAME, szEnterName, _countof(szEnterName));
SetDlgItemTextW(hwnd, cmb1, szEnterName);
SendDlgItemMessageW(hwnd, cmb1, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
const INT Count = _countof(g_CharSetList);
for (INT i = 0; i < Count; ++i)
{
Item.pszText = const_cast<LPWSTR>(g_CharSetList[i].DisplayName);
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb3));
SendDlgItemMessageW(hwnd, cmb3, CBEM_INSERTITEM, 0, (LPARAM)&Item);
Item.iItem = ComboBox_GetCount(GetDlgItem(hwnd, cmb4));
SendDlgItemMessageW(hwnd, cmb4, CBEM_INSERTITEM, 0, (LPARAM)&Item);
}
SendDlgItemMessageW(hwnd, cmb3, CB_SETCURSEL, 0, 0);
SendDlgItemMessageW(hwnd, cmb4, CB_SETCURSEL, 0, 0);
for (INT i = 0; i < Count; ++i)
{
if (g_CharSet1 == g_CharSetList[i].CharSet)
{
SendDlgItemMessageW(hwnd, cmb3, CB_SETCURSEL, i, 0);
}
if (g_CharSet2 == g_CharSetList[i].CharSet)
{
SendDlgItemMessageW(hwnd, cmb4, CB_SETCURSEL, i, 0);
}
}
SIZE siz;
HDC hDC = CreateCompatibleDC(NULL);
SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
GetTextExtentPoint32W(hDC, g_LongestName, lstrlenW(g_LongestName), &siz);
DeleteDC(hDC);
SendDlgItemMessageW(hwnd, cmb3, CB_SETHORIZONTALEXTENT, siz.cx + 16, 0);
SendDlgItemMessageW(hwnd, cmb4, CB_SETHORIZONTALEXTENT, siz.cx + 16, 0);
return TRUE;
}
void AddDlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
WCHAR szKey[MAX_STRING], szValue[MAX_STRING], sz[MAX_STRING];
INT i, iCharSet1, iCharSet2;
BYTE CharSet1, CharSet2;
STRING key, value;
switch (id)
{
case IDOK:
GetDlgItemTextW(hwnd, cmb1, szKey, _countof(szKey));
key = szKey;
trim(key);
LoadStringW(g_hInstance, IDS_ENTERNAME, sz, _countof(sz));
if (key.empty() || key == sz)
{
SendDlgItemMessageW(hwnd, cmb1, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
SetFocus(GetDlgItem(hwnd, cmb1));
LoadStringW(g_hInstance, IDS_ENTERNAME2, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
GetDlgItemTextW(hwnd, cmb2, szValue, _countof(szValue));
value = szValue;
trim(value);
if (value.empty())
{
SendDlgItemMessageW(hwnd, cmb2, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
SetFocus(GetDlgItem(hwnd, cmb2));
LoadStringW(g_hInstance, IDS_ENTERNAME2, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
iCharSet1 = SendDlgItemMessageW(hwnd, cmb3, CB_GETCURSEL, 0, 0);
if (iCharSet1 == CB_ERR)
iCharSet1 = 0;
iCharSet2 = SendDlgItemMessageW(hwnd, cmb4, CB_GETCURSEL, 0, 0);
if (iCharSet2 == CB_ERR)
iCharSet2 = 0;
CharSet1 = g_CharSetList[iCharSet1].CharSet;
CharSet2 = g_CharSetList[iCharSet2].CharSet;
for (i = 0; i < (INT)g_Items.size(); ++i)
{
if (g_Items[i].m_Name == key &&
g_Items[i].m_CharSet1 == CharSet1)
{
WCHAR sz[MAX_STRING];
SendDlgItemMessageW(hwnd, cmb1, CB_SETEDITSEL, 0, MAKELPARAM(0, -1));
SetFocus(GetDlgItem(hwnd, cmb1));
LoadStringW(g_hInstance, IDS_ALREADYEXISTS, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
}
{
ITEM Item(key, value, CharSet1, CharSet2);
g_Items.push_back(Item);
g_bModified = TRUE;
i = (INT)g_Items.size();
LV_ITEM LvItem;
ZeroMemory(&LvItem, sizeof(LvItem));
LvItem.mask = LVIF_PARAM;
LvItem.iItem = i;
LvItem.lParam = i;
LvItem.iSubItem = 0;
ListView_InsertItem(g_hListView, &LvItem);
LvItem.iSubItem = 1;
ListView_InsertItem(g_hListView, &LvItem);
}
g_bModified = TRUE;
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
}
INT_PTR CALLBACK
AddDlg_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, AddDlg_OnInitDialog);
HANDLE_MSG(hwnd, WM_COMMAND, AddDlg_OnCommand);
}
return 0;
}
void MainWnd_OnNew(HWND hwnd)
{
g_iItem = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
if (g_iItem == -1)
return;
g_strFontName = g_Items[g_iItem].m_Name;
g_strSubstitute = g_Items[g_iItem].m_Substitute;
g_CharSet1 = g_Items[g_iItem].m_CharSet1;
g_CharSet2 = g_Items[g_iItem].m_CharSet2;
if (IDOK == DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ADD), g_hMainWnd,
AddDlg_DlgProc))
{
INT i = ListView_GetItemCount(g_hListView) - 1;
UINT State = LVIS_SELECTED | LVIS_FOCUSED;
ListView_SetItemState(g_hListView, i, State, State);
ListView_EnsureVisible(g_hListView, i, FALSE);
}
}
BOOL MainWnd_OnUpdateRegistry(HWND hwnd)
{
// open the key
HKEY hKey = NULL;
RegOpenKeyExW(HKEY_LOCAL_MACHINE, g_pszKey, 0, KEY_ALL_ACCESS, &hKey);
if (hKey == NULL)
return FALSE;
// clear all values
WCHAR szName[MAX_STRING], szValue[MAX_STRING];
DWORD cbName, cbValue;
for (;;)
{
cbName = sizeof(szName);
cbValue = sizeof(szValue);
LONG Error = RegEnumValueW(hKey, 0, szName, &cbName,
NULL, NULL, (LPBYTE)szValue, &cbValue);
if (Error != ERROR_SUCCESS)
break;
RegDeleteValueW(hKey, szName);
}
// set values
size_t Count = g_Items.size();
for (size_t i = 0; i < Count; ++i)
{
DWORD cbData = (g_Items[i].m_Substitute.size() + 1) * sizeof(WCHAR);
RegSetValueExW(hKey, g_Items[i].m_Name.c_str(), 0,
REG_SZ, (LPBYTE)g_Items[i].m_Substitute.c_str(), cbData);
}
// close now
RegCloseKey(hKey);
g_bModified = FALSE;
g_bNeedsReboot = TRUE;
return TRUE;
}
LPWSTR SkipSpace(LPCWSTR pch)
{
while (*pch && wcschr(L" \t\r\n", *pch) != NULL)
{
++pch;
}
return const_cast<LPWSTR>(pch);
}
LPWSTR SkipQuoted(LPWSTR pch)
{
++pch; // L'"'
while (*pch)
{
if (*pch == L'"')
{
++pch;
break;
}
if (*pch == L'\\')
{
++pch;
}
++pch;
}
return pch;
}
void UnescapeHex(const STRING& str, size_t& i, STRING& Ret, BOOL Unicode)
{
STRING Num;
// hexadecimal
if (iswxdigit(str[i]))
{
Num += str[i];
++i;
if (iswxdigit(str[i]))
{
Num += str[i];
++i;
if (Unicode)
{
if (iswxdigit(str[i]))
{
Num += str[i];
++i;
if (iswxdigit(str[i]))
{
Num += str[i];
++i;
}
}
}
}
}
if (!Num.empty())
{
Ret += (WCHAR)wcstoul(&Num[0], NULL, 16);
}
}
void UnescapeOther(const STRING& str, size_t& i, STRING& Ret)
{
STRING Num;
// check octal
if (L'0' <= str[i] && str[i] < L'8')
{
Num += str[i];
++i;
if (L'0' <= str[i] && str[i] < L'8')
{
Num += str[i];
++i;
if (L'0' <= str[i] && str[i] < L'8')
{
Num += str[i];
++i;
}
}
}
if (Num.empty())
{
Ret += str[i];
++i;
}
else
{
// octal
Ret += (WCHAR)wcstoul(&Num[0], NULL, 8);
}
}
// process escape sequence
void UnescapeChar(const STRING& str, size_t& i, STRING& Ret)
{
if (str[i] != L'\\')
{
Ret += str[i];
++i;
return;
}
++i;
switch (str[i])
{
case L'a': Ret += L'\a'; ++i; break;
case L'b': Ret += L'\b'; ++i; break;
case L'f': Ret += L'\f'; ++i; break;
case L'n': Ret += L'\n'; ++i; break;
case L'r': Ret += L'\r'; ++i; break;
case L't': Ret += L'\t'; ++i; break;
case L'v': Ret += L'\v'; ++i; break;
case L'x':
// hexidemical
++i;
UnescapeHex(str, i, Ret, FALSE);
break;
case L'u':
// Unicode hexidemical
++i;
UnescapeHex(str, i, Ret, TRUE);
break;
default:
// other case
UnescapeOther(str, i, Ret);
break;
}
}
STRING Unquote(const STRING& str)
{
if (str[0] != L'"')
return str;
STRING Ret;
size_t i = 1;
while (i < str.size())
{
if (str[i] == L'"' || str[i] == UNICODE_NULL)
break;
UnescapeChar(str, i, Ret);
}
return Ret;
}
BOOL DoParseFile(LPVOID pvContents, DWORD dwSize)
{
ITEMVECTOR Items;
LPWSTR pch, pchSep, pchStart = (LPWSTR)pvContents;
pchStart[dwSize / sizeof(WCHAR)] = UNICODE_NULL;
// check header
const DWORD cbHeader = lstrlenW(g_pszFileHeader) * sizeof(WCHAR);
if (memcmp(pchStart, g_pszFileHeader, cbHeader) != 0)
return FALSE;
pchStart += cbHeader / sizeof(WCHAR);
// find the key
WCHAR szKey[MAX_STRING];
wsprintfW(szKey, L"[HKEY_LOCAL_MACHINE\\%s]", g_pszKey);
pch = wcsstr(pchStart, szKey);
if (pch == NULL)
return FALSE;
pchStart = pch + lstrlenW(szKey);
for (;;)
{
pchStart = SkipSpace(pchStart);
if (*pchStart == UNICODE_NULL || *pchStart == L'[')
break;
pch = wcschr(pchStart, L'\n');
if (pch)
*pch = UNICODE_NULL;
pchSep = SkipQuoted(pchStart);
if (*pchSep == L'=')
{
*pchSep = UNICODE_NULL;
STRING key = pchStart;
trim(key);
key = Unquote(key);
STRING value = pchSep + 1;
trim(value);
value = Unquote(value);
BYTE CharSet1 = DEFAULT_CHARSET, CharSet2 = DEFAULT_CHARSET;
size_t pos;
pos = key.find(L',');
if (pos != STRING::npos)
{
CharSet1 = (BYTE)_wtoi(&key[pos + 1]);
key.resize(pos);
trim(key);
}
pos = value.find(L',');
if (pos != STRING::npos)
{
CharSet2 = (BYTE)_wtoi(&value[pos + 1]);
value.resize(pos);
trim(value);
}
ITEM Item(key, value, CharSet1, CharSet2);
Items.push_back(Item);
}
if (pch == NULL)
break;
pchStart = pch + 1;
}
g_Items = Items;
g_bModified = TRUE;
LV_AddItems(g_hListView);
return TRUE;
}
BOOL DoImport(HWND hwnd, LPCWSTR pszFile)
{
HANDLE hFile = CreateFileW(pszFile, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
BOOL bSuccess = FALSE;
DWORD dwSize = GetFileSize(hFile, NULL);
if (dwSize != 0xFFFFFFFF)
{
std::vector<BYTE> Contents(dwSize + 2);
DWORD cbRead;
if (ReadFile(hFile, &Contents[0], dwSize, &cbRead, NULL) &&
cbRead == dwSize)
{
/* check BOM */
if (memcmp(&Contents[0], "\xFF\xFE", 2) == 0)
{
bSuccess = DoParseFile(&Contents[2], dwSize - 2);
}
else
{
bSuccess = DoParseFile(&Contents[0], dwSize);
}
}
}
CloseHandle(hFile);
return bSuccess;
}
STRING Escape(const STRING& str)
{
STRING Ret;
for (size_t i = 0; i < str.size(); ++i)
{
switch (str[i])
{
case L'"': case L'\\':
Ret += L'\\';
Ret += str[i];
break;
default:
Ret += str[i];
}
}
return Ret;
}
BOOL DoExport(HWND hwnd, LPCWSTR pszFile)
{
HANDLE hFile = CreateFileW(pszFile, GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
BOOL bSuccess;
DWORD dwSize, cbWritten;
WCHAR szCharSet1[MAX_STRING], szCharSet2[MAX_STRING];
WCHAR szLine[MAX_STRING * 2 + 4];
/* write header */
dwSize = lstrlenW(g_pszFileHeader) * sizeof(WCHAR);
bSuccess =
WriteFile(hFile, "\xFF\xFE", 2, &cbWritten, NULL) &&
WriteFile(hFile, g_pszFileHeader, dwSize, &cbWritten, NULL);
if (bSuccess)
{
wsprintfW(szLine, L"\r\n\r\n[HKEY_LOCAL_MACHINE\\%s]\r\n", g_pszKey);
dwSize = lstrlenW(szLine) * sizeof(WCHAR);
bSuccess = WriteFile(hFile, szLine, dwSize, &cbWritten, NULL);
}
if (bSuccess)
{
size_t i, Count = g_Items.size();
for (i = 0; i < Count; ++i)
{
if (g_Items[i].m_CharSet1 != DEFAULT_CHARSET)
wsprintfW(szCharSet1, L",%u", g_Items[i].m_CharSet1);
else
szCharSet1[0] = UNICODE_NULL;
if (g_Items[i].m_CharSet2 != DEFAULT_CHARSET)
wsprintfW(szCharSet2, L",%u", g_Items[i].m_CharSet2);
else
szCharSet2[0] = UNICODE_NULL;
STRING Name = Escape(g_Items[i].m_Name);
STRING Substitute = Escape(g_Items[i].m_Substitute);
wsprintfW(szLine, L"\"%s%s\"=\"%s%s\"\r\n",
Name.c_str(), szCharSet1,
Substitute.c_str(), szCharSet2);
dwSize = lstrlenW(szLine) * sizeof(WCHAR);
if (!WriteFile(hFile, szLine, dwSize, &cbWritten, NULL))
{
bSuccess = FALSE;
break;
}
}
WriteFile(hFile, L"\r\n", 2 * sizeof(WCHAR), &cbWritten, NULL);
}
CloseHandle(hFile);
if (!bSuccess)
{
DeleteFileW(pszFile);
}
return bSuccess;
}
void MakeFilter(LPWSTR pszFilter)
{
while (*pszFilter)
{
if (*pszFilter == L'|')
*pszFilter = 0;
++pszFilter;
}
}
void MainWnd_OnImport(HWND hwnd)
{
OPENFILENAMEW ofn = {0};
WCHAR szFile[MAX_PATH] = L"";
WCHAR szImportTitle[MAX_STRING];
WCHAR szCannotImport[MAX_STRING];
WCHAR szImportFilter[MAX_STRING];
LoadStringW(g_hInstance, IDS_IMPORT, szImportTitle, _countof(szImportTitle));
LoadStringW(g_hInstance, IDS_CANTIMPORT, szCannotImport, _countof(szCannotImport));
LoadStringW(g_hInstance, IDS_INPFILTER, szImportFilter, _countof(szImportFilter));
MakeFilter(szImportFilter);
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szImportFilter;
ofn.lpstrFile = szFile;
ofn.nMaxFile = _countof(szFile);
ofn.lpstrTitle = szImportTitle;
ofn.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING |
OFN_EXPLORER | OFN_FILEMUSTEXIST |
OFN_HIDEREADONLY | OFN_LONGNAMES |
OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = L"reg";
if (GetOpenFileNameW(&ofn))
{
if (!DoImport(hwnd, szFile))
{
MessageBoxW(hwnd, szCannotImport, g_szTitle, MB_ICONERROR);
}
}
}
void MainWnd_OnExport(HWND hwnd)
{
OPENFILENAMEW ofn = {0};
WCHAR szFile[MAX_PATH] = L"";
WCHAR szExportTitle[MAX_STRING];
WCHAR szCannotExport[MAX_STRING];
WCHAR szExportFilter[MAX_STRING];
LoadStringW(g_hInstance, IDS_EXPORT, szExportTitle, _countof(szExportTitle));
LoadStringW(g_hInstance, IDS_CANTEXPORT, szCannotExport, _countof(szCannotExport));
LoadStringW(g_hInstance, IDS_OUTFILTER, szExportFilter, _countof(szExportFilter));
MakeFilter(szExportFilter);
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szExportFilter;
ofn.lpstrFile = szFile;
ofn.nMaxFile = _countof(szFile);
ofn.lpstrTitle = szExportTitle;
ofn.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING |
OFN_EXPLORER | OFN_HIDEREADONLY | OFN_LONGNAMES |
OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
ofn.lpstrDefExt = L"reg";
if (GetSaveFileNameW(&ofn))
{
if (!DoExport(hwnd, szFile))
{
MessageBoxW(hwnd, szCannotExport, g_szTitle, MB_ICONERROR);
}
}
}
void MainWnd_OnReload(HWND hwnd)
{
DoLoad();
}
void MainWnd_OnEdit(HWND hwnd)
{
LV_OnDblClk(g_hListView);
}
void MainWnd_OnDelete(HWND hwnd)
{
LV_OnDelete(g_hListView);
}
void MainWnd_OnOpenRegKey(HWND hwnd)
{
static const WCHAR s_szRegeditKey[] =
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit";
WCHAR sz[MAX_STRING];
// open regedit key
HKEY hKey = NULL;
LSTATUS Result = RegCreateKeyExW(HKEY_CURRENT_USER, s_szRegeditKey, 0,
NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
if (Result != ERROR_SUCCESS)
{
LoadStringW(g_hInstance, IDS_CANTOPENKEY, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
// set LastKey value
wsprintfW(sz, L"HKEY_LOCAL_MACHINE\\%s", g_pszKey);
DWORD dwSize = sizeof(sz);
Result = RegSetValueExW(hKey, L"LastKey", 0, REG_SZ,
(LPBYTE)sz, dwSize);
// close now
RegCloseKey(hKey);
if (Result != ERROR_SUCCESS)
{
LoadStringW(g_hInstance, IDS_CANTOPENKEY, sz, _countof(sz));
MessageBoxW(hwnd, sz, NULL, MB_ICONERROR);
return;
}
// open by regedit
ShellExecuteW(hwnd, NULL, L"regedit.exe", NULL, NULL, SW_SHOWNORMAL);
}
void MainWnd_OnAbout(HWND hwnd)
{
WCHAR szAbout[MAX_PATH];
LoadStringW(g_hInstance, IDS_ABOUT, szAbout, _countof(szAbout));
MSGBOXPARAMS Params;
ZeroMemory(&Params, sizeof(Params));
Params.cbSize = sizeof(Params);
Params.hwndOwner = hwnd;
Params.hInstance = g_hInstance;
Params.lpszText = szAbout;
Params.lpszCaption = g_szTitle;
Params.dwStyle = MB_OK | MB_USERICON;
Params.lpszIcon = MAKEINTRESOURCEW(1);
Params.dwLanguageId = LANG_USER_DEFAULT;
MessageBoxIndirectW(&Params);
}
void MainWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case ID_NEW:
MainWnd_OnNew(hwnd);
break;
case ID_EDIT:
MainWnd_OnEdit(hwnd);
break;
case ID_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_RELOAD:
MainWnd_OnReload(hwnd);
break;
case ID_UPDATE_REGISTRY:
MainWnd_OnUpdateRegistry(hwnd);
break;
case ID_DELETE:
MainWnd_OnDelete(hwnd);
break;
case ID_IMPORT:
MainWnd_OnImport(hwnd);
break;
case ID_EXPORT:
MainWnd_OnExport(hwnd);
break;
case ID_OPEN_REGKEY:
MainWnd_OnOpenRegKey(hwnd);
break;
case ID_ABOUT:
MainWnd_OnAbout(hwnd);
break;
}
}
void MainWnd_OnDestroy(HWND hwnd)
{
PostQuitMessage(0);
}
void MainWnd_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
MoveWindow(g_hListView, 0, 0, cx, cy, TRUE);
}
void MainWnd_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT *lpDrawItem)
{
if (lpDrawItem->CtlType != ODT_LISTVIEW)
return;
HDC hDC = lpDrawItem->hDC;
SetBkMode(hDC, TRANSPARENT);
INT iColumn = 0, x, cx;
RECT rcItem, rcSubItem, rcText;
STRING Str;
x = -GetScrollPos(g_hListView, SB_HORZ);
rcItem = lpDrawItem->rcItem;
if (lpDrawItem->itemState & ODS_SELECTED)
{
FillRect(hDC, &rcItem, (HBRUSH)(COLOR_HIGHLIGHT + 1));
SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
FillRect(hDC, &rcItem, (HBRUSH)(COLOR_WINDOW + 1));
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
}
cx = ListView_GetColumnWidth(g_hListView, iColumn);
rcSubItem = rcItem;
rcSubItem.left = x;
rcSubItem.right = x + cx;
WCHAR sz[MAX_STRING];
rcText = rcSubItem;
InflateRect(&rcText, -1, -1);
Str = g_Items[lpDrawItem->itemID].m_Name;
BYTE CharSet1 = g_Items[lpDrawItem->itemID].m_CharSet1;
if (CharSet1 != DEFAULT_CHARSET)
wsprintfW(sz, L"%s,%u", Str.c_str(), CharSet1);
else
wsprintfW(sz, L"%s", Str.c_str());
DrawTextW(hDC, sz, lstrlenW(sz), &rcText,
DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS |
DT_NOPREFIX);
x += cx;
++iColumn;
cx = ListView_GetColumnWidth(g_hListView, iColumn);
rcSubItem = rcItem;
rcSubItem.left = x;
rcSubItem.right = x + cx;
rcText = rcSubItem;
InflateRect(&rcText, -1, -1);
Str = g_Items[lpDrawItem->itemID].m_Substitute;
BYTE CharSet2 = g_Items[lpDrawItem->itemID].m_CharSet2;
if (CharSet2 != DEFAULT_CHARSET)
wsprintfW(sz, L"%s,%u", Str.c_str(), CharSet2);
else
wsprintfW(sz, L"%s", Str.c_str());
DrawTextW(hDC, sz, lstrlenW(sz), &rcText,
DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS |
DT_NOPREFIX);
}
void MainWnd_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *lpMeasureItem)
{
if (lpMeasureItem->CtlType != ODT_LISTVIEW)
return;
TEXTMETRIC tm;
HDC hDC = GetDC(hwnd);
GetTextMetrics(hDC, &tm);
ReleaseDC(hwnd, hDC);
lpMeasureItem->itemHeight = tm.tmHeight * 4 / 3;
}
LRESULT MainWnd_OnNotify(HWND hwnd, int idFrom, NMHDR *pnmhdr)
{
NM_LISTVIEW *pNMLV = (NM_LISTVIEW *)pnmhdr;
LV_KEYDOWN *pLVKD = (LV_KEYDOWN *)pnmhdr;
switch (pnmhdr->code)
{
case LVN_COLUMNCLICK:
if (pNMLV->iSubItem == g_iSortColumn)
DoSort(pNMLV->iSubItem, !g_bSortAscendant);
else
DoSort(pNMLV->iSubItem, TRUE);
break;
case NM_DBLCLK:
LV_OnDblClk(g_hListView);
break;
case LVN_KEYDOWN:
if (pLVKD->wVKey == VK_RETURN) // [Enter] key
{
LV_OnDblClk(g_hListView);
}
if (pLVKD->wVKey == VK_DELETE) // [Del] key
{
LV_OnDelete(g_hListView);
}
break;
}
return 0;
}
LRESULT MainWnd_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
{
POINT pt = {(INT)xPos, (INT)yPos};
ScreenToClient(g_hListView, &pt);
SendMessageW(g_hListView, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(2));
if (hMenu == NULL)
return 0;
HMENU hSubMenu = GetSubMenu(hMenu, 0);
if (hSubMenu == NULL)
return 0;
SetForegroundWindow(hwnd);
TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
xPos, yPos, 0, g_hMainWnd, NULL);
PostMessage(g_hMainWnd, WM_NULL, 0, 0);
return 0;
}
void MainWnd_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized)
{
if (state != WA_INACTIVE)
{
SetFocus(g_hListView);
}
}
BOOL EnableProcessPrivileges(LPCWSTR lpPrivilegeName, BOOL bEnable = TRUE)
{
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tokenPrivileges;
BOOL Ret;
Ret = ::OpenProcessToken(::GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken);
if (!Ret)
return Ret; // failure
Ret = ::LookupPrivilegeValueW(NULL, lpPrivilegeName, &luid);
if (Ret)
{
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luid;
tokenPrivileges.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
Ret = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, 0, 0);
}
::CloseHandle(hToken);
return Ret;
}
void MainWnd_OnClose(HWND hwnd)
{
if (!g_bNeedsReboot && !g_bModified)
{
DestroyWindow(hwnd);
return;
}
if (g_bModified)
{
WCHAR szUpdateNow[MAX_STRING];
LoadStringW(g_hInstance, IDS_QUERYUPDATE, szUpdateNow, _countof(szUpdateNow));
INT id = MessageBoxW(hwnd, szUpdateNow, g_szTitle,
MB_ICONINFORMATION | MB_YESNOCANCEL);
switch (id)
{
case IDYES:
MainWnd_OnUpdateRegistry(hwnd);
break;
case IDNO:
break;
case IDCANCEL:
return;
}
}
if (g_bNeedsReboot)
{
WCHAR szRebootNow[MAX_STRING];
LoadStringW(g_hInstance, IDS_REBOOTNOW, szRebootNow, _countof(szRebootNow));
INT id = MessageBoxW(hwnd, szRebootNow, g_szTitle,
MB_ICONINFORMATION | MB_YESNOCANCEL);
switch (id)
{
case IDYES:
EnableProcessPrivileges(SE_SHUTDOWN_NAME, TRUE);
::ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);
break;
case IDNO:
break;
case IDCANCEL:
return;
}
}
::DestroyWindow(hwnd);
}
LRESULT CALLBACK
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_CREATE, MainWnd_OnCreate);
HANDLE_MSG(hwnd, WM_COMMAND, MainWnd_OnCommand);
HANDLE_MSG(hwnd, WM_DESTROY, MainWnd_OnDestroy);
HANDLE_MSG(hwnd, WM_SIZE, MainWnd_OnSize);
HANDLE_MSG(hwnd, WM_DRAWITEM, MainWnd_OnDrawItem);
HANDLE_MSG(hwnd, WM_MEASUREITEM, MainWnd_OnMeasureItem);
HANDLE_MSG(hwnd, WM_NOTIFY, MainWnd_OnNotify);
HANDLE_MSG(hwnd, WM_CONTEXTMENU, MainWnd_OnContextMenu);
HANDLE_MSG(hwnd, WM_ACTIVATE, MainWnd_OnActivate);
HANDLE_MSG(hwnd, WM_CLOSE, MainWnd_OnClose);
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
INT WINAPI wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
INT nCmdShow)
{
g_hInstance = hInstance;
InitCommonControls();
HACCEL hAccel = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(1));
LoadStringW(hInstance, IDS_TITLE, g_szTitle, _countof(g_szTitle));
LoadStringW(hInstance, IDS_FONTNAME, g_szNameHead, _countof(g_szNameHead));
LoadStringW(hInstance, IDS_SUBSTITUTE, g_szSubstituteHead, _countof(g_szSubstituteHead));
WNDCLASSW wc = {0};
wc.style = 0;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
g_hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(1));
wc.hIcon = g_hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.lpszMenuName = MAKEINTRESOURCEW(1);
wc.lpszClassName = g_pszClassName;
if (!RegisterClassW(&wc))
{
MessageBoxA(NULL, "ERROR: RegisterClass failed.", NULL, MB_ICONERROR);
return 1;
}
const DWORD dwStyle = WS_OVERLAPPEDWINDOW;
INT Width = NAME_COLUMN_WIDTH + SUB_COLUMN_WIDTH +
GetSystemMetrics(SM_CXVSCROLL) +
GetSystemMetrics(SM_CXSIZEFRAME);
INT Height = 320;
RECT Rect = { 0, 0, Width, Height };
AdjustWindowRect(&Rect, dwStyle, TRUE);
Width = Rect.right - Rect.left;
Height = Rect.bottom - Rect.top;
g_hMainWnd = CreateWindowW(g_pszClassName, g_szTitle, dwStyle,
CW_USEDEFAULT, CW_USEDEFAULT, Width, Height,
NULL, NULL, hInstance, NULL);
if (g_hMainWnd == NULL)
{
MessageBoxA(NULL, "ERROR: CreateWindow failed.", NULL, MB_ICONERROR);
return 2;
}
ShowWindow(g_hMainWnd, nCmdShow);
UpdateWindow(g_hMainWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (TranslateAccelerator(g_hMainWnd, hAccel, &msg))
continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (INT)msg.wParam;
}