PATCH: [0/1] split twain_32

Marcus Meissner marcus at jet.franken.de
Thu Apr 20 16:05:36 CDT 2006


Hi,

As earlier mailed, I want to add gphoto support 
to the twain management framework.

TWAIN itself has the concept of:

- DSM / Data Source Manager

  This is the code that lives in twain_32.dll, and manages
  data sources.

  The only interface is DSM_Entry().

  Requests that are not handled by the DSM are forwarded to the
  respective DS, via their DS_Entry() function.

- DS / Data Source

  This is the actual driver, found in "xyz.ds" DLLs.
  It is loaded by twain_32.dll, and calls forwarded to it.

  The only interface is DS_Entry().


Why split up twain_32:
- Allow support of gphoto (the sane gphoto backend is not up
  to todays usability standards)
- Allow support of native drivers.

Since the classical DS have a 1:1 device:DLL mapping, adding
support for multiple autodetected SANE or GPHOTO devices is
problematic.

This is the reason why twain_32.dll still contains SANE code
and will likely contain GPHOTO autodetection code.

Everything else is handled by the seperate sane.ds and (future)
gphoto.ds.


Delivery is in a patch for twain_32 and a tarball for sane.ds

Please also do:
rm dlls/twain_32/capability.c
rm dlls/twain_32/ds_audio.c
rm dlls/twain_32/ds_ctrl.c
rm dlls/twain_32/ds_image.c
rm dlls/twain_32/resource.h
rm dlls/twain_32/rsrc.rc
rm dlls/twain_32/twain_De.rc
rm dlls/twain_32/twain_En.rc
rm dlls/twain_32/twain_Fi.rc
rm dlls/twain_32/twain_Fr.rc
rm dlls/twain_32/twain_Ko.rc
rm dlls/twain_32/twain_No.rc
rm dlls/twain_32/ui.c

Ciao, Marcus

Changelog:
	Split out the Data Source Manager components from twain_32.

Index: dlls/twain_32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/twain_32/Makefile.in,v
retrieving revision 1.1
diff -u -r1.1 Makefile.in
--- dlls/twain_32/Makefile.in	10 Apr 2006 18:49:32 -0000	1.1
+++ dlls/twain_32/Makefile.in	20 Apr 2006 21:04:15 -0000
@@ -3,25 +3,17 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = twain_32.dll
-IMPORTS   = comctl32 user32 gdi32 kernel32 ntdll
+IMPORTS   = kernel32 ntdll
 EXTRALIBS = @SANELIBS@
 EXTRAINCL = @SANEINCL@
 
 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@
Index: dlls/twain_32/dsm_ctrl.c
===================================================================
RCS file: /home/wine/wine/dlls/twain_32/dsm_ctrl.c,v
retrieving revision 1.1
diff -u -r1.1 dsm_ctrl.c
--- dlls/twain_32/dsm_ctrl.c	10 Apr 2006 18:49:32 -0000	1.1
+++ dlls/twain_32/dsm_ctrl.c	20 Apr 2006 21:04:15 -0000
@@ -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,56 +35,174 @@
 
 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;
+enum twain_devtype {
+	DEVTYPE_SANE,
+	DEVTYPE_GPHOTO,
+	DEVTYPE_NATIVE
+};
 
-    TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+struct sane_device {
+#ifdef HAVE_SANE
+	const SANE_Device	*dev;
+#endif
+};
 
-    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;
+struct gphoto_device {
+	const char *name;
+	const char *port;
+};
+
+struct native_device {
+	const char *modname;
+};
+
+struct all_devices {
+	enum	twain_devtype	type;
+	union {
+		struct sane_device	sane;
+		struct gphoto_device	gphoto;
+		struct native_device	native;
+	} u;
+};
+
+
+static int nrdevices = 0;
+static struct all_devices *devices = NULL;
+
+static int detectionrun = 0;
+
+static void
+detect_sane_devices() {
+#ifdef HAVE_SANE
+	const SANE_Device **sane_devlist;
+	int i;
+
+	TRACE("detecting sane...\n");
+	if (sane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
+		return;
+	for (	i=0;
+		sane_devlist[i]		&&
+		sane_devlist[i]->model	&&
+		sane_devlist[i]->vendor	&&
+		sane_devlist[i]->name;
+		i++
+	) {
+		if (nrdevices)
+			devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+		else
+			devices = malloc(sizeof(devices[0]));
+		TRACE("Adding sane device %s/%s/%s\n", sane_devlist[i]->model, sane_devlist[i]->vendor, sane_devlist[i]->name);
+		devices[nrdevices].type = DEVTYPE_SANE;
+		devices[nrdevices].u.sane.dev = sane_devlist[i];
+		nrdevices++;
+	}
+	return;
+#endif
+}
+
+static void
+detect_gphoto_devices() {
+#ifdef HAVE_GPHOTO2
+        int x, count;
+        CameraList *list;
+        CameraAbilitiesList *al = NULL;
+        int  result;
+
+        GPPortInfoList *plist = NULL;
+
+	TRACE("detecting gphoto...\n");
+        if (gp_port_info_list_new (&plist) < GP_OK)
+                return;
+        result = gp_port_info_list_load (plist);
+        if (result < 0) {
+                gp_port_info_list_free (plist);
+                return;
         }
-        else
-        {
-            twRC = TWRC_FAILURE;
-            DSM_twCC = TWCC_SEQERROR;
+        count = gp_port_info_list_count (plist);
+	if (count <= 0)
+		return;
+        if (gp_list_new (&list) < GP_OK)
+		return;
+        gp_abilities_list_new (&al);
+        gp_abilities_list_load (al, NULL);
+        gp_abilities_list_detect (al, plist, list, NULL);
+        gp_abilities_list_free (al);
+
+        count = gp_list_count (list);
+	if (count < GP_OK) {
+		gp_list_free (list);
+		return;
+	}
+        for (x = 0; x < count; x++) {
+		const char *s;
+		if (nrdevices)
+			devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+		else
+			devices = malloc(sizeof(devices[0]));
+		devices[nrdevices].type = DEVTYPE_GPHOTO;
+                gp_list_get_name  (list, x, &s);
+                devices[nrdevices].u.gphoto.name = strdup(s);
+                gp_list_get_value (list, x, &s);
+                devices[nrdevices].u.gphoto.port = strdup(s);
+		TRACE("Adding gphoto device %s:%s...\n", devices[nrdevices].u.gphoto.name, devices[nrdevices].u.gphoto.port);
+		nrdevices++;
         }
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-
-    return twRC;
+        gp_list_free (list);
 #endif
 }
 
+static void
+twain_add_onedevice(const char *dsname) {
+	if (nrdevices)
+		devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+	else
+		devices = malloc(sizeof(devices[0]));
+	devices[nrdevices].type = DEVTYPE_NATIVE;
+	devices[nrdevices].u.native.modname = strdup(dsname);
+	nrdevices++;
+}
+
+static void
+twain_autodetect() {
+	if (detectionrun) return;
+	detectionrun = 1;
+	
+	/* twain_add_onedevice("c:\\windows\\Twain_32\\camio\\camio320int.ds"); */
+	detect_sane_devices();
+	detect_gphoto_devices();
+}
+
+/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
+TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+{
+	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);
+	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;
+}
+
 /* 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
@@ -118,336 +237,309 @@
 }
 #endif
 
+static int
+_get_id(pTW_IDENTITY pSourceIdentity, int i) {
+	pSourceIdentity->Id = DSM_sourceId++;
+	pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
+	pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
+
+	/* FIXME: the default device is not necessarily the first device.  *
+	 * Users should be able to choose the default device               */
+	switch (devices[i].type) {
+#ifdef HAVE_SANE
+	case DEVTYPE_SANE: {
+		copy_sane_short_name(devices[i].u.sane.dev->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
+		TRACE("got: %s (short [%s]), %s, %s\n",
+			devices[i].u.sane.dev->name,
+			pSourceIdentity->ProductName,
+			devices[i].u.sane.dev->vendor,
+			devices[i].u.sane.dev->model
+		);
+		lstrcpynA (pSourceIdentity->Manufacturer,  devices[i].u.sane.dev->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
+		lstrcpynA (pSourceIdentity->ProductFamily, devices[i].u.sane.dev->model, sizeof(pSourceIdentity->ProductFamily) - 1);
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_SUCCESS;
+	}
+#endif
+	case DEVTYPE_GPHOTO: {
+		TRACE ("return gphoto entry %s.%s\n", devices[i].u.gphoto.name, devices[i].u.gphoto.port);
+		lstrcpynA (pSourceIdentity->Manufacturer, devices[i].u.gphoto.name, sizeof(pSourceIdentity->Manufacturer) - 1);
+		lstrcpynA (pSourceIdentity->ProductFamily, "GPhoto Camera", sizeof(pSourceIdentity->ProductFamily) - 1);
+		lstrcpynA (pSourceIdentity->ProductName, devices[i].u.gphoto.port, sizeof(pSourceIdentity->ProductName) - 1);
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_SUCCESS;
+	}
+	case DEVTYPE_NATIVE: {
+		TRACE ("return native entry %s\n", devices[i].u.native.modname);
+		lstrcpynA (pSourceIdentity->Manufacturer, "3rd Party Vendor", sizeof(pSourceIdentity->Manufacturer) - 1);
+		lstrcpynA (pSourceIdentity->ProductFamily, "Native DS", sizeof(pSourceIdentity->ProductFamily) - 1);
+		lstrcpynA (pSourceIdentity->ProductName, devices[i].u.native.modname, sizeof(pSourceIdentity->ProductName) - 1);
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_SUCCESS;
+	}
+	default:
+		TRACE("No TWAIN device available.\n");
+		DSM_twCC = TWCC_NODS;
+		return TWRC_FAILURE;
+	}
+}
+
 /* 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;
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
 
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
-
-    return twRC;
-#endif
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
+	DSM_twCC = TWCC_NODS;
+	twain_autodetect();
+	if (!nrdevices)
+		return TWRC_FAILURE;
+	return _get_id(pSourceIdentity,0);
 }
 
 /* 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;
-    }
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
 
-    return twRC;
-#endif
+	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;
+	return _get_id(pSourceIdentity,DSM_currentDevice++);
 }
 
 /* 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;
-    }
+	pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
 
-    return twRC;
-#endif
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
+	if (!nrdevices || (DSM_currentDevice == nrdevices)) {
+		DSM_twCC = TWCC_SUCCESS;
+		return TWRC_ENDOFLIST;
+	}
+	return _get_id(pSourceIdentity,DSM_currentDevice++);
 }
 
 /* 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;
+	TW_UINT16 i = 0;
+	pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+	TW_STR32 shortname;
+	activeDS *newSource;
+	const char *devname = NULL, *modname = NULL;
+	HMODULE hmod;
+	BOOL (*func)(LPCSTR);
+
+	TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
+
+	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++) {
+			int found = 0;
+			switch (devices[i].type) {
+#ifdef HAVE_SANE
+			case DEVTYPE_SANE:
+				copy_sane_short_name(devices[i].u.sane.dev->name, shortname, sizeof(shortname) - 1);
+				if (strcmp (shortname, pIdentity->ProductName) == 0)
+					found = 1;
+				break;
+#endif
+			case DEVTYPE_GPHOTO:
+				if (strcmp (devices[i].u.gphoto.port, pIdentity->ProductName) == 0)
+					found = 1;
+				break;
+			case DEVTYPE_NATIVE:
+				if (strcmp (devices[i].u.native.modname, pIdentity->ProductName) == 0)
+					found = 1;
+				break;
+			default:break;
+			}
+			if (found)
+				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;
+	}
+	switch (devices[i].type) {
+#ifdef HAVE_SANE
+	case DEVTYPE_SANE:
+		modname = "sane.ds";
+		devname = devices[i].u.sane.dev->name;
+		break;
+#endif
+	case DEVTYPE_GPHOTO:
+		modname = "gphoto2.ds";
+		devname = devices[i].u.gphoto.port;
+		break;
+	case DEVTYPE_NATIVE:
+		modname = devices[i].u.native.modname;
+		devname = "Native DS";
+		break;
+	default:
+		FIXME("Unknown devtype %d.\n",devices[i].type);
+		DSM_twCC = TWCC_OPERATIONERROR;
+		return TWRC_FAILURE;
+	}
+
+	hmod = LoadLibraryA(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"); 
+
+	/* Give our .DS drivers a hint for multiple device support.
+	 * This is a bit hacky, but currently necessary, since twain associates
+	 * 1 device <-> 1 driver.
+	 */
+	switch (devices[i].type) {
+	case DEVTYPE_SANE:
+#ifdef HAVE_SANE
+		func = (void*)GetProcAddress(hmod, "DS_WINE_Open"); 
+		if (func && !func(devices[i].u.sane.dev->name)) {
+			FIXME("Failed to do DS_WINE_Open(%s)\n", devices[i].u.sane.dev->name);
+			DSM_twCC = TWCC_OPERATIONERROR;
+			return TWRC_FAILURE;
+		}
 #endif
+		break;
+	case DEVTYPE_GPHOTO:
+		func = (void*)GetProcAddress(hmod, "DS_WINE_Open"); 
+		if (func && !func(devices[i].u.gphoto.port)) {
+			FIXME("Failed to do DS_WINE_Open(%s)\n", devices[i].u.gphoto.port);
+			DSM_twCC = TWCC_OPERATIONERROR;
+			return TWRC_FAILURE;
+		}
+		break;
+	case DEVTYPE_NATIVE:
+		break;
+	}
+	newSource->dsEntry (pOrigin, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, pIdentity);
+	FIXME("new source has productname %s\n", pIdentity->ProductName);
+
+	/* 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);
+	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;
+	TW_UINT16 twRC = TWRC_SUCCESS;
 
-    TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
+	FIXME("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
 
-    /* FIXME: we should replace xscanimage with our own  User Select UI */
-    system("xscanimage");
+	/* FIXME: we should replace xscanimage with our own  User Select UI */
+	system("xscanimage");
 
-    DSM_twCC = TWCC_SUCCESS;
-    return twRC;
-#endif
+	DSM_twCC = TWCC_SUCCESS;
+	return twRC;
 }
 
 /* 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)
     {
+#ifdef HAV_SANE
         sane_exit ();
+#endif
         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");
+	TW_UINT16 twRC = TWRC_SUCCESS;
 
-    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;
-    }
+	TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
+	if (DSM_currentState == 2) {
+		if (!DSM_initialized) {
+#ifdef HAVE_SANE
+			SANE_Status status;
+			SANE_Int version_code;
 
-    return twRC;
+			status = sane_init (&version_code, NULL);
 #endif
+			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;
 }
Index: dlls/twain_32/twain32_main.c
===================================================================
RCS file: /home/wine/wine/dlls/twain_32/twain32_main.c,v
retrieving revision 1.1
diff -u -r1.1 twain32_main.c
--- dlls/twain_32/twain32_main.c	10 Apr 2006 18:49:32 -0000	1.1
+++ dlls/twain_32/twain32_main.c	20 Apr 2006 21:04:15 -0000
@@ -2,6 +2,7 @@
  * TWAIN32 functions
  *
  * Copyright 2000 Shi Quan He <shiquan at 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 @@
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             DSM_currentState = 2;
-            DSM_instance = hinstDLL;
             break;
 
         case DLL_PROCESS_DETACH:
@@ -116,12 +128,9 @@
             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 @@
     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 @@
 
     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;
-}
Index: dlls/twain_32/twain_i.h
===================================================================
RCS file: /home/wine/wine/dlls/twain_32/twain_i.h,v
retrieving revision 1.1
diff -u -r1.1 twain_i.h
--- dlls/twain_32/twain_i.h	10 Apr 2006 18:49:32 -0000	1.1
+++ dlls/twain_32/twain_i.h	20 Apr 2006 21:04:15 -0000
@@ -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
@@ -28,6 +29,15 @@
 #endif
 #include <stdarg.h>
 
+/* Note: currently off, until we have gphoto.ds */
+#undef HAVE_GPHOTO2
+#ifdef HAVE_GPHOTO2
+/* Hack ... otherwise gphoto2 thinks its on Windows */
+# undef WIN32
+# include <gphoto2/gphoto2-camera.h>
+# define WIN32
+#endif
+
 #include "windef.h"
 #include "winbase.h"
 #include "twain.h"
@@ -37,42 +47,20 @@
 {
     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 +93,4 @@
 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



More information about the wine-patches mailing list