diff --git a/configure b/configure
index 7afb536cc68c4433497dac23f3c09ffb9e6c255f..080376b708ff9ce58c9f7f30d09d30e3c54dfbcc 100755
--- a/configure
+++ b/configure
@@ -19798,7 +19798,7 @@ MAKE_LIB_RULES=libs/Makelib.rules
 MAKE_PROG_RULES=programs/Makeprog.rules
 
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Makeimplib.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/activeds/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/advpack/Makefile dlls/advpack/tests/Makefile dlls/amstream/Makefile dlls/atl/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/cabinet/tests/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/comdlg32/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/crypt32/tests/Makefile dlls/cryptdll/Makefile dlls/ctl3d32/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3d9/tests/Makefile dlls/d3dim/Makefile dlls/d3drm/Makefile dlls/d3dx8/Makefile dlls/d3dxof/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput/tests/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dnsapi/Makefile dlls/dnsapi/tests/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imaadp32.acm/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/itss/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lz32/Makefile dlls/lz32/tests/Makefile dlls/mapi32/Makefile dlls/mapi32/tests/Makefile dlls/mciavi32/Makefile dlls/mcicda/Makefile dlls/mciseq/Makefile dlls/midimap/Makefile dlls/mlang/Makefile dlls/mlang/tests/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/mprapi/Makefile dlls/msacm32/Makefile dlls/msacm32/tests/Makefile dlls/msadp32.acm/Makefile dlls/mscms/Makefile dlls/mscms/tests/Makefile dlls/msdmo/Makefile dlls/msftedit/Makefile dlls/msg711.acm/Makefile dlls/mshtml/Makefile dlls/mshtml/tests/Makefile dlls/msi/Makefile dlls/msi/tests/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvcrtd/tests/Makefile dlls/msvfw32/Makefile dlls/msvidc32/Makefile dlls/mswsock/Makefile dlls/msxml3/Makefile dlls/msxml3/tests/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/objsel/Makefile dlls/odbc32/Makefile dlls/odbccp32/Makefile dlls/ole32/Makefile dlls/ole32/tests/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli32/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr32/Makefile dlls/opengl32/Makefile dlls/powrprof/Makefile dlls/psapi/Makefile dlls/psapi/tests/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/quartz/tests/Makefile dlls/rasapi32/Makefile dlls/riched20/Makefile dlls/riched20/tests/Makefile dlls/riched32/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/rsabase/tests/Makefile dlls/rsaenh/Makefile dlls/rsaenh/tests/Makefile dlls/secur32/Makefile dlls/secur32/tests/Makefile dlls/security/Makefile dlls/sensapi/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/setupapi/tests/Makefile dlls/sfc/Makefile dlls/shdocvw/Makefile dlls/shdocvw/tests/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/spoolss/Makefile dlls/stdole2.tlb/Makefile dlls/stdole32.tlb/Makefile dlls/sti/Makefile dlls/strmiids/Makefile dlls/tapi32/Makefile dlls/twain_32/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/usp10/Makefile dlls/usp10/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/w32skrnl/Makefile dlls/winecrt0/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/winemp3.acm/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/wineesd/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls32/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wldap32/Makefile dlls/wnaspi32/Makefile dlls/wow32/Makefile dlls/ws2_32/Makefile dlls/ws2_32/tests/Makefile dlls/wsock32/Makefile dlls/wtsapi32/Makefile dlls/x11drv/Makefile documentation/Makefile fonts/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/eject/Makefile programs/expand/Makefile programs/explorer/Makefile programs/hh/Makefile programs/icinfo/Makefile programs/iexplore/Makefile programs/msiexec/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile programs/wordpad/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Makeimplib.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/activeds/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/advpack/Makefile dlls/advpack/tests/Makefile dlls/amstream/Makefile dlls/atl/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/cabinet/tests/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/comdlg32/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/crypt32/tests/Makefile dlls/cryptdll/Makefile dlls/ctl3d32/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3d9/tests/Makefile dlls/d3dim/Makefile dlls/d3drm/Makefile dlls/d3dx8/Makefile dlls/d3dxof/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput/tests/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dnsapi/Makefile dlls/dnsapi/tests/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imaadp32.acm/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/itss/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lz32/Makefile dlls/lz32/tests/Makefile dlls/mapi32/Makefile dlls/mapi32/tests/Makefile dlls/mciavi32/Makefile dlls/mcicda/Makefile dlls/mciseq/Makefile dlls/midimap/Makefile dlls/mlang/Makefile dlls/mlang/tests/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/mprapi/Makefile dlls/msacm32/Makefile dlls/msacm32/tests/Makefile dlls/msadp32.acm/Makefile dlls/mscms/Makefile dlls/mscms/tests/Makefile dlls/msdmo/Makefile dlls/msftedit/Makefile dlls/msg711.acm/Makefile dlls/mshtml/Makefile dlls/mshtml/tests/Makefile dlls/msi/Makefile dlls/msi/tests/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvcrtd/tests/Makefile dlls/msvfw32/Makefile dlls/msvidc32/Makefile dlls/mswsock/Makefile dlls/msxml3/Makefile dlls/msxml3/tests/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/objsel/Makefile dlls/odbc32/Makefile dlls/odbccp32/Makefile dlls/ole32/Makefile dlls/ole32/tests/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli32/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr32/Makefile dlls/opengl32/Makefile dlls/powrprof/Makefile dlls/psapi/Makefile dlls/psapi/tests/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/quartz/tests/Makefile dlls/rasapi32/Makefile dlls/riched20/Makefile dlls/riched20/tests/Makefile dlls/riched32/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/rsabase/tests/Makefile dlls/rsaenh/Makefile dlls/rsaenh/tests/Makefile dlls/sane.ds/Makefile dlls/secur32/Makefile dlls/secur32/tests/Makefile dlls/security/Makefile dlls/sensapi/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/setupapi/tests/Makefile dlls/sfc/Makefile dlls/shdocvw/Makefile dlls/shdocvw/tests/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/spoolss/Makefile dlls/stdole2.tlb/Makefile dlls/stdole32.tlb/Makefile dlls/sti/Makefile dlls/strmiids/Makefile dlls/tapi32/Makefile dlls/twain_32/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/usp10/Makefile dlls/usp10/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/w32skrnl/Makefile dlls/winecrt0/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/winemp3.acm/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/wineesd/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls32/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wldap32/Makefile dlls/wnaspi32/Makefile dlls/wow32/Makefile dlls/ws2_32/Makefile dlls/ws2_32/tests/Makefile dlls/wsock32/Makefile dlls/wtsapi32/Makefile dlls/x11drv/Makefile documentation/Makefile fonts/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/eject/Makefile programs/expand/Makefile programs/explorer/Makefile programs/hh/Makefile programs/icinfo/Makefile programs/iexplore/Makefile programs/msiexec/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile programs/wordpad/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
 
 
 cat >confcache <<\_ACEOF
@@ -20488,6 +20488,7 @@ do
   "dlls/rsabase/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/rsabase/tests/Makefile" ;;
   "dlls/rsaenh/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/rsaenh/Makefile" ;;
   "dlls/rsaenh/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/rsaenh/tests/Makefile" ;;
+  "dlls/sane.ds/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/sane.ds/Makefile" ;;
   "dlls/secur32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/secur32/Makefile" ;;
   "dlls/secur32/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/secur32/tests/Makefile" ;;
   "dlls/security/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/security/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index 6de7e1b3cd8e9e75baf6232a10f979a5d84675ff..f852a0033ee872278139fb312e52a709c8233660 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1636,6 +1636,7 @@ dlls/rsabase/Makefile
 dlls/rsabase/tests/Makefile
 dlls/rsaenh/Makefile
 dlls/rsaenh/tests/Makefile
+dlls/sane.ds/Makefile
 dlls/secur32/Makefile
 dlls/secur32/tests/Makefile
 dlls/security/Makefile
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index 0c64976ce0da9669c03afe48af9d61c0efe37be4..d044337db6ce6f144aef485fb6fc258425efb422 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -124,6 +124,7 @@ BASEDIRS = \
 	rpcrt4 \
 	rsabase \
 	rsaenh \
+	sane.ds \
 	secur32 \
 	security \
 	sensapi \
diff --git a/dlls/sane.ds/.gitignore b/dlls/sane.ds/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..581860b6baa06ed16efc8913cf2d13c21ed5fec2
--- /dev/null
+++ b/dlls/sane.ds/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+rsrc.res
diff --git a/dlls/sane.ds/Makefile.in b/dlls/sane.ds/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..ee7f35c6afd11e2925d623f5395b9a279a9e9a3a
--- /dev/null
+++ b/dlls/sane.ds/Makefile.in
@@ -0,0 +1,22 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = sane.ds
+IMPORTS   = comctl32 user32 gdi32 kernel32 ntdll
+EXTRALIBS = @SANELIBS@
+EXTRAINCL = @SANEINCL@
+
+C_SRCS = \
+	capability.c \
+	ds_ctrl.c \
+	ds_image.c \
+	sane_main.c \
+	ui.c
+
+RC_SRCS = \
+	rsrc.rc
+
+@MAKE_DLL_RULES@
+
+### Dependencies:
diff --git a/dlls/twain_32/capability.c b/dlls/sane.ds/capability.c
similarity index 92%
rename from dlls/twain_32/capability.c
rename to dlls/sane.ds/capability.c
index 64b480e48734cf5d597c0cdbe1157e7bda41b088..4bdf186ff60c18c3cabe05d00fadf818da78b0ed 100644
--- a/dlls/twain_32/capability.c
+++ b/dlls/sane.ds/capability.c
@@ -26,13 +26,12 @@
 #include "windef.h"
 #include "winbase.h"
 #include "twain.h"
-#include "twain_i.h"
+#include "sane_i.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
-TW_UINT16 TWAIN_SaneCapability (activeDS *pSource, pTW_CAPABILITY pCapability,
-                                TW_UINT16 action)
+TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
 {
     TW_UINT16 twCC = TWCC_SUCCESS;
 
@@ -158,7 +157,7 @@ TW_UINT16 TWAIN_SaneCapability (activeDS *pSource, pTW_CAPABILITY pCapability,
             twCC = TWCC_CAPUNSUPPORTED;
             break;
         case ICAP_XFERMECH:
-            twCC = TWAIN_ICAPXferMech (pSource, pCapability, action);
+            twCC = SANE_ICAPXferMech (pCapability, action);
             break;
         case ICAP_UNDEFINEDIMAGESIZE:
         case CAP_CAMERAPREVIEWUI:
@@ -206,8 +205,7 @@ static TW_BOOL TWAIN_OneValueGet (pTW_CAPABILITY pCapability, TW_UINT32 *pValue)
 }
 
 /* ICAP_XFERMECH */
-TW_UINT16 TWAIN_ICAPXferMech (activeDS *pSource, pTW_CAPABILITY pCapability,
-                              TW_UINT16 action)
+TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
 {
     TRACE("ICAP_XFERMECH\n");
 
@@ -216,7 +214,7 @@ TW_UINT16 TWAIN_ICAPXferMech (activeDS *pSource, pTW_CAPABILITY pCapability,
         case MSG_GET:
             if (pCapability->ConType == TWON_ONEVALUE)
             {
-                if (!TWAIN_OneValueSet (pCapability, pSource->capXferMech))
+                if (!TWAIN_OneValueSet (pCapability, activeDS.capXferMech))
                     return TWCC_LOWMEMORY;
             }
             break;
@@ -226,7 +224,7 @@ TW_UINT16 TWAIN_ICAPXferMech (activeDS *pSource, pTW_CAPABILITY pCapability,
 		TW_UINT32 xfermechtemp = 0;
                 if (!TWAIN_OneValueGet (pCapability, &xfermechtemp))
                     return TWCC_LOWMEMORY;
-		pSource->capXferMech = xfermechtemp;
+		activeDS.capXferMech = xfermechtemp;
             }
             else if (pCapability->ConType == TWON_ENUMERATION)
             {
@@ -234,7 +232,7 @@ TW_UINT16 TWAIN_ICAPXferMech (activeDS *pSource, pTW_CAPABILITY pCapability,
             }
             break;
         case MSG_GETCURRENT:
-            if (!TWAIN_OneValueSet (pCapability, pSource->capXferMech))
+            if (!TWAIN_OneValueSet (pCapability, activeDS.capXferMech))
                 return TWCC_LOWMEMORY;
             break;
         case MSG_GETDEFAULT:
@@ -242,7 +240,7 @@ TW_UINT16 TWAIN_ICAPXferMech (activeDS *pSource, pTW_CAPABILITY pCapability,
                 return TWCC_LOWMEMORY;
             break;
         case MSG_RESET:
-            pSource->capXferMech = TWSX_NATIVE;
+            activeDS.capXferMech = TWSX_NATIVE;
             break;
     }
     return TWCC_SUCCESS;
diff --git a/dlls/twain_32/ds_ctrl.c b/dlls/sane.ds/ds_ctrl.c
similarity index 54%
rename from dlls/twain_32/ds_ctrl.c
rename to dlls/sane.ds/ds_ctrl.c
index 50805a522fcf25ef5bc9434cb3a0662879b4f28c..51c597b341eeaf3035ceba89e2f7087c81190ea7 100644
--- a/dlls/twain_32/ds_ctrl.c
+++ b/dlls/sane.ds/ds_ctrl.c
@@ -23,104 +23,83 @@
 #endif
 #include <stdlib.h>
 #include "twain.h"
-#include "twain_i.h"
+#include "sane_i.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_GET */
-TW_UINT16 TWAIN_CapabilityGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
-                               TW_MEMREF pData)
+TW_UINT16 SANE_CapabilityGet (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS, twCC = TWCC_SUCCESS;
     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GET\n");
 
-    if (!pDest)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 4 || pSource->currentState > 7)
+    if (activeDS.currentState < 4 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        twCC = TWAIN_SaneCapability (pSource, pCapability, MSG_GET);
+        twCC = SANE_SaneCapability (pCapability, MSG_GET);
         twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
-        pSource->twCC = twCC;
+        activeDS.twCC = twCC;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_GETCURRENT */
-TW_UINT16 TWAIN_CapabilityGetCurrent (pTW_IDENTITY pOrigin,
-                                      pTW_IDENTITY pDest,TW_MEMREF pData)
+TW_UINT16 SANE_CapabilityGetCurrent (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS, twCC = TWCC_SUCCESS;
     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GETCURRENT\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 4 || pSource->currentState > 7)
+    if (activeDS.currentState < 4 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        twCC = TWAIN_SaneCapability (pSource, pCapability, MSG_GETCURRENT);
+        twCC = SANE_SaneCapability (pCapability, MSG_GETCURRENT);
         twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
-        pSource->twCC = twCC;
+        activeDS.twCC = twCC;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_CapabilityGetDefault (pTW_IDENTITY pOrigin,
-                                      pTW_IDENTITY pDest, TW_MEMREF pData)
+TW_UINT16 SANE_CapabilityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS, twCC = TWCC_SUCCESS;
     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_GETDEFAULT\n");
 
-    if (!pDest)
+    if (activeDS.currentState < 4 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 4 || pSource->currentState > 7)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        twCC = TWAIN_SaneCapability (pSource, pCapability, MSG_GETDEFAULT);
+        twCC = SANE_SaneCapability (pCapability, MSG_GETDEFAULT);
         twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
-        pSource->twCC = twCC;
+        activeDS.twCC = twCC;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_QUERYSUPPORT */
-TW_UINT16 TWAIN_CapabilityQuerySupport (pTW_IDENTITY pOrigin,
-                                        pTW_IDENTITY pDest, TW_MEMREF pData)
+TW_UINT16 SANE_CapabilityQuerySupport (pTW_IDENTITY pOrigin,
+                                        TW_MEMREF pData)
 {
     FIXME ("stub!\n");
 
@@ -128,66 +107,54 @@ TW_UINT16 TWAIN_CapabilityQuerySupport (pTW_IDENTITY pOrigin,
 }
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_RESET */
-TW_UINT16 TWAIN_CapabilityReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CapabilityReset (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS, twCC = TWCC_SUCCESS;
     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_CAPABILITY/MSG_RESET\n");
 
-    if (!pDest)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 4 || pSource->currentState > 7)
+    if (activeDS.currentState < 4 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        twCC = TWAIN_SaneCapability (pSource, pCapability, MSG_RESET);
+        twCC = SANE_SaneCapability (pCapability, MSG_RESET);
         twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
-        pSource->twCC = twCC;
+        activeDS.twCC = twCC;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_CAPABILITY/MSG_SET */
-TW_UINT16 TWAIN_CapabilitySet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CapabilitySet (pTW_IDENTITY pOrigin, 
                                TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS, twCC = TWCC_SUCCESS;
     pTW_CAPABILITY pCapability = (pTW_CAPABILITY) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE ("DG_CONTROL/DAT_CAPABILITY/MSG_SET\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 4)
+    if (activeDS.currentState != 4)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        twCC = TWAIN_SaneCapability (pSource, pCapability, MSG_SET);
+        twCC = SANE_SaneCapability (pCapability, MSG_SET);
         twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
-        pSource->twCC = twCC;
+        activeDS.twCC = twCC;
     }
     return twRC;
 }
 
 /* DG_CONTROL/DAT_CUSTOMDSDATA/MSG_GET */
-TW_UINT16 TWAIN_CustomDSDataGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CustomDSDataGet (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -196,7 +163,7 @@ TW_UINT16 TWAIN_CustomDSDataGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_CUSTOMDSDATA/MSG_SET */
-TW_UINT16 TWAIN_CustomDSDataSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CustomDSDataSet (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -205,8 +172,8 @@ TW_UINT16 TWAIN_CustomDSDataSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_AUTOMATICCAPTUREDIRECTORY */
-TW_UINT16 TWAIN_AutomaticCaptureDirectory (pTW_IDENTITY pOrigin,
-                                           pTW_IDENTITY pDest,
+TW_UINT16 SANE_AutomaticCaptureDirectory (pTW_IDENTITY pOrigin,
+                                           
                                            TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -215,7 +182,7 @@ TW_UINT16 TWAIN_AutomaticCaptureDirectory (pTW_IDENTITY pOrigin,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_CHANGEDIRECTORY */
-TW_UINT16 TWAIN_ChangeDirectory (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ChangeDirectory (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -224,7 +191,7 @@ TW_UINT16 TWAIN_ChangeDirectory (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_COPY */
-TW_UINT16 TWAIN_FileSystemCopy (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemCopy (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -233,7 +200,7 @@ TW_UINT16 TWAIN_FileSystemCopy (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_CREATEDIRECTORY */
-TW_UINT16 TWAIN_CreateDirectory (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CreateDirectory (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -242,7 +209,7 @@ TW_UINT16 TWAIN_CreateDirectory (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_DELETE */
-TW_UINT16 TWAIN_FileSystemDelete (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemDelete (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -251,7 +218,7 @@ TW_UINT16 TWAIN_FileSystemDelete (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_FORMATMEDIA */
-TW_UINT16 TWAIN_FormatMedia (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FormatMedia (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -260,7 +227,7 @@ TW_UINT16 TWAIN_FormatMedia (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETCLOSE */
-TW_UINT16 TWAIN_FileSystemGetClose (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemGetClose (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -269,8 +236,8 @@ TW_UINT16 TWAIN_FileSystemGetClose (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETFIRSTFILE */
-TW_UINT16 TWAIN_FileSystemGetFirstFile (pTW_IDENTITY pOrigin,
-                                        pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemGetFirstFile (pTW_IDENTITY pOrigin,
+                                        
                                         TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -279,7 +246,7 @@ TW_UINT16 TWAIN_FileSystemGetFirstFile (pTW_IDENTITY pOrigin,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETINFO */
-TW_UINT16 TWAIN_FileSystemGetInfo (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemGetInfo (pTW_IDENTITY pOrigin, 
                                    TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -288,8 +255,8 @@ TW_UINT16 TWAIN_FileSystemGetInfo (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_GETNEXTFILE */
-TW_UINT16 TWAIN_FileSystemGetNextFile (pTW_IDENTITY pOrigin,
-                                       pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemGetNextFile (pTW_IDENTITY pOrigin,
+                                       
                                        TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -298,7 +265,7 @@ TW_UINT16 TWAIN_FileSystemGetNextFile (pTW_IDENTITY pOrigin,
 }
 
 /* DG_CONTROL/DAT_FILESYSTEM/MSG_RENAME */
-TW_UINT16 TWAIN_FileSystemRename (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_FileSystemRename (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -307,31 +274,25 @@ TW_UINT16 TWAIN_FileSystemRename (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_EVENT/MSG_PROCESSEVENT */
-TW_UINT16 TWAIN_ProcessEvent (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ProcessEvent (pTW_IDENTITY pOrigin, 
                               TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_EVENT pEvent = (pTW_EVENT) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_EVENT/MSG_PROCESSEVENT\n");
 
-    if (!pSource)
-    {
-         twRC = TWRC_FAILURE;
-         DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 5 || pSource->currentState > 7)
+    if (activeDS.currentState < 5 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        if (pSource->pendingEvent.TWMessage != MSG_NULL)
+        if (activeDS.pendingEvent.TWMessage != MSG_NULL)
         {
-            pEvent->TWMessage = pSource->pendingEvent.TWMessage;
-            pSource->pendingEvent.TWMessage = MSG_NULL;
+            pEvent->TWMessage = activeDS.pendingEvent.TWMessage;
+            activeDS.pendingEvent.TWMessage = MSG_NULL;
             twRC = TWRC_NOTDSEVENT;
         }
         else
@@ -339,14 +300,14 @@ TW_UINT16 TWAIN_ProcessEvent (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
             pEvent->TWMessage = MSG_NULL;  /* no message to the application */
             twRC = TWRC_NOTDSEVENT;
         }
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_PASSTHRU/MSG_PASSTHRU */
-TW_UINT16 TWAIN_PassThrough (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_PassThrough (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -355,110 +316,92 @@ TW_UINT16 TWAIN_PassThrough (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_ENDXFER */
-TW_UINT16 TWAIN_PendingXfersEndXfer (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_PendingXfersEndXfer (pTW_IDENTITY pOrigin, 
                                      TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_ENDXFER\n");
 
-    if (!pSource)
+    if (activeDS.currentState != 6 && activeDS.currentState != 7)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 6 && pSource->currentState != 7)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
         if (pPendingXfers->Count != 0)
         {
             pPendingXfers->Count --;
-            pSource->currentState = 6;
+            activeDS.currentState = 6;
         }
         else
         {
-            pSource->currentState = 5;
+            activeDS.currentState = 5;
             /* Notify the application that it can close the data source */
-            pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
+            activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
         }
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_GET */
-TW_UINT16 TWAIN_PendingXfersGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_PendingXfersGet (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_GET\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState < 4 || pSource->currentState > 7)
+    if (activeDS.currentState < 4 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
         /* FIXME: we shouldn't return 1 here */
         pPendingXfers->Count = 1;
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_RESET */
-TW_UINT16 TWAIN_PendingXfersReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_PendingXfersReset (pTW_IDENTITY pOrigin, 
                                    TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_PENDINGXFERS pPendingXfers = (pTW_PENDINGXFERS) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_PENDINGXFERS/MSG_RESET\n");
 
-    if (!pSource)
+    if (activeDS.currentState != 6)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 6)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
         pPendingXfers->Count = 0;
-        pSource->currentState = 5;
+        activeDS.currentState = 5;
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_PENDINGXFERS/MSG_STOPFEEDER */
-TW_UINT16 TWAIN_PendingXfersStopFeeder (pTW_IDENTITY pOrigin,
-                                        pTW_IDENTITY pDest, TW_MEMREF pData)
+TW_UINT16 SANE_PendingXfersStopFeeder (pTW_IDENTITY pOrigin,
+                                        TW_MEMREF pData)
 {
     FIXME ("stub!\n");
 
@@ -466,7 +409,7 @@ TW_UINT16 TWAIN_PendingXfersStopFeeder (pTW_IDENTITY pOrigin,
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_GET */
-TW_UINT16 TWAIN_SetupFileXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXferGet (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -475,7 +418,7 @@ TW_UINT16 TWAIN_SetupFileXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPXFER/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_SetupFileXferGetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXferGetDefault (pTW_IDENTITY pOrigin, 
                                          TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -485,7 +428,7 @@ TW_UINT16 TWAIN_SetupFileXferGetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDes
 
 
 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_RESET */
-TW_UINT16 TWAIN_SetupFileXferReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXferReset (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -494,7 +437,7 @@ TW_UINT16 TWAIN_SetupFileXferReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER/MSG_SET */
-TW_UINT16 TWAIN_SetupFileXferSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXferSet (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -503,7 +446,7 @@ TW_UINT16 TWAIN_SetupFileXferSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER2/MSG_GET */
-TW_UINT16 TWAIN_SetupFileXfer2Get (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXfer2Get (pTW_IDENTITY pOrigin, 
                                    TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -512,7 +455,7 @@ TW_UINT16 TWAIN_SetupFileXfer2Get (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER2/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_SetupFileXfer2GetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXfer2GetDefault (pTW_IDENTITY pOrigin, 
                                          TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -521,7 +464,7 @@ TW_UINT16 TWAIN_SetupFileXfer2GetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDe
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER2/MSG_RESET */
-TW_UINT16 TWAIN_SetupFileXfer2Reset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXfer2Reset (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -530,7 +473,7 @@ TW_UINT16 TWAIN_SetupFileXfer2Reset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPFILEXFER2/MSG_SET */
-TW_UINT16 TWAIN_SetupFileXfer2Set (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupFileXfer2Set (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -539,21 +482,20 @@ TW_UINT16 TWAIN_SetupFileXfer2Set (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_SETUPMEMXFER/MSG_GET */
-TW_UINT16 TWAIN_SetupMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_SetupMemXferGet (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
 #ifndef HAVE_SANE
     return TWRC_FAILURE;
 #else
-    activeDS *pSource = TWAIN_LookupSource (pDest);
     pTW_SETUPMEMXFER  pSetupMemXfer = (pTW_SETUPMEMXFER)pData;
 
     TRACE("DG_CONTROL/DAT_SETUPMEMXFER/MSG_GET\n");
-    if (pSource->sane_param_valid)
+    if (activeDS.sane_param_valid)
     {
-        pSetupMemXfer->MinBufSize = pSource->sane_param.bytes_per_line;
-        pSetupMemXfer->MaxBufSize = pSource->sane_param.bytes_per_line * 8;
-        pSetupMemXfer->Preferred = pSource->sane_param.bytes_per_line * 2;
+        pSetupMemXfer->MinBufSize = activeDS.sane_param.bytes_per_line;
+        pSetupMemXfer->MaxBufSize = activeDS.sane_param.bytes_per_line * 8;
+        pSetupMemXfer->Preferred = activeDS.sane_param.bytes_per_line * 2;
     }
     else
     {
@@ -568,148 +510,119 @@ TW_UINT16 TWAIN_SetupMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_STATUS/MSG_GET */
-TW_UINT16 TWAIN_GetDSStatus (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_GetDSStatus (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
-    TW_UINT16 twRC = TWRC_FAILURE;
     pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
-
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-        pSourceStatus->ConditionCode = TWCC_BADDEST;
-    }
-    else
-    {
-        twRC = TWRC_SUCCESS;
-        pSourceStatus->ConditionCode = pSource->twCC;
-        /* Reset the condition code */
-        pSource->twCC = TWCC_SUCCESS;
-    }
-
-    return twRC;
+    pSourceStatus->ConditionCode = activeDS.twCC;
+    /* Reset the condition code */
+    activeDS.twCC = TWCC_SUCCESS;
+    return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_USERINTERFACE/MSG_DISABLEDS */
-TW_UINT16 TWAIN_DisableDSUserInterface (pTW_IDENTITY pOrigin,
-                                        pTW_IDENTITY pDest, TW_MEMREF pData)
+TW_UINT16 SANE_DisableDSUserInterface (pTW_IDENTITY pOrigin,
+                                        TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE ("DG_CONTROL/DAT_USERINTERFACE/MSG_DISABLEDS\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 5)
+    if (activeDS.currentState != 5)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        pSource->currentState = 4;
+        activeDS.currentState = 4;
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDS */
-TW_UINT16 TWAIN_EnableDSUserInterface (pTW_IDENTITY pOrigin,
-                                       pTW_IDENTITY pDest, TW_MEMREF pData)
+TW_UINT16 SANE_EnableDSUserInterface (pTW_IDENTITY pOrigin,
+                                       TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_USERINTERFACE pUserInterface = (pTW_USERINTERFACE) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE ("DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDS\n");
 
-    if (!pSource)
+    if (activeDS.currentState != 4)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 4)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
+	FIXME("sequence error %d\n", activeDS.currentState);
     }
     else
     {
+        activeDS.hwndOwner = pUserInterface->hParent;
         if (pUserInterface->ShowUI)
         {
             BOOL rc;
-            pSource->currentState = 5; /* Transitions to state 5 */
-            rc = DoScannerUI(pSource);
+            activeDS.currentState = 5; /* Transitions to state 5 */
+		FIXME("showing UI\n");
+            rc = DoScannerUI();
             if (!rc)
             {
-                pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
+                activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
             }
 #ifdef HAVE_SANE
             else
             {
-                sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
-                pSource->sane_param_valid = TRUE;
+                sane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
+                activeDS.sane_param_valid = TRUE;
             }
 #endif
         }
         else
         {
             /* no UI will be displayed, so source is ready to transfer data */
-            pSource->pendingEvent.TWMessage = MSG_XFERREADY;
-            pSource->currentState = 6; /* Transitions to state 6 directly */
+            activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
+            activeDS.currentState = 6; /* Transitions to state 6 directly */
         }
 
-        pSource->hwndOwner = pUserInterface->hParent;
+        activeDS.hwndOwner = pUserInterface->hParent;
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDSUIONLY */
-TW_UINT16 TWAIN_EnableDSUIOnly (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_EnableDSUIOnly (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     TW_UINT16 twRC = TWRC_SUCCESS;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
 
     TRACE("DG_CONTROL/DAT_USERINTERFACE/MSG_ENABLEDSUIONLY\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 4)
+    if (activeDS.currentState != 4)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
         /* FIXME: we should replace xscanimage with our own UI */
         system ("xscanimage");
-        pSource->currentState = 5;
+        activeDS.currentState = 5;
         twRC = TWRC_SUCCESS;
-        pSource->twCC = TWCC_SUCCESS;
+        activeDS.twCC = TWCC_SUCCESS;
     }
 
     return twRC;
 }
 
 /* DG_CONTROL/DAT_XFERGROUP/MSG_GET */
-TW_UINT16 TWAIN_XferGroupGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_XferGroupGet (pTW_IDENTITY pOrigin, 
                               TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -718,7 +631,7 @@ TW_UINT16 TWAIN_XferGroupGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_CONTROL/DAT_XFERGROUP/MSG_SET */
-TW_UINT16 TWAIN_XferGroupSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_XferGroupSet (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
diff --git a/dlls/twain_32/ds_image.c b/dlls/sane.ds/ds_image.c
similarity index 60%
rename from dlls/twain_32/ds_image.c
rename to dlls/sane.ds/ds_image.c
index 92ec70046cde79c313dc7820d13f3b8282b81b1f..7e26b1dbc28142e6c96b7d6895e29d014d1585b2 100644
--- a/dlls/twain_32/ds_image.c
+++ b/dlls/sane.ds/ds_image.c
@@ -26,13 +26,13 @@
 #include "wingdi.h"
 #include "winuser.h"
 #include "twain.h"
-#include "twain_i.h"
+#include "sane_i.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
 /* DG_IMAGE/DAT_CIECOLOR/MSG_GET */
-TW_UINT16 TWAIN_CIEColorGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_CIEColorGet (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -41,7 +41,7 @@ TW_UINT16 TWAIN_CIEColorGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_EXTIMAGEINFO/MSG_GET */
-TW_UINT16 TWAIN_ExtImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ExtImageInfoGet (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -50,7 +50,7 @@ TW_UINT16 TWAIN_ExtImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_RESET */
-TW_UINT16 TWAIN_GrayResponseReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_GrayResponseReset (pTW_IDENTITY pOrigin, 
                                    TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -59,7 +59,7 @@ TW_UINT16 TWAIN_GrayResponseReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_GRAYRESPONSE/MSG_SET */
-TW_UINT16 TWAIN_GrayResponseSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_GrayResponseSet (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -68,7 +68,7 @@ TW_UINT16 TWAIN_GrayResponseSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGEFILEXFER/MSG_GET */
-TW_UINT16 TWAIN_ImageFileXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageFileXferGet (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -77,7 +77,7 @@ TW_UINT16 TWAIN_ImageFileXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
-TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin, 
                               TW_MEMREF pData)
 {
 #ifndef HAVE_SANE
@@ -85,28 +85,22 @@ TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 #else
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
     SANE_Status status;
 
     TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
 
-    if (!pSource)
+    if (activeDS.currentState != 6 && activeDS.currentState != 7)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 6 && pSource->currentState != 7)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
-        if (pSource->currentState == 6)
+        if (activeDS.currentState == 6)
         {
             /* return general image description information about the image about to be transferred */
-            status = sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
-            pSource->sane_param_valid = TRUE;
+            status = sane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
+            activeDS.sane_param_valid = TRUE;
             TRACE("Getting parameters\n");
         }
 
@@ -114,37 +108,37 @@ TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
         pImageInfo->XResolution.Frac = 0;
         pImageInfo->YResolution.Whole = -1;
         pImageInfo->YResolution.Frac = 0;
-        pImageInfo->ImageWidth = pSource->sane_param.pixels_per_line;
-        pImageInfo->ImageLength = pSource->sane_param.lines;
+        pImageInfo->ImageWidth = activeDS.sane_param.pixels_per_line;
+        pImageInfo->ImageLength = activeDS.sane_param.lines;
 
-        TRACE("Bits per Sample %i\n",pSource->sane_param.depth);
-        TRACE("Frame Format %i\n",pSource->sane_param.format);
+        TRACE("Bits per Sample %i\n",activeDS.sane_param.depth);
+        TRACE("Frame Format %i\n",activeDS.sane_param.format);
 
-        if (pSource->sane_param.format == SANE_FRAME_RGB )
+        if (activeDS.sane_param.format == SANE_FRAME_RGB )
         {
-            pImageInfo->BitsPerPixel = pSource->sane_param.depth * 3;
+            pImageInfo->BitsPerPixel = activeDS.sane_param.depth * 3;
             pImageInfo->Compression = TWCP_NONE;
             pImageInfo->Planar = TRUE;
             pImageInfo->SamplesPerPixel = 3;
-            pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
-            pImageInfo->BitsPerSample[1] = pSource->sane_param.depth;
-            pImageInfo->BitsPerSample[2] = pSource->sane_param.depth;
+            pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
+            pImageInfo->BitsPerSample[1] = activeDS.sane_param.depth;
+            pImageInfo->BitsPerSample[2] = activeDS.sane_param.depth;
             pImageInfo->PixelType = TWPT_RGB;
         }
-        else if (pSource->sane_param.format == SANE_FRAME_GRAY)
+        else if (activeDS.sane_param.format == SANE_FRAME_GRAY)
         {
-            pImageInfo->BitsPerPixel = pSource->sane_param.depth;
+            pImageInfo->BitsPerPixel = activeDS.sane_param.depth;
             pImageInfo->Compression = TWCP_NONE;
             pImageInfo->Planar = TRUE;
             pImageInfo->SamplesPerPixel = 1;
-            pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
+            pImageInfo->BitsPerSample[0] = activeDS.sane_param.depth;
             pImageInfo->PixelType = TWPT_GRAY;
         }
         else
         {
-            ERR("Unhandled source frame type %i\n",pSource->sane_param.format);
+            ERR("Unhandled source frame type %i\n",activeDS.sane_param.format);
             twRC = TWRC_FAILURE;
-            pSource->twCC = TWCC_SEQERROR;
+            activeDS.twCC = TWCC_SEQERROR;
         }
     }
 
@@ -153,7 +147,7 @@ TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
-TW_UINT16 TWAIN_ImageLayoutGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -162,7 +156,7 @@ TW_UINT16 TWAIN_ImageLayoutGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, 
                                        TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -171,7 +165,7 @@ TW_UINT16 TWAIN_ImageLayoutGetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
-TW_UINT16 TWAIN_ImageLayoutReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -180,7 +174,7 @@ TW_UINT16 TWAIN_ImageLayoutReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
-TW_UINT16 TWAIN_ImageLayoutSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -189,7 +183,7 @@ TW_UINT16 TWAIN_ImageLayoutSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
-TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin, 
                                  TW_MEMREF pData)
 {
 #ifndef HAVE_SANE
@@ -197,20 +191,14 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 #else
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
     SANE_Status status = SANE_STATUS_GOOD;
 
     TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
 
-    if (!pSource)
+    if (activeDS.currentState < 6 || activeDS.currentState > 7)
     {
         twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-    else if (pSource->currentState < 6 || pSource->currentState > 7)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
@@ -221,48 +209,48 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
         int rows;
 
         /* Transfer an image from the source to the application */
-        if (pSource->currentState == 6)
+        if (activeDS.currentState == 6)
         {
 
             /* trigger scanning dialog */
-            pSource->progressWnd = ScanningDialogBox(NULL,0);
+            activeDS.progressWnd = ScanningDialogBox(NULL,0);
 
-            ScanningDialogBox(pSource->progressWnd,0);
+            ScanningDialogBox(activeDS.progressWnd,0);
 
-            status = sane_start (pSource->deviceHandle);
+            status = sane_start (activeDS.deviceHandle);
             if (status != SANE_STATUS_GOOD)
             {
                 WARN("sane_start: %s\n", sane_strstatus (status));
-                sane_cancel (pSource->deviceHandle);
-                pSource->twCC = TWCC_OPERATIONERROR;
+                sane_cancel (activeDS.deviceHandle);
+                activeDS.twCC = TWCC_OPERATIONERROR;
                 return TWRC_FAILURE;
             }
 
-            status = sane_get_parameters (pSource->deviceHandle,
-                    &pSource->sane_param);
-            pSource->sane_param_valid = TRUE;
+            status = sane_get_parameters (activeDS.deviceHandle,
+                    &activeDS.sane_param);
+            activeDS.sane_param_valid = TRUE;
 
             if (status != SANE_STATUS_GOOD)
             {
                 WARN("sane_get_parameters: %s\n", sane_strstatus (status));
-                sane_cancel (pSource->deviceHandle);
-                pSource->twCC = TWCC_OPERATIONERROR;
+                sane_cancel (activeDS.deviceHandle);
+                activeDS.twCC = TWCC_OPERATIONERROR;
                 return TWRC_FAILURE;
             }
 
             TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
-              , pSource->sane_param.pixels_per_line, pSource->sane_param.lines,
-              pSource->sane_param.depth, pSource->sane_param.format,
-              pSource->sane_param.last_frame);
+              , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
+              activeDS.sane_param.depth, activeDS.sane_param.format,
+              activeDS.sane_param.last_frame);
 
-            pSource->currentState = 7;
+            activeDS.currentState = 7;
         }
 
         /* access memory buffer */
-        if (pImageMemXfer->Memory.Length < pSource->sane_param.bytes_per_line)
+        if (pImageMemXfer->Memory.Length < activeDS.sane_param.bytes_per_line)
         {
-            sane_cancel (pSource->deviceHandle);
-            pSource->twCC = TWCC_BADVALUE;
+            sane_cancel (activeDS.deviceHandle);
+            activeDS.twCC = TWCC_BADVALUE;
             return TWRC_FAILURE;
         }
 
@@ -278,14 +266,14 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 
         ptr = buffer;
         consumed_len = 0;
-        rows = pImageMemXfer->Memory.Length / pSource->sane_param.bytes_per_line;
+        rows = pImageMemXfer->Memory.Length / activeDS.sane_param.bytes_per_line;
 
         /* must fill full lines */
-        while (consumed_len < (pSource->sane_param.bytes_per_line*rows) && 
+        while (consumed_len < (activeDS.sane_param.bytes_per_line*rows) && 
                 status == SANE_STATUS_GOOD)
         {
-            status = sane_read (pSource->deviceHandle, ptr, 
-                    (pSource->sane_param.bytes_per_line*rows) - consumed_len ,
+            status = sane_read (activeDS.deviceHandle, ptr, 
+                    (activeDS.sane_param.bytes_per_line*rows) - consumed_len ,
                     &buff_len);
             consumed_len += buff_len;
             ptr += buff_len;
@@ -294,30 +282,30 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
         if (status == SANE_STATUS_GOOD || status == SANE_STATUS_EOF)
         {
             pImageMemXfer->Compression = TWCP_NONE;
-            pImageMemXfer->BytesPerRow = pSource->sane_param.bytes_per_line;
-            pImageMemXfer->Columns = pSource->sane_param.pixels_per_line;
+            pImageMemXfer->BytesPerRow = activeDS.sane_param.bytes_per_line;
+            pImageMemXfer->Columns = activeDS.sane_param.pixels_per_line;
             pImageMemXfer->Rows = rows;
             pImageMemXfer->XOffset = 0;
             pImageMemXfer->YOffset = 0;
             pImageMemXfer->BytesWritten = consumed_len;
 
-            ScanningDialogBox(pSource->progressWnd, consumed_len);
+            ScanningDialogBox(activeDS.progressWnd, consumed_len);
 
             if (status == SANE_STATUS_EOF)
             {
-                ScanningDialogBox(pSource->progressWnd, -1);
+                ScanningDialogBox(activeDS.progressWnd, -1);
                 TRACE("sane_read: %s\n", sane_strstatus (status));
-                sane_cancel (pSource->deviceHandle);
+                sane_cancel (activeDS.deviceHandle);
                 twRC = TWRC_XFERDONE;
             }
-            pSource->twCC = TWRC_SUCCESS;
+            activeDS.twCC = TWRC_SUCCESS;
         }
         else if (status != SANE_STATUS_EOF)
         {
-            ScanningDialogBox(pSource->progressWnd, -1);
+            ScanningDialogBox(activeDS.progressWnd, -1);
             WARN("sane_read: %s\n", sane_strstatus (status));
-            sane_cancel (pSource->deviceHandle);
-            pSource->twCC = TWCC_OPERATIONERROR;
+            sane_cancel (activeDS.deviceHandle);
+            activeDS.twCC = TWCC_OPERATIONERROR;
             twRC = TWRC_FAILURE;
         }
     }
@@ -330,7 +318,7 @@ TW_UINT16 TWAIN_ImageMemXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
-TW_UINT16 TWAIN_ImageNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
 #ifndef HAVE_SANE
@@ -338,7 +326,6 @@ TW_UINT16 TWAIN_ImageNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 #else
     TW_UINT16 twRC = TWRC_SUCCESS;
     pTW_UINT32 pHandle = (pTW_UINT32) pData;
-    activeDS *pSource = TWAIN_LookupSource (pDest);
     SANE_Status status;
     SANE_Byte buffer[32*1024];
     int buff_len;
@@ -349,49 +336,44 @@ TW_UINT16 TWAIN_ImageNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 
     TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
 
-    if (!pSource)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-    else if (pSource->currentState != 6)
+    if (activeDS.currentState != 6)
     {
         twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
+        activeDS.twCC = TWCC_SEQERROR;
     }
     else
     {
         /* Transfer an image from the source to the application */
-        status = sane_start (pSource->deviceHandle);
+        status = sane_start (activeDS.deviceHandle);
         if (status != SANE_STATUS_GOOD)
         {
             WARN("sane_start: %s\n", sane_strstatus (status));
-            sane_cancel (pSource->deviceHandle);
-            pSource->twCC = TWCC_OPERATIONERROR;
+            sane_cancel (activeDS.deviceHandle);
+            activeDS.twCC = TWCC_OPERATIONERROR;
             return TWRC_FAILURE;
         }
 
-        status = sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
-        pSource->sane_param_valid = TRUE;
+        status = sane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
+        activeDS.sane_param_valid = TRUE;
         if (status != SANE_STATUS_GOOD)
         {
             WARN("sane_get_parameters: %s\n", sane_strstatus (status));
-            sane_cancel (pSource->deviceHandle);
-            pSource->twCC = TWCC_OPERATIONERROR;
+            sane_cancel (activeDS.deviceHandle);
+            activeDS.twCC = TWCC_OPERATIONERROR;
             return TWRC_FAILURE;
         }
 
         TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
-              , pSource->sane_param.pixels_per_line, pSource->sane_param.lines,
-              pSource->sane_param.depth, pSource->sane_param.format,
-              pSource->sane_param.last_frame);
+              , activeDS.sane_param.pixels_per_line, activeDS.sane_param.lines,
+              activeDS.sane_param.depth, activeDS.sane_param.format,
+              activeDS.sane_param.last_frame);
 
         ZeroMemory (&bmpInfo, sizeof (BITMAPINFO));
         bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
-        bmpInfo.bmiHeader.biWidth = pSource->sane_param.pixels_per_line;
-        bmpInfo.bmiHeader.biHeight = pSource->sane_param.lines;
+        bmpInfo.bmiHeader.biWidth = activeDS.sane_param.pixels_per_line;
+        bmpInfo.bmiHeader.biHeight = activeDS.sane_param.lines;
         bmpInfo.bmiHeader.biPlanes = 1;
-        bmpInfo.bmiHeader.biBitCount = pSource->sane_param.depth;
+        bmpInfo.bmiHeader.biBitCount = activeDS.sane_param.depth;
         bmpInfo.bmiHeader.biCompression = BI_RGB;
         bmpInfo.bmiHeader.biSizeImage = 0;
         bmpInfo.bmiHeader.biXPelsPerMeter = 0;
@@ -401,18 +383,18 @@ TW_UINT16 TWAIN_ImageNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
         bmpInfo.bmiColors[0].rgbBlue = 128;
         bmpInfo.bmiColors[0].rgbGreen = 128;
         bmpInfo.bmiColors[0].rgbRed = 128;
-        hDIB = CreateDIBSection ((dc = GetDC(pSource->hwndOwner)), &bmpInfo,
+        hDIB = CreateDIBSection ((dc = GetDC(activeDS.hwndOwner)), &bmpInfo,
                                  DIB_RGB_COLORS, &pBits, 0, 0);
         if (!hDIB)
         {
-            sane_cancel (pSource->deviceHandle);
-            pSource->twCC = TWCC_LOWMEMORY;
+            sane_cancel (activeDS.deviceHandle);
+            activeDS.twCC = TWCC_LOWMEMORY;
             return TWRC_FAILURE;
         }
 
         do
         {
-            status = sane_read (pSource->deviceHandle, buffer,
+            status = sane_read (activeDS.deviceHandle, buffer,
                                 sizeof (buffer),  &buff_len);
             if (status == SANE_STATUS_GOOD)
             {
@@ -422,25 +404,25 @@ TW_UINT16 TWAIN_ImageNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
             else if (status != SANE_STATUS_EOF)
             {
                 WARN("sane_read: %s\n", sane_strstatus (status));
-                sane_cancel (pSource->deviceHandle);
-                pSource->twCC = TWCC_OPERATIONERROR;
+                sane_cancel (activeDS.deviceHandle);
+                activeDS.twCC = TWCC_OPERATIONERROR;
                 return TWRC_FAILURE;
             }
         } while (status == SANE_STATUS_GOOD);
 
-        sane_cancel (pSource->deviceHandle);
-        ReleaseDC (pSource->hwndOwner, dc);
+        sane_cancel (activeDS.deviceHandle);
+        ReleaseDC (activeDS.hwndOwner, dc);
         *pHandle = (TW_UINT32)hDIB;
         twRC = TWRC_XFERDONE;
-        pSource->twCC = TWCC_SUCCESS;
-        pSource->currentState = 7;
+        activeDS.twCC = TWCC_SUCCESS;
+        activeDS.currentState = 7;
     }
     return twRC;
 #endif
 }
 
 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GET */
-TW_UINT16 TWAIN_JPEGCompressionGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_JPEGCompressionGet (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -449,8 +431,8 @@ TW_UINT16 TWAIN_JPEGCompressionGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
-                                           pTW_IDENTITY pDest,
+TW_UINT16 SANE_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
+                                           
                                            TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -459,7 +441,7 @@ TW_UINT16 TWAIN_JPEGCompressionGetDefault (pTW_IDENTITY pOrigin,
 }
 
 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_RESET */
-TW_UINT16 TWAIN_JPEGCompressionReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_JPEGCompressionReset (pTW_IDENTITY pOrigin, 
                                       TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -468,7 +450,7 @@ TW_UINT16 TWAIN_JPEGCompressionReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_JPEGCOMPRESSION/MSG_SET */
-TW_UINT16 TWAIN_JPEGCompressionSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_JPEGCompressionSet (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -477,7 +459,7 @@ TW_UINT16 TWAIN_JPEGCompressionSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_PALETTE8/MSG_GET */
-TW_UINT16 TWAIN_Palette8Get (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_Palette8Get (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -486,7 +468,7 @@ TW_UINT16 TWAIN_Palette8Get (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_PALETTE8/MSG_GETDEFAULT */
-TW_UINT16 TWAIN_Palette8GetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_Palette8GetDefault (pTW_IDENTITY pOrigin, 
                                     TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -495,7 +477,7 @@ TW_UINT16 TWAIN_Palette8GetDefault (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_PALETTE8/MSG_RESET */
-TW_UINT16 TWAIN_Palette8Reset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_Palette8Reset (pTW_IDENTITY pOrigin, 
                                TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -504,7 +486,7 @@ TW_UINT16 TWAIN_Palette8Reset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_PALETTE8/MSG_SET */
-TW_UINT16 TWAIN_Palette8Set (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_Palette8Set (pTW_IDENTITY pOrigin, 
                              TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -513,7 +495,7 @@ TW_UINT16 TWAIN_Palette8Set (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_RESET */
-TW_UINT16 TWAIN_RGBResponseReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_RGBResponseReset (pTW_IDENTITY pOrigin, 
                                   TW_MEMREF pData)
 {
     FIXME ("stub!\n");
@@ -522,7 +504,7 @@ TW_UINT16 TWAIN_RGBResponseReset (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
 }
 
 /* DG_IMAGE/DAT_RGBRESPONSE/MSG_SET */
-TW_UINT16 TWAIN_RGBResponseSet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
+TW_UINT16 SANE_RGBResponseSet (pTW_IDENTITY pOrigin, 
                                 TW_MEMREF pData)
 {
     FIXME ("stub!\n");
diff --git a/dlls/twain_32/resource.h b/dlls/sane.ds/resource.h
similarity index 100%
rename from dlls/twain_32/resource.h
rename to dlls/sane.ds/resource.h
diff --git a/dlls/twain_32/rsrc.rc b/dlls/sane.ds/rsrc.rc
similarity index 87%
rename from dlls/twain_32/rsrc.rc
rename to dlls/sane.ds/rsrc.rc
index 6732c67fd1c76d797de8c214fcbad75425976c87..eca031bfac1d571dde3f28fb9b24fac97a4d4f7d 100644
--- a/dlls/twain_32/rsrc.rc
+++ b/dlls/sane.ds/rsrc.rc
@@ -25,9 +25,9 @@
 
 #include "resource.h"
 
-#include "twain_De.rc"
-#include "twain_En.rc"
-#include "twain_Fi.rc"
-#include "twain_Fr.rc"
-#include "twain_Ko.rc"
-#include "twain_No.rc"
+#include "sane_De.rc"
+#include "sane_En.rc"
+#include "sane_Fi.rc"
+#include "sane_Fr.rc"
+#include "sane_Ko.rc"
+#include "sane_No.rc"
diff --git a/dlls/sane.ds/sane.ds.spec b/dlls/sane.ds/sane.ds.spec
new file mode 100644
index 0000000000000000000000000000000000000000..d9c64073dfd1a43bd4c28fb738690d497530d2e2
--- /dev/null
+++ b/dlls/sane.ds/sane.ds.spec
@@ -0,0 +1 @@
+@ stdcall DS_Entry(ptr long long long ptr)
diff --git a/dlls/twain_32/twain_De.rc b/dlls/sane.ds/sane_De.rc
similarity index 100%
rename from dlls/twain_32/twain_De.rc
rename to dlls/sane.ds/sane_De.rc
diff --git a/dlls/twain_32/twain_En.rc b/dlls/sane.ds/sane_En.rc
similarity index 100%
rename from dlls/twain_32/twain_En.rc
rename to dlls/sane.ds/sane_En.rc
diff --git a/dlls/twain_32/twain_Fi.rc b/dlls/sane.ds/sane_Fi.rc
similarity index 100%
rename from dlls/twain_32/twain_Fi.rc
rename to dlls/sane.ds/sane_Fi.rc
diff --git a/dlls/twain_32/twain_Fr.rc b/dlls/sane.ds/sane_Fr.rc
similarity index 100%
rename from dlls/twain_32/twain_Fr.rc
rename to dlls/sane.ds/sane_Fr.rc
diff --git a/dlls/twain_32/twain_Ko.rc b/dlls/sane.ds/sane_Ko.rc
similarity index 100%
rename from dlls/twain_32/twain_Ko.rc
rename to dlls/sane.ds/sane_Ko.rc
diff --git a/dlls/twain_32/twain_No.rc b/dlls/sane.ds/sane_No.rc
similarity index 100%
rename from dlls/twain_32/twain_No.rc
rename to dlls/sane.ds/sane_No.rc
diff --git a/dlls/sane.ds/sane_i.h b/dlls/sane.ds/sane_i.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e95b06bbc9c7df8ffd26997bf5554d113bb132a
--- /dev/null
+++ b/dlls/sane.ds/sane_i.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2000 Corel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _TWAIN32_H
+#define _TWAIN32_H
+
+#ifndef __WINE_CONFIG_H
+# error You must include config.h first
+#endif
+
+#ifdef HAVE_SANE
+# include <sane/sane.h>
+#endif
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "twain.h"
+
+extern HINSTANCE SANE_instance;
+
+/* internal information about an active data source */
+struct tagActiveDS
+{
+    struct tagActiveDS	*next;			/* next active DS */
+    TW_IDENTITY		identity;		/* identity */
+    TW_UINT16		currentState;		/* current state */
+    TW_EVENT		pendingEvent;		/* pending event to be sent to
+                                                   application */
+    TW_UINT16		twCC;			/* condition code */
+    HWND		hwndOwner;		/* window handle of the app */
+    HWND		progressWnd;		/* window handle of the scanning window */
+#ifdef HAVE_SANE
+    SANE_Handle		deviceHandle;		/* device handle */
+    SANE_Parameters     sane_param;             /* parameters about the image
+                                                   transferred */
+    BOOL                sane_param_valid;  /* true if valid sane_param*/
+    INT                 deviceIndex;    /* index of the current device */
+#endif
+    /* Capabiblities */
+    TW_UINT16		capXferMech;		/* ICAP_XFERMECH */
+} activeDS;
+
+/* Helper functions */
+extern TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action);
+
+/*  */
+extern TW_UINT16 SANE_ControlGroupHandler (
+	pTW_IDENTITY pOrigin, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData);
+extern TW_UINT16 SANE_ImageGroupHandler (
+	pTW_IDENTITY pOrigin, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData);
+extern TW_UINT16 SANE_AudioGroupHandler (
+	pTW_IDENTITY pOrigin, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData);
+extern TW_UINT16 SANE_SourceManagerHandler (
+	pTW_IDENTITY pOrigin, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData);
+
+/* Implementation of operation triplets
+ * From Application to Source (Control Information) */
+TW_UINT16 SANE_CapabilityGet (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CapabilityGetCurrent
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CapabilityGetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CapabilityQuerySupport
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CapabilityReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CapabilitySet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CustomDSDataGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CustomDSDataSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_AutomaticCaptureDirectory
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ChangeDirectory
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemCopy
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_CreateDirectory
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemDelete
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FormatMedia
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemGetClose
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemGetFirstFile
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemGetInfo
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemGetNextFile
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_FileSystemRename
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ProcessEvent
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_PassThrough
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_PendingXfersEndXfer
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_PendingXfersGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_PendingXfersReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_PendingXfersStopFeeder
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXferGetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXferReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXferSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXfer2Get
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXfer2GetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXfer2Reset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupFileXfer2Set
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_SetupMemXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_GetDSStatus
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_DisableDSUserInterface
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_EnableDSUserInterface
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_EnableDSUIOnly
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_XferGroupGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_XferGroupSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+
+/* Implementation of operation triplets
+ * From Application to Source (Image Information) */
+TW_UINT16 SANE_CIEColorGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ExtImageInfoGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_GrayResponseReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_GrayResponseSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageFileXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageInfoGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageLayoutGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageLayoutGetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageLayoutReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageLayoutSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageMemXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_ImageNativeXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_JPEGCompressionGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_JPEGCompressionGetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_JPEGCompressionReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_JPEGCompressionSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_Palette8Get
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_Palette8GetDefault
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_Palette8Reset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_Palette8Set
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_RGBResponseReset
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_RGBResponseSet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+
+/* Implementation of operation triplets
+ * From Application to Source (Audio Information) */
+TW_UINT16 SANE_AudioFileXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_AudioInfoGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+TW_UINT16 SANE_AudioNativeXferGet
+    (pTW_IDENTITY pOrigin, TW_MEMREF pData);
+
+/* Implementation of TWAIN capabilities */
+TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action);
+
+/* UI function */
+BOOL DoScannerUI(void);
+HWND ScanningDialogBox(HWND dialog, LONG progress);
+
+#endif
diff --git a/dlls/sane.ds/sane_main.c b/dlls/sane.ds/sane_main.c
new file mode 100644
index 0000000000000000000000000000000000000000..eda672741844234d334576f28b0524ce26aef63c
--- /dev/null
+++ b/dlls/sane.ds/sane_main.c
@@ -0,0 +1,611 @@
+/*
+ * SANE.DS functions
+ *
+ * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "twain.h"
+#include "sane_i.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(twain);
+
+HINSTANCE SANE_instance;
+
+BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
+
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH: {
+#ifdef HAVE_SANE
+	    SANE_Status status;
+	    SANE_Int version_code;
+	    status = sane_init (&version_code, NULL);
+#endif
+	    SANE_instance = hinstDLL;
+            DisableThreadLibraryCalls(hinstDLL);
+            break;
+	}
+        case DLL_PROCESS_DETACH:
+#ifdef HAVE_SANE
+		FIXME("calling sane_Exit()\n");
+	    sane_exit ();
+#endif 
+	    SANE_instance = NULL;
+            break;
+    }
+
+    return TRUE;
+}
+
+#ifdef HAVE_SANE
+static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
+static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
+#endif
+
+TW_UINT16 SANE_SourceControlHandler (
+           pTW_IDENTITY pOrigin,
+           TW_UINT16    DAT,
+           TW_UINT16    MSG,
+           TW_MEMREF    pData)
+{
+    TW_UINT16 twRC = TWRC_SUCCESS;
+
+    switch (DAT)
+    {
+	case DAT_IDENTITY:
+	    switch (MSG)
+	    {
+		case MSG_CLOSEDS:
+#ifdef HAVE_SANE
+		     sane_close (activeDS.deviceHandle);
+#endif
+		     break;
+		case MSG_OPENDS:
+#ifdef HAVE_SANE
+		     twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
+#else
+		     twRC = TWRC_FAILURE;
+#endif
+		     break;
+		case MSG_GET:
+#ifdef HAVE_SANE
+		     twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
+#else
+		     twRC = TWRC_FAILURE;
+#endif
+		     break;
+	    }
+	    break;
+        case DAT_CAPABILITY:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_CapabilityGet (pOrigin, pData);
+                    break;
+                case MSG_GETCURRENT:
+                    twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_CapabilityGetDefault (pOrigin, pData);
+                    break;
+                case MSG_QUERYSUPPORT:
+                    twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_CapabilityReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_CapabilitySet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    FIXME("unrecognized opertion triplet\n");
+            }
+            break;
+
+        case DAT_CUSTOMDSDATA:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_CustomDSDataGet (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_CustomDSDataSet (pOrigin, pData);
+                    break;
+                default:
+                    break;
+            }
+            break;
+
+        case DAT_FILESYSTEM:
+            switch (MSG)
+            {
+                /*case MSG_AUTOMATICCAPTUREDIRECTORY:
+                    twRC = SANE_AutomaticCaptureDirectory
+                               (pOrigin, pData);
+                    break;*/
+                case MSG_CHANGEDIRECTORY:
+                    twRC = SANE_ChangeDirectory (pOrigin, pData);
+                    break;
+                /*case MSG_COPY:
+                    twRC = SANE_FileSystemCopy (pOrigin, pData);
+                    break;*/
+                case MSG_CREATEDIRECTORY:
+                    twRC = SANE_CreateDirectory (pOrigin, pData);
+                    break;
+                case MSG_DELETE:
+                    twRC = SANE_FileSystemDelete (pOrigin, pData);
+                    break;
+                case MSG_FORMATMEDIA:
+                    twRC = SANE_FormatMedia (pOrigin, pData);
+                    break;
+                case MSG_GETCLOSE:
+                    twRC = SANE_FileSystemGetClose (pOrigin, pData);
+                    break;
+                case MSG_GETFIRSTFILE:
+                    twRC = SANE_FileSystemGetFirstFile (pOrigin, pData);
+                    break;
+                case MSG_GETINFO:
+                    twRC = SANE_FileSystemGetInfo (pOrigin, pData);
+                    break;
+                case MSG_GETNEXTFILE:
+                    twRC = SANE_FileSystemGetNextFile (pOrigin, pData);
+                    break;
+                case MSG_RENAME:
+                    twRC = SANE_FileSystemRename (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    break;
+            }
+            break;
+
+        case DAT_EVENT:
+            if (MSG == MSG_PROCESSEVENT)
+                twRC = SANE_ProcessEvent (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_PASSTHRU:
+            if (MSG == MSG_PASSTHRU)
+                twRC = SANE_PassThrough (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_PENDINGXFERS:
+            switch (MSG)
+            {
+                case MSG_ENDXFER:
+                    twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
+                    break;
+                case MSG_GET:
+                    twRC = SANE_PendingXfersGet (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_PendingXfersReset (pOrigin, pData);
+                    break;
+                /*case MSG_STOPFEEDER:
+                    twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
+                    break;*/
+                default:
+                    twRC = TWRC_FAILURE;
+            }
+            break;
+
+        case DAT_SETUPFILEXFER:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_SetupFileXferGet (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_SetupFileXferGetDefault (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_SetupFileXferReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_SetupFileXferSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    break;
+            }
+            break;
+
+        /*case DAT_SETUPFILEXFER2:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
+                    break;
+            }
+            break;*/
+        case DAT_SETUPMEMXFER:
+            if (MSG == MSG_GET)
+                twRC = SANE_SetupMemXferGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_STATUS:
+            if (MSG == MSG_GET)
+                twRC = SANE_GetDSStatus (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_USERINTERFACE:
+            switch (MSG)
+            {
+                case MSG_DISABLEDS:
+                    twRC = SANE_DisableDSUserInterface (pOrigin, pData);
+                    break;
+                case MSG_ENABLEDS:
+                    twRC = SANE_EnableDSUserInterface (pOrigin, pData);
+                    break;
+                case MSG_ENABLEDSUIONLY:
+                    twRC = SANE_EnableDSUIOnly (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    break;
+            }
+            break;
+
+        case DAT_XFERGROUP:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_XferGroupGet (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_XferGroupSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    break;
+            }
+            break;
+
+        default:
+	    FIXME("code unknown: %d\n", DAT);
+            twRC = TWRC_FAILURE;
+            break;
+    }
+
+    return twRC;
+}
+
+
+TW_UINT16 SANE_ImageGroupHandler (
+           pTW_IDENTITY pOrigin,
+           TW_UINT16    DAT,
+           TW_UINT16    MSG,
+           TW_MEMREF    pData)
+{
+    TW_UINT16 twRC = TWRC_SUCCESS;
+
+    switch (DAT)
+    {
+        case DAT_CIECOLOR:
+            if (MSG == MSG_GET)
+                twRC = SANE_CIEColorGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_EXTIMAGEINFO:
+            if (MSG == MSG_GET)
+                twRC = SANE_ExtImageInfoGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_GRAYRESPONSE:
+            switch (MSG)
+            {
+                case MSG_RESET:
+                    twRC = SANE_GrayResponseReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_GrayResponseSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    activeDS.twCC = TWCC_BADPROTOCOL;
+                    FIXME("unrecognized operation triplet\n");
+                    break;
+            }
+            break;
+        case DAT_IMAGEFILEXFER:
+            if (MSG == MSG_GET)
+                twRC = SANE_ImageFileXferGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_IMAGEINFO:
+            if (MSG == MSG_GET)
+                twRC = SANE_ImageInfoGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_IMAGELAYOUT:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_ImageLayoutGet (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_ImageLayoutReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_ImageLayoutSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    activeDS.twCC = TWCC_BADPROTOCOL;
+                    ERR("unrecognized operation triplet\n");
+                    break;
+            }
+            break;
+
+        case DAT_IMAGEMEMXFER:
+            if (MSG == MSG_GET)
+                twRC = SANE_ImageMemXferGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_IMAGENATIVEXFER:
+            if (MSG == MSG_GET)
+                twRC = SANE_ImageNativeXferGet (pOrigin, pData);
+            else
+                twRC = TWRC_FAILURE;
+            break;
+
+        case DAT_JPEGCOMPRESSION:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_JPEGCompressionGet (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_JPEGCompressionGetDefault (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_JPEGCompressionReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_JPEGCompressionSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    activeDS.twCC = TWCC_BADPROTOCOL;
+                    WARN("unrecognized operation triplet\n");
+                    break;
+            }
+            break;
+
+        case DAT_PALETTE8:
+            switch (MSG)
+            {
+                case MSG_GET:
+                    twRC = SANE_Palette8Get (pOrigin, pData);
+                    break;
+                case MSG_GETDEFAULT:
+                    twRC = SANE_Palette8GetDefault (pOrigin, pData);
+                    break;
+                case MSG_RESET:
+                    twRC = SANE_Palette8Reset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_Palette8Set (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    activeDS.twCC = TWCC_BADPROTOCOL;
+                    WARN("unrecognized operation triplet\n");
+            }
+            break;
+
+        case DAT_RGBRESPONSE:
+            switch (MSG)
+            {
+                case MSG_RESET:
+                    twRC = SANE_RGBResponseReset (pOrigin, pData);
+                    break;
+                case MSG_SET:
+                    twRC = SANE_RGBResponseSet (pOrigin, pData);
+                    break;
+                default:
+                    twRC = TWRC_FAILURE;
+                    activeDS.twCC = TWCC_BADPROTOCOL;
+                    WARN("unrecognized operation triplet\n");
+                    break;
+            }
+            break;
+
+        default:
+            twRC = TWRC_FAILURE;
+            activeDS.twCC = TWCC_BADPROTOCOL;
+            FIXME("unrecognized DG type %d\n", DAT);
+    }
+    return twRC;
+}
+
+/* Main entry point for the TWAIN library */
+TW_UINT16 WINAPI
+DS_Entry ( pTW_IDENTITY pOrigin,
+           TW_UINT32    DG,
+           TW_UINT16    DAT,
+           TW_UINT16    MSG,
+           TW_MEMREF    pData)
+{
+    TW_UINT16 twRC = TWRC_SUCCESS;  /* Return Code */
+
+    TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
+
+    switch (DG)
+    {
+        case DG_CONTROL:
+            twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
+            break;
+        case DG_IMAGE:
+            twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
+            break;
+        case DG_AUDIO:
+            FIXME("Audio group of controls not implemented yet.\n");
+        default:
+            activeDS.twCC = TWCC_BADPROTOCOL;
+            twRC = TWRC_FAILURE;
+    }
+
+    return twRC;
+}
+
+#ifdef HAVE_SANE
+/* Sane returns device names that are longer than the 32 bytes allowed
+   by TWAIN.  However, it colon separates them, and the last bit is
+   the most interesting.  So we use the last bit, and add a signature
+   to ensure uniqueness */
+static void copy_sane_short_name(const char *in, char *out, size_t outsize)
+{
+    const char *p;
+    int  signature = 0;
+
+    if (strlen(in) <= outsize - 1)
+    {
+        strcpy(out, in);
+        return;
+    }
+
+    for (p = in; *p; p++)
+        signature += *p;
+
+    p = strrchr(in, ':');
+    if (!p)
+        p = in;
+    else
+        p++;
+
+    if (strlen(p) > outsize - 7 - 1)
+        p += strlen(p) - (outsize - 7 - 1);
+
+    strcpy(out, p);
+    sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
+
+}
+
+static const SANE_Device **sane_devlist;
+
+static void
+detect_sane_devices() {
+    if (sane_devlist && sane_devlist[0]) return;
+    TRACE("detecting sane...\n");
+    if (sane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
+	return;
+}
+
+static TW_UINT16
+SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
+    static int cursanedev = 0;
+
+    detect_sane_devices();
+    if (!sane_devlist[cursanedev])
+	return TWRC_FAILURE;
+    self->ProtocolMajor = TWON_PROTOCOLMAJOR;
+    self->ProtocolMinor = TWON_PROTOCOLMINOR;
+    copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
+    lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
+    lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
+    cursanedev++;
+
+    if (!sane_devlist[cursanedev] 		||
+	!sane_devlist[cursanedev]->model	||
+	!sane_devlist[cursanedev]->vendor	||
+	!sane_devlist[cursanedev]->name
+    )
+	cursanedev = 0; /* wrap to begin */
+    return TWRC_SUCCESS;
+}
+
+static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
+    SANE_Status status;
+    int i;
+
+    detect_sane_devices();
+    if (!sane_devlist[0]) {
+	ERR("No scanners? We should not get to OpenDS?\n");
+	return TWRC_FAILURE;
+    }
+
+    for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
+	TW_STR32 name;
+
+	/* To make string as short as above */
+	lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
+	if (strcmp(name, self->Manufacturer))
+	    continue;
+	lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
+	if (strcmp(name, self->ProductFamily))
+	    continue;
+        copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
+	if (strcmp(name, self->ProductName))
+	    continue;
+	break;
+    }
+    if (!sane_devlist[i]) {
+	FIXME("Scanner not found? Using first one!\n");
+	i=0;
+    }
+    status = sane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
+    if (status == SANE_STATUS_GOOD) {
+	activeDS.currentState = 4;
+	activeDS.twCC = TWRC_SUCCESS;
+	return TWRC_SUCCESS;
+    }
+    FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, sane_strstatus (status));
+    return TWRC_FAILURE;
+}
+#endif
diff --git a/dlls/twain_32/ui.c b/dlls/sane.ds/ui.c
similarity index 86%
rename from dlls/twain_32/ui.c
rename to dlls/sane.ds/ui.c
index d925512069ad7789529c07258183a07acd3f1d65..4bf703a149912e7cfcffd045320fc9d4da99a0f0 100644
--- a/dlls/twain_32/ui.c
+++ b/dlls/sane.ds/ui.c
@@ -33,7 +33,7 @@
 #include "wingdi.h"
 #include "prsht.h"
 #include "twain.h"
-#include "twain_i.h"
+#include "sane_i.h"
 #include "wine/debug.h"
 #include "resource.h"
 
@@ -138,7 +138,7 @@ static int create_trailing_edit(HDC hdc, LPDLGITEMTEMPLATEW* template_out, int i
 }
 
 
-static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *opt,
+static int create_item(HDC hdc, const SANE_Option_Descriptor *opt,
         INT id, LPDLGITEMTEMPLATEW *template_out, int y, int *cx, int* count)
 {
     LPDLGITEMTEMPLATEW tpl = NULL,rc = NULL;
@@ -175,7 +175,7 @@ static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *
     {
         SANE_Int i;
 
-        sane_control_option(pSource->deviceHandle, id-ID_BASE,
+        sane_control_option(activeDS.deviceHandle, id-ID_BASE,
                 SANE_ACTION_GET_VALUE, &i,NULL);
 
         sprintf(buffer,"%i",i);
@@ -211,7 +211,7 @@ static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *
 
         i = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
 
-        sane_control_option(pSource->deviceHandle, id-ID_BASE,
+        sane_control_option(activeDS.deviceHandle, id-ID_BASE,
                 SANE_ACTION_GET_VALUE, i, NULL);
 
         dd = SANE_UNFIX(*i);
@@ -255,7 +255,7 @@ static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *
         }
         leading_len += create_leading_static(hdc, opt->title, &lead_static, y,
                 id+ID_STATIC_BASE);
-        sane_control_option(pSource->deviceHandle, id-ID_BASE,
+        sane_control_option(activeDS.deviceHandle, id-ID_BASE,
                 SANE_ACTION_GET_VALUE, buffer,NULL);
 
         title = buffer;
@@ -369,7 +369,7 @@ static int create_item(activeDS *pSource,HDC hdc, const SANE_Option_Descriptor *
 }
 
 
-static LPDLGTEMPLATEW create_options_page(HDC hdc, activeDS *pSource, int *from_index,
+static LPDLGTEMPLATEW create_options_page(HDC hdc, int *from_index,
                                           BOOL split_tabs)
 {
     SANE_Status rc;
@@ -385,7 +385,7 @@ static LPDLGTEMPLATEW create_options_page(HDC hdc, activeDS *pSource, int *from_
     int group_offset = -1;
     INT control_count = 0;
 
-    rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE, 
+    rc = sane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE, 
             &optcount, NULL);
 
     if (rc != SANE_STATUS_GOOD)
@@ -404,7 +404,7 @@ static LPDLGTEMPLATEW create_options_page(HDC hdc, activeDS *pSource, int *from_
         int count;
         int hold_for_group = 0;
 
-        opt = sane_get_option_descriptor(pSource->deviceHandle, i);
+        opt = sane_get_option_descriptor(activeDS.deviceHandle, i);
         if (opt->type == SANE_TYPE_GROUP && split_tabs)
         {
             if (control_len > 0)
@@ -419,8 +419,7 @@ static LPDLGTEMPLATEW create_options_page(HDC hdc, activeDS *pSource, int *from_
             }
         }
 
-        len = create_item(pSource, hdc, opt, ID_BASE + i, &item_tpl, y, &x,
-                &count);
+        len = create_item(hdc, opt, ID_BASE + i, &item_tpl, y, &x, &count);
 
         control_count += count;
 
@@ -523,7 +522,7 @@ exit:
     return tpl;
 }
 
-BOOL DoScannerUI(activeDS *pSource)
+BOOL DoScannerUI(void)
 {
     HDC hdc;
     PROPSHEETPAGEW psp[10];
@@ -539,15 +538,15 @@ BOOL DoScannerUI(activeDS *pSource)
     hdc = GetDC(0);
 
     memset(&psp,0,sizeof(psp));
-    rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE, 
+    rc = sane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE, 
             &optcount, NULL);
 
     while (index < optcount)
     {
         const SANE_Option_Descriptor *opt;
-        psp[page_count].u.pResource = create_options_page(hdc, pSource, &index,
+        psp[page_count].u.pResource = create_options_page(hdc, &index,
                 TRUE);
-        opt = sane_get_option_descriptor(pSource->deviceHandle, index);
+        opt = sane_get_option_descriptor(activeDS.deviceHandle, index);
 
         if (opt->type == SANE_TYPE_GROUP)
         {
@@ -565,29 +564,27 @@ BOOL DoScannerUI(activeDS *pSource)
         {
             psp[page_count].dwSize = sizeof(PROPSHEETPAGEW);
             psp[page_count].dwFlags =  PSP_DLGINDIRECT | PSP_USETITLE;
-            psp[page_count].hInstance = DSM_instance;
+            psp[page_count].hInstance = SANE_instance;
             psp[page_count].pfnDlgProc = DialogProc;
-            psp[page_count].lParam = (LPARAM)pSource;
+            psp[page_count].lParam = (LPARAM)&activeDS;
             page_count ++;
         }
        
         index ++;
     }
  
-    len = lstrlenA(device_list[pSource->deviceIndex]->vendor)
-         + lstrlenA(device_list[pSource->deviceIndex]->model) + 2;
-
+    len = lstrlenA(activeDS.identity.Manufacturer)
+         + lstrlenA(activeDS.identity.ProductName) + 2;
     szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
-    MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->vendor,-1,
+    MultiByteToWideChar(CP_ACP,0,activeDS.identity.Manufacturer,-1,
             szCaption,len);
-    szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)] = ' ';
-    MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->model,-1,
-            &szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)+1],len);
-    
+    szCaption[lstrlenA(activeDS.identity.Manufacturer)] = ' ';
+    MultiByteToWideChar(CP_ACP,0,activeDS.identity.ProductName,-1,
+            &szCaption[lstrlenA(activeDS.identity.Manufacturer)+1],len);
     psh.dwSize = sizeof(PROPSHEETHEADERW);
     psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;
-    psh.hwndParent = DSM_parentHWND;
-    psh.hInstance = DSM_instance;
+    psh.hwndParent = activeDS.hwndOwner;
+    psh.hInstance = SANE_instance;
     psh.u.pszIcon = 0;
     psh.pszCaption = szCaption;
     psh.nPages = page_count;
@@ -616,7 +613,7 @@ static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
     HWND edit_w;
     CHAR unit[20];
 
-    LoadStringA(DSM_instance, opt->unit, unit,20);
+    LoadStringA(SANE_instance, opt->unit, unit,20);
 
     if (opt->type == SANE_TYPE_INT)
     {
@@ -652,7 +649,7 @@ static void UpdateRelevantEdit(HWND hwnd, const SANE_Option_Descriptor *opt,
 
 }
 
-static BOOL UpdateSaneScrollOption(activeDS *pSource, 
+static BOOL UpdateSaneScrollOption(
         const SANE_Option_Descriptor *opt, int index, DWORD position)
 {
     SANE_Status rc = SANE_STATUS_GOOD;  
@@ -667,7 +664,7 @@ static BOOL UpdateSaneScrollOption(activeDS *pSource,
         else
             si = position;
 
-        rc = sane_control_option (pSource->deviceHandle,index,
+        rc = sane_control_option (activeDS.deviceHandle,index,
             SANE_ACTION_SET_VALUE, &si, &result);
 
     }
@@ -687,7 +684,7 @@ static BOOL UpdateSaneScrollOption(activeDS *pSource,
 
         *sf = SANE_FIX(dd);
 
-        rc = sane_control_option (pSource->deviceHandle,index,
+        rc = sane_control_option (activeDS.deviceHandle,index,
             SANE_ACTION_SET_VALUE, sf, &result);
 
         HeapFree(GetProcessHeap(),0,sf);
@@ -702,7 +699,7 @@ static BOOL UpdateSaneScrollOption(activeDS *pSource,
     return FALSE;
 }
 
-static BOOL UpdateSaneBoolOption(activeDS *pSource, int index, BOOL position)
+static BOOL UpdateSaneBoolOption(int index, BOOL position)
 {
     SANE_Status rc = SANE_STATUS_GOOD;  
     SANE_Int result = 0;
@@ -710,7 +707,7 @@ static BOOL UpdateSaneBoolOption(activeDS *pSource, int index, BOOL position)
 
     si = position;
 
-    rc = sane_control_option (pSource->deviceHandle,index,
+    rc = sane_control_option (activeDS.deviceHandle,index,
             SANE_ACTION_SET_VALUE, &si, &result);
 
     if(rc == SANE_STATUS_GOOD)
@@ -722,13 +719,12 @@ static BOOL UpdateSaneBoolOption(activeDS *pSource, int index, BOOL position)
     return FALSE;
 }
 
-static BOOL UpdateSaneStringOption(activeDS *pSource, int index, 
-        SANE_String value)
+static BOOL UpdateSaneStringOption(int index, SANE_String value)
 {
     SANE_Status rc = SANE_STATUS_GOOD;  
     SANE_Int result = 0;
 
-    rc = sane_control_option (pSource->deviceHandle,index,
+    rc = sane_control_option (activeDS.deviceHandle,index,
             SANE_ACTION_SET_VALUE, value, &result);
 
     if(rc == SANE_STATUS_GOOD)
@@ -740,14 +736,14 @@ static BOOL UpdateSaneStringOption(activeDS *pSource, int index,
     return FALSE;
 }
 
-static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
+static INT_PTR InitializeDialog(HWND hwnd)
 {
     SANE_Status rc;
     SANE_Int optcount;
     HWND control;
     int i;
 
-    rc = sane_control_option(pSource->deviceHandle, 0, SANE_ACTION_GET_VALUE, 
+    rc = sane_control_option(activeDS.deviceHandle, 0, SANE_ACTION_GET_VALUE, 
             &optcount, NULL);
 
     for ( i = 1; i < optcount; i++)
@@ -759,7 +755,7 @@ static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
         if (!control)
             continue;
 
-        opt = sane_get_option_descriptor(pSource->deviceHandle, i);
+        opt = sane_get_option_descriptor(activeDS.deviceHandle, i);
 
         TRACE("%i %s %i %i\n",i,opt->title,opt->type,opt->constraint_type);
         
@@ -781,13 +777,13 @@ static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
                         (LPARAM)opt->constraint.string_list[j]);
                 j++;
             }
-            sane_control_option(pSource->deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
+            sane_control_option(activeDS.deviceHandle, i, SANE_ACTION_GET_VALUE, buffer,NULL);
             SendMessageA(control,CB_SELECTSTRING,0,(LPARAM)buffer);
         }
         else if (opt->type == SANE_TYPE_BOOL)
         {
             SANE_Bool b;
-            sane_control_option(pSource->deviceHandle, i,
+            sane_control_option(activeDS.deviceHandle, i,
                     SANE_ACTION_GET_VALUE, &b, NULL);
             if (b)
                 SendMessageA(control,BM_SETCHECK,BST_CHECKED,0);
@@ -810,7 +806,7 @@ static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
 
                 SendMessageA(control,SBM_SETRANGE,min,max);
 
-                sane_control_option(pSource->deviceHandle, i,
+                sane_control_option(activeDS.deviceHandle, i,
                         SANE_ACTION_GET_VALUE, &si,NULL);
                 if (opt->constraint.range->quant)
                     si = si / opt->constraint.range->quant;
@@ -846,7 +842,7 @@ static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
 
 
                 sf = HeapAlloc(GetProcessHeap(),0,opt->size*sizeof(SANE_Word));
-                sane_control_option(pSource->deviceHandle, i,
+                sane_control_option(activeDS.deviceHandle, i,
                         SANE_ACTION_GET_VALUE, sf,NULL);
 
                 dd = SANE_UNFIX(*sf);
@@ -867,8 +863,7 @@ static INT_PTR InitializeDialog(HWND hwnd, activeDS *pSource)
     return TRUE;
 }
 
-static INT_PTR ProcessScroll(HWND hwnd, activeDS *pSource, WPARAM wParam, 
-        LPARAM lParam)
+static INT_PTR ProcessScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     int index;
     const SANE_Option_Descriptor *opt;
@@ -879,7 +874,7 @@ static INT_PTR ProcessScroll(HWND hwnd, activeDS *pSource, WPARAM wParam,
     if (index < 0)
         return FALSE;
 
-    opt = sane_get_option_descriptor(pSource->deviceHandle, index);
+    opt = sane_get_option_descriptor(activeDS.deviceHandle, index);
 
     if (!opt)
         return FALSE;
@@ -918,14 +913,14 @@ static INT_PTR ProcessScroll(HWND hwnd, activeDS *pSource, WPARAM wParam,
     position = SendMessageW((HWND)lParam,SBM_GETPOS,0,0);
 
     UpdateRelevantEdit(hwnd, opt, index, position);
-    if (UpdateSaneScrollOption(pSource, opt, index, position))
-        InitializeDialog(hwnd,pSource);
+    if (UpdateSaneScrollOption(opt, index, position))
+        InitializeDialog(hwnd);
 
     return TRUE;
 }
 
 
-static void ButtonClicked(HWND hwnd, activeDS* pSource,INT id, HWND control)
+static void ButtonClicked(HWND hwnd, INT id, HWND control)
 {
     int index;
     const SANE_Option_Descriptor *opt;
@@ -934,7 +929,7 @@ static void ButtonClicked(HWND hwnd, activeDS* pSource,INT id, HWND control)
     if (index < 0)
         return;
 
-    opt = sane_get_option_descriptor(pSource->deviceHandle, index);
+    opt = sane_get_option_descriptor(activeDS.deviceHandle, index);
 
     if (!opt)
         return;
@@ -942,12 +937,12 @@ static void ButtonClicked(HWND hwnd, activeDS* pSource,INT id, HWND control)
     if (opt->type == SANE_TYPE_BOOL)
     {
         BOOL r = SendMessageW(control,BM_GETCHECK,0,0)==BST_CHECKED;
-        if (UpdateSaneBoolOption(pSource, index, r))
-                InitializeDialog(hwnd,pSource);
+        if (UpdateSaneBoolOption(index, r))
+                InitializeDialog(hwnd);
     }
 }
 
-static void ComboChanged(HWND hwnd, activeDS* pSource,INT id, HWND control)
+static void ComboChanged(HWND hwnd, INT id, HWND control)
 {
     int index;
     int selection;
@@ -959,7 +954,7 @@ static void ComboChanged(HWND hwnd, activeDS* pSource,INT id, HWND control)
     if (index < 0)
         return;
 
-    opt = sane_get_option_descriptor(pSource->deviceHandle, index);
+    opt = sane_get_option_descriptor(activeDS.deviceHandle, index);
 
     if (!opt)
         return;
@@ -973,23 +968,20 @@ static void ComboChanged(HWND hwnd, activeDS* pSource,INT id, HWND control)
 
     if (opt->type == SANE_TYPE_STRING)
     {
-        if (UpdateSaneStringOption(pSource, index, value))
-                InitializeDialog(hwnd,pSource);
+        if (UpdateSaneStringOption(index, value))
+                InitializeDialog(hwnd);
     }
 }
 
 
 static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    static activeDS *pSource = NULL;
-
     switch (msg)
     {
         case WM_INITDIALOG:
-            pSource = (activeDS*)((LPPROPSHEETPAGEW)lParam)->lParam;
-            return InitializeDialog(hwndDlg, pSource);
+            return InitializeDialog(hwndDlg);
         case WM_HSCROLL:
-            return ProcessScroll(hwndDlg, pSource, wParam, lParam);
+            return ProcessScroll(hwndDlg, wParam, lParam);
             break;
         case WM_NOTIFY:
             {
@@ -999,15 +991,15 @@ static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM
                     case PSN_APPLY:
                         if (psn->lParam == TRUE)
                         {
-                            pSource->currentState = 6;
-                            pSource->pendingEvent.TWMessage = MSG_XFERREADY;
+                            activeDS.currentState = 6;
+                            activeDS.pendingEvent.TWMessage = MSG_XFERREADY;
                         }
                         break;
                     case PSN_QUERYCANCEL:
-                        pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
+                        activeDS.pendingEvent.TWMessage = MSG_CLOSEDSREQ;
                         break;
                     case PSN_SETACTIVE:
-                        InitializeDialog(hwndDlg, pSource);
+                        InitializeDialog(hwndDlg);
                         break;
                 }
             }
@@ -1016,11 +1008,11 @@ static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM
                 switch (HIWORD(wParam))
                 {
                     case BN_CLICKED:
-                        ButtonClicked(hwndDlg, pSource,LOWORD(wParam),
+                        ButtonClicked(hwndDlg,LOWORD(wParam),
                                 (HWND)lParam);
                         break;
                     case CBN_SELCHANGE:
-                        ComboChanged(hwndDlg, pSource,LOWORD(wParam),
+                        ComboChanged(hwndDlg,LOWORD(wParam),
                                 (HWND)lParam);
                 }
             }
@@ -1046,10 +1038,10 @@ static INT_PTR CALLBACK ScanningProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
     return FALSE;
 }
 
-HWND ScanningDialogBox(HWND dialog, DWORD progress)
+HWND ScanningDialogBox(HWND dialog, LONG progress)
 {
     if (!dialog)
-        dialog = CreateDialogW(DSM_instance,
+        dialog = CreateDialogW(SANE_instance,
                 (LPWSTR)MAKEINTRESOURCE(IDD_DIALOG1), NULL, ScanningProc);
 
     if (progress == -1)
@@ -1066,7 +1058,7 @@ HWND ScanningDialogBox(HWND dialog, DWORD progress)
 
 #else  /* HAVE_SANE */
 
-BOOL DoScannerUI(activeDS *pSource)
+BOOL DoScannerUI(void)
 {
     return FALSE;
 }
diff --git a/dlls/twain_32/.gitignore b/dlls/twain_32/.gitignore
index 581860b6baa06ed16efc8913cf2d13c21ed5fec2..f3c7a7c5da68804a1bdf391127ba34aed33c3cca 100644
--- a/dlls/twain_32/.gitignore
+++ b/dlls/twain_32/.gitignore
@@ -1,2 +1 @@
 Makefile
-rsrc.res
diff --git a/dlls/twain_32/Makefile.in b/dlls/twain_32/Makefile.in
index c4550ced7117929e9d61ac569be869ab98e32806..3e37234d4863ca4e041d2aafc999289e888d0f3e 100644
--- a/dlls/twain_32/Makefile.in
+++ b/dlls/twain_32/Makefile.in
@@ -3,25 +3,15 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = twain_32.dll
-IMPORTS   = comctl32 user32 gdi32 kernel32 ntdll
-EXTRALIBS = @SANELIBS@
-EXTRAINCL = @SANEINCL@
+IMPORTS   = kernel32 ntdll
 
 C_SRCS = \
-	capability.c \
-	ds_audio.c \
-	ds_ctrl.c \
-	ds_image.c \
 	dsm_ctrl.c \
-	twain32_main.c \
-	ui.c
+	twain32_main.c
 
 C_SRCS16 = \
 	twain16_main.c
 
-RC_SRCS = \
-	rsrc.rc
-
 SPEC_SRCS16 = twain.spec
 
 @MAKE_DLL_RULES@
diff --git a/dlls/twain_32/ds_audio.c b/dlls/twain_32/ds_audio.c
deleted file mode 100644
index 105c4b7778906b23195e683643685d5162937cb5..0000000000000000000000000000000000000000
--- a/dlls/twain_32/ds_audio.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2000 Corel Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include "twain.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(twain);
-
-/* DG_AUDIO/DAT_AUDIOFILEXFER/MSG_GET */
-TW_UINT16 TWAIN_AudioFileXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
-                                  TW_MEMREF pData)
-{
-    FIXME ("stub!\n");
-
-    return TWRC_FAILURE;
-}
-
-/* DG_AUDIO/DAT_AUDIOINFO/MSG_GET */
-TW_UINT16 TWAIN_AudioInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
-                              TW_MEMREF pData)
-{
-    FIXME ("stub!\n");
-
-    return TWRC_FAILURE;
-}
-
-/* DG_AUDIO/DAT_AUDIONATIVEXFER/MSG_GET */
-TW_UINT16 TWAIN_AudioNativeXferGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
-                                    TW_MEMREF pData)
-{
-    FIXME ("stub!\n");
-
-    return TWRC_FAILURE;
-}
diff --git a/dlls/twain_32/dsm_ctrl.c b/dlls/twain_32/dsm_ctrl.c
index dce7add51b48223e6c3b64f3f891e8f27d76817a..75d5c648798d9a8bcb9aefe3d1a1280113d9cb9b 100644
--- a/dlls/twain_32/dsm_ctrl.c
+++ b/dlls/twain_32/dsm_ctrl.c
@@ -2,6 +2,7 @@
  * TWAIN32 Source Manager
  *
  * Copyright 2000 Corel Corporation
+ * Copyright 2006 Marcus Meissner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,420 +35,296 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
-/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
-TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
-{
-#ifndef HAVE_SANE
-    DSM_twCC = TWCC_NODS;
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-    pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
-    activeDS *currentDS = NULL, *prevDS = NULL;
+struct all_devices {
+	char 		*modname;
+	TW_IDENTITY	identity;
+};
+
+static int nrdevices = 0;
+static struct all_devices *devices = NULL;
+
+static void
+twain_add_onedriver(const char *dsname) {
+	HMODULE 	hmod;
+	DSENTRYPROC	dsEntry;
+	TW_IDENTITY	fakeOrigin;
+	TW_IDENTITY	sourceId;
+	TW_UINT16	ret;
+
+	hmod = LoadLibraryA(dsname);
+	if (!hmod) {
+		ERR("Failed to load TWAIN Source %s\n", dsname);
+		return;
+	}
+	dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
+	if (!dsEntry) {
+		ERR("Failed to find DS_Entry() in TWAIN DS %s\n", dsname);
+		return;
+	}
+	/* Loop to do multiple detects, mostly for sane.ds and gphoto2.ds */
+	do {
+		int i;
+
+		sourceId.Id 		= DSM_sourceId;
+		sourceId.ProtocolMajor	= TWON_PROTOCOLMAJOR;
+		sourceId.ProtocolMinor	= TWON_PROTOCOLMINOR;
+		ret = dsEntry (&fakeOrigin, DG_CONTROL, DAT_IDENTITY, MSG_GET, &sourceId);
+		if (ret != TWRC_SUCCESS) {
+			ERR("Source->(DG_CONTROL,DAT_IDENTITY,MSG_GET) failed!\n");
+			return;
+		}
+		TRACE("Manufacturer: %s\n",	debugstr_a(sourceId.Manufacturer));
+		TRACE("ProductFamily: %s\n",	debugstr_a(sourceId.ProductFamily));
+		TRACE("ProductName: %s\n",	debugstr_a(sourceId.ProductName));
+
+		for (i=0;i<nrdevices;i++) {
+			if (!strcmp(sourceId.ProductName,devices[i].identity.ProductName))
+				break;
+		}
+		if (i < nrdevices)
+			break;
+		if (nrdevices)
+			devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+		else
+			devices = malloc(sizeof(devices[0]));
+		devices[nrdevices].modname = strdup(dsname);
+		memcpy (&devices[nrdevices].identity, &sourceId, sizeof(sourceId));
+		nrdevices++;
+		DSM_sourceId++;
+	} while (1);
+	FreeLibrary (hmod);
+}
 
-    TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+static int detectionrun = 0;
 
-    for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
-    {
-        if (currentDS->identity.Id == pIdentity->Id)
-            break;
-        prevDS = currentDS;
-    }
-    if (currentDS)
-    {
-        /* Only valid to close a data source if it is in state 4 */
-        if (currentDS->currentState == 4)
-        {
-            sane_close (currentDS->deviceHandle);
-            /* remove the data source from active data source list */
-            if (prevDS)
-                prevDS->next = currentDS->next;
-            else
-                activeSources = currentDS->next;
-            HeapFree (GetProcessHeap(), 0, currentDS);
-            twRC = TWRC_SUCCESS;
-            DSM_twCC = TWCC_SUCCESS;
-        }
-        else
-        {
-            twRC = TWRC_FAILURE;
-            DSM_twCC = TWCC_SEQERROR;
-        }
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
+static void
+twain_autodetect() {
+	if (detectionrun) return;
+	detectionrun = 1;
 
-    return twRC;
+	twain_add_onedriver("gphoto2.ds");
+	twain_add_onedriver("sane.ds");
+#if 0
+	twain_add_onedriver("c:\\windows\\Twain_32\\Largan\\sp503a.ds");
+	twain_add_onedriver("c:\\windows\\Twain_32\\vivicam10\\vivicam10.ds");
+	twain_add_onedriver("c:\\windows\\Twain_32\\ws30slim\\sp500a.ds");
 #endif
 }
 
-/* Sane returns device names that are longer than the 32 bytes allowed
-   by TWAIN.  However, it colon separates them, and the last bit is
-   the most interesting.  So we use the last bit, and add a signature
-   to ensure uniqueness */
-#ifdef HAVE_SANE
-static void copy_sane_short_name(const char *in, char *out, size_t outsize)
+/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
+TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-    const char *p;
-    int  signature = 0;
-
-    if (strlen(in) <= outsize - 1)
-    {
-        strcpy(out, in);
-        return;
-    }
-
-    for (p = in; *p; p++)
-        signature += *p;
-
-    p = strrchr(in, ':');
-    if (!p)
-        p = in;
-    else
-        p++;
-
-    if (strlen(p) > outsize - 7 - 1)
-        p += strlen(p) - (outsize - 7 - 1);
-
-    strcpy(out, p);
-    sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
-
+	TW_UINT16 twRC = TWRC_SUCCESS;
+	pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+	activeDS *currentDS = NULL, *prevDS = NULL;
+
+	TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+
+	for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
+		if (currentDS->identity.Id == pIdentity->Id)
+			break;
+		prevDS = currentDS;
+	}
+	if (!currentDS) {
+		DSM_twCC = TWCC_NODS;
+		return TWRC_FAILURE;
+	}
+	twRC = currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
+	/* This causes crashes due to still open Windows, so leave out for now.
+	 * FreeLibrary (currentDS->hmod);
+	 */
+	if (prevDS)
+		prevDS->next = currentDS->next;
+	else
+		activeSources = currentDS->next;
+	HeapFree (GetProcessHeap(), 0, currentDS);
+	if (twRC == TWRC_SUCCESS)
+		DSM_twCC = TWCC_SUCCESS;
+	else /* FIXME: unclear how to get TWCC */
+		DSM_twCC = TWCC_SEQERROR;
+	return twRC;
 }
-#endif
 
 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    DSM_twCC = TWCC_NODS;
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-    pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
-
-    TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
-
-    if (!device_list)
-    {
-        if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
-        {
-            DSM_twCC = TWCC_NODS;
-            return TWRC_FAILURE;
-        }
-    }
-
-    /* FIXME: the default device is not necessarily the first device.  *
-     * Users should be able to choose the default device               */
-    if (device_list && device_list[0])
-    {
-        pSourceIdentity->Id = DSM_sourceId ++;
-        copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
-        TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
-        lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
-        lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
-        pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
-        pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-
-        twRC = TWRC_SUCCESS;
-        DSM_twCC = TWCC_SUCCESS;
-
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-
-    return twRC;
-#endif
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
+	DSM_twCC = TWCC_NODS;
+	twain_autodetect();
+	if (!nrdevices)
+		return TWRC_FAILURE;
+	memcpy (pSourceIdentity, &devices[0].identity, sizeof(TW_IDENTITY));
+	return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    DSM_twCC = TWCC_NODS;
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-    pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
-    SANE_Status status;
-
-    TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
-
-    device_list = NULL;
-    status = sane_get_devices (&device_list, SANE_FALSE);
-    if (status == SANE_STATUS_GOOD)
-    {
-        if (device_list[0])
-        {
-            pSourceIdentity->Id = DSM_sourceId ++;
-            copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
-            TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
-            lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
-            lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
-            pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
-            pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-
-            DSM_currentDevice = 1;
-            twRC = TWRC_SUCCESS;
-            DSM_twCC = TWCC_SUCCESS;
-        }
-        else
-        {
-            TRACE("got empty device list\n");
-            twRC = TWRC_FAILURE;
-            DSM_twCC = TWCC_NODS;
-        }
-    }
-    else if (status == SANE_STATUS_NO_MEM)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_LOWMEMORY;
-    }
-    else
-    {
-        WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-
-    return twRC;
-#endif
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+	TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
+	twain_autodetect();
+	if (!nrdevices) {
+		TRACE ("no entries found.\n");
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_ENDOFLIST;
+	}
+	DSM_currentDevice = 0;
+	memcpy (pSourceIdentity, &devices[DSM_currentDevice++].identity, sizeof(TW_IDENTITY));
+	return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    DSM_twCC = TWCC_SUCCESS;
-    return TWRC_ENDOFLIST;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-    pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
-
-    TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
-
-    if (device_list && device_list[DSM_currentDevice] &&
-        device_list[DSM_currentDevice]->name &&
-        device_list[DSM_currentDevice]->vendor &&
-        device_list[DSM_currentDevice]->model)
-    {
-        pSourceIdentity->Id = DSM_sourceId ++;
-        copy_sane_short_name(device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
-        TRACE("got: %s (short [%s]), %s, %s\n", device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, device_list[DSM_currentDevice]->vendor, device_list[DSM_currentDevice]->model);
-        lstrcpynA (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
-        lstrcpynA (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
-        pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
-        pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-        DSM_currentDevice ++;
-
-        twRC = TWRC_SUCCESS;
-        DSM_twCC = TWCC_SUCCESS;
-    }
-    else
-    {
-        DSM_twCC = TWCC_SUCCESS;
-        twRC = TWRC_ENDOFLIST;
-    }
-
-    return twRC;
-#endif
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
+
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
+	if (!nrdevices || (DSM_currentDevice == nrdevices)) {
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_ENDOFLIST;
+	}
+	memcpy (pSourceIdentity, &devices[DSM_currentDevice++].identity, sizeof(TW_IDENTITY));
+	return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    DSM_twCC = TWCC_NODS;
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
-    pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
-    TW_STR32 shortname;
-    activeDS *newSource;
-    SANE_Status status;
-
-    TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
-
-    if (DSM_currentState != 3)
-    {
-        DSM_twCC = TWCC_SEQERROR;
-        return TWRC_FAILURE;
-    }
-
-    if (!device_list &&
-       (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
-    {
-        DSM_twCC = TWCC_NODS;
-        return TWRC_FAILURE;
-    }
-
-    if (pIdentity->ProductName[0] != '\0')
-    {
-        /* Make sure the source to be opened exists in the device list */
-        for (i = 0; device_list[i]; i ++)
-        {
-            copy_sane_short_name(device_list[i]->name, shortname, sizeof(shortname) - 1);
-            if (strcmp (shortname, pIdentity->ProductName) == 0)
-                break;
-        }
-
-    }
-
-    if (device_list[i])
-    {
-        /* the source is found in the device list */
-        newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
-        if (newSource)
-        {
-            newSource->deviceIndex = i;
-            status = sane_open(device_list[i]->name,&newSource->deviceHandle);
-            if (status == SANE_STATUS_GOOD)
-            {
-                /* Assign name and id for the opened data source */
-                lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
-                pIdentity->Id = DSM_sourceId ++;
-                /* add the data source to an internal active source list */
-                newSource->next = activeSources;
-                newSource->identity.Id = pIdentity->Id;
-                strcpy (newSource->identity.ProductName, pIdentity->ProductName);
-                newSource->currentState = 4; /*transition into state 4*/
-                newSource->twCC = TWCC_SUCCESS;
-                activeSources = newSource;
-                twRC = TWRC_SUCCESS;
-                DSM_twCC = TWCC_SUCCESS;
-            }
-            else
-            {
-                twRC = TWRC_FAILURE;
-                DSM_twCC = TWCC_OPERATIONERROR;
-            }
-        }
-        else
-        {
-            twRC = TWRC_FAILURE;
-            DSM_twCC = TWCC_LOWMEMORY;
-        }
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-
-    return twRC;
-#endif
+	TW_UINT16 i = 0;
+	pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+	activeDS *newSource;
+	const char *modname = NULL;
+	HMODULE hmod;
+
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
+        TRACE("pIdentity is %s\n", pIdentity->ProductName);
+	if (DSM_currentState != 3) {
+		FIXME("seq errror\n");
+		DSM_twCC = TWCC_SEQERROR;
+		return TWRC_FAILURE;
+	}
+	twain_autodetect();
+	if (!nrdevices) {
+		FIXME("no devs.\n");
+		DSM_twCC = TWCC_NODS;
+		return TWRC_FAILURE;
+	}
+
+	if (pIdentity->ProductName[0] != '\0') {
+		/* Make sure the source to be opened exists in the device list */
+		for (i = 0; i<nrdevices; i++)
+			if (!strcmp (devices[i].identity.ProductName, pIdentity->ProductName))
+				break;
+		if (i == nrdevices)
+			i = 0;
+	} /* else use the first device */
+
+	/* the source is found in the device list */
+	newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
+	if (!newSource) {
+		DSM_twCC = TWCC_LOWMEMORY;
+		FIXME("Out of memory.\n");
+		return TWRC_FAILURE;
+	}
+	hmod = LoadLibraryA(devices[i].modname);
+	if (!hmod) {
+		ERR("Failed to load TWAIN Source %s\n", modname);
+		DSM_twCC = TWCC_OPERATIONERROR;
+		return TWRC_FAILURE;
+	}
+	newSource->hmod = hmod; 
+	newSource->dsEntry = (DSENTRYPROC)GetProcAddress(hmod, "DS_Entry"); 
+	if (TWRC_SUCCESS != newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity)) {
+		DSM_twCC = TWCC_OPERATIONERROR;
+		return TWRC_FAILURE;
+	}
+	/* Assign name and id for the opened data source */
+	pIdentity->Id = DSM_sourceId ++;
+	/* add the data source to an internal active source list */
+	newSource->next = activeSources;
+	newSource->identity.Id = pIdentity->Id;
+	strcpy (newSource->identity.ProductName, pIdentity->ProductName);
+	activeSources = newSource;
+	DSM_twCC = TWCC_SUCCESS;
+	return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    return TWRC_SUCCESS;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-
-    TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
-
-    /* FIXME: we should replace xscanimage with our own  User Select UI */
-    system("xscanimage");
-
-    DSM_twCC = TWCC_SUCCESS;
-    return twRC;
-#endif
+	pTW_IDENTITY	selected = (pTW_IDENTITY)pData;
+
+	if (!nrdevices) {
+		DSM_twCC = TWCC_OPERATIONERROR;
+		return TWRC_FAILURE;
+	}
+	memcpy (selected, &devices[0].identity, sizeof(TW_IDENTITY));
+	DSM_twCC = TWCC_SUCCESS;
+	return TWRC_SUCCESS;
 }
 
 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
     activeDS *currentDS = activeSources, *nextDS;
 
     TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
 
     if (DSM_currentState == 3)
     {
-        sane_exit ();
         DSM_initialized = FALSE;
-        DSM_parentHWND = 0;
         DSM_currentState = 2;
 
         /* If there are data sources still open, close them now. */
         while (currentDS != NULL)
         {
             nextDS = currentDS->next;
-            sane_close (currentDS->deviceHandle);
+	    currentDS->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, pData);
             HeapFree (GetProcessHeap(), 0, currentDS);
             currentDS = nextDS;
         }
         activeSources = NULL;
         DSM_twCC = TWCC_SUCCESS;
-        twRC = TWRC_SUCCESS;
-    }
-    else
-    {
+        return TWRC_SUCCESS;
+    } else {
         DSM_twCC = TWCC_SEQERROR;
-        twRC = TWRC_FAILURE;
+        return TWRC_FAILURE;
     }
-
-    return twRC;
-#endif
 }
 
 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-#ifndef HAVE_SANE
-    return TWRC_FAILURE;
-#else
-    TW_UINT16 twRC = TWRC_SUCCESS;
-    SANE_Status status;
-    SANE_Int version_code;
-
-    TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
-
-    if (DSM_currentState == 2)
-    {
-        if (!DSM_initialized)
-        {
-            DSM_initialized = TRUE;
-            status = sane_init (&version_code, NULL);
-            device_list = NULL;
-            DSM_currentDevice = 0;
-            DSM_sourceId = 0;
-        }
-        DSM_parentHWND = *(TW_HANDLE*)pData;
-        DSM_currentState = 3; /* transition to state 3 */
-        DSM_twCC = TWCC_SUCCESS;
-        twRC = TWRC_SUCCESS;
-    }
-    else
-    {
-        /* operation invoked in invalid state */
-        DSM_twCC = TWCC_SEQERROR;
-        twRC = TWRC_FAILURE;
-    }
-
-    return twRC;
-#endif
+	TW_UINT16 twRC = TWRC_SUCCESS;
+
+	TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
+	if (DSM_currentState == 2) {
+		if (!DSM_initialized) {
+			DSM_currentDevice = 0;
+			DSM_initialized = TRUE;
+		}
+        	DSM_currentState = 3;
+		DSM_twCC = TWCC_SUCCESS;
+		twRC = TWRC_SUCCESS;
+	} else {
+		/* operation invoked in invalid state */
+		DSM_twCC = TWCC_SEQERROR;
+		twRC = TWRC_FAILURE;
+	}
+	return twRC;
 }
 
 /* DG_CONTROL/DAT_STATUS/MSG_GET */
 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
-    pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
-
-    TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
+	pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
 
-    pSourceStatus->ConditionCode = DSM_twCC;
-    DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
+	TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
 
-    return TWRC_SUCCESS;
+	pSourceStatus->ConditionCode = DSM_twCC;
+	DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
+	return TWRC_SUCCESS;
 }
diff --git a/dlls/twain_32/twain32_main.c b/dlls/twain_32/twain32_main.c
index df59afc22f6fe05cea26a88c6621600483a7c853..358059a5142294bc23c3742d35a667b202cf2a02 100644
--- a/dlls/twain_32/twain32_main.c
+++ b/dlls/twain_32/twain32_main.c
@@ -2,6 +2,7 @@
  * TWAIN32 functions
  *
  * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
+ * Copyright 2006 Marcus Meissner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,18 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
+/* A helper function that looks up a destination identity in the active
+   source list */
+static activeDS *TWAIN_LookupSource (pTW_IDENTITY pDest)
+{
+    activeDS *pSource;
+
+    for (pSource = activeSources; pSource; pSource = pSource->next)
+        if (pSource->identity.Id == pDest->Id)
+            break;
+    return pSource;
+}
+
 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
     TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
@@ -39,7 +52,6 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             DSM_currentState = 2;
-            DSM_instance = hinstDLL;
             break;
 
         case DLL_PROCESS_DETACH:
@@ -116,12 +128,9 @@ TW_UINT16 TWAIN_SourceManagerHandler (
             break;
 
         case DAT_STATUS:
-            if (MSG == MSG_GET)
-            {
+            if (MSG == MSG_GET) {
                 twRC = TWAIN_GetDSMStatus (pOrigin, pData);
-            }
-            else
-            {
+            } else {
                 twRC = TWRC_FAILURE;
                 DSM_twCC = TWCC_BADPROTOCOL;
                 WARN("unrecognized operation triplet\n");
@@ -138,461 +147,6 @@ TW_UINT16 TWAIN_SourceManagerHandler (
     return twRC;
 }
 
-TW_UINT16 TWAIN_SourceControlHandler (
-           pTW_IDENTITY pOrigin,
-           pTW_IDENTITY pDest,
-           TW_UINT16    DAT,
-           TW_UINT16    MSG,
-           TW_MEMREF    pData)
-{
-    TW_UINT16 twRC = TWRC_SUCCESS;
-
-    switch (DAT)
-    {
-        case DAT_CAPABILITY:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_CapabilityGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETCURRENT:
-                    twRC = TWAIN_CapabilityGetCurrent (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_CapabilityGetDefault (pOrigin, pDest, pData);
-                    break;
-                case MSG_QUERYSUPPORT:
-                    twRC = TWAIN_CapabilityQuerySupport (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_CapabilityReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_CapabilitySet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    WARN("unrecognized opertion triplet\n");
-            }
-            break;
-
-        case DAT_CUSTOMDSDATA:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_CustomDSDataGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_CustomDSDataSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    break;
-            }
-            break;
-
-        case DAT_FILESYSTEM:
-            switch (MSG)
-            {
-                /*case MSG_AUTOMATICCAPTUREDIRECTORY:
-                    twRC = TWAIN_AutomaticCaptureDirectory
-                               (pOrigin, pDest, pData);
-                    break;*/
-                case MSG_CHANGEDIRECTORY:
-                    twRC = TWAIN_ChangeDirectory (pOrigin, pDest, pData);
-                    break;
-                /*case MSG_COPY:
-                    twRC = TWAIN_FileSystemCopy (pOrigin, pDest, pData);
-                    break;*/
-                case MSG_CREATEDIRECTORY:
-                    twRC = TWAIN_CreateDirectory (pOrigin, pDest, pData);
-                    break;
-                case MSG_DELETE:
-                    twRC = TWAIN_FileSystemDelete (pOrigin, pDest, pData);
-                    break;
-                case MSG_FORMATMEDIA:
-                    twRC = TWAIN_FormatMedia (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETCLOSE:
-                    twRC = TWAIN_FileSystemGetClose (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETFIRSTFILE:
-                    twRC = TWAIN_FileSystemGetFirstFile
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETINFO:
-                    twRC = TWAIN_FileSystemGetInfo (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETNEXTFILE:
-                    twRC = TWAIN_FileSystemGetNextFile
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_RENAME:
-                    twRC = TWAIN_FileSystemRename (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    break;
-            }
-            break;
-
-        case DAT_EVENT:
-            if (MSG == MSG_PROCESSEVENT)
-                twRC = TWAIN_ProcessEvent (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_PASSTHRU:
-            if (MSG == MSG_PASSTHRU)
-                twRC = TWAIN_PassThrough (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_PENDINGXFERS:
-            switch (MSG)
-            {
-                case MSG_ENDXFER:
-                    twRC = TWAIN_PendingXfersEndXfer (pOrigin, pDest, pData);
-                    break;
-                case MSG_GET:
-                    twRC = TWAIN_PendingXfersGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_PendingXfersReset (pOrigin, pDest, pData);
-                    break;
-                /*case MSG_STOPFEEDER:
-                    twRC = TWAIN_PendingXfersStopFeeder
-                               (pOrigin, pDest, pData);
-                    break;*/
-                default:
-                    twRC = TWRC_FAILURE;
-            }
-            break;
-
-        case DAT_SETUPFILEXFER:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_SetupFileXferGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_SetupFileXferGetDefault
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_SetupFileXferReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_SetupFileXferSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    break;
-            }
-            break;
-
-        /*case DAT_SETUPFILEXFER2:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_SetupFileXfer2Get (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_SetupFileXfer2GetDefault
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_SetupFileXfer2Reset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_SetupFileXfer2Set (pOrigin, pDest, pData);
-                    break;
-            }
-            break;*/
-        case DAT_SETUPMEMXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_SetupMemXferGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_STATUS:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_GetDSStatus (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_USERINTERFACE:
-            switch (MSG)
-            {
-                case MSG_DISABLEDS:
-                    twRC = TWAIN_DisableDSUserInterface
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_ENABLEDS:
-                    twRC = TWAIN_EnableDSUserInterface
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_ENABLEDSUIONLY:
-                    twRC = TWAIN_EnableDSUIOnly (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    break;
-            }
-            break;
-
-        case DAT_XFERGROUP:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_XferGroupGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_XferGroupSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    break;
-            }
-            break;
-
-        default:
-            twRC = TWRC_FAILURE;
-            break;
-    }
-
-    return twRC;
-}
-
-TW_UINT16 TWAIN_ControlGroupHandler (
-           pTW_IDENTITY pOrigin,
-           pTW_IDENTITY pDest,
-           TW_UINT16    DAT,
-           TW_UINT16    MSG,
-           TW_MEMREF    pData)
-{
-    TW_UINT16 twRC = TWRC_SUCCESS;
-
-    if (pDest)
-    {
-        /* This operation's destination is a source */
-        twRC = TWAIN_SourceControlHandler (pOrigin, pDest, DAT, MSG, pData);
-    }
-    else
-    {
-        /* This operation's destination is the Source Manager */
-        twRC = TWAIN_SourceManagerHandler (pOrigin, DAT, MSG, pData);
-    }
-
-    return twRC;
-}
-
-TW_UINT16 TWAIN_ImageGroupHandler (
-           pTW_IDENTITY pOrigin,
-           pTW_IDENTITY pDest,
-           TW_UINT16    DAT,
-           TW_UINT16    MSG,
-           TW_MEMREF    pData)
-{
-    TW_UINT16 twRC = TWRC_SUCCESS;
-
-    if (pDest == NULL)
-    {
-        DSM_twCC = TWCC_BADDEST;
-        return TWRC_FAILURE;
-    }
-
-    switch (DAT)
-    {
-        case DAT_CIECOLOR:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_CIEColorGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_EXTIMAGEINFO:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_ExtImageInfoGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_GRAYRESPONSE:
-            switch (MSG)
-            {
-                case MSG_RESET:
-                    twRC = TWAIN_GrayResponseReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_GrayResponseSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    DSM_twCC = TWCC_BADPROTOCOL;
-                    WARN("unrecognized operation triplet\n");
-                    break;
-            }
-            break;
-        case DAT_IMAGEFILEXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_ImageFileXferGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_IMAGEINFO:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_ImageInfoGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_IMAGELAYOUT:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_ImageLayoutGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_ImageLayoutGetDefault (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_ImageLayoutReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_ImageLayoutSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    DSM_twCC = TWCC_BADPROTOCOL;
-                    WARN("unrecognized operation triplet\n");
-                    break;
-            }
-            break;
-
-        case DAT_IMAGEMEMXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_ImageMemXferGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_IMAGENATIVEXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_ImageNativeXferGet (pOrigin, pDest, pData);
-            else
-                twRC = TWRC_FAILURE;
-            break;
-
-        case DAT_JPEGCOMPRESSION:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_JPEGCompressionGet (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_JPEGCompressionGetDefault
-                               (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_JPEGCompressionReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_JPEGCompressionSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    DSM_twCC = TWCC_BADPROTOCOL;
-                    WARN("unrecognized operation triplet\n");
-                    break;
-            }
-            break;
-
-        case DAT_PALETTE8:
-            switch (MSG)
-            {
-                case MSG_GET:
-                    twRC = TWAIN_Palette8Get (pOrigin, pDest, pData);
-                    break;
-                case MSG_GETDEFAULT:
-                    twRC = TWAIN_Palette8GetDefault (pOrigin, pDest, pData);
-                    break;
-                case MSG_RESET:
-                    twRC = TWAIN_Palette8Reset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_Palette8Set (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    DSM_twCC = TWCC_BADPROTOCOL;
-                    WARN("unrecognized operation triplet\n");
-            }
-            break;
-
-        case DAT_RGBRESPONSE:
-            switch (MSG)
-            {
-                case MSG_RESET:
-                    twRC = TWAIN_RGBResponseReset (pOrigin, pDest, pData);
-                    break;
-                case MSG_SET:
-                    twRC = TWAIN_RGBResponseSet (pOrigin, pDest, pData);
-                    break;
-                default:
-                    twRC = TWRC_FAILURE;
-                    DSM_twCC = TWCC_BADPROTOCOL;
-                    WARN("unrecognized operation triplet\n");
-                    break;
-            }
-            break;
-
-        default:
-            twRC = TWRC_FAILURE;
-            DSM_twCC = TWCC_BADPROTOCOL;
-            WARN("unrecognized operation triplet\n");
-    }
-    return twRC;
-}
-
-TW_UINT16 TWAIN_AudioGroupHandler (
-           pTW_IDENTITY pOrigin,
-           pTW_IDENTITY pDest,
-           TW_UINT16    DAT,
-           TW_UINT16    MSG,
-           TW_MEMREF    pData)
-{
-    TW_UINT16 twRC = TWRC_FAILURE;
-
-    switch (DAT)
-    {
-        case DAT_AUDIOFILEXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_AudioFileXferGet (pOrigin, pDest, pData);
-            break;
-
-        case DAT_AUDIOINFO:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_AudioInfoGet (pOrigin, pDest, pData);
-            break;
-
-        case DAT_AUDIONATIVEXFER:
-            if (MSG == MSG_GET)
-                twRC = TWAIN_AudioNativeXferGet (pOrigin, pDest, pData);
-            break;
-
-        default:
-            DSM_twCC = TWCC_BADPROTOCOL;
-            twRC = TWRC_FAILURE;
-            break;
-    }
-
-    return twRC;
-}
 
 /* Main entry point for the TWAIN library */
 TW_UINT16 WINAPI
@@ -607,34 +161,31 @@ DSM_Entry (pTW_IDENTITY pOrigin,
 
     TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
 
+    if (pDest)
+    {
+        activeDS *pSource = TWAIN_LookupSource (pDest);
+	/* This operation's destination is a source */
+
+        if (!pSource) {
+	    ERR("No source associated with pDest %p\n", pDest);
+	    DSM_twCC = TWCC_BADDEST;
+	    return TWRC_FAILURE;
+	}
+	DSM_twCC = TWCC_SUCCESS;
+	TRACE("Forwarding %ld/%d/%d/%p to DS.\n", DG, DAT, MSG, pData);
+	twRC = pSource->dsEntry(pOrigin, DG, DAT, MSG, pData);
+	TRACE("return value is %d\n", twRC);
+	return twRC;
+    }
     switch (DG)
     {
         case DG_CONTROL:
-            twRC = TWAIN_ControlGroupHandler (pOrigin,pDest,DAT,MSG,pData);
-            break;
-        case DG_IMAGE:
-            twRC = TWAIN_ImageGroupHandler (pOrigin,pDest,DAT,MSG,pData);
-            break;
-        case DG_AUDIO:
-            twRC = TWAIN_AudioGroupHandler (pOrigin,pDest,DAT,MSG,pData);
+            twRC = TWAIN_SourceManagerHandler (pOrigin, DAT, MSG, pData);
             break;
         default:
+	    FIXME("The DSM does not handle DG %ld\n", DG);
             DSM_twCC = TWCC_BADPROTOCOL;
             twRC = TWRC_FAILURE;
     }
-
     return twRC;
 }
-
-/* A helper function that looks up a destination identity in the active
-   source list */
-activeDS *TWAIN_LookupSource (pTW_IDENTITY pDest)
-{
-    activeDS *pSource;
-
-    for (pSource = activeSources; pSource; pSource = pSource->next)
-        if (pSource->identity.Id == pDest->Id)
-            break;
-
-    return pSource;
-}
diff --git a/dlls/twain_32/twain_i.h b/dlls/twain_32/twain_i.h
index d2202c4ab0d1dec0e58f8b4672af9dc11e09d0ae..0b7f38aadcedbaa71abe1a17b7c59a84a5ca615e 100644
--- a/dlls/twain_32/twain_i.h
+++ b/dlls/twain_32/twain_i.h
@@ -1,5 +1,6 @@
 /*
  * Copyright 2000 Corel Corporation
+ * Copyright 2006 Marcus Meissner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,9 +24,6 @@
 # error You must include config.h first
 #endif
 
-#ifdef HAVE_SANE
-# include <sane/sane.h>
-#endif
 #include <stdarg.h>
 
 #include "windef.h"
@@ -37,42 +35,20 @@ typedef struct tagActiveDS
 {
     struct tagActiveDS	*next;			/* next active DS */
     TW_IDENTITY		identity;		/* identity */
-    TW_UINT16		currentState;		/* current state */
-    TW_EVENT		pendingEvent;		/* pending event to be sent to
-                                                   application */
-    TW_UINT16		twCC;			/* condition code */
-    HWND		hwndOwner;		/* window handle of the app */
-    HWND		progressWnd;		/* window handle of the scanning window */
-#ifdef HAVE_SANE
-    SANE_Handle		deviceHandle;		/* device handle */
-    SANE_Parameters     sane_param;             /* parameters about the image
-                                                   transferred */
-    BOOL                sane_param_valid;  /* true if valid sane_param*/
-    INT                 deviceIndex;    /* index of the current device */
-#endif
-    /* Capabiblities */
-    TW_UINT16		capXferMech;		/* ICAP_XFERMECH */
+    HMODULE		hmod;
+    DSENTRYPROC		dsEntry;
 } activeDS;
 
 TW_UINT16 DSM_initialized;      /* whether Source Manager is initialized */
 TW_UINT16 DSM_currentState;     /* current state of Source Manager */
 TW_UINT16 DSM_twCC;             /* current condition code of Source Manager */
-TW_HANDLE DSM_parentHWND;       /* window handle of the Source's "parent" */
 TW_UINT32 DSM_sourceId;         /* source id generator */
 TW_UINT16 DSM_currentDevice;    /* keep track of device during enumeration */
 HINSTANCE DSM_instance;
 
-#ifdef HAVE_SANE
-const SANE_Device **device_list;/* a list of all sane devices */
-#endif
 activeDS *activeSources;	/* list of active data sources */
 
-/* Helper functions */
-extern activeDS *TWAIN_LookupSource (pTW_IDENTITY pDest);
-extern TW_UINT16 TWAIN_SaneCapability (activeDS *pSource,
-        pTW_CAPABILITY pCapability, TW_UINT16 action);
-
-/*  */
+/* Device Source Manager Control handlers */
 extern TW_UINT16 TWAIN_ControlGroupHandler (
 	pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
     TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData);
@@ -105,151 +81,4 @@ extern TW_UINT16 TWAIN_OpenDSM
 extern TW_UINT16 TWAIN_GetDSMStatus
            (pTW_IDENTITY pOrigin, TW_MEMREF pData);
 
-/* Implementation of operation triplets
- * From Application to Source (Control Information) */
-TW_UINT16 TWAIN_CapabilityGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CapabilityGetCurrent
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,TW_MEMREF pData);
-TW_UINT16 TWAIN_CapabilityGetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CapabilityQuerySupport
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CapabilityReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CapabilitySet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CustomDSDataGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CustomDSDataSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_AutomaticCaptureDirectory
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ChangeDirectory
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemCopy
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_CreateDirectory
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemDelete
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FormatMedia
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemGetClose
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemGetFirstFile
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemGetInfo
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemGetNextFile
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_FileSystemRename
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ProcessEvent
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_PassThrough
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_PendingXfersEndXfer
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_PendingXfersGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_PendingXfersReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_PendingXfersStopFeeder
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXferGetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXferReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXferSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXfer2Get
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXfer2GetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXfer2Reset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupFileXfer2Set
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_SetupMemXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_GetDSStatus
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_DisableDSUserInterface
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_EnableDSUserInterface
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_EnableDSUIOnly
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_XferGroupGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_XferGroupSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-
-/* Implementation of operation triplets
- * From Application to Source (Image Information) */
-TW_UINT16 TWAIN_CIEColorGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ExtImageInfoGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_GrayResponseReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_GrayResponseSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageFileXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageInfoGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageLayoutGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageLayoutGetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageLayoutReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageLayoutSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageMemXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_ImageNativeXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_JPEGCompressionGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_JPEGCompressionGetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_JPEGCompressionReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_JPEGCompressionSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_Palette8Get
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_Palette8GetDefault
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_Palette8Reset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_Palette8Set
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_RGBResponseReset
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_RGBResponseSet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-
-/* Implementation of operation triplets
- * From Application to Source (Audio Information) */
-TW_UINT16 TWAIN_AudioFileXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_AudioInfoGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-TW_UINT16 TWAIN_AudioNativeXferGet
-    (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest, TW_MEMREF pData);
-
-/* Implementation of TWAIN capabilities */
-TW_UINT16 TWAIN_ICAPXferMech
-    (activeDS *pSource, pTW_CAPABILITY pCapability, TW_UINT16 action);
-
-/* UI function */
-BOOL DoScannerUI(activeDS *pSource);
-HWND ScanningDialogBox(HWND dialog, DWORD progress);
-
 #endif