diff --git a/sane/DlgSetting.cpp b/sane/DlgSetting.cpp index a670633..bd709fc 100644 --- a/sane/DlgSetting.cpp +++ b/sane/DlgSetting.cpp @@ -545,9 +545,12 @@ void dlg_setting::save_changes_to_cur_scheme(int reason) if (changed) { dlg_save_scheme dlg(hwnd()); - + std::wstring sug(L""); + + sug = local_trans::a2u(twain_schm_->auto_gen_scheme_name(local_trans::lang_trans_between_hz936, nullptr, false).c_str(), CP_UTF8); dlg.set_info(local_trans::a2u(twain_schm_->get_scheme_name().c_str(), CP_UTF8).c_str(), now - , SAVE_METHOD_MASK(SAVE_DISCARD) | SAVE_METHOD_MASK(SAVE_NEW)); + , SAVE_METHOD_MASK(SAVE_DISCARD) | SAVE_METHOD_MASK(SAVE_NEW), + sug.c_str()); dlg.do_modal(hwnd()); if(dlg.get_dispose() == SAVE_NEW) { diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 208ae8c..e7ebfff 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -333,7 +333,7 @@ scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BAS , dpi_(200), tmp_path_(L""), img_ind_(0) , scanner_name_(L""), cfg_(NULL), is_ui_wait_img_(false), is_scanning_(false) , scanner_ev_handler_(NULL), evh_param_(NULL), app_wnd_(NULL), user_cancel_(false) - , max_img_mem_(1 * 1024), twain_set_(false) + , max_img_mem_(1 * 1024), twain_set_(false), ev_cnt_(0) { cfg_ = new gb::scanner_cfg(); cfg_->set_language_transform(&callback::language_trans, NULL); @@ -624,41 +624,41 @@ void scanner::on_ui_event(int uev, void* sender) if (indicator) indicator_.reset(); + is_scanning_ = false; if (err_ && setting_.get()) { return; } - is_scanning_ = false; } - int(__stdcall * h)(int, void*) = scanner_ev_handler_; - if (h) - { - if (SANE_EVENT_UI_CLOSE_SETTING == uev) - { - is_scanning_ = false; - setting_.reset(); - } + //int(__stdcall * h)(int, void*) = scanner_ev_handler_; + //if (h) + //{ + // if (SANE_EVENT_UI_CLOSE_SETTING == uev) + // { + // is_scanning_ = false; + // setting_.reset(); + // } - h(uev, evh_param_); - return; - } + // h(uev, evh_param_); + // return; + //} - if (prev_start_result_ != SANE_STATUS_GOOD && indicator) - indicator_.reset(); - else + //if (prev_start_result_ != SANE_STATUS_GOOD && indicator) + // indicator_.reset(); + //else { - if (uev == SANE_EVENT_UI_SCAN_COMMAND) - { - ui_show_progress(NULL); - start(); - return; - } + //if (uev == SANE_EVENT_UI_SCAN_COMMAND) + //{ + // ui_show_progress(NULL); + // start(); + // return; + //} if (/*events_.count() > 5 && !is_ui_wait_img_ &&*/ (uev == SANE_EVENT_UI_CLOSE_CANCEL || uev == SANE_EVENT_UI_CLOSE_NORMAL || uev == SANE_EVENT_UI_CLOSE_SETTING)) { - events_.clear(); + // events_.clear(); ui_hide(); if(indicator || !indicator_.get()) uev = SANE_EVENT_SCAN_FINISHED; @@ -667,6 +667,21 @@ void scanner::on_ui_event(int uev, void* sender) } events_.save(uev, sizeof(uev)); + ev_cnt_++; + } + + if (ev_cnt_ == events_.count() && + (ev_cnt_ >= 5 || (ev_cnt_ > 1 && !is_scanning_))) + { + // maybe no event has been handled by APP, triggered by callback + int(__stdcall * h)(int, void*) = scanner_ev_handler_; + if (h) + { + wchar_t info[128] = { 0 }; + swprintf_s(info, _countof(info) - 1, L"[CRAZY]%d scanner events stored but APP has no action, we try to trigger it ONCE ...\r\n", ev_cnt_); + ev_cnt_--; + h(events_.take(), evh_param_); + } } } std::string scanner::choose_scanner(const std::vector& scanners) @@ -2261,6 +2276,7 @@ COM_API_IMPLEMENT(scanner, int, start(void)) { int ret = SANE_STATUS_GOOD; + ev_cnt_ = 0; events_.clear(); images_.clear(); scan_msg_ = "OK"; diff --git a/sane/scanner.h b/sane/scanner.h index 4c83890..f6df115 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -50,6 +50,7 @@ class scanner : public ISaneInvoker, virtual public refer safe_img_queue images_; size_t max_img_mem_; safe_queue events_; //如果有界面,则全部保存从界面传回的消息;否则只保存开始扫描和结束扫描的事件 + int ev_cnt_; SANE_FinalImgFormat img_fmt_; std::unique_ptr indicator_; std::unique_ptr setting_; diff --git a/twain/load_sane.cpp b/twain/load_sane.cpp index 38ef566..9660d61 100644 --- a/twain/load_sane.cpp +++ b/twain/load_sane.cpp @@ -181,8 +181,14 @@ namespace load_sane_util } void uninitialize(void) { + sane_inst = NULL; + is_on = NULL; + init = NULL; + log = NULL; + if (uninit) uninit(NULL); + uninit = NULL; if (sane_module) { diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index e575f53..a5b9855 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -161,6 +161,191 @@ TWPP_ENTRY(huagao_ds) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // utilites ... // some helper functions to handle capability stuff +#define RETURN_ENUM_DESC(en, v, space) \ + if(v == space::en) \ + return L###en; + +const wchar_t* desc_state(DsState s, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Closed, s, DsState); + RETURN_ENUM_DESC(Open, s, DsState); + RETURN_ENUM_DESC(Enabled, s, DsState); + RETURN_ENUM_DESC(XferReady, s, DsState); + RETURN_ENUM_DESC(Xferring, s, DsState); + + swprintf(unk, L"%d", s); + + return unk; +} +const wchar_t* desc_data_group(DataGroup d, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Control, d, DataGroup); + RETURN_ENUM_DESC(Image, d, DataGroup); + RETURN_ENUM_DESC(Audio, d, DataGroup); + + { + swprintf(unk, L"%d", d); + + return unk; + } +} +const wchar_t* desc_data(Dat d, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Null, d, Dat); + RETURN_ENUM_DESC(Capability, d, Dat); + RETURN_ENUM_DESC(Event, d, Dat); + RETURN_ENUM_DESC(Identity, d, Dat); + RETURN_ENUM_DESC(Parent, d, Dat); + RETURN_ENUM_DESC(PendingXfers, d, Dat); + RETURN_ENUM_DESC(SetupMemXfer, d, Dat); + RETURN_ENUM_DESC(SetupFileXfer, d, Dat); + RETURN_ENUM_DESC(Status, d, Dat); + RETURN_ENUM_DESC(UserInterface, d, Dat); + RETURN_ENUM_DESC(XferGroup, d, Dat); + RETURN_ENUM_DESC(CustomData, d, Dat); + RETURN_ENUM_DESC(DeviceEvent, d, Dat); + RETURN_ENUM_DESC(FileSystem, d, Dat); + RETURN_ENUM_DESC(PassThrough, d, Dat); + RETURN_ENUM_DESC(Callback, d, Dat); + RETURN_ENUM_DESC(StatusUtf8, d, Dat); + RETURN_ENUM_DESC(Callback2, d, Dat); + RETURN_ENUM_DESC(ImageInfo, d, Dat); + RETURN_ENUM_DESC(ImageLayout, d, Dat); + RETURN_ENUM_DESC(ImageMemXfer, d, Dat); + RETURN_ENUM_DESC(ImageNativeXfer, d, Dat); + RETURN_ENUM_DESC(ImageFileXfer, d, Dat); + RETURN_ENUM_DESC(CieColor, d, Dat); + RETURN_ENUM_DESC(GrayResponse, d, Dat); + RETURN_ENUM_DESC(RgbResponse, d, Dat); + RETURN_ENUM_DESC(JpegCompression, d, Dat); + RETURN_ENUM_DESC(Palette8, d, Dat); + RETURN_ENUM_DESC(ExtImageInfo, d, Dat); + RETURN_ENUM_DESC(Filter, d, Dat); + RETURN_ENUM_DESC(AudioFileXfer, d, Dat); + RETURN_ENUM_DESC(AudioInfo, d, Dat); + RETURN_ENUM_DESC(AudioNativeXfer, d, Dat); + RETURN_ENUM_DESC(IccProfile, d, Dat); + RETURN_ENUM_DESC(ImageMemFileXfer, d, Dat); + RETURN_ENUM_DESC(EntryPoint, d, Dat); + + { + swprintf(unk, L"%d", d); + + return unk; + } +} +const wchar_t* desc_msg(Msg m, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Null, m, Msg); + RETURN_ENUM_DESC(Get, m, Msg); + RETURN_ENUM_DESC(GetCurrent, m, Msg); + RETURN_ENUM_DESC(GetDefault, m, Msg); + RETURN_ENUM_DESC(GetFirst, m, Msg); + RETURN_ENUM_DESC(GetNext, m, Msg); + RETURN_ENUM_DESC(Set, m, Msg); + RETURN_ENUM_DESC(Reset, m, Msg); + RETURN_ENUM_DESC(QuerySupport, m, Msg); + RETURN_ENUM_DESC(GetHelp, m, Msg); + RETURN_ENUM_DESC(GetLabel, m, Msg); + RETURN_ENUM_DESC(GetLabelEnum, m, Msg); + RETURN_ENUM_DESC(SetConstraint, m, Msg); + RETURN_ENUM_DESC(XferReady, m, Msg); + RETURN_ENUM_DESC(CloseDsReq, m, Msg); + RETURN_ENUM_DESC(CloseDsOk, m, Msg); + RETURN_ENUM_DESC(DeviceEvent, m, Msg); + RETURN_ENUM_DESC(OpenDsm, m, Msg); + RETURN_ENUM_DESC(CloseDsm, m, Msg); + RETURN_ENUM_DESC(OpenDs, m, Msg); + RETURN_ENUM_DESC(CloseDs, m, Msg); + RETURN_ENUM_DESC(UserSelect, m, Msg); + RETURN_ENUM_DESC(DisableDs, m, Msg); + RETURN_ENUM_DESC(EnableDs, m, Msg); + RETURN_ENUM_DESC(EnableDsUiOnly, m, Msg); + RETURN_ENUM_DESC(ProcessEvent, m, Msg); + RETURN_ENUM_DESC(EndXfer, m, Msg); + RETURN_ENUM_DESC(StopFeeder, m, Msg); + RETURN_ENUM_DESC(ChangeDir, m, Msg); + RETURN_ENUM_DESC(CreateDir, m, Msg); + RETURN_ENUM_DESC(Delete, m, Msg); + RETURN_ENUM_DESC(FormatMedia, m, Msg); + RETURN_ENUM_DESC(GetClose, m, Msg); + RETURN_ENUM_DESC(GetFirstFile, m, Msg); + RETURN_ENUM_DESC(GetInfo, m, Msg); + RETURN_ENUM_DESC(GetNextFile, m, Msg); + RETURN_ENUM_DESC(Rename, m, Msg); + RETURN_ENUM_DESC(Copy, m, Msg); + RETURN_ENUM_DESC(AutomaticCaptureDir, m, Msg); + RETURN_ENUM_DESC(PassThrough, m, Msg); + RETURN_ENUM_DESC(RegisterCallback, m, Msg); + RETURN_ENUM_DESC(ResetAll, m, Msg); + RETURN_ENUM_DESC(CustomBase, m, Msg); + + + { + swprintf(unk, L"%d", m); + + return unk; + } +} +const wchar_t* desc_return_code(ReturnCode rc, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Success, rc, ReturnCode); + RETURN_ENUM_DESC(Failure, rc, ReturnCode); + RETURN_ENUM_DESC(CheckStatus, rc, ReturnCode); + RETURN_ENUM_DESC(Cancel, rc, ReturnCode); + RETURN_ENUM_DESC(DsEvent, rc, ReturnCode); + RETURN_ENUM_DESC(NotDsEvent, rc, ReturnCode); + RETURN_ENUM_DESC(XferDone, rc, ReturnCode); + RETURN_ENUM_DESC(EndOfList, rc, ReturnCode); + RETURN_ENUM_DESC(InfoNotSupported, rc, ReturnCode); + RETURN_ENUM_DESC(DataNotAvailable, rc, ReturnCode); + RETURN_ENUM_DESC(Busy, rc, ReturnCode); + RETURN_ENUM_DESC(ScannerLocked, rc, ReturnCode); + + { + swprintf(unk, L"%d", rc); + + return unk; + } +} +const wchar_t* desc_condition_code(ConditionCode c, wchar_t unk[20]) +{ + RETURN_ENUM_DESC(Success, c, ConditionCode); + RETURN_ENUM_DESC(Bummer, c, ConditionCode); + RETURN_ENUM_DESC(LowMemory, c, ConditionCode); + RETURN_ENUM_DESC(NoDs, c, ConditionCode); + RETURN_ENUM_DESC(MaxConnections, c, ConditionCode); + RETURN_ENUM_DESC(OperationError, c, ConditionCode); + RETURN_ENUM_DESC(BadCap, c, ConditionCode); + RETURN_ENUM_DESC(BadProtocol, c, ConditionCode); + RETURN_ENUM_DESC(BadValue, c, ConditionCode); + RETURN_ENUM_DESC(SeqError, c, ConditionCode); + RETURN_ENUM_DESC(BadDest, c, ConditionCode); + RETURN_ENUM_DESC(CapUnsupported, c, ConditionCode); + RETURN_ENUM_DESC(CapBadOperation, c, ConditionCode); + RETURN_ENUM_DESC(CapSeqError, c, ConditionCode); + RETURN_ENUM_DESC(Denied, c, ConditionCode); + RETURN_ENUM_DESC(FileExists, c, ConditionCode); + RETURN_ENUM_DESC(FileNotFound, c, ConditionCode); + RETURN_ENUM_DESC(NotEmpty, c, ConditionCode); + RETURN_ENUM_DESC(PaperJam, c, ConditionCode); + RETURN_ENUM_DESC(PaperDoubleFeed, c, ConditionCode); + RETURN_ENUM_DESC(FileWriteError, c, ConditionCode); + RETURN_ENUM_DESC(CheckDeviceOnline, c, ConditionCode); + RETURN_ENUM_DESC(InterLock, c, ConditionCode); + RETURN_ENUM_DESC(DamagedCorner, c, ConditionCode); + RETURN_ENUM_DESC(FocusError, c, ConditionCode); + RETURN_ENUM_DESC(DocTooLight, c, ConditionCode); + RETURN_ENUM_DESC(DocTooDark, c, ConditionCode); + RETURN_ENUM_DESC(NoMedia, c, ConditionCode); + + { + swprintf(unk, L"%d", c); + + return unk; + } +} + template static Result oneValGet(Msg msg, Capability& data, const T& value) { switch (msg) { @@ -668,7 +853,7 @@ static const SCANNERID scanner_guid = MAKE_SCANNER_ID(PRODUCT_PID, PRODUCT_VID); static std::once_flag oc; -huagao_ds::huagao_ds() : cur_head_(NULL), dpi_(200) +huagao_ds::huagao_ds() : cur_head_(NULL), dpi_(200), xfer_ready_failed_(false), log_all_triple_(false), scanner_status_(SCANNER_STATUS_NOT_INIT) { //std::call_once(oc, [&]() { log4cplus::Initializer(); }); } @@ -707,7 +892,7 @@ void huagao_ds::showmsg(const char* msg, int err) } int __stdcall huagao_ds::on_scanner_event(int ev, void* param) { - return ((huagao_ds*)param)->handle_scanner_event(ev); + return ((huagao_ds*)param)->handle_scanner_event(ev, false); } const Identity& huagao_ds::defaultIdentity() noexcept { @@ -866,10 +1051,12 @@ Result huagao_ds::identityOpenDs(const Identity& id) cur_head_ = new SANE_Parameters; memset(cur_head_, 0, sizeof(SANE_Parameters)); } + log_all_triple_ = get_config_number(L"twain-app", L"log-all-triple") == 1; m_compression = Compression::None; init_support_caps(); m_fileXfer.setFormat(ImageFileFormat::Bmp); + scanner_status_ = SCANNER_STATUS_READY; return success(); } @@ -887,6 +1074,7 @@ Result huagao_ds::identityCloseDs(const Identity&) singleton_ = NULL; } load_sane_util::uninitialize(); + scanner_status_ = SCANNER_STATUS_NOT_INIT; return success(); } @@ -895,7 +1083,7 @@ Result huagao_ds::pendingXfersGet(const Identity&, PendingXfers& data) if (!scanner_.get()) return seqError(); - data.setCount(scanner_->get_scanned_images(-1)); + data.setCount(get_scanned_image_count(-1)); return success(); } Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data) @@ -905,7 +1093,7 @@ Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data) Result huagao_ds::pendingXfersReset(const Identity&, PendingXfers& data) { pending_xfer_.clear(); - data.setCount(scanner_->get_scanned_images(-1)); + data.setCount(get_scanned_image_count(-1)); return success(); } @@ -915,7 +1103,7 @@ Result huagao_ds::setupMemXferGet(const Identity& id, SetupMemXfer& data) size_t total = 0; DWORD to = cur_head_ ? -1 : 0; - if (!scanner_.get() || scanner_->get_scanned_images(to) == 0) + if (!scanner_.get() || get_scanned_image_count(to) == 0) { if (cur_head_) { @@ -969,7 +1157,10 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui) if (m_bIndicator && !scanner_->ui_show_progress((HWND)ui.parent().raw())) return seqError(); + xfer_ready_failed_ = false; scanner_->twain_set_transfer((twain_xfer)m_capXferMech); + scanner_status_ = SCANNER_STATUS_SCAN_1; + app_trigger_event_ = false; int err = scanner_->start(); if (err == SCANNER_ERR_OK) { @@ -977,6 +1168,7 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui) } else { + scanner_status_ = SCANNER_STATUS_READY; // if (err == SCANNER_ERR_DEVICE_NO_PAPER) return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) }; @@ -1045,7 +1237,7 @@ Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data) { if (!scanner_->wait_image()) { - notifyCloseOk(); + // notifyCloseOk(); return success(); // ÷Ҫسɹ } ok = scanner_->get_first_image_header(&head, NULL, &res); @@ -1091,8 +1283,10 @@ Result huagao_ds::imageLayoutGet(const Identity&, ImageLayout& data) { SANE_Parameters head = { 0 }; - if (!scanner_.get() || scanner_->get_scanned_images(-1) == 0) + if (!scanner_.get()) return seqError(); + else if(get_scanned_image_count(-1) == 0) + return { ReturnCode::XferDone, ConditionCode::Success }; int res = 200; @@ -1126,13 +1320,15 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) if (!scanner_.get()) return seqError(); - if (scanner_->get_scanned_images(-1) == 0 && !pending_xfer_.img) + if (get_scanned_image_count(-1) == 0 && !pending_xfer_.img) { - if (!cur_head_ || !scanner_->wait_image()) - { - notifyCloseOk(); - return seqError(); - } + //if (!cur_head_ || !scanner_->wait_image()) + //{ + // notifyCloseOk(); + // return seqError(); + //} + + return { ReturnCode::XferDone, ConditionCode::Success }; } IScanImg *img = pending_xfer_.img ? pending_xfer_.img : scanner_->take_first_image(TWAIN_XFER_Memory); @@ -1205,8 +1401,10 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) } Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) { - if (!scanner_.get() || scanner_->get_scanned_images(-1) == 0) + if (!scanner_.get()) return seqError(); + else if(get_scanned_image_count(-1) == 0) + return { ReturnCode::XferDone, ConditionCode::Success }; IScanImg* img = scanner_->take_first_image(TWAIN_XFER_Native); @@ -1244,8 +1442,10 @@ Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXf Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin) { // assume that the file format has set before start-scanning, so we write-down the image content to file directly here ... - if (!scanner_.get() || scanner_->get_scanned_images(-1) == 0) + if (!scanner_.get()) return seqError(); + else if(get_scanned_image_count(-1) == 0) + return { ReturnCode::XferDone, ConditionCode::Success }; IScanImg* img = scanner_->take_first_image(TWAIN_XFER_File); Twpp::Result ret = seqError(); @@ -1410,14 +1610,19 @@ Result huagao_ds::call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, v try { // we can override almost anything from SourceFromThis, even the top-most source instance call //FileTools::write_log("D:\\1.txt", "call:datagroup-"+to_string((int)dg)+"dat-"+to_string(int(dat))+"msg-"+to_string(int(msg))); - if (dat == Dat::ImageNativeXfer && state() == DsState::Enabled) // ľɨ˲״̬ı䣬ֱȡͼ˴һ״̬ 2022-11-07 + Result rt; + + trigger_ProcessEvent(dg, dat, msg); // some APPs may be not trigger (Control, Event, ProcessEvent), we help them :( ... // ľɨ˲״̬ı䣬ֱȡͼ˴һ״̬ 2022-11-07 + + rt = Base::call(origin, dg, dat, msg, data); + if(log_all_triple_ || (int)rt.returnCode()) { - load_sane_util::log_info(L"APP SEQ ERROR: fetch image while status in 'Enabled' yet! we change it to 'XferReady' manually.\r\n", 0); - - notifyXferReady(); + wchar_t buf[128] = { 0 }, dgs[20] = { 0 }, dts[20] = { 0 }, ms[20] = { 0 }, ss[20] = { 0 }, rcs[20] = { 0 }, cs[20] = { 0 }; + swprintf_s(buf, _countof(buf) - 1, L"[%x - %s]DSEntry(%s, %s, %s) = {%s, %s}\r\n", GetCurrentThreadId(), desc_state(state(), ss), + desc_data_group(dg, dgs), desc_data(dat, dts), desc_msg(msg, ms), desc_return_code(rt, rcs), desc_condition_code((ConditionCode)(Status)rt, cs)); + load_sane_util::log_info(buf, 0); } - - return Base::call(origin, dg, dat, msg, data); + return rt; } catch (const CapabilityException& e) { //FileTools::writelog(log_ERROR, e.what()); @@ -3085,31 +3290,53 @@ void huagao_ds::init_support_caps_ex(void) } std::wstring huagao_ds::get_config_file(void) { - wchar_t path[MAX_PATH] = { 0 }, * name = NULL; + char* tmp = getenv("LOCALAPPDATA"); + if (tmp) + { + std::wstring str(L""); + std::string path(tmp); - GetModuleFileNameW(me_, path, _countof(path) - 1); - name = wcsrchr(path, L'\\'); - if (name++ == NULL) - name = path; - wcscpy_s(name, _countof(path) - 1 - (name - path), L"first.cfg"); + path += std::string("\\") + PRODUCT_VENDOR + "Scan\\config\\debug.cfg"; - return path; + return std::move(load_sane_util::ansi2unic(path.c_str())); + } + else + { + wchar_t path[MAX_PATH] = { 0 }, * name = NULL; + + GetModuleFileNameW(me_, path, _countof(path) - 1); + name = wcsrchr(path, L'\\'); + if (name++ == NULL) + name = path; + wcscpy_s(name, _countof(path) - 1 - (name - path), L"debug.cfg"); + + return path; + } } std::wstring huagao_ds::get_config_value(const wchar_t* sec, const wchar_t* key) { wchar_t v[256] = { 0 }; + std::wstring cfg_f(get_config_file()); - GetPrivateProfileStringW(sec, key, L"", v, _countof(v) - 1, get_config_file().c_str()); + if(!cfg_f.empty()) + GetPrivateProfileStringW(sec, key, L"", v, _countof(v) - 1, get_config_file().c_str()); return v; } DWORD huagao_ds::get_config_number(const wchar_t* sec, const wchar_t* key) { - return GetPrivateProfileIntW(sec, key, 0, get_config_file().c_str()); + std::wstring cfg_f(get_config_file()); + + if (cfg_f.empty()) + return 0; + else + return GetPrivateProfileIntW(sec, key, 0, get_config_file().c_str()); } -int huagao_ds::handle_scanner_event(int ev) +int huagao_ds::handle_scanner_event(int ev, bool from_event_proc) { static int count_0 = 0; + ReturnCode rc = ReturnCode::Success; + int ret = 0; if (ev == 0) count_0++; @@ -3117,41 +3344,149 @@ int huagao_ds::handle_scanner_event(int ev) { wchar_t msg[128] = { 0 }; if (count_0) - swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x0 +%d)\r\nds::eventProcess(0x%x)\r\n", count_0, ev); + swprintf_s(msg, _countof(msg) - 1, L"[%x]handle_scanner_event(0x0 +%d)\r\nds::eventProcess(0x%x)\r\n", GetCurrentThreadId(), count_0, ev); else - swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x%x)\r\n", ev); + swprintf_s(msg, _countof(msg) - 1, L"[%x]handle_scanner_event(0x%x)\r\n", GetCurrentThreadId(), ev); load_sane_util::log_info(msg, 0); count_0 = 0; } switch (ev) { case SANE_EVENT_WORKING: - notifyXferReady(); + scanner_status_ = SCANNER_STATUS_SCANNING; + rc = notifyXferReady(); + if (!Twpp::success(rc)) + { + wchar_t msg[128] = { 0 }; + swprintf_s(msg, _countof(msg) - 1, L"[%x]Warning: change state to XferReady failed with error %d while in state(%d), STOP scanning ...\r\n", GetCurrentThreadId(), rc, state()); + load_sane_util::log_info(msg, 0); + + // we stop scanning here ... + scanner_->stop(); + } break; case SANE_EVENT_UI_CLOSE_CANCEL: scanner_->stop(); - // notifyEndWithoutImages(); - notifyCloseCancel(); // ޸ȿ"ȡ"ťUIBUG - added on 2023-02-14 - break; + //notifyCloseCancel(); // ޸ȿ"ȡ"ťUIBUG - added on 2023-02-14 + //break; case SANE_EVENT_UI_CLOSE_NORMAL: scanner_->ui_hide(); case SANE_EVENT_SCAN_FINISHED: + scanner_status_ = SCANNER_STATUS_STOPPED; //notifyCloseOk(); //break; case SANE_EVENT_UI_CLOSE_SETTING: - if(m_bIndicator) - notifyCloseCancel(); - else - notifyXferReady(); // ÷Ҫ֪ͨ FAINT :( - modified on 2022-10-20 + notifyCloseCancel(); + if (ev == SANE_EVENT_UI_CLOSE_SETTING) + { + rc = notifyXferReady(); // ÷Ҫ֪ͨ FAINT :( - modified on 2022-10-20 + if (!Twpp::success(rc)) + { + wchar_t msg[128] = { 0 }, unk[20] = { 0 }; + swprintf_s(msg, _countof(msg) - 1, L"[%x]yscan: notifyXferReady failed after setting UI closed with error %d\r\n", GetCurrentThreadId(), rc); + load_sane_util::log_info(msg, 0); + } + } break; case SANE_EVENT_UI_SCAN_COMMAND: - scanner_->ui_show_progress(NULL); - scanner_->start(); + if (m_bIndicator) + scanner_->ui_show_progress(NULL); + else + scanner_->ui_hide(); + scanner_status_ = SCANNER_STATUS_SCAN_1; + app_trigger_event_ = false; + if ((ret = scanner_->start())) + { + wchar_t msg[128] = { 0 }, unk[20] = { 0 }; + swprintf_s(msg, _countof(msg) - 1, L"[%x - %s]Fatal: start scanning from setting UI failed with error %d\r\n", GetCurrentThreadId(), desc_state(state(), unk), ret); + load_sane_util::log_info(msg, 0); + + scanner_status_ = SCANNER_STATUS_STOPPED; + rc = notifyCloseCancel(); + if (Twpp::success(rc)) + { + scanner_status_ = SCANNER_STATUS_READY; + } + else + { + swprintf_s(msg, _countof(msg) - 1, L"[%x]Warning: notifyCloseCancel failed with error %d after start scanning failed\r\n", GetCurrentThreadId(), rc, state()); + load_sane_util::log_info(msg, 0); + } + } break; } return 0; } +int huagao_ds::get_scanned_image_count(DWORD timeout) +{ + int cnt = scanner_->get_scanned_images(timeout); + //if (cnt == -1) + //{ + // // This is a special value indicates the scanning is over + // cnt = 0; + // scanner_->ui_hide(); + // notifyCloseCancel(); + //} + return cnt; +} +void huagao_ds::trigger_ProcessEvent(Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg) +{ + ReturnCode rc; + + if (state() == DsState::Enabled && scanner_status_ >= SCANNER_STATUS_SCAN_1) // in scanning events ... + { + // here ensure APP enter into XferImage process ... + if (!app_trigger_event_ && scanner_status_ == SCANNER_STATUS_STOPPED) + { + // scanning stopped, reset APP state to ready ... + scanner_status_ = SCANNER_STATUS_READY; + rc = notifyCloseCancel(); + if (!Twpp::success(rc)) + { + wchar_t info[128] = { 0 }, unk[20] = { 0 }; + swprintf_s(info, _countof(info) - 1, L"[%x]Warning: notifyCloseCancel failed with error %s!\r\n", GetCurrentThreadId(), desc_return_code(rc, unk)); + load_sane_util::log_info(info, 0); + } + } + else + { + // start scanning, expect frist TRIPLE is ProcessEvent ... + if (dg == DataGroup::Control && dat == Dat::Event && msg == Msg::ProcessEvent && scanner_status_ == SCANNER_STATUS_SCAN_1) + { + app_trigger_event_ = true; // nothing else to do + load_sane_util::log_info(L"Good! first event is (Control, Event, ProcessEvent) after start scanning ^_^.\r\n", 0); + } + else if(!app_trigger_event_) + { + int ev = 0; + + if (scanner_status_ == SCANNER_STATUS_SCAN_1) + load_sane_util::log_info(L"Sorry, first event is not (Control, Event, ProcessEvent) after start scanning, we takeover it!\r\n", 0); + if (scanner_.get()) + { + ev = scanner_->get_event(); + if (ev) + handle_scanner_event(ev, true); + } + } + } + } + else if (state() >= DsState::XferReady && scanner_status_ == SCANNER_STATUS_STOPPED) + { + // here ensure APP return to ready state ... + if (scanner_.get() && scanner_->get_scanned_images(0) == 0) + { + rc = notifyCloseCancel(); + if (!Twpp::success(rc)) + { + wchar_t info[128] = { 0 }, unk[20] = { 0 }; + swprintf_s(info, _countof(info) - 1, L"[%x]Warning: notifyCloseCancel failed with error %s when scanner is stopped!\r\n", GetCurrentThreadId(), desc_return_code(rc, unk)); + load_sane_util::log_info(info, 0); + } + } + } +} diff --git a/twain/twain/huagaods.hpp b/twain/twain/huagaods.hpp index 4a96d96..f1b9b98 100644 --- a/twain/twain/huagaods.hpp +++ b/twain/twain/huagaods.hpp @@ -23,6 +23,14 @@ namespace std { class twain_ui; +enum scanner_status +{ + SCANNER_STATUS_NOT_INIT = 0, // has not call identityOpenDs or called identityCloseDs + SCANNER_STATUS_READY, // called identityOpenDs + SCANNER_STATUS_SCAN_1, // scanner_->start() should be called + SCANNER_STATUS_SCANNING, // received SANE_EVENT_WORKING + SCANNER_STATUS_STOPPED, // received SANE_EVENT_SCAN_FINISHED +}; class huagao_ds : public Twpp::SourceFromThis { std::unordered_map> m_caps; std::unordered_map m_query; @@ -42,6 +50,10 @@ class huagao_ds : public Twpp::SourceFromThis { Twpp::Compression m_compression = Twpp::Compression::None; SANE_Parameters* cur_head_; int dpi_; + int scanner_status_; + bool xfer_ready_failed_; + bool log_all_triple_; + bool app_trigger_event_; static std::string get_hidedlg_path(void); static void showmsg(const char* msg, int err); @@ -55,7 +67,9 @@ class huagao_ds : public Twpp::SourceFromThis { std::wstring get_config_file(void); std::wstring get_config_value(const wchar_t* sec, const wchar_t* key); DWORD get_config_number(const wchar_t* sec, const wchar_t* key); - int handle_scanner_event(int ev); + int handle_scanner_event(int ev, bool from_event_proc = true); + int get_scanned_image_count(DWORD timeout); + void trigger_ProcessEvent(Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg); typedef struct _pending_xfer {