// DlgInput.cpp : implementation file // #include "stdafx.h" #include "hgjson.h" #include "DlgTwain.h" #include "afxdialogex.h" #include #include #include namespace util { enum { BOM_ANSI, BOM_UTF8, BOM_UNICODE, }; static INTER_MODULE_CALLBACK(got_str) { *(std::string*)param += std::string(data, len); return inter_module_data::SET_RESULT_CONTINUE; } static INTER_MODULE_CALLBACK(got_wstr) { *(std::wstring*)param += std::wstring((const wchar_t*)data, len / 2); return inter_module_data::SET_RESULT_CONTINUE; } static bool is_space(wchar_t ch) { return ch == L' ' || ch == L'\t' || ch == L'\r' || ch == L'\n'; } static bool is_var_char(wchar_t ch, bool allow_num) { return ch == L'_' || (ch >= L'0' && ch <= L'9' && allow_num) || (ch >= L'a' && ch <= L'z') || (ch >= L'A' && ch <= L'Z'); } static bool skip_space(const wchar_t** str) { const wchar_t* bgn = *str; while (is_space(str[0][0])) (*str)++; return *str > bgn; } static void to_line_head(const wchar_t** str) { while (str[0][0] != L'\n') (*str)--; } static void erase_multiline_comment(std::wstring& cont) { for (int i = 0; i < cont.length(); ++i) { if (cont[i] == L'/') { if (cont[i + 1] == L'/') { std::wstring val(L""); int next = 0; coding_util::pick_line(cont.c_str() + i, got_wstr, &val, &next); i += next; } else if (cont[i + 1] == L'*') { size_t pos = cont.find(L"*/", i + 2); if (pos++ == std::wstring::npos) { cont.erase(i); break; } else cont.erase(i, pos - i + 1); } } } } static void transform_hz(std::wstring& hz) { int prev = -1; std::string inner(""); for (int i = 0; i < hz.length() - 3; ++i) { if (hz[i] == L'\\') { if (hz[i + 1] == L'u') { } else if (hz[i + 1] == L'x') { } else if (hz[i + 1] >= L'0' && hz[i + 1] <= L'7') { if (hz[i + 2] >= L'0' && hz[i + 2] <= L'7' && hz[i + 3] >= L'0' && hz[i + 3] <= L'7') { if (prev == -1) prev = i; char ch = (hz[i + 1] - L'0') * 64 + (hz[i + 2] - L'0') * 8 + hz[i + 3] - L'0'; inner.append(1, ch); i += 3; } } } else { if (inner.length()) { std::wstring trans(L""); coding_util::utf8_2_unicode(inner.c_str(), got_wstr, &trans); hz.replace(prev, i - prev, trans); i = prev + trans.length(); } prev = -1; inner = ""; } } if (inner.length()) { std::wstring trans(L""); coding_util::utf8_2_unicode(inner.c_str(), got_wstr, &trans); hz.replace(prev, hz.length() - prev, trans); } } static std::wstring now(void) { time_t t = time(NULL); tm* pt = localtime(&t); wchar_t buf[40] = { 0 }; swprintf_s(buf, _countof(buf) - 1, L"%04d-%02d-%02d %02d:%02d:%02d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec); return buf; } static std::wstring get_text(HWND wnd) { int len = GetWindowTextLengthW(wnd); wchar_t * buf = new wchar_t[len + 128]; std::wstring ret(L""); len = ::GetWindowTextW(wnd, buf, len + 20); buf[len] = 0; ret = buf; delete[] buf; return std::move(ret); } static void append_log(const wchar_t* log, HWND edit, bool scroll_last) { std::wstring text(std::move(get_text(edit))), cur(now() + L": "), str(log), space(L""); size_t pos = str.find(L"\r\n"); space.append(cur.length() * 2, L' '); while (pos != std::wstring::npos && pos < str.length() - 2) { str.insert(pos + 2, space); pos = str.find(L"\r\n", pos + space.length() + 2); } text += cur + str; ::SetWindowTextW(edit, text.c_str()); if (scroll_last) ::SendMessage(edit, EM_LINESCROLL, 0, ::SendMessageW(edit, EM_GETLINECOUNT, 0, 0)); else ::SendMessageW(edit, EM_LINESCROLL, 0, (LPARAM)::GetPropW(edit, L"stop_line")); } static std::wstring load_file(const wchar_t* file, int *bom) { std::wstring cont(L""); std::string raw(""); file_util::load_file(file, got_str, &raw); if (raw.empty()) return false; if (bom) *bom = coding_util::bom::is_unicode(raw.c_str(), NULL) ? BOM_UNICODE : (coding_util::bom::is_utf8(raw.c_str()) ? BOM_UTF8 : BOM_ANSI); coding_util::bom::to_unicode(raw.c_str(), raw.length(), got_wstr, &cont); return std::move(cont); } static bool save_file(const wchar_t* file, const wchar_t* cont, int bom, std::wstring* bak = NULL) { std::string raw(""); if (bom == BOM_UNICODE) coding_util::bom::from_unicode(cont, lstrlenW(cont) * 2, got_str, &raw); else if (bom == BOM_UTF8) { std::string utf8(""); coding_util::unicode_2_utf8(cont, got_str, &utf8); coding_util::bom::from_utf8(utf8.c_str(), utf8.length(), got_str, &raw); } else coding_util::unicode_2_ansi(cont, got_str, &raw); if (bak) { *bak = file; *bak += L".bak"; file_util::force_copy_file(file, bak->c_str()); } return file_util::save_2_file(raw.c_str(), raw.length(), file) == 0; } std::string u2a(const wchar_t* u, bool to_utf8 = false) { std::string a(""); if (to_utf8) coding_util::unicode_2_utf8(u, got_str, &a); else coding_util::unicode_2_ansi(u, got_str, &a); return std::move(a); } std::wstring a2u(const char* a, bool from_utf8 = false) { std::wstring u(L""); if (from_utf8) coding_util::utf8_2_unicode(a, got_wstr, &u); else coding_util::ansi_2_unicode(a, got_wstr, &u); return std::move(u); } static std::wstring get_sane_opt_title(const wchar_t* key, const std::wstring& cont) { size_t pos = cont.find(key); std::wstring title(L""); while (pos != std::wstring::npos) { if (pos) { int check = pos - 1; if (cont[check] == L' ' || cont[check] == L'\t') { const wchar_t* l = cont.c_str() + check; to_line_head(&l); skip_space(&l); if (wcsstr(l, L"#define") == l) { l += 7; skip_space(&l); if (wcsstr(l, key) == l) { l += lstrlenW(key); if (skip_space(&l) && *l++ == L'\"') { while (*l != L'\r' && *l != L'\n' && *l != L'\"' && *l != 0) title.append(1, *l++); transform_hz(title); break; } } } } } pos += lstrlenW(key); pos = cont.find(key, pos); } return std::move(title); } static void get_sane_opts(const wchar_t* file, std::vector& opts) { std::wstring tf(file), name(L"\r\n"), title(L"\r\n") , pre_n(L"SANE_STD_OPT_NAME_"), pre_t(L"OPTION_TITLE_"), define(L"#define") , line(L""), val(L""); std::string bom(""); SANEOPT opt; int off = 0, next = 0; STR_PARENT_FOLDER(tf); tf += L"\\sane_option_definitions.h"; STR_TO_ABSOLUTE_PATH(tf); file_util::load_file(file, got_str, &bom); if (bom.empty()) return; coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &name); erase_multiline_comment(name); bom = ""; file_util::load_file(tf.c_str(), got_str, &bom); if (bom.empty()) return; coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &title); bom = ""; erase_multiline_comment(title); // search ... coding_util::pick_line(name.c_str(), got_wstr, &line, &next); while (line.length() || next) { size_t pos = line.find(define); if (pos == 0 && line.length() > define.length() && is_space(line[define.length()])) { const wchar_t* str = line.c_str() + define.length(), * bgn = NULL;; util::skip_space(&str); if (wcsstr(str, pre_n.c_str()) == str) { bgn = str; str += pre_n.length(); while (is_var_char(*str, true)) str++; opt.name_key = std::wstring(bgn, str - bgn); if (util::skip_space(&str) && *str++ == L'\"') { bgn = str; while (*str != L'\"') str++; opt.name = std::wstring(bgn, str - bgn); str++; util::skip_space(&str); if (wcsstr(str, L"//") == str) { str += 2; util::skip_space(&str); if (wcsstr(str, pre_t.c_str()) == str) { bgn = str; str += pre_t.length(); while (is_var_char(*str, true)) str++; opt.title_key = std::wstring(bgn, str - bgn); opt.title = std::move(get_sane_opt_title(opt.title_key.c_str(), title)); opts.push_back(opt); } } } } } off += next; line = L""; coding_util::pick_line(name.c_str() + off, got_wstr, &line, &next); } } static bool pick_option_id_function(std::wstring& code, int* off = NULL, const wchar_t* api_decl = L"scanner::init_options_id(void)", const wchar_t* ret = L"int") { std::wstring api(api_decl); size_t pos = code.find(api); const wchar_t* l = NULL; while (pos != std::wstring::npos) { l = code.c_str() + pos; to_line_head(&l); skip_space(&l); if (wcsstr(l, ret) == l) { l += lstrlenW(ret); if (skip_space(&l)) { if (wcsstr(l, api.c_str()) == l) { int bgn = 0, end = 0; coding_util::pick_value(l, L"{", L"}", &bgn, &end); if (end > bgn) { api = std::wstring(l + bgn, end - bgn + 1); if (off) *off = l + bgn - code.c_str(); code = std::move(api); return true; } } } } pos += api.length(); pos = code.find(api, pos); } return false; } static bool pick_twain_ex_enum(std::wstring& code, int* start = NULL) { // enum CapTypeEx : unsigned short { size_t pos = code.find(L"enum"); while (pos != std::wstring::npos) { const wchar_t* l = code.c_str() + pos; to_line_head(&l); skip_space(&l); if (wcsstr(l, L"enum") == l) { l += 4; if (skip_space(&l)) { if (wcsstr(l, L"CapTypeEx") == l) { int bgn = 0, end = 0; coding_util::pick_value(l, L"{", L"}", &bgn, &end); if (start) *start = l + bgn - code.c_str(); code = std::move(std::wstring(l + bgn, end - bgn + 1)); return true; } } } pos = code.find(L"enum", pos + 4); } return false; } static bool get_twain_id(const std::wstring& idtext, std::vector& used) { std::wstring pre(L"CAP_EX_SANE_"), line(L""), key(L""); OPTUSED ou; int off = 0, next = 0, id = 0x8801; coding_util::pick_line(idtext.c_str(), got_wstr, &line, &next); while (!line.empty() || next) { const wchar_t* bgn = line.c_str(), * l = bgn; skip_space(&l); if (wcsstr(l, pre.c_str()) == l) { l += pre.length(); bgn = l; while (is_var_char(*l, true)) l++; key = std::wstring(bgn, l - bgn); ou.id_key = ""; coding_util::unicode_2_ansi(key.c_str(), got_str, &ou.id_key); ou.id = id++; used.push_back(ou); } off += next; line.clear(); coding_util::pick_line(idtext.c_str() + off, got_wstr, &line, &next); } std::sort(used.begin(), used.end()); return true; } static void get_used_opts(const wchar_t* file, std::vector& used) { std::wstring key(L""), id(L""), idf(file), line(L""), pre_nk(L"SANE_STD_OPT_NAME_"), pre_ik(L"CAP_EX_SANE_"), setoid(L"SET_OPT_ID("); std::string bom(""); OPTUSED ou; int off = 0, next = 0; STR_PARENT_FOLDER(idf); idf += L"\\..\\..\\code_twain\\twain\\twain\\huagaods.cpp"; STR_TO_ABSOLUTE_PATH(idf); file_util::load_file(file, got_str, &bom); if (bom.empty()) return; coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &key); erase_multiline_comment(key); bom = ""; file_util::load_file(idf.c_str(), got_str, &bom); if (bom.empty()) return; coding_util::bom::to_unicode(bom.c_str(), bom.length(), got_wstr, &id); erase_multiline_comment(id); get_twain_id(id, used); if (!pick_option_id_function(key) || !pick_twain_ex_enum(id)) return; bom = ""; coding_util::pick_line(key.c_str(), got_wstr, &line, &next); while (!line.empty() || next > 0) { const wchar_t* l = line.c_str(), * bgn = NULL; skip_space(&l); if (wcsstr(l, L"else") == l) { l += 4; skip_space(&l); } if (wcsstr(l, setoid.c_str()) == l) { l += setoid.length(); bgn = l; if (is_var_char(*l++, false)) { while (is_var_char(*l, true)) l++; ou.id_key = ""; coding_util::unicode_2_ansi(std::wstring(bgn, l - bgn).c_str(), got_str, &ou.id_key); skip_space(&l); if (*l++ == L',') { skip_space(&l); bgn = l; if (is_var_char(*l++, false)) { while (is_var_char(*l, true)) l++; ou.name_key = std::wstring(bgn, l - bgn); std::vector::iterator it = std::find(used.begin(), used.end(), ou.id_key.c_str()); if (it != used.end()) it->name_key = std::move(L"SANE_STD_OPT_NAME_" + ou.name_key); } } } } off += next; line = L""; coding_util::pick_line(key.c_str() + off, got_wstr, &line, &next); } } static bool add_2_huagaods_cpp(const wchar_t* file, const SANEOPT& sane, const OPTUSED& twain, std::wstring* msg) { int off = 0, next = 0, bom = BOM_ANSI; std::wstring cont(std::move(load_file(file, &bom))), line(L""), lead(L"CAP_EX_SANE_"); if (cont.empty()) { if (msg) *msg = L"File 'huagaods.cpp' is not found or empty."; return false; } line = cont; if (pick_twain_ex_enum(line, &off)) { size_t pos = line.rfind(L','); const wchar_t* l = line.c_str() + pos, * bgn = NULL; to_line_head(&l); bgn = ++l; skip_space(&l); std::wstring en(bgn, l - bgn); en += lead + a2u(twain.id_key.c_str()) + L",\t\t// " + now() + L" " + sane.title; lead = line; lead.insert(pos + 1, L"\r\n" + en); cont.replace(off, line.length(), lead); line = cont; if (pick_option_id_function(line, &off, L"huagao_ds::init_support_caps_ex(void)", L"void")) { pos = line.rfind(L';'); l = line.c_str() + pos; to_line_head(&l); l++; bgn = l; skip_space(&l); en = std::wstring(bgn, l - bgn); en += L"ADD_SANE_CAP("; en += a2u(twain.id_key.c_str()); en += L");\r\n"; lead = line + en; cont.replace(off, line.length(), lead); if (save_file(file, cont.c_str(), bom, &line)) { if (msg) *msg += std::wstring(L"Changed: ") + file + L"\r\n"; return true; } else if (msg) *msg = L"Failed to save changes into file 'huagaods.cpp'."; if (file_util::is_file_existing(line.c_str())) file_util::force_move_file(line.c_str(), file); } else if (msg) { *msg = L"Failed to find function 'huagao_ds::init_support_caps_ex(void)' in huagaods.cpp."; } } else if (msg) { *msg = L"Failed to find 'enum CapTypeEx' in huagaods.cpp."; } return false; } static bool add_2_scanner_codes(const wchar_t* cpp, const SANEOPT& sane, const OPTUSED& twain, std::wstring* msg) { int bom_c = BOM_ANSI, bom_h = BOM_ANSI; std::wstring hf(cpp), code_c(load_file(cpp, &bom_c)), code_h(L""), tag(L"// SANE options ID ..."), val(L""), hbak(L""), cbak(L""); size_t pos = hf.rfind(L'.'); const wchar_t *l = NULL, *bgn = NULL; if (code_c.empty()) { if (msg) *msg = std::wstring(L"File '") + cpp + L"' is not found or empty."; return false; } hf.erase(pos); hf += L".h"; code_h = std::move(load_file(hf.c_str(), &bom_h)); if (code_h.empty()) { if (msg) *msg = std::wstring(L"File '") + hf + L"' is not found or empty."; return false; } pos = code_h.find(tag); if (pos == std::wstring::npos) { if (msg) *msg = L"Cannot find tag '" + tag + L"' in file " + hf; return false; } bgn = l = code_h.c_str() + pos; to_line_head(&bgn); bgn++; val = L"\r\n" + std::wstring(bgn, l - bgn) + L"SANE_OPTION_ID(" + a2u(twain.id_key.c_str()) + L");"; code_h.insert(pos + tag.length(), val + L"\t\t// " + now() + L" " + sane.title); if (save_file(hf.c_str(), code_h.c_str(), bom_h, &hbak)) { code_h.clear(); pos = code_c.find(L"SANE_OPTION_ID_IMPLEMENT("); if (pos != std::wstring::npos) { int off = 0; val = L"SANE_OPTION_ID_IMPLEMENT(" + a2u(twain.id_key.c_str()) + L")\r\n"; code_c.insert(pos, val); code_h = code_c; if (pick_option_id_function(code_h, &off)) { pos = code_h.find(L"op_id++;"); if (pos != std::wstring::npos) { l = bgn = code_h.c_str() + pos; to_line_head(&bgn); bgn++; tag = sane.name_key; if (tag.find(L"SANE_STD_OPT_NAME_") == 0) tag.erase(0, lstrlenW(L"SANE_STD_OPT_NAME_")); val = std::wstring(bgn, l - bgn) + L"else SET_OPT_ID(" + a2u(twain.id_key.c_str()) + L", " + tag + L", extension_none)\r\n"; off += bgn - code_h.c_str(); code_c.insert(off, val); if (save_file(cpp, code_c.c_str(), bom_c, &cbak)) { std::wstring s2t(hf); STR_PARENT_FOLDER(s2t); s2t += L"\\s2t_api.h"; code_h = std::move(load_file(s2t.c_str(), &bom_h)); if (!code_h.empty()) { tag = L"// SANE options ID ..."; pos = code_h.find(tag); if (pos == std::wstring::npos) { if (msg) *msg = L"Cannot find tag '// SANE options ID ...' in file " + s2t; return false; } bgn = l = code_h.c_str() + pos; to_line_head(&bgn); bgn++; val = L"\r\n" + std::wstring(bgn, l - bgn) + L"SANE_OPTION_ID_API(" + a2u(twain.id_key.c_str()) + L");"; code_h.insert(pos + tag.length(), val + L"\t\t// " + now() + L" " + sane.title); if (save_file(s2t.c_str(), code_h.c_str(), bom_h, &val)) { if (msg) *msg += std::wstring(L"Changed: ") + hf + L"\r\n" + L"Changed: " + cpp + L"\r\nChanged: " + s2t + L"\r\n"; return true; } else if (msg) *msg = L"Failed to save changes into file: " + s2t; if (file_util::is_file_existing(val.c_str())) file_util::force_move_file(val.c_str(), s2t.c_str()); } else if (msg) *msg = std::wstring(L"File '") + s2t + L"' is not found or empty."; } else if (msg) { *msg = L"Failed to save changes into file: " + std::wstring(cpp); } if (file_util::is_file_existing(cbak.c_str())) file_util::force_move_file(cbak.c_str(), cpp); } else if (msg) { *msg = L"Failed to find function 'scanner::init_options_id(void) - op_id++' in file: " + std::wstring(cpp); } } else if (msg) { *msg = L"Failed to find function 'scanner::init_options_id(void)' in file: " + std::wstring(cpp); } } else if (msg) { *msg = L"Failed to find 'SANE_OPTION_ID_IMPLEMENT' in file: " + std::wstring(cpp); } } else if (msg) { *msg = L"Failed to save changes into file: " + hf; } if (file_util::is_file_existing(hbak.c_str())) file_util::force_move_file(hbak.c_str(), hf.c_str()); return false; } } // CDlgTwain dialog IMPLEMENT_DYNAMIC(CDlgTwain, CDialogEx) CDlgTwain::CDlgTwain(CWnd* pParent /*=NULL*/) : CDialogEx(CDlgTwain::IDD, pParent) { } CDlgTwain::~CDlgTwain() { } void CDlgTwain::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO1, sane_); } BOOL CDlgTwain::OnInitDialog() { CDialogEx::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog return TRUE; // return TRUE unless you set the focus to a control } void CDlgTwain::on_sln_path_changed(void) { GetDlgItem(IDC_BUTTON_BROWSE)->EnableWindow(FALSE); GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE); GetDlgItem(IDC_COMBO1)->EnableWindow(FALSE); util::append_log(L"parsing SANE attributes ...\r\n", GetDlgItem(IDC_EDIT2)->m_hWnd, true); sane_.ResetContent(); std::wstring path(util::get_text(GetDlgItem(IDC_EDIT1)->m_hWnd)); opts_.clear(); used_.clear(); STR_PARENT_FOLDER(path); path += L"\\..\\..\\"; STR_TO_ABSOLUTE_PATH(path); root_ = path; util::get_sane_opts((path + L"sdk\\include\\sane\\sane_ex.h").c_str(), opts_); if (opts_.size() == 0) { ::MessageBoxW(m_hWnd, L"没有找到SANE属性定义。", L"错误", MB_OK | MB_ICONSTOP); return; } for (auto& v : opts_) sane_.AddString((v.title + L" (" + v.name + L")").c_str()); GetDlgItem(IDC_BUTTON_BROWSE)->EnableWindow(TRUE); GetDlgItem(IDC_COMBO1)->EnableWindow(TRUE); GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE); util::append_log((L"Found " + std::to_wstring(opts_.size()) + L" options\r\n").c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true); // find used ... util::get_used_opts((path + L"code_twain\\sane\\scanner.cpp").c_str(), used_); } void CDlgTwain::synchronize_opt(const SANEOPT& opt) { OPTUSED ou; std::wstring pre(L"SANE_STD_OPT_NAME_"), key(L""), msg(L""); if (used_.size()) ou.id = used_[used_.size() - 1].id + 1; else ou.id = 0x8801; ou.name_key = opt.name_key; if (ou.name_key.find(pre) == 0) key = ou.name_key.substr(pre.length()); else key = ou.name_key; std::transform(key.begin(), key.end(), key.begin(), tolower); coding_util::unicode_2_ansi(key.c_str(), util::got_str, &ou.id_key); std::vector::iterator it = std::find(used_.begin(), used_.end(), ou.id_key.c_str()); if (it != used_.end()) { ::MessageBoxW(m_hWnd, (opt.title + L" already synchronized into TWAIN.").c_str(), L"Error", MB_OK | MB_ICONINFORMATION); return; } if (util::add_2_huagaods_cpp((root_ + L"code_twain\\twain\\twain\\huagaods.cpp").c_str(), opt, ou, &msg) && util::add_2_scanner_codes((root_ + L"code_twain\\sane\\scanner.cpp").c_str(), opt, ou, &msg)) { used_.push_back(ou); std::wstring tips(L"Added New TWAIN extended ATTR: CAP_EX_SANE_"); wchar_t hex[40] = { 0 }; coding_util::ansi_2_unicode(ou.id_key.c_str(), util::got_wstr, &tips); swprintf_s(hex, _countof(hex) - 1, L" (ID: 0x%04x) - ", ou.id); tips += hex + opt.title + L"\r\n"; util::append_log(tips.c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true); } util::append_log(msg.c_str(), GetDlgItem(IDC_EDIT2)->m_hWnd, true); } BEGIN_MESSAGE_MAP(CDlgTwain, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CDlgTwain::OnBnClickedButtonBrowse) ON_BN_CLICKED(IDC_BUTTON_ADD, &CDlgTwain::OnBnClickedButtonAdd) END_MESSAGE_MAP() // CDlgTwain message handlers void CDlgTwain::OnBnClickedButtonBrowse() { // TODO: 在此添加控件通知处理程序代码 file_util::PATHFILE path = { 0 }; if (file_util::browser_file(m_hWnd, &path, L"Solution File(*.sln)\0\0")) { ::SetDlgItemTextW(m_hWnd, IDC_EDIT1, path.path); on_sln_path_changed(); } } void CDlgTwain::OnBnClickedButtonAdd() { // TODO: 在此添加控件通知处理程序代码 std::wstring text(util::get_text(sane_.m_hWnd)); std::string ansi(""); size_t pos = text.rfind(L'('); if (pos++ == std::wstring::npos) { ::MessageBoxW(m_hWnd, L"Invalid option name! (lost '()')", L"Error", MB_OK | MB_ICONSTOP); return; } text.erase(0, pos); pos = text.find(L")"); if (pos != std::wstring::npos) text.erase(pos); if (text.empty()) { ::MessageBoxW(m_hWnd, L"Invalid option name! (empty)", L"Error", MB_OK | MB_ICONSTOP); return; } coding_util::unicode_2_ansi(text.c_str(), util::got_str, &ansi); pos = sane_.GetCurSel(); synchronize_opt(opts_[pos]); }