调整组件名称,增加设置界面

This commit is contained in:
gb 2022-06-20 15:17:55 +08:00
parent eec6290cf4
commit 9ce97e3061
13 changed files with 867 additions and 124 deletions

View File

@ -10,96 +10,19 @@
#define WM_IMAGE_RECEIVED WM_USER + 2 #define WM_IMAGE_RECEIVED WM_USER + 2
#define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err #define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err
ATOM dlg_indicator::indicator_class_atom = 0;
std::wstring dlg_indicator::handle_name = L"dlg_indicator_prop_handle";
std::wstring dlg_indicator::indicator_class_name = L"dlg_indicator_class";
extern HMODULE g_my_inst;
dlg_indicator::dlg_indicator() : hwnd_(NULL), papers_(0), images_(0), notify_(NULL), notify_param_(NULL), parent_(NULL), err_(false) dlg_indicator::dlg_indicator(HWND parent) : dlg_base(parent, IDD_INDICATOR)
, papers_(0), images_(0), notify_(NULL), notify_param_(NULL), err_(false)
{ {
HANDLE wait = CreateEvent(NULL, TRUE, FALSE, NULL); create();
#ifdef USE_SOLE_WIN_THREAD SetWindowLongW(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE, GetWindowLong(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE) | SS_OWNERDRAW);
thread_.reset(new std::thread(&dlg_indicator::create, this, wait));
#else
create(wait);
#endif
WaitForSingleObject(wait, INFINITE);
CloseHandle(wait);
} }
dlg_indicator::~dlg_indicator() dlg_indicator::~dlg_indicator()
{ {
#ifdef USE_SOLE_WIN_THREAD
if (IsWindow(hwnd_))
PostMessage(hwnd_, WM_QUIT, 0, 0);
if (thread_.get() && thread_->joinable())
thread_->join();
thread_.reset();
#else
if (IsWindow(hwnd_))
DestroyWindow(hwnd_);
#endif
} }
BOOL CALLBACK dlg_indicator::dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (msg == WM_INITDIALOG)
{
dlg_indicator *obj = (dlg_indicator*)lp;
SetPropW(hwnd, dlg_indicator::handle_name.c_str(), (HANDLE)obj); BOOL dlg_indicator::handle_message(UINT msg, WPARAM wp, LPARAM lp)
}
dlg_indicator* obj = (dlg_indicator*)GetPropW(hwnd, dlg_indicator::handle_name.c_str());
BOOL handled = FALSE, ret = FALSE;
if (obj)
ret = obj->handle_msg(msg, wp, lp);
return ret;
}
ATOM dlg_indicator::register_indicator_class(void)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = WS_POPUP;
wcex.lpfnWndProc = (WNDPROC)dlg_indicator::dlg_indicator_proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = g_my_inst;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = dlg_indicator::indicator_class_name.c_str();
wcex.hIconSm = NULL;
return RegisterClassExW(&wcex);
}
void dlg_indicator::create(HANDLE wait)
{
MSG msg = { 0 };
BOOL ret = TRUE;
hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(IDD_INDICATOR), NULL, &dlg_indicator::dlg_indicator_proc, (LPARAM)this);
SetWindowLongW(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE, GetWindowLong(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE) | SS_OWNERDRAW);
SetEvent(wait);
#ifdef USE_SOLE_WIN_THREAD
while ((ret = GetMessage(&msg, NULL, 0, 0)))
{
if (ret == -1)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(hwnd_);
#endif
}
BOOL dlg_indicator::handle_msg(UINT msg, WPARAM wp, LPARAM lp)
{ {
wchar_t text[40] = { 0 }; wchar_t text[40] = { 0 };
BOOL ret = TRUE; BOOL ret = TRUE;
@ -110,6 +33,7 @@ BOOL dlg_indicator::handle_msg(UINT msg, WPARAM wp, LPARAM lp)
swprintf_s(text, _countof(text) - 1, L"%u", papers_); swprintf_s(text, _countof(text) - 1, L"%u", papers_);
SetDlgItemTextW(hwnd_, IDC_EDIT_IMAGE, text); SetDlgItemTextW(hwnd_, IDC_EDIT_IMAGE, text);
SetDlgItemTextW(hwnd_, IDC_EDIT_PAPER, text); SetDlgItemTextW(hwnd_, IDC_EDIT_PAPER, text);
UpdateWindow(hwnd_);
break; break;
case WM_USB_PACKET_RECEIVED: case WM_USB_PACKET_RECEIVED:
papers_++; papers_++;
@ -206,17 +130,16 @@ HWND dlg_indicator::parent(void)
{ {
return parent_; return parent_;
} }
void dlg_indicator::show(HWND parent) void dlg_indicator::show()
{ {
RECT rp, r; RECT rp, r;
if (IsWindow(parent)) if (IsWindow(parent_))
GetWindowRect(parent, &rp); GetWindowRect(parent_, &rp);
else else
GetWindowRect(GetDesktopWindow(), &rp); GetWindowRect(GetDesktopWindow(), &rp);
GetWindowRect(hwnd_, &r); GetWindowRect(hwnd_, &r);
parent_ = parent;
rp.left += (rp.right - rp.left - (r.right - r.left)) / 2; rp.left += (rp.right - rp.left - (r.right - r.left)) / 2;
rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 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); SetWindowPos(hwnd_, HWND_TOPMOST, rp.left, rp.top, r.right - r.left, r.bottom - r.top, SWP_NOSIZE | SWP_SHOWWINDOW);

View File

@ -3,47 +3,31 @@
#include <Windows.h> #include <Windows.h>
#include <string> #include <string>
#include "DlgPage.h"
// CDlgIndicator 对话框 // CDlgIndicator 对话框
//#define USE_SOLE_WIN_THREAD
#ifdef USE_SOLE_WIN_THREAD class dlg_indicator : public dlg_base
#include <thread>
#include <memory>
#endif
class dlg_indicator
{ {
HWND hwnd_; unsigned int papers_;
HWND parent_; unsigned int images_;
unsigned int papers_; bool err_;
unsigned int images_;
bool err_;
#ifdef USE_SOLE_WIN_THREAD
std::unique_ptr<std::thread> thread_;
#endif
void(__stdcall* notify_)(bool, void*); void(__stdcall* notify_)(bool, void*);
void* notify_param_; void* notify_param_;
static ATOM indicator_class_atom; BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override;
static std::wstring handle_name;
static std::wstring indicator_class_name;
static BOOL CALLBACK dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
static ATOM register_indicator_class(void);
void create(HANDLE wait);
BOOL handle_msg(UINT msg, WPARAM wp, LPARAM lp);
void handle_command(WORD code, WORD id, HANDLE ctrl); void handle_command(WORD code, WORD id, HANDLE ctrl);
void notify_over(void); void notify_over(void);
public: public:
dlg_indicator(); dlg_indicator(HWND parent);
~dlg_indicator(); ~dlg_indicator();
public: public:
void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param); void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param);
HWND window(void); HWND window(void);
HWND parent(void); HWND parent(void);
void show(HWND parent); void show(void);
void hide(void); void hide(void);
void notify_data_arrived(bool image); void notify_data_arrived(bool image);
void notify_scan_over(const char* msg, bool err); void notify_scan_over(const char* msg, bool err);

247
sane/DlgPage.cpp Normal file
View File

@ -0,0 +1,247 @@
// DlgIndicator.cpp: 实现文件
//
#include "DlgPage.h"
#include "resource.h"
#include "scanned_img.h" // for local_trans
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dlg_base 对话框
extern HMODULE g_my_inst;
std::wstring dlg_base::prop_name = L"dlg_base_object_prop_name";
dlg_base::dlg_base(HWND parent, UINT idd) : parent_(parent), hwnd_(NULL), idd_(idd)
{
}
dlg_base::~dlg_base()
{
if(IsWindow(hwnd_))
DestroyWindow(hwnd_);
}
BOOL CALLBACK dlg_base::dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (msg == WM_INITDIALOG)
{
dlg_base* obj = (dlg_base*)lp;
SetPropW(hwnd, dlg_base::prop_name.c_str(), (HANDLE)obj);
obj->hwnd_ = hwnd;
}
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;
}
bool dlg_base::get_max_size(SIZE& dst, const SIZE& src)
{
bool changed = false;
if (dst.cx < src.cx)
{
dst.cx = src.cx;
changed = true;
}
if (dst.cy < src.cy)
{
dst.cy = src.cy;
changed = true;
}
return changed;
}
bool dlg_base::get_max_size(SIZE& dst, int cx, int cy)
{
bool changed = false;
if (dst.cx < cx)
{
dst.cx = cx;
changed = true;
}
if (dst.cy < cy)
{
dst.cy = cy;
changed = true;
}
return changed;
}
BOOL dlg_base::handle_message(UINT msg, WPARAM wp, LPARAM lp)
{
return FALSE;
}
void dlg_base::on_font_changed(void)
{
}
void dlg_base::create(void)
{
hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(idd_), parent_, &dlg_base::dlg_proc, (LPARAM)this);
}
HWND dlg_base::hwnd(void)
{
return hwnd_;
}
void dlg_base::screen_2_client(LPRECT r)
{
POINT pt = { r->left, r->top };
ScreenToClient(hwnd_, &pt);
OffsetRect(r, pt.x - r->left, pt.y - r->top);
}
void dlg_base::client_2_screen(LPRECT r)
{
POINT pt = { r->left, r->top };
ClientToScreen(hwnd_, &pt);
OffsetRect(r, pt.x - r->left, pt.y - r->top);
}
HWND dlg_base::get_item(UINT id)
{
return GetDlgItem(hwnd_, id);
}
BOOL dlg_base::set_font(HFONT font)
{
BOOL ret = SendMessage(hwnd_, WM_SETFONT, (WPARAM)font, 1) == 0;
if (ret)
on_font_changed();
return ret;
}
HFONT dlg_base::get_font(void)
{
return (HFONT)SendMessage(hwnd_, WM_GETFONT, 0, 0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dlg_page 对话框
UINT dlg_page::dyn_id_base = 3000;
int dlg_page::gap_x = 20;
int dlg_page::gap_y = 12;
dlg_page::dlg_page(HWND parent, const wchar_t* name) : dlg_base(parent, IDD_PAGE), name_(name ? name : L""), ctrl_id_(0)
{
size_.cx = size_.cy = 0;
create();
refresh_font();
}
dlg_page::~dlg_page()
{}
BOOL dlg_page::handle_message(UINT msg, WPARAM wp, LPARAM lp)
{
return FALSE;
}
void dlg_page::on_font_changed(void)
{
refresh_font();
}
void dlg_page::refresh_font(void)
{
HFONT font = get_font();
LOGFONTW lf = { 0 };
GetObjectW(font, sizeof(lf), &lf);
font_size_.cx = lf.lfWidth;
font_size_.cy = lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight;
}
bool dlg_page::create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
std::wstring title(local_trans::a2u(desc->title, CP_UTF8));
bool ret = true;
bool now = *(SANE_Bool*)cur_val == SANE_TRUE ? true : false;
int w = title.length() * font_size_.cx + 18,
h = font_size_.cy;
HWND wnd = CreateWindowW(L"Button", L"check", WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX, pos_.x, pos_.y, w, h, hwnd(), NULL, g_my_inst, NULL);
pos_.y += h + dlg_page::gap_y;
if (size_.cx < w)
size_.cx = w;
if (size_.cy < pos_.y)
size_.cy = pos_.y;
if (desc->cap & SANE_CAP_INACTIVE)
EnableWindow(wnd, FALSE);
ShowWindow(wnd, SW_SHOW);
if (now)
SendMessage(wnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
return ret;
}
bool dlg_page::create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool ret = true;
return ret;
}
bool dlg_page::create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool ret = true;
return ret;
}
bool dlg_page::create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool ret = true;
return ret;
}
bool dlg_page::create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool ret = true;
return ret;
}
bool dlg_page::add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val)
{
bool ret = false;
struct
{
int sane_type;
bool(dlg_page::* func)(int, const SANE_Option_Descriptor*, void*);
}creat[] = { {SANE_TYPE_BOOL, &dlg_page::create_control_bool}
, {SANE_TYPE_INT, &dlg_page::create_control_int}
, {SANE_TYPE_FIXED, &dlg_page::create_control_float}
, {SANE_TYPE_STRING, &dlg_page::create_control_string}
, {SANE_TYPE_BUTTON, &dlg_page::create_control_button}
};
for (int i = 0; i < _countof(creat); ++i)
{
if (creat[i].sane_type == desc->type)
{
ret = (this->*creat[i].func)(sn, desc, cur_val);
break;
}
}
return ret;
}
SIZE dlg_page::desired_size(void)
{
return size_;
}
void dlg_page::show(void)
{
ShowWindow(hwnd_, SW_SHOW);
}
void dlg_page::hide(void)
{
ShowWindow(hwnd_, SW_HIDE);
}
const wchar_t* dlg_page::name(void)
{
return name_.c_str();
}

76
sane/DlgPage.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <Windows.h>
#include <CommCtrl.h>
#include <string>
#include <vector>
#include <sane/sane_ex.h>
#include <sane/sane_option_definitions.h>
// CDlgIndicator 对话框
#define WM_REFRESH_OPTION WM_USER + 111 // WPARAM: source option SN, LPARAM: unused now
extern HMODULE g_my_inst;
class dlg_base
{
protected:
HWND hwnd_;
HWND parent_;
UINT idd_;
static std::wstring prop_name;
static BOOL CALLBACK dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
virtual BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp);
virtual void on_font_changed(void);
void create(void);
public:
dlg_base(HWND parent, UINT idd);
virtual ~dlg_base();
static bool get_max_size(SIZE& dst, const SIZE& src); // return whether changed dst
static bool get_max_size(SIZE& dst, int cx, int cy); // return whether changed dst
public:
HWND hwnd(void);
void screen_2_client(LPRECT r);
void client_2_screen(LPRECT r);
HWND get_item(UINT id);
BOOL set_font(HFONT font);
HFONT get_font(void);
};
class dlg_page : public dlg_base
{
std::wstring name_;
SIZE size_;
SIZE font_size_;
UINT ctrl_id_;
POINT pos_;
static UINT dyn_id_base;
static int gap_x;
static int gap_y;
BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override;
void on_font_changed(void) override;
void refresh_font(void);
bool create_control_bool(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_int(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_float(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_string(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
bool create_control_button(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
public:
dlg_page(HWND parent, const wchar_t* name);
~dlg_page();
public:
bool add_control(int sn, const SANE_Option_Descriptor* desc, void* cur_val);
SIZE desired_size(void);
void show(void);
void hide(void);
const wchar_t* name(void);
};

324
sane/DlgSetting.cpp Normal file
View File

@ -0,0 +1,324 @@
// DlgIndicator.cpp: 实现文件
//
#include "DlgSetting.h"
#include "resource.h"
#include "scanned_img.h" // for local_trans
#include "DlgPage.h"
// CDlgIndicator 对话框
#define WM_USB_PACKET_RECEIVED WM_USER + 1
#define WM_IMAGE_RECEIVED WM_USER + 2
#define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err
static IMPLEMENT_OPTION_STRING_COMPARE(cmp_sane_opt);
dlg_setting::dlg_setting(HWND parent, LPSANEAPI api, SANE_Handle dev, bool with_scan, const wchar_t* name) : dlg_base(parent, IDD_SETTING)
, sane_api_(*api), sane_dev_(dev), with_scan_(with_scan)
, papers_(0), images_(0), notify_(NULL), notify_param_(NULL), err_(false), tab_(NULL)
{
create();
SetWindowTextW(hwnd(), (std::wstring(name) + L" \u8bbe\u7f6e").c_str());
}
dlg_setting::~dlg_setting()
{
if (IsWindow(tab_))
{
for (int i = 0; i < get_tab_count(); ++i)
{
TCITEMW item = { 0 };
item.mask = TCIF_PARAM;
TabCtrl_GetItem(tab_, i, &item);
if (item.lParam)
delete (dlg_page*)item.lParam;
}
DestroyWindow(tab_);
}
}
BOOL dlg_setting::handle_message(UINT msg, WPARAM wp, LPARAM lp)
{
wchar_t text[40] = { 0 };
BOOL ret = TRUE;
switch (msg)
{
case WM_INITDIALOG:
on_init_dialog();
break;
case WM_COMMAND:
handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp);
break;
case WM_NOTIFY:
on_notify((int)wp, (LPNMHDR)lp);
break;
case WM_REFRESH_OPTION:
refresh_controls((int)wp);
break;
default:
ret = FALSE;
break;
}
return ret;
}
void dlg_setting::handle_command(WORD code, WORD id, HANDLE ctrl)
{
if (id == IDOK)
{
notify_over();
}
else if (id == IDC_BUTTON_HELP)
{
}
else if (id == IDC_BUTTON_RESTORE)
{
}
}
void dlg_setting::notify_over(void)
{
if (notify_)
notify_(true, notify_param_);
}
void dlg_setting::on_init_dialog(void)
{
dlg_page* page = NULL;
SANE_Int sn = 1;
SIZE size = { 0 };
RECT r = { 0 }, rme = { 0 };
int y = 0;
const SANE_Option_Descriptor* desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++);
while (desc)
{
if (desc->type == SANE_TYPE_GROUP)
{
if (page)
dlg_base::get_max_size(size, page->desired_size());
page = add_tab(desc->title);
}
else if (page)
{
char* buf = new char[desc->size + 4];
SANE_Int info = 0;
memset(buf, 0, desc->size + 4);
sane_api_.sane_control_option_api(sane_dev_, sn - 1, SANE_ACTION_GET_VALUE, buf, &info);
page->add_control(sn - 1, desc, buf);
delete[] buf;
}
else if(desc->type == SANE_TYPE_BUTTON)
{
if (cmp_sane_opt(OPTION_TITLE_BZ, desc->title))
ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_HELP), SW_SHOW);
if (cmp_sane_opt(OPTION_TITLE_HFMRSZ, desc->title))
ShowWindow(GetDlgItem(hwnd_, IDC_BUTTON_RESTORE), SW_SHOW);
}
desc = sane_api_.sane_get_option_descriptor_api(sane_dev_, sn++);
}
if (page)
dlg_base::get_max_size(size, page->desired_size());
if (size.cx || size.cy || IsWindow(tab_))
{
// resize ...
GetClientRect(hwnd(), &rme);
if (size.cx < rme.right - rme.left)
size.cx = rme.right - rme.left;
if (IsWindow(tab_))
{
GetWindowRect(tab_, &r);
y = r.bottom - r.top;
size.cy += y;
r.right = r.left + rme.right - rme.left;
screen_2_client(&r);
MoveWindow(tab_, r.left, r.top, r.right - r.left, y, TRUE);
}
GetWindowRect(hwnd(), &r);
r.right += size.cx - (rme.right - rme.left);
r.bottom += size.cy;
MoveWindow(hwnd(), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
for (int i = 0; page = get_page(i); ++i)
{
MoveWindow(page->hwnd(), 0, y, size.cx, size.cy - y, TRUE);
}
GetWindowRect(get_item(IDC_BUTTON_SCAN), &r);
OffsetRect(&r, 0, size.cy);
screen_2_client(&r);
MoveWindow(get_item(IDC_BUTTON_SCAN), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
GetWindowRect(get_item(IDC_BUTTON_HELP), &r);
OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy);
screen_2_client(&r);
MoveWindow(get_item(IDC_BUTTON_HELP), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
GetWindowRect(get_item(IDC_BUTTON_RESTORE), &r);
OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy);
screen_2_client(&r);
MoveWindow(get_item(IDC_BUTTON_RESTORE), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
GetWindowRect(get_item(IDOK), &r);
OffsetRect(&r, size.cx - (rme.right - rme.left), size.cy);
screen_2_client(&r);
MoveWindow(get_item(IDOK), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
}
select_page(0);
UpdateWindow(hwnd());
}
void dlg_setting::on_notify(int ctrl_id, LPNMHDR pnmh)
{
}
int dlg_setting::get_tab_count(void)
{
int count = 0;
if (IsWindow(tab_))
count = TabCtrl_GetItemCount(tab_);
return count;
}
dlg_page* dlg_setting::add_tab(const char* utf8_title)
{
std::wstring title(local_trans::a2u(utf8_title, CP_UTF8));
dlg_page *page = new dlg_page(hwnd(), title.c_str());
HFONT font = (HFONT)SendMessage(get_item(IDOK), WM_GETFONT, 0, 0);
LOGFONTW lf = { 0 };
GetObjectW(font, sizeof(lf), &lf);
page->set_font(font);
if (!IsWindow(tab_))
{
tab_ = CreateWindowW(L"SysTabControl32", L"pages", WS_CHILD | WS_VISIBLE, 0, 0, 100, lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, hwnd(), NULL, g_my_inst, NULL);
SendMessage(tab_, WM_SETFONT, (WPARAM)SendMessage(get_item(IDOK), WM_GETFONT, 0, 0), 1);
SetWindowLong(tab_, GWL_ID, 1234);
ShowWindow(tab_, SW_SHOW);
}
TC_ITEMW item = { 0 };
item.mask = TCIF_PARAM | TCIF_TEXT;
item.lParam = (LPARAM)page;
item.pszText = &title[0];
TabCtrl_InsertItem(tab_, get_tab_count(), &item);
page->hide();
return page;
}
dlg_page* dlg_setting::get_page(int index)
{
dlg_page* page = NULL;
if (IsWindow(tab_) && index >= 0 && index < get_tab_count())
{
TCITEMW item = { 0 };
item.mask = TCIF_PARAM;
TabCtrl_GetItem(tab_, index, &item);
page = (dlg_page*)item.lParam;
}
return page;
}
dlg_page* dlg_setting::get_page(const char* utf8_title)
{
dlg_page* page = NULL;
std::wstring unic(local_trans::a2u(utf8_title, CP_UTF8));
for (int i = 0; i < get_tab_count(); ++i)
{
TCITEMW item = { 0 };
wchar_t buf[80] = { 0 };
item.mask = TCIF_TEXT | TCIF_PARAM;
item.pszText = buf;
item.cchTextMax = _countof(buf) - 1;
TabCtrl_GetItem(tab_, i, &item);
if (unic == buf)
{
page = (dlg_page*)item.lParam;
break;
}
}
return page;
}
dlg_page* dlg_setting::select_page(int index)
{
dlg_page* ret = NULL, *cur = NULL;
for (int i = 0; cur = get_page(i); ++i)
{
if (i == index)
{
ret = cur;
cur->show();
}
else
cur->hide();
}
return ret;
}
void dlg_setting::refresh_controls(int src_sn)
{
}
void dlg_setting::set_quit_notify(void(__stdcall* notify)(bool, void*), void* param)
{
notify_ = notify;
notify_param_ = param;
}
HWND dlg_setting::window(void)
{
return hwnd_;
}
HWND dlg_setting::parent(void)
{
return parent_;
}
void dlg_setting::show(void)
{
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_setting::hide(void)
{
ShowWindow(hwnd_, SW_HIDE);
}
void dlg_setting::notify_data_arrived(bool image)
{
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();
}
}
// CDlgIndicator 消息处理程序

59
sane/DlgSetting.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <Windows.h>
#include <string>
#include <vector>
#include <sane/sane_ex.h>
#include "DlgPage.h"
// CDlgIndicator 对话框
//#define USE_SOLE_WIN_THREAD
#ifdef USE_SOLE_WIN_THREAD
#include <thread>
#include <memory>
#endif
class dlg_setting : public dlg_base
{
SANEAPI sane_api_;
SANE_Handle sane_dev_;
bool with_scan_;
unsigned int papers_;
unsigned int images_;
bool err_;
HWND tab_;
#ifdef USE_SOLE_WIN_THREAD
std::unique_ptr<std::thread> thread_;
#endif
void(__stdcall* notify_)(bool, void*);
void* notify_param_;
BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override;
void handle_command(WORD code, WORD id, HANDLE ctrl);
void notify_over(void);
void on_init_dialog(void);
void on_notify(int ctrl_id, LPNMHDR pnmh);
int get_tab_count(void);
dlg_page* add_tab(const char* utf8_title);
dlg_page* get_page(int index);
dlg_page* get_page(const char* utf8_title);
dlg_page* select_page(int index);
void refresh_controls(int src_sn);
public:
dlg_setting(HWND parent, LPSANEAPI api, SANE_Handle dev, bool with_scan, const wchar_t* name);
~dlg_setting();
public:
void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param);
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);
};

View File

@ -3,19 +3,25 @@
// ¹© sane.rc ʹÓà // ¹© sane.rc ʹÓÃ
// //
#define IDD_INDICATOR 101 #define IDD_INDICATOR 101
#define IDD_SETTING 103
#define IDD_PAGE 105
#define IDC_EDIT_PAPER 1001 #define IDC_EDIT_PAPER 1001
#define IDC_EDIT_IMAGE 1002 #define IDC_EDIT_IMAGE 1002
#define IDC_STATIC_PAPER 1003 #define IDC_STATIC_PAPER 1003
#define IDC_STATIC_IMAGE 1004 #define IDC_STATIC_IMAGE 1004
#define IDC_STATIC_ERR 1005 #define IDC_STATIC_ERR 1005
#define IDC_BUTTON_SCAN 1007
#define IDC_BUTTON_RESTORE 1008
#define IDC_BUTTON3 1009
#define IDC_BUTTON_HELP 1009
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_RESOURCE_VALUE 107
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1006 #define _APS_NEXT_CONTROL_VALUE 1008
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -4,3 +4,19 @@ EXPORTS
open_scanner open_scanner
is_scanner_online is_scanner_online
uninitialize uninitialize
sane_hgsane_init
sane_hgsane_exit
sane_hgsane_get_devices
sane_hgsane_open
sane_hgsane_close
sane_hgsane_get_option_descriptor
sane_hgsane_control_option
sane_hgsane_get_parameters
sane_hgsane_start
sane_hgsane_read
sane_hgsane_cancel
sane_hgsane_set_io_mode
sane_hgsane_get_select_fd
sane_hgsane_strstatus
sane_hgsane_init_ex
sane_hgsane_io_control

View File

@ -63,6 +63,23 @@ BEGIN
LTEXT "",IDC_STATIC_ERR,7,7,131,9,NOT WS_VISIBLE LTEXT "",IDC_STATIC_ERR,7,7,131,9,NOT WS_VISIBLE
END END
IDD_SETTING DIALOGEX 0, 0, 263, 28
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "确定",IDOK,223,8,33,13
PUSHBUTTON "扫描",IDC_BUTTON_SCAN,7,7,39,14,NOT WS_VISIBLE
PUSHBUTTON "恢复默认值",IDC_BUTTON_RESTORE,113,7,48,14,NOT WS_VISIBLE
PUSHBUTTON "帮助",IDC_BUTTON_HELP,167,7,48,14,NOT WS_VISIBLE
END
IDD_PAGE DIALOGEX 0, 0, 257, 133
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -79,6 +96,22 @@ BEGIN
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 31 BOTTOMMARGIN, 31
END END
IDD_SETTING, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 256
TOPMARGIN, 7
BOTTOMMARGIN, 21
END
IDD_PAGE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 250
TOPMARGIN, 7
BOTTOMMARGIN, 126
END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -93,6 +126,16 @@ BEGIN
0 0
END END
IDD_SETTING AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_PAGE AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // 中文(简体,中国) resources #endif // 中文(简体,中国) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -103,7 +103,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4996</DisableSpecificWarnings> <DisableSpecificWarnings>4996</DisableSpecificWarnings>
@ -128,7 +128,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>BACKEND_NAME=sane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4996</DisableSpecificWarnings> <DisableSpecificWarnings>4996</DisableSpecificWarnings>
@ -198,6 +198,8 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<ClCompile Include="..\..\code_device\hgsane\sane_hg_mdw.cpp" /> <ClCompile Include="..\..\code_device\hgsane\sane_hg_mdw.cpp" />
<ClCompile Include="..\..\code_device\hgsane\sane_option.cpp" /> <ClCompile Include="..\..\code_device\hgsane\sane_option.cpp" />
<ClCompile Include="DlgIndicator.cpp" /> <ClCompile Include="DlgIndicator.cpp" />
<ClCompile Include="DlgPage.cpp" />
<ClCompile Include="DlgSetting.cpp" />
<ClCompile Include="sane_option_trans.cpp" /> <ClCompile Include="sane_option_trans.cpp" />
<ClCompile Include="scanned_img.cpp" /> <ClCompile Include="scanned_img.cpp" />
<ClCompile Include="scanner.cpp" /> <ClCompile Include="scanner.cpp" />
@ -216,6 +218,8 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$
<ClInclude Include="..\..\sdk\include\sane\sane_ex.h" /> <ClInclude Include="..\..\sdk\include\sane\sane_ex.h" />
<ClInclude Include="..\..\sdk\include\sane\sane_option_definitions.h" /> <ClInclude Include="..\..\sdk\include\sane\sane_option_definitions.h" />
<ClInclude Include="DlgIndicator.h" /> <ClInclude Include="DlgIndicator.h" />
<ClInclude Include="DlgPage.h" />
<ClInclude Include="DlgSetting.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="s2t_api.h" /> <ClInclude Include="s2t_api.h" />
<ClInclude Include="sane_option_trans.h" /> <ClInclude Include="sane_option_trans.h" />

View File

@ -16,6 +16,9 @@
<Filter Include="sane2twain"> <Filter Include="sane2twain">
<UniqueIdentifier>{8ae15a45-410d-4611-b852-f82b64bb1fcc}</UniqueIdentifier> <UniqueIdentifier>{8ae15a45-410d-4611-b852-f82b64bb1fcc}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="sane2twain\UI">
<UniqueIdentifier>{5c86255e-570e-4921-9c62-c98d05edcab4}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\code_device\hgsane\cJSON.c"> <ClCompile Include="..\..\code_device\hgsane\cJSON.c">
@ -43,7 +46,13 @@
<Filter>sane2twain</Filter> <Filter>sane2twain</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="DlgIndicator.cpp"> <ClCompile Include="DlgIndicator.cpp">
<Filter>源文件</Filter> <Filter>sane2twain\UI</Filter>
</ClCompile>
<ClCompile Include="DlgSetting.cpp">
<Filter>sane2twain\UI</Filter>
</ClCompile>
<ClCompile Include="DlgPage.cpp">
<Filter>sane2twain\UI</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -99,7 +108,13 @@
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="DlgIndicator.h"> <ClInclude Include="DlgIndicator.h">
<Filter>头文件</Filter> <Filter>sane2twain\UI</Filter>
</ClInclude>
<ClInclude Include="DlgSetting.h">
<Filter>sane2twain\UI</Filter>
</ClInclude>
<ClInclude Include="DlgPage.h">
<Filter>sane2twain\UI</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -8,6 +8,7 @@
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include "DlgIndicator.h" #include "DlgIndicator.h"
#include "DlgSetting.h"
static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt);
@ -24,6 +25,27 @@ static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// callback // callback
extern "C"
{
extern SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize);
extern void inner_sane_exit(void);
extern SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only);
extern SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle);
extern void inner_sane_close(SANE_Handle handle);
extern const SANE_Option_Descriptor* inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option);
extern SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info);
extern SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params);
extern SANE_Status inner_sane_start(SANE_Handle handle);
extern SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length);
extern void inner_sane_cancel(SANE_Handle handle);
extern SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking);
extern SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd);
extern SANE_String_Const inner_sane_strstatus(SANE_Status status);
extern SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param);
extern SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len);
}
namespace callback namespace callback
{ {
static std::mutex cb_lock_; static std::mutex cb_lock_;
@ -87,7 +109,7 @@ namespace callback
// class scanner // class scanner
scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) 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) , dpi_(200), tmp_path_(L""), img_ind_(0), cb_invoker_(NULL), cb_param_(NULL), working_(false)
, ui_quit_(true) , ui_quit_(true), scanner_name_(L"")
{ {
tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str());
tmp_path_ += L"imgs"; tmp_path_ += L"imgs";
@ -190,12 +212,14 @@ int scanner::open(void)
int ret = close(); int ret = close();
std::string name(scanner::get_scanner_name(id_)); std::string name(scanner::get_scanner_name(id_));
scanner_name_ = L"";
if (name.empty()) if (name.empty())
return SCANNER_ERR_DEVICE_NOT_FOUND; return SCANNER_ERR_DEVICE_NOT_FOUND;
ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_);
if (ret == SANE_STATUS_GOOD) if (ret == SANE_STATUS_GOOD)
{ {
scanner_name_ = local_trans::a2u(name.c_str(), CP_UTF8);
callback::reg_callback(handle_, this); callback::reg_callback(handle_, this);
ret = init_options_id(); ret = init_options_id();
} }
@ -1818,18 +1842,34 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent))
} }
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))
{ {
indicator_.reset(new dlg_indicator()); SANEAPI api = { NULL };
indicator_->set_quit_notify(&scanner::ui_callback, this);
indicator_->show(parent); api.sane_cancel_api = inner_sane_cancel;
api.sane_close_api = inner_sane_close;
api.sane_control_option_api = inner_sane_control_option;
api.sane_get_devices_api = inner_sane_get_devices;
api.sane_get_option_descriptor_api = inner_sane_get_option_descriptor;
api.sane_get_parameters_api = inner_sane_get_parameters;
api.sane_get_select_fd_api = inner_sane_get_select_fd;
api.sane_io_control_api = inner_sane_io_control;
api.sane_open_api = inner_sane_open;
api.sane_read_api = inner_sane_read;
api.sane_set_io_mode_api = inner_sane_set_io_mode;
api.sane_start_api = inner_sane_start;
api.sane_strstatus_api = inner_sane_strstatus;
setting_.reset(new dlg_setting(parent, &api, handle_, with_scan, scanner_name_.c_str()));
setting_->set_quit_notify(&scanner::ui_callback, this);
setting_->show();
ui_quit_ = false; ui_quit_ = false;
return true; return true;
} }
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent)) COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent))
{ {
indicator_.reset(new dlg_indicator()); indicator_.reset(new dlg_indicator(parent));
indicator_->set_quit_notify(&scanner::ui_callback, this); indicator_->set_quit_notify(&scanner::ui_callback, this);
indicator_->show(parent); indicator_->show();
ui_quit_ = false; ui_quit_ = false;
return true; return true;
@ -1838,6 +1878,8 @@ COM_API_IMPLEMENT(scanner, void, ui_hide(void))
{ {
if (indicator_.get()) if (indicator_.get())
indicator_.reset(); indicator_.reset();
if (setting_.get())
setting_.reset();
} }
COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void)) COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
{ {

View File

@ -23,6 +23,8 @@
class dlg_indicator; class dlg_indicator;
class dlg_setting;
class scanner : public ISaneInvoker, virtual public refer class scanner : public ISaneInvoker, virtual public refer
{ {
SANE_Handle handle_; SANE_Handle handle_;
@ -34,6 +36,7 @@ class scanner : public ISaneInvoker, virtual public refer
int prev_start_result_; int prev_start_result_;
int dpi_; int dpi_;
unsigned int img_ind_; unsigned int img_ind_;
std::wstring scanner_name_;
std::wstring tmp_path_; std::wstring tmp_path_;
std::string scan_msg_; std::string scan_msg_;
bool scan_err_; bool scan_err_;
@ -43,6 +46,7 @@ class scanner : public ISaneInvoker, virtual public refer
bool ui_quit_; bool ui_quit_;
SANE_FinalImgFormat img_fmt_; SANE_FinalImgFormat img_fmt_;
std::unique_ptr<dlg_indicator> indicator_; std::unique_ptr<dlg_indicator> indicator_;
std::unique_ptr<dlg_setting> setting_;
void on_ui_quit(bool cancel); void on_ui_quit(bool cancel);
int open(void); int open(void);