This allows combining the capability negotiation with the application program with the user interface.
# Capability values ignored with User Interface
The recent patch to save sanner parameters from the twain user interface to the registry restores these parameters from the registry while displaying the dialog box.
Settings performed by the application program via the capabilities mechanism are thus overwritten from the registry and ignored.
So negotiated parameters are only honoured if the Twain user Interface is not being displayed. In that case _all_ old settings from the previous scan with UI displayed are ignored.
# Solution in this merge request
The TWAIN 2.4 specification says on Page 4-2 (PDF-Page 76):
``` At the time of loading the data source, all current values for the appropriate capabilities would be set to values that have either been restored from a previous session, or those that are "preferred" by the data source. This current value will remain until it has been explicitly changed by the calling application, or that application issues a MSG_RESET. ```
This is the approach choosen for this merge request:
The new function SANE_LoadOptions loads parameter values from the registry when the data source is being opened and transfers them to the sane parameter store.
The code in InitializeDialog, that loaded data from the registry, is restored to an older version and does not handle the registry at all. Instead dialog controls are filled based on the information in the SANE parameter database.
Saving changed parameters remains as before.
-- v5: dlls/sane.ds: Load last settings from registry immediatly when opening the DS
From: Bernd Herd codeberg@herdsoft.com
This allows combining the capability negotiation with the application program with the user interface. --- dlls/sane.ds/sane_i.h | 1 + dlls/sane.ds/sane_main.c | 3 + dlls/sane.ds/ui.c | 264 +++++++++++++++++++-------------------- 3 files changed, 132 insertions(+), 136 deletions(-)
diff --git a/dlls/sane.ds/sane_i.h b/dlls/sane.ds/sane_i.h index 0691f02e22d..66fdf0dc4c9 100644 --- a/dlls/sane.ds/sane_i.h +++ b/dlls/sane.ds/sane_i.h @@ -72,6 +72,7 @@ extern void SANE_Notify (TW_UINT16 message); extern TW_UINT16 SANE_Start(void); extern void SANE_Cancel(void); extern void SANE_XferReady(void); +extern void SANE_LoadOptions(void);
/* Implementation of operation triplets * From Application to Source (Control Information) */ diff --git a/dlls/sane.ds/sane_main.c b/dlls/sane.ds/sane_main.c index 0ff665c08dd..b4d471ea48f 100644 --- a/dlls/sane.ds/sane_main.c +++ b/dlls/sane.ds/sane_main.c @@ -82,6 +82,9 @@ static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) activeDS.appIdentity = *pOrigin; activeDS.capXferMech = TWSX_NATIVE; activeDS.capXferCount = -1; + + SANE_LoadOptions(); + return TWRC_SUCCESS; } SANE_CALL( close_ds, NULL ); diff --git a/dlls/sane.ds/ui.c b/dlls/sane.ds/ui.c index 3849220b4ef..e77d570595d 100644 --- a/dlls/sane.ds/ui.c +++ b/dlls/sane.ds/ui.c @@ -52,7 +52,6 @@ typedef struct } ScannerOption;
static char reg_path[MAX_PATH]; -static int gOptCount;
static INT_PTR CALLBACK DialogProc (HWND , UINT , WPARAM , LPARAM ); static INT CALLBACK PropSheetProc(HWND, UINT,LPARAM); @@ -508,8 +507,6 @@ BOOL DoScannerUI(void)
hdc = CreateCompatibleDC(0);
- gOptCount = optcount; - while (index < optcount) { struct option_descriptor opt; @@ -540,12 +537,6 @@ BOOL DoScannerUI(void) len = lstrlenA(activeDS.identity.Manufacturer) + lstrlenA(activeDS.identity.ProductName) + 2; szCaption = malloc(len *sizeof(WCHAR)); - - snprintf(reg_path, MAX_PATH, "Software\ScannersSettings\%s\%s_%s", - activeDS.identity.Manufacturer, - activeDS.identity.ProductFamily, - activeDS.identity.ProductName); - MultiByteToWideChar(CP_ACP,0,activeDS.identity.Manufacturer,-1, szCaption,len); szCaption[lstrlenA(activeDS.identity.Manufacturer)] = ' '; @@ -593,37 +584,6 @@ static BOOL save_to_reg( DWORD reg_type, CHAR* name, const BYTE* value, DWORD si return res == ERROR_SUCCESS; }
-static BOOL load_from_reg( int opt_type, CHAR* name, void* value ) -{ - HKEY h_key; - DWORD flag, size; - LSTATUS res; - - if (RegOpenKeyExA( HKEY_CURRENT_USER, reg_path, 0, KEY_ALL_ACCESS, &h_key )) return FALSE; - - switch( opt_type ) - { - case TYPE_INT: - case TYPE_FIXED: - case TYPE_BOOL: - flag = RRF_RT_REG_DWORD; - size = sizeof(DWORD); - break; - case TYPE_STRING: - flag = RRF_RT_REG_SZ; - size = OPTION_VALUE_MAX; - break; - default: - RegCloseKey( h_key ); - ERR( "Unknown type: %d\n", opt_type ); - return FALSE; - } - - res = RegGetValueA( h_key, NULL, name, flag, NULL, value, &size ); - RegCloseKey( h_key ); - return res == ERROR_SUCCESS; -} - static BOOL get_option(struct option_descriptor* opt, ScannerOption* option) { lstrcpynA(option->name, opt->name, OPTION_NAME_MAX); @@ -793,66 +753,41 @@ static BOOL UpdateSaneScrollOption(const struct option_descriptor *opt, DWORD po return result; }
+ +/* @brief Set Dialog control values to SANE values + * + * Set the values of controls in the Scanner GUI property sheet dialog + * to those selected in the SANE parameter space. + * Set Combobox options to the list of possible values. + * + * @param hwnd Property sheet Dialog window. + * + * @return Return value for dialog function WM_INITDIALOG. Always TRUE. + */ static INT_PTR InitializeDialog(HWND hwnd) { TW_UINT16 rc; int optcount; HWND control; int i; - int o; - int *opt_order=NULL;
rc = sane_option_get_value( 0, &optcount ); if (rc != TWCC_SUCCESS) { ERR("Unable to read number of options\n"); - optcount = gOptCount; - } - else - gOptCount = optcount; - - /* Determine the order in which options shall be set in sane */ - opt_order = malloc((optcount+1) * sizeof(int)); - if (!opt_order) - { - ERR("Out of memory allocation opt_order\n"); return FALSE; }
- for ( o = 0; o < optcount; o++) - { - opt_order[o] = o; - } - - for ( o = 1; o < optcount; o++) - { - struct option_descriptor opt; - opt.optno = opt_order[o]; - SANE_CALL( option_get_descriptor, &opt ); - - if (!strcmp(opt.name, "source")) - { - /* Source (adf, flatbed) must be set before resolution - * so process it first */ - memmove(opt_order+2, - opt_order+1, - (o-1) * sizeof(int)); - opt_order[1] = opt.optno; - } - } - - for ( o = 1; o < optcount; o++) + for ( i = 1; i < optcount; i++) { struct option_descriptor opt;
- opt.optno = - i = opt_order[o]; - control = GetDlgItem(hwnd,i+ID_BASE);
if (!control) continue;
+ opt.optno = i; SANE_CALL( option_get_descriptor, &opt );
TRACE("%i %s %i %i\n",i,debugstr_w(opt.title),opt.type,opt.constraint_type); @@ -864,37 +799,15 @@ static INT_PTR InitializeDialog(HWND hwnd) { CHAR buffer[255]; WCHAR *p; - char oldvalue[256]; - - sane_option_get_value(opt.optno, oldvalue);
for (p = opt.constraint.strings; *p; p += lstrlenW(p) + 1) SendMessageW( control,CB_ADDSTRING,0, (LPARAM)p ); - - if (load_from_reg(opt.type, opt.name, buffer)) - { - for (p = opt.constraint.strings; *p; p += lstrlenW(p) + 1) - { - CHAR param[256]; - WideCharToMultiByte(CP_UTF8, 0, p, -1, param, sizeof(param), NULL, NULL); - if (!strcmp(param, buffer)) - { - if (strcmp(param, oldvalue)) - sane_option_set_value(opt.optno, buffer, NULL); - break; - } - } - if (!*p) ERR("%s=%s is incorrect. The default value is set!", opt.name, buffer); - } - sane_option_get_value( i, buffer ); SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer); } else if (opt.type == TYPE_BOOL) { BOOL b; - - if (load_from_reg(opt.type, opt.name, &b)) sane_option_set_value( i, &b, NULL ); sane_option_get_value( i, &b ); SendMessageA(control,BM_SETCHECK, b ? BST_CHECKED : BST_UNCHECKED,0); } @@ -908,20 +821,6 @@ static INT_PTR InitializeDialog(HWND hwnd) sprintf(buffer, "%d", opt.constraint.word_list[j]); SendMessageA(control, CB_ADDSTRING, 0, (LPARAM)buffer); } - - if (load_from_reg(opt.type, opt.name, &val)) - { - for (j=1; j<=count; j++) - { - if (opt.constraint.word_list[j] == val) - { - sane_option_set_value( i, &val, NULL ); - break; - } - } - if (j > count) ERR("%s=%d is incorrect. The default value is set!\n", opt.name, val); - } - sane_option_get_value( i, &val ); sprintf(buffer, "%d", val); SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer); @@ -941,12 +840,6 @@ static INT_PTR InitializeDialog(HWND hwnd)
SendMessageA(control,SBM_SETRANGE,min,max);
- if (load_from_reg(opt.type, opt.name, &si)) - { - if (si >= min && si <= max) sane_option_set_value( i, &si, NULL); - else ERR("%s=%d is out of range [%d..%d]. The default value is used!\n", opt.name, si, min, max); - } - sane_option_get_value( i, &si ); if (opt.constraint.range.quant) si = si / opt.constraint.range.quant; @@ -956,7 +849,7 @@ static INT_PTR InitializeDialog(HWND hwnd) } else if (opt.type == TYPE_FIXED) { - int pos, min, max, *sf, val; + int pos, min, max, *sf;
if (opt.constraint.range.quant) { @@ -971,19 +864,6 @@ static INT_PTR InitializeDialog(HWND hwnd)
SendMessageA(control,SBM_SETRANGE,min,max);
- if (load_from_reg(opt.type, opt.name, &val)) - { - if (val >= min && val <= max) - { - int valSet; - if (opt.constraint.range.quant) - valSet = val * opt.constraint.range.quant; - else - valSet = MulDiv(val, 65536, 100); - sane_option_set_value(i, &valSet, NULL); - } - else ERR("%s = %d is out of range [%d..%d]. The default value is used!\n", opt.name, val, min, max); - }
sf = calloc( opt.size, sizeof(int) ); sane_option_get_value( i, sf ); @@ -1004,8 +884,6 @@ static INT_PTR InitializeDialog(HWND hwnd) } }
- free(opt_order); - return TRUE; }
@@ -1201,3 +1079,117 @@ HWND ScanningDialogBox(HWND dialog, LONG progress)
return dialog; } + + +/** @brief Load all current settings from registry to sane + * + * Called when opening a data source. + * Loads all SANE options from the registry and sets them + * in the SANE parameter space for later negotiation + * with the CAP_xxx machanism and display in the UI. + */ +void +SANE_LoadOptions(void) +{ + TW_UINT16 rc; + int optcount; + int o; + int *opt_order=NULL; + + HKEY h_key; + DWORD size; + + int ivalue; + char svalue[OPTION_VALUE_MAX+1]; + + snprintf(reg_path, MAX_PATH, "Software\ScannersSettings\%s\%s_%s", + activeDS.identity.Manufacturer, + activeDS.identity.ProductFamily, + activeDS.identity.ProductName); + + rc = sane_option_get_value( 0, &optcount ); + if (rc != TWCC_SUCCESS) + { + ERR("SANE_LoadOptions: Unable to read number of options\n"); + return; + } + + if (RegOpenKeyExA( HKEY_CURRENT_USER, reg_path, 0, KEY_ALL_ACCESS, &h_key)==ERROR_SUCCESS) + { + /* Determine the order in which options shall be set in sane */ + opt_order = malloc((optcount+1) * sizeof(int)); + if (!opt_order) + { + ERR("Out of memory allocating opt_order\n"); + RegCloseKey( h_key ); + return; + } + + for ( o = 0; o < optcount; o++) + { + opt_order[o] = o; + } + + for ( o = 1; o < optcount; o++) + { + struct option_descriptor opt; + opt.optno = opt_order[o]; + SANE_CALL( option_get_descriptor, &opt ); + + if (!strcmp(opt.name, "source")) + { + /* Source (adf, flatbed) must be set before resolution + * so process it first */ + memmove(opt_order+2, + opt_order+1, + (o-1) * sizeof(int)); + opt_order[1] = opt.optno; + } + } + + for ( o = 1; o < optcount; o++) + { + struct option_descriptor opt; + opt.optno = opt_order[o]; + + SANE_CALL( option_get_descriptor, &opt ); + + TRACE("%i %s %i %i\n",opt.optno,debugstr_w(opt.title),opt.type,opt.constraint_type); + + switch( opt.type ) + { + case TYPE_INT: + case TYPE_BOOL: + size = sizeof(ivalue); + if (RegGetValueA( h_key, NULL, opt.name, RRF_RT_REG_DWORD, NULL, &ivalue, &size)==ERROR_SUCCESS) + { + sane_option_set_value( opt.optno, &ivalue, NULL ); + } + break; + case TYPE_FIXED: + size = sizeof(ivalue); + if (RegGetValueA( h_key, NULL, opt.name, RRF_RT_REG_DWORD, NULL, &ivalue, &size)==ERROR_SUCCESS) + { + int valSet; + if (opt.constraint.range.quant) + valSet = ivalue * opt.constraint.range.quant; + else + valSet = MulDiv(ivalue, 65536, 100); + sane_option_set_value( opt.optno, &valSet, NULL); + } + break; + case TYPE_STRING: + size = OPTION_VALUE_MAX; + if (RegGetValueA( h_key, NULL, opt.name, RRF_RT_REG_SZ, NULL, svalue, &size)==ERROR_SUCCESS) + { + sane_option_set_value( opt.optno, svalue, NULL ); + } + break; + default: ; + } + } + free(opt_order); + + RegCloseKey( h_key ); + } +}