From 73a5ea2cce4798f34d5fc7330b2c96a7bd110746 Mon Sep 17 00:00:00 2001 From: gb <741021719@qq.com> Date: Fri, 24 Feb 2023 16:55:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/apps/hgjson/DlgTwain.cpp | 886 +++++++++++++++++++++++++++++++++ tools/apps/hgjson/DlgTwain.h | 66 +++ 2 files changed, 952 insertions(+) create mode 100644 tools/apps/hgjson/DlgTwain.cpp create mode 100644 tools/apps/hgjson/DlgTwain.h diff --git a/tools/apps/hgjson/DlgTwain.cpp b/tools/apps/hgjson/DlgTwain.cpp new file mode 100644 index 0000000..54d8a0a --- /dev/null +++ b/tools/apps/hgjson/DlgTwain.cpp @@ -0,0 +1,886 @@ +// 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]); +} diff --git a/tools/apps/hgjson/DlgTwain.h b/tools/apps/hgjson/DlgTwain.h new file mode 100644 index 0000000..c32be1c --- /dev/null +++ b/tools/apps/hgjson/DlgTwain.h @@ -0,0 +1,66 @@ +#pragma once + + +// CDlgTwain dialog +#include +#include + + +typedef struct _san_opt +{ + std::wstring name_key; + std::wstring name; + std::wstring title_key; + std::wstring title; +}SANEOPT; +typedef struct _opt_used +{ + std::wstring name_key; // same as SANEOPT::name_key + std::string id_key; + int id; // ID of CAP_SANE_EX_xxx + + bool operator==(const wchar_t* key) + { + return name_key == key; + } + bool operator==(const char* key) + { + return id_key == key; + } + bool operator==(const int eid) + { + return eid == id; + } + bool operator<(const struct _opt_used& r) + { + return id < r.id; + } +}OPTUSED; + +class CDlgTwain : public CDialogEx +{ + DECLARE_DYNAMIC(CDlgTwain) + +public: + CDlgTwain(CWnd* pParent = NULL); // standard constructor + virtual ~CDlgTwain(); + +// Dialog Data + enum { IDD = IDD_ADD_TWAIN_ATTR }; + + std::vector opts_; + std::vector used_; + std::wstring root_; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + void on_sln_path_changed(void); + void synchronize_opt(const SANEOPT& opt); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButtonBrowse(); + afx_msg void OnBnClickedButtonAdd(); + CComboBox sane_; +};