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.
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 | 265 +++++++++++++++++++-------------------- 3 files changed, 135 insertions(+), 134 deletions(-)
diff --git a/dlls/sane.ds/sane_i.h b/dlls/sane.ds/sane_i.h index e35ed77c935..e98d96340f7 100644 --- a/dlls/sane.ds/sane_i.h +++ b/dlls/sane.ds/sane_i.h @@ -59,6 +59,7 @@ extern struct tagActiveDS activeDS; extern TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action); extern TW_UINT16 SANE_SaneSetDefaults (void); extern void SANE_Notify (TW_UINT16 message); +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 360509e2bf6..45d936f38d4 100644 --- a/dlls/sane.ds/sane_main.c +++ b/dlls/sane.ds/sane_main.c @@ -80,6 +80,9 @@ static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) activeDS.currentState = 4; activeDS.identity.Id = self->Id; activeDS.appIdentity = *pOrigin; + + 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 51c7f54eea9..a74aa3914a7 100644 --- a/dlls/sane.ds/ui.c +++ b/dlls/sane.ds/ui.c @@ -539,12 +539,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)] = ' '; @@ -592,37 +586,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); @@ -792,66 +755,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); @@ -863,39 +801,19 @@ 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); + if (b) + SendMessageA(control,BM_SETCHECK,BST_CHECKED,0); + } else if (opt.type == TYPE_INT && opt.constraint_type == CONSTRAINT_WORD_LIST) { @@ -907,20 +825,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); @@ -940,12 +844,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; @@ -955,7 +853,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) { @@ -970,19 +868,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 ); @@ -1003,8 +888,6 @@ static INT_PTR InitializeDialog(HWND hwnd) } }
- free(opt_order); - return TRUE; }
@@ -1201,3 +1084,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; + } + gOptCount = optcount; + + 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 allocation opt_order\n"); + 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 ); + } +}