调整UI与APP交互方式,设备层回调不直接调用UI;屏蔽Twpp框架中自动调用“notifyXferReady()”,统一为在事件队列eventProcess中通知;所有弹出窗口自动禁用其父窗口,退出时再启用父窗口并在前方显示

This commit is contained in:
gb 2022-07-02 17:27:21 +08:00
parent fdd12a953c
commit 6cbe8f125c
14 changed files with 244 additions and 224 deletions

View File

@ -64,7 +64,7 @@ BOOL dlg_indicator::handle_message(UINT msg, WPARAM wp, LPARAM lp)
ret = FALSE;
break;
case WM_SCAN_WORKING:
notify_ui_event(UI_EVENT_SCAN_WORKING);
notify_ui_event(SANE_EVENT_WORKING);
break;
case WM_SCAN_FINISHED:
if (lp)
@ -117,7 +117,7 @@ void dlg_indicator::handle_command(WORD code, WORD id, HANDLE ctrl)
}
void dlg_indicator::notify_over(bool cancel)
{
notify_ui_event(cancel ? UI_EVENT_CLOSE_CANCEL : UI_EVENT_CLOSE_NORMAL);
notify_ui_event(cancel ? SANE_EVENT_UI_CLOSE_CANCEL : SANE_EVENT_SCAN_FINISHED);
}
HWND dlg_indicator::window(void)
@ -128,25 +128,6 @@ HWND dlg_indicator::parent(void)
{
return parent_;
}
void dlg_indicator::show()
{
RECT rp, r;
if (IsWindow(parent_))
GetWindowRect(parent_, &rp);
else
GetWindowRect(GetDesktopWindow(), &rp);
GetWindowRect(hwnd_, &r);
rp.left += (rp.right - rp.left - (r.right - r.left)) / 2;
rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 2;
SetWindowPos(hwnd_, HWND_TOPMOST, rp.left, rp.top, r.right - r.left, r.bottom - r.top, SWP_NOSIZE | SWP_SHOWWINDOW);
UpdateWindow(hwnd_);
}
void dlg_indicator::hide(void)
{
ShowWindow(hwnd_, SW_HIDE);
}
void dlg_indicator::notify_data_arrived(bool image)
{
PostMessage(hwnd_, image ? WM_IMAGE_RECEIVED : WM_USB_PACKET_RECEIVED, 0, 0);

View File

@ -24,8 +24,6 @@ public:
public:
HWND window(void);
HWND parent(void);
void show(void);
void hide(void);
void notify_data_arrived(bool image);
void notify_scan_over(const char* msg, bool err);
void notify_working(void);

View File

@ -31,8 +31,13 @@ dlg_base::dlg_base(HWND parent, UINT idd) : parent_(parent), hwnd_(NULL), idd_(i
}
dlg_base::~dlg_base()
{
if(IsWindow(hwnd_))
if (IsWindow(hwnd_))
{
//if (GetCurrentThreadId() == GetWindowThreadProcessId(hwnd_, NULL))
DestroyWindow(hwnd_);
}
EnableWindow(parent_, TRUE);
BringWindowToTop(parent_);
}
BOOL CALLBACK dlg_base::dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
@ -44,12 +49,21 @@ BOOL CALLBACK dlg_base::dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
SetPropW(hwnd, dlg_base::prop_name.c_str(), (HANDLE)obj);
obj->hwnd_ = hwnd;
}
else if (msg == WM_DESTROY)
{
dlg_base* obj = (dlg_base*)GetPropW(hwnd, dlg_base::prop_name.c_str());
SetPropW(hwnd, dlg_base::prop_name.c_str(), NULL);
return FALSE;
}
dlg_base *obj = (dlg_base*)GetPropW(hwnd, dlg_base::prop_name.c_str());
BOOL ret = FALSE;
if (obj)
{
ret = obj->handle_message(msg, wp, lp);
}
return ret;
}
@ -101,7 +115,7 @@ void dlg_base::create(void)
{
hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(idd_), parent_, &dlg_base::dlg_proc, (LPARAM)this);
}
void dlg_base::notify_ui_event(ui_event ev)
void dlg_base::notify_ui_event(int ev)
{
if (ui_event_notify_)
ui_event_notify_(ev, this, ui_notify_param_);
@ -115,7 +129,7 @@ gb::sane_config* dlg_base::get_config(void)
return cfg;
}
void dlg_base::set_ui_event_notify(void(__stdcall* notify)(ui_event, void*, void*), void* param)
void dlg_base::set_ui_event_notify(void(__stdcall* notify)(int, void*, void*), void* param)
{
ui_event_notify_ = notify;
ui_notify_param_ = param;
@ -163,11 +177,12 @@ void dlg_base::show(bool visible)
pt.y = r0.bottom - RECT_H(rme);
if (pt.y < r0.top)
pt.y = r0.top;
SetWindowPos(hwnd_, HWND_TOPMOST, pt.x, pt.y, RECT_W(rme), RECT_H(rme), SWP_NOSIZE);
SetWindowPos(hwnd_, HWND_TOP, pt.x, pt.y, RECT_W(rme), RECT_H(rme), SWP_NOSIZE);
UpdateWindow(hwnd_);
}
}
ShowWindow(hwnd_, cmd);
EnableWindow(parent_, !visible);
}
void dlg_base::enable(bool enable)
{

View File

@ -13,13 +13,6 @@
#define WM_REFRESH_OPTION WM_USER + 111 // WPARAM: source option SN, LPARAM: unused now
#define WM_GET_CONFIG_OBJ WM_USER + 112 // WPARAM: not use, LPARAM: to receive the gb::sane_config* object
enum ui_event
{
UI_EVENT_CLOSE_NORMAL = 0,
UI_EVENT_CLOSE_CANCEL,
UI_EVENT_BEGIN_SCANNING, // setting ui notify button 'scan' clicked
UI_EVENT_SCAN_WORKING, // scanner thread notify working
};
extern HMODULE g_my_inst;
namespace gb
@ -33,7 +26,7 @@ protected:
HWND hwnd_;
HWND parent_;
UINT idd_;
void(__stdcall* ui_event_notify_)(ui_event uev, void* sender, void* param);
void(__stdcall* ui_event_notify_)(int uev, void* sender, void* param);
void* ui_notify_param_;
static std::wstring prop_name;
static BOOL CALLBACK dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
@ -41,7 +34,7 @@ protected:
virtual BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp);
virtual void on_font_changed(void);
void create(void);
void notify_ui_event(ui_event ev);
void notify_ui_event(int ev);
gb::sane_config* get_config(void);
public:
@ -52,7 +45,7 @@ public:
static bool get_max_size(SIZE& dst, int cx, int cy); // return whether changed dst
public:
void set_ui_event_notify(void(__stdcall* notify)(ui_event, void*, void*), void* param);
void set_ui_event_notify(void(__stdcall* notify)(int, void*, void*), void* param);
HWND hwnd(void);
void show(bool visible);
void enable(bool enable);

View File

@ -95,13 +95,13 @@ void dlg_setting::handle_command(WORD code, WORD id, HANDLE ctrl)
}
else if (id == IDC_BUTTON_SCAN)
{
enable(false);
notify_ui_event(UI_EVENT_BEGIN_SCANNING);
// enable(false);
notify_ui_event(SANE_EVENT_UI_SCAN_COMMAND);
}
}
void dlg_setting::notify_over(void)
{
notify_ui_event(UI_EVENT_CLOSE_NORMAL);
notify_ui_event(SANE_EVENT_UI_CLOSE_NORMAL);
}
void dlg_setting::on_init_dialog(void)
{
@ -380,19 +380,8 @@ void dlg_setting::hide(void)
{
ShowWindow(hwnd_, SW_HIDE);
}
void dlg_setting::notify_data_arrived(bool image)
void dlg_setting::notify_scan_over(void)
{
PostMessage(hwnd_, image ? WM_IMAGE_RECEIVED : WM_USB_PACKET_RECEIVED, 0, 0);
}
void dlg_setting::notify_scan_over(const char* msg, bool err)
{
std::string* mstr(new std::string(msg ? msg : ""));
err_ = err;
if (!PostMessage(hwnd_, WM_SCAN_FINISHED, (WPARAM)mstr, (LPARAM)err))
{
delete mstr;
notify_over();
}
enable(true);
}
// CDlgIndicator 消息处理程序

View File

@ -60,6 +60,5 @@ public:
HWND parent(void);
//void show(void);
void hide(void);
void notify_data_arrived(bool image);
void notify_scan_over(const char* msg, bool err);
void notify_scan_over(void);
};

View File

@ -148,7 +148,7 @@ __declspec(novtable) struct ISaneInvoker : public IRef
{
COM_API_DECLARE(int, start(void));
COM_API_DECLARE(int, stop(void));
COM_API_DECLARE(void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param));
COM_API_DECLARE(int, get_event(void));
COM_API_DECLARE(bool, wait_image(DWORD milliseconds = -1));
COM_API_DECLARE(int, get_scanned_images(DWORD milliseconds = 0));
COM_API_DECLARE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz
@ -258,7 +258,7 @@ __declspec(novtable) struct ISaneInvoker : public IRef
// ui ...
COM_API_DECLARE(bool, ui_show_main(HWND parent));
COM_API_DECLARE(bool, ui_show_setting(HWND parent, bool with_scan));
COM_API_DECLARE(bool, ui_show_setting(HWND parent, bool with_scan, bool indicator = true));
COM_API_DECLARE(bool, ui_show_progress(HWND parent));
COM_API_DECLARE(void, ui_hide(void));
COM_API_DECLARE(bool, ui_is_ok(void));

View File

@ -719,57 +719,36 @@ safe_img_queue::~safe_img_queue()
clear();
}
size_t safe_img_queue::count(void)
void __stdcall safe_img_queue::access_image(scanned_img* img)
{
std::lock_guard<std::mutex> lock(que_lock_);
return queue_.size();
img->add_ref();
}
bool safe_img_queue::save(scanned_img* img)
void __stdcall safe_img_queue::free_image(scanned_img* img)
{
std::lock_guard<std::mutex> lock(que_lock_);
queue_.push_back(img);
return true;
img->release();
}
bool safe_img_queue::get_header(SANE_Parameters* header, size_t* bytes)
{
std::lock_guard<std::mutex> lock(que_lock_);
scanned_img *img = take(false, &safe_img_queue::access_image);
bool ok = false;
if (bytes)
*bytes = 0;
if (queue_.size())
if (img)
{
if(header)
queue_[0]->copy_header(header);
img->copy_header(header);
if(bytes)
*bytes = queue_[0]->bytes();
*bytes = img->bytes();
ok = true;
img->release();
}
return ok;
}
scanned_img* safe_img_queue::take(void)
{
std::lock_guard<std::mutex> lock(que_lock_);
scanned_img* img = NULL;
if (queue_.size())
{
img = queue_[0];
queue_.erase(queue_.begin());
}
return img;
}
void safe_img_queue::clear()
{
std::lock_guard<std::mutex> lock(que_lock_);
for (size_t i = 0; i < queue_.size(); ++i)
queue_[i]->release();
queue_.clear();
safe_queue<scanned_img*>::clear(&safe_img_queue::free_image);
}

View File

@ -98,20 +98,73 @@ public:
COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head));
};
class safe_img_queue
template<class T>
class safe_queue
{
std::mutex que_lock_;
std::vector<scanned_img*> queue_;
std::mutex lock_;
std::vector<T> queue_;
public:
safe_queue()
{}
virtual ~safe_queue()
{}
public:
size_t count(void)
{
std::lock_guard<std::mutex> lock(lock_);
return queue_.size();
}
bool save(T v)
{
std::lock_guard<std::mutex> lock(lock_);
queue_.push_back(v);
return true;
}
T take(bool remove = true, void(__stdcall* first)(T) = NULL)
{
std::lock_guard<std::mutex> lock(lock_);
T t = 0;
if (queue_.size())
{
t = queue_[0];
if(remove)
queue_.erase(queue_.begin());
if (first)
first(t);
}
return t;
}
void clear(void(__stdcall* tfree)(T) = NULL)
{
std::lock_guard<std::mutex> lock(lock_);
if (tfree)
{
for (auto& v : queue_)
tfree(v);
}
queue_.clear();
}
};
class safe_img_queue : public safe_queue<scanned_img*>
{
static void __stdcall access_image(scanned_img* img);
static void __stdcall free_image(scanned_img* img);
public:
safe_img_queue();
~safe_img_queue();
public:
size_t count(void);
bool save(scanned_img* img);
bool get_header(SANE_Parameters* header, size_t* bytes = NULL);
scanned_img* take(void);
void clear();
};

View File

@ -78,7 +78,7 @@ namespace callback
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev);
if (it != g_scanner_instances.end())
return it->invoker->handle_event(code, data, len);
return it->invoker->handle_device_event(code, data, len);
else
return 0;
}
@ -109,8 +109,8 @@ namespace callback
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class scanner
scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START)
, dpi_(200), tmp_path_(L""), img_ind_(0), cb_invoker_(NULL), cb_param_(NULL), working_(false)
, ui_quit_(true), scanner_name_(L""), cfg_(NULL)
, dpi_(200), tmp_path_(L""), img_ind_(0)
, scanner_name_(L""), cfg_(NULL)
{
cfg_ = new gb::sane_config();
tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str());
@ -190,9 +190,9 @@ float __stdcall scanner::to_float(SANE_Fixed v)
{
return SANE_UNFIX(v);
}
void __stdcall scanner::ui_callback(ui_event uev, void* sender, void* param)
void __stdcall scanner::ui_callback(int uev, void* sender, void* param)
{
((scanner*)param)->on_ui_quit(uev, sender);
((scanner*)param)->on_ui_event(uev, sender);
}
// IRef
@ -244,46 +244,9 @@ void scanner::apply_config(void)
} while (cfg_->next_config(t, v));
}
}
void scanner::on_ui_quit(ui_event uev, void* sender)
void scanner::on_ui_event(int uev, void* sender)
{
switch (uev)
{
case UI_EVENT_CLOSE_CANCEL: // post from indicator
stop();
case UI_EVENT_CLOSE_NORMAL: // post from indicator & dlg_setting
if (/*sender == indicator_.get() &&*/ setting_.get())
{
setting_->hide();
setting_.reset();
}
/*else*/ if (/*sender == setting_.get() &&*/ indicator_.get())
{
indicator_->hide();
indicator_.reset();
}
ui_quit_ = true;
break;
case UI_EVENT_BEGIN_SCANNING: // post from dlg_setting, so we show indicator ...
if (start() == SANE_STATUS_GOOD)
{
if (indicator_.get())
{
indicator_->show();
return;
}
}
else
{
setting_->enable(true);
return;
}
case UI_EVENT_SCAN_WORKING:
break;
default:
break;
}
if (cb_invoker_)
cb_invoker_(ui_quit_ ? SANE_EVENT_SCAN_FINISHED : SANE_EVENT_WORKING, NULL, NULL, cb_param_);
events_.save(uev);
}
int scanner::open(void)
{
@ -1583,7 +1546,10 @@ COM_API_IMPLEMENT(scanner, int, start(void))
scan_msg_ = "OK";
scan_err_ = false;
hg_sane_middleware::instance()->start(handle_, NULL);
ret = hg_sane_middleware::instance()->start(handle_, NULL);
if (indicator_.get() && !IsWindowVisible(indicator_->hwnd()))
indicator_->show(true);
// the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ...
if(ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD)
@ -1596,7 +1562,6 @@ COM_API_IMPLEMENT(scanner, int, start(void))
if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l))
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
img_fmt_.compress.compression = cmprsn;
working_ = true;
}
prev_start_result_ = ret;
@ -1604,13 +1569,11 @@ COM_API_IMPLEMENT(scanner, int, start(void))
}
COM_API_IMPLEMENT(scanner, int, stop(void))
{
working_ = false;
return hg_sane_middleware::instance()->stop(handle_);
}
COM_API_IMPLEMENT(scanner, void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param))
COM_API_IMPLEMENT(scanner, int, get_event(void))
{
cb_invoker_ = cb;
cb_param_ = param;
return events_.take();
}
COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds))
{
@ -1621,7 +1584,7 @@ COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds))
COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds))
{
size_t count = images_.count();
bool notify = true;
DWORD elapse = 10;
while (count == 0 && milliseconds)
{
@ -1631,24 +1594,33 @@ COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds))
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
Sleep(10);
if (!working_)
Sleep(elapse);
int ev = get_event();
count = images_.count();
if (ev == SANE_EVENT_SCAN_FINISHED)
{
if (notify && indicator_.get())
{
notify = false;
indicator_->notify_scan_over(scan_msg_.c_str(), scan_err_); // Ending by UI
}
else if(ui_quit_)
ui_hide();
break;
}
else if (ev == SANE_EVENT_UI_CLOSE_CANCEL)
{
stop();
ui_hide();
break;
}
else if (ev == SANE_EVENT_UI_CLOSE_NORMAL)
{
ui_hide();
break;
}
count = images_.count();
if (milliseconds != -1)
{
if (milliseconds <= 10)
if (milliseconds <= elapse)
break;
milliseconds -= 10;
milliseconds -= elapse;
}
}
@ -1992,7 +1964,7 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent))
{
return false;
}
COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan))
COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan, bool indicator))
{
SANEAPI api = { NULL };
@ -2014,15 +1986,13 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan))
setting_->set_ui_event_notify(&scanner::ui_callback, this);
setting_->set_config(cfg_, (cfg_path_ + scanner_name_).c_str());
cfg_->begin_setting();
if (with_scan)
indicator_.reset();
if (indicator)
{
indicator_.reset(new dlg_indicator(parent));
indicator_.reset(new dlg_indicator(setting_->hwnd()));
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
}
else
indicator_.reset();
setting_->show(true);
ui_quit_ = false;
return true;
}
@ -2030,8 +2000,7 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent))
{
indicator_.reset(new dlg_indicator(parent));
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
indicator_->show();
ui_quit_ = false;
indicator_->show(true);
return true;
}
@ -2050,12 +2019,14 @@ COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
// called from device-layer ...
int scanner::handle_event(int ev_code, void* data, unsigned int* len)
int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
{
if (ev_code == SANE_EVENT_WORKING)
{
if (indicator_.get())
indicator_->notify_working();
else
events_.save(ev_code);
}
else if (ev_code == SANE_EVENT_IMAGE_OK)
{
@ -2068,29 +2039,25 @@ int scanner::handle_event(int ev_code, void* data, unsigned int* len)
if (img->bytes() /*>= simg->bytes*/)
{
images_.save(img);
if (cb_invoker_) // added for notify twain-app XferReady ...
cb_invoker_(ev_code, NULL, NULL, cb_param_);
}
else
{
img->release();
}
if (indicator_)
if (indicator_.get())
indicator_->notify_data_arrived(true);
}
else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED)
{
if (indicator_)
if (indicator_.get())
indicator_->notify_data_arrived(false);
}
else if (ev_code == SANE_EVENT_SCAN_FINISHED)
{
if (indicator_.get())
{
scan_msg_ = (char*)data;
scan_err_ = *len != SCANNER_ERR_OK;
}
working_ = false;
indicator_->notify_scan_over((char*)data, *len != SCANNER_ERR_OK);
else
events_.save(ev_code);
}
return 0;

View File

@ -34,8 +34,6 @@ class scanner : public ISaneInvoker, virtual public refer
SANE_Handle handle_;
SCANNERID id_;
int err_;
void(*cb_invoker_)(int ev_type, void* data, unsigned int* len, void* param);
void* cb_param_;
int ex_id_;
int prev_start_result_;
int dpi_;
@ -47,8 +45,7 @@ class scanner : public ISaneInvoker, virtual public refer
bool scan_err_;
twain_xfer xfer_;
safe_img_queue images_;
volatile bool working_;
bool ui_quit_;
safe_queue<int> events_; //如果有界面,则全部保存从界面传回的消息;否则只保存开始扫描和结束扫描的事件
SANE_FinalImgFormat img_fmt_;
std::unique_ptr<dlg_indicator> indicator_;
std::unique_ptr<dlg_setting> setting_;
@ -57,7 +54,7 @@ class scanner : public ISaneInvoker, virtual public refer
void load_config(const wchar_t* file);
void save_config(const wchar_t* file);
void apply_config(void);
void on_ui_quit(ui_event uev, void* sender);
void on_ui_event(int uev, void* sender);
int open(void);
int close(void);
int init_options_id(void);
@ -175,7 +172,7 @@ class scanner : public ISaneInvoker, virtual public refer
static int __stdcall to_int(SANE_Int v);
static float __stdcall to_float(SANE_Fixed v);
static void __stdcall ui_callback(ui_event uev, void* sender, void* param);
static void __stdcall ui_callback(int uev, void* sender, void* param);
public:
scanner(SCANNERID id);
@ -196,7 +193,7 @@ public:
public:
COM_API_OVERRIDE(int, start(void));
COM_API_OVERRIDE(int, stop(void));
COM_API_OVERRIDE(void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param));
COM_API_OVERRIDE(int, get_event(void));
COM_API_OVERRIDE(bool, wait_image(DWORD milliseconds = -1));
COM_API_OVERRIDE(int, get_scanned_images(DWORD milliseconds = 0));
COM_API_OVERRIDE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz
@ -294,7 +291,7 @@ public:
// ui ...
COM_API_OVERRIDE(bool, ui_show_main(HWND parent));
COM_API_OVERRIDE(bool, ui_show_setting(HWND parent, bool with_scan));
COM_API_OVERRIDE(bool, ui_show_setting(HWND parent, bool with_scan, bool indicator = true));
COM_API_OVERRIDE(bool, ui_show_progress(HWND parent));
COM_API_OVERRIDE(void, ui_hide(void));
COM_API_OVERRIDE(bool, ui_is_ok(void));
@ -307,5 +304,5 @@ public:
// methods:
public:
int handle_event(int ev_code, void* data, unsigned int* len);
int handle_device_event(int ev_code, void* data, unsigned int* len);
};

View File

@ -126,6 +126,11 @@ enum CapTypeEx : unsigned short {
// END for SANE设备层原始设置项透传属性
/////////////////////////////////////////////////////////////////////////
};
enum // .twain/first.cfg: [twain-app] flow=0
{
TWAIN_APP_TRANSFER_NORMAL = 0, // first get head and then bits
TWAIN_APP_TRANSFER_REVERSE, // first get bits and then head
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -618,10 +623,6 @@ void huagao_ds::showmsg(const char* msg, int err)
{
ShellExecuteA(NULL, "open", huagao_ds::get_hidedlg_path().c_str(), msg, NULL, SW_HIDE);
}
void huagao_ds::scan_event(int sane_event, void* data, unsigned int* len, void* param)
{
((huagao_ds*)param)->on_scan_event(sane_event, data, len);
}
const Identity& huagao_ds::defaultIdentity() noexcept {
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
@ -709,6 +710,25 @@ Result huagao_ds::eventProcess(const Identity&, Event& event)
{
const MSG* msg = (const MSG*)event.event();
// event.setMessage(Msg::Null);
if (scanner_.get())
{
switch (scanner_->get_event())
{
case SANE_EVENT_WORKING:
notifyXferReady();
break;
case SANE_EVENT_UI_CLOSE_CANCEL:
scanner_->stop();
notifyEndWithoutImages();
case SANE_EVENT_UI_CLOSE_NORMAL:
scanner_->ui_hide();
notifyCloseOk();
break;
case SANE_EVENT_UI_SCAN_COMMAND:
scanner_->start();
break;
}
}
return { ReturnCode::NotDsEvent, ConditionCode::Success };
}
@ -763,7 +783,13 @@ Result huagao_ds::identityOpenDs(const Identity& id)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) };
}
// ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str()));
scanner_->set_event_callback(&huagao_ds::scan_event, this);
if (get_config_number(L"twain-app", L"flow") == TWAIN_APP_TRANSFER_REVERSE)
{
cur_head_ = new SANE_Parameters;
memset(cur_head_, 0, sizeof(SANE_Parameters));
}
m_compression = Compression::None;
init_support_caps();
m_fileXfer.setFormat(ImageFileFormat::Bmp);
@ -846,7 +872,8 @@ Result huagao_ds::setupMemXferGet(const Identity& id, SetupMemXfer& data)
}
Result huagao_ds::userInterfaceDisable(const Identity&, UserInterface& ui)
{
scanner_->ui_hide();
if (scanner_.get())
scanner_->stop();
return success();
}
@ -854,8 +881,6 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui)
{
if (!ui.showUi())
{
bool xfer_ready = !m_bIndicator;
if (m_bIndicator && !scanner_->ui_show_progress((HWND)ui.parent().raw()))
return seqError();
@ -863,14 +888,11 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui)
if (scanner_->start() == SCANNER_ERR_OK)
{
if (xfer_ready)
notifyXferReady();
return success();
}
else
{
return seqError();
return bummer();
}
}
@ -897,7 +919,10 @@ Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data)
else
{
if (!scanner_->wait_image())
{
notifyCloseOk();
return bummer();
}
ok = scanner_->get_first_image_header(&head);
}
@ -914,6 +939,9 @@ Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data)
data.bitsPerSample()[0] = 8;
}
data.setHeight(head.lines);
if (m_compression == Compression::Group4)
data.setPixelType(PixelType::BlackWhite);
else
data.setPixelType(head.format == SANE_FRAME_RGB ? PixelType::Rgb : PixelType::Gray);
data.setPlanar(false);
data.setWidth(head.pixels_per_line);
@ -964,9 +992,18 @@ Result huagao_ds::imageLayoutReset(const Identity& origin, ImageLayout& data)
}
Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data)
{
if (!scanner_.get() || (scanner_->get_scanned_images() == 0 && !pending_xfer_.img))
if (!scanner_.get())
return seqError();
if (scanner_->get_scanned_images() == 0 && !pending_xfer_.img)
{
if (!cur_head_ || !scanner_->wait_image())
{
notifyCloseOk();
return seqError();
}
}
IScanImg *img = pending_xfer_.img ? pending_xfer_.img : scanner_->take_first_image(TWAIN_XFER_Memory);
unsigned long long off = pending_xfer_.img ? pending_xfer_.off : 0;
unsigned char *dst = (unsigned char*)data.memory().data().data();
@ -1227,7 +1264,7 @@ Result huagao_ds::capCommon(const Identity&, Msg msg, Capability& data) {
Twpp::Result huagao_ds::showTwainUI(Twpp::UserInterface& data, bool bUiOnly)
{
// display user UI ... (setting UI, can we show my own main window here ?)
return scanner_->ui_show_setting((HWND)data.parent().raw(), !bUiOnly) ? success() : seqError();
return scanner_->ui_show_setting((HWND)data.parent().raw(), !bUiOnly, m_bIndicator) ? success() : seqError();
}
void huagao_ds::init_support_caps(void)
{
@ -2587,23 +2624,29 @@ void huagao_ds::init_support_caps_ex(void)
ADD_SANE_CAP(skew_range);
ADD_SANE_CAP(black_white_threshold);
}
void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len)
std::wstring huagao_ds::get_config_file(void)
{
if (scanner_.get())
{
/*if (sane_event == SANE_EVENT_IMAGE_OK)
{
notifyDeviceEvent();
}
else*/ if (sane_event == SANE_EVENT_SCAN_FINISHED)
{
notifyCloseCancel();
}
else if (sane_event == SANE_EVENT_WORKING)
{
notifyXferReady();
}
}
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"first.cfg");
return path;
}
std::wstring huagao_ds::get_config_value(const wchar_t* sec, const wchar_t* key)
{
wchar_t v[256] = { 0 };
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());
}

View File

@ -44,14 +44,15 @@ class huagao_ds : public Twpp::SourceFromThis<huagao_ds> {
static std::string get_hidedlg_path(void);
static void showmsg(const char* msg, int err);
static void scan_event(int sane_event, void* data, unsigned int* len, void* param);
void CapabilityPrintf(Twpp::Msg msg, std::string capability, std::string value = "");
Twpp::Result capCommon(const Twpp::Identity& origin, Twpp::Msg msg, Twpp::Capability& data);
Twpp::Result showTwainUI(Twpp::UserInterface& data, bool bUiOnly = false);
void init_support_caps(void);
void init_support_caps_ex(void);
void on_scan_event(int sane_event, void* data, unsigned int* len);
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);
typedef struct _pending_xfer
{

View File

@ -302,6 +302,11 @@ namespace Twpp {
return notifyApp(Msg::XferReady);
}
/// Notifies application scanning complete with no image got - added on 2022-07-02
ReturnCode notifyEndWithoutImages() noexcept {
return notifyApp(Msg::Null);
}
/// Root of source TWAIN calls.
@ -1185,8 +1190,8 @@ namespace Twpp {
if (Twpp::success(rc) || rc == ReturnCode::CheckStatus) {
if (inState(DsState::Open)) { // allow userInterfaceEnable to transfer to higher states
setState(DsState::Enabled);
if(!data.showUi())
notifyXferReady();
//if(!data.showUi())
// notifyXferReady();
}
}