This is really cool! I have poked a bit at it to see and like how it is going so far. It does not appear to actually get any photos from the cameras yet or am i missing that code.

The ImageInfoGet and ImageMemXferGet are sort of the heart of that. At least for the program I am working on support for.

Very cool. I look forward to seeing more on this!
-aric

Marcus Meissner wrote:

Hi,

I have started adding gphoto2 support to twain.dll.

My current work (before a otherwise busy week begins again), is attached.

I started to break up the currently very sane centric view.

Alexandre/Aric, can I do it this way? Some other general comments?

(The code btw works as-is for detection at least.)

Ciao, Marcus

Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.468
diff -u -r1.468 configure.ac
--- configure.ac        6 Apr 2006 10:53:39 -0000       1.468
+++ configure.ac        9 Apr 2006 19:13:29 -0000
@@ -521,6 +521,37 @@
    CPPFLAGS="$ac_save_CPPFLAGS"
fi

+dnl **** Check for libgphoto2 ****
+AC_CHECK_PROG(gphoto2_devel,gphoto2-config,gphoto2-config,no)
+AC_CHECK_PROG(gphoto2port_devel,gphoto2-port-config,gphoto2-port-config,no)
+AC_SUBST(GPHOTO2LIBS,"")
+AC_SUBST(GPHOTO2INCL,"")
+if test "$gphoto2_devel" != "no" -a "$gphoto2port_devel" != "no"
+then
+    GPHOTO2INCL="`$gphoto2_devel --cflags` `$gphoto2port_devel --cflags`"
+    GPHOTO2LIBS=""
+    for i in `$gphoto2_devel --libs` `$gphoto2port_devel --libs`
+    do
+      case "$i" in
+        -L/usr/lib|-L/usr/lib64) ;;
+        -L*|-l*) GPHOTO2LIBS="$GPHOTO2LIBS $i";;
+      esac
+    done
+    ac_save_CPPFLAGS="$CPPFLAGS"
+    ac_save_LIBS="$LIBS"
+    CPPFLAGS="$CPPFLAGS $GPHOTO2INCL"
+    LIBS="$LIBS $GPHOTO2LIBS"
+    AC_CHECK_HEADER(gphoto2-camera.h,
+                    [AC_CHECK_LIB(gphoto2,gp_camera_new,
+                                  [AC_DEFINE(HAVE_GPHOTO2, 1, [Define if we 
have libgphoto2 development environment])],
+                                  [GPHOTO2LIBS=""
+                                  GPHOTO2INCL=""])],
+                    [GPHOTO2LIBS=""
+                    GPHOTO2INCL=""])
+    LIBS="$ac_save_LIBS"
+    CPPFLAGS="$ac_save_CPPFLAGS"
+fi
+
dnl **** Check for the ICU library ****
if test "$ac_cv_header_unicode_ubidi_h" = "yes"
then
Index: dlls/twain/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/twain/Makefile.in,v
retrieving revision 1.10
diff -u -r1.10 Makefile.in
--- dlls/twain/Makefile.in      28 Mar 2006 18:13:00 -0000      1.10
+++ dlls/twain/Makefile.in      9 Apr 2006 19:13:29 -0000
@@ -4,8 +4,8 @@
VPATH     = @srcdir@
MODULE    = twain_32.dll
IMPORTS   = comctl32 user32 gdi32 kernel32 ntdll
-EXTRALIBS = @SANELIBS@
-EXTRAINCL = @SANEINCL@
+EXTRALIBS = @SANELIBS@ @GPHOTO2LIBS@
+EXTRAINCL = @SANEINCL@ @GPHOTO2INCL@

C_SRCS = \
        capability.c \
Index: dlls/twain/ds_ctrl.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ds_ctrl.c,v
retrieving revision 1.6
diff -u -r1.6 ds_ctrl.c
--- dlls/twain/ds_ctrl.c        28 Mar 2006 18:13:00 -0000      1.6
+++ dlls/twain/ds_ctrl.c        9 Apr 2006 19:13:29 -0000
@@ -648,27 +650,37 @@
        if (pUserInterface->ShowUI)
        {
            BOOL rc;
+           FIXME("Showing UI now.\n");
            pSource->currentState = 5; /* Transitions to state 5 */
-            rc = DoScannerUI(pSource);
-            if (!rc)
-            {
-                pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
-            }
+           switch (devices[pSource->deviceIndex].type) {
#ifdef HAVE_SANE
-            else
-            {
-                sane_get_parameters (pSource->deviceHandle, 
&pSource->sane_param);
-                pSource->sane_param_valid = TRUE;
-            }
+           case DEVTYPE_SANE:
+               rc = DoScannerUI(pSource);
+               if (!rc) {
+                       pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
+               } else {
+                       sane_get_parameters (pSource->deviceHandle, 
&pSource->sane_param);
+                       pSource->sane_param_valid = TRUE;
+               }
+               break;
#endif
-        }
-        else
-        {
+#ifdef HAVE_GPHOTO2
+           case DEVTYPE_GPHOTO:
+               FIXME("No GPHOTO UI yet.\n");
+               pSource->pendingEvent.TWMessage = MSG_XFERREADY;
+               pSource->currentState = 6; /* Transitions to state 6 directly */
+               break;
+#endif
+           default:
+               FIXME("Device type %d is unknown\n", 
devices[pSource->deviceIndex].type);
+               break;
+           }
+        } else {
+           FIXME("UI not shown, preparing to transfer data.\n");
            /* 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 */
        }
-
        pSource->hwndOwner = pUserInterface->hParent;
        twRC = TWRC_SUCCESS;
        pSource->twCC = TWCC_SUCCESS;
Index: dlls/twain/ds_image.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ds_image.c,v
retrieving revision 1.8
diff -u -r1.8 ds_image.c
--- dlls/twain/ds_image.c       28 Mar 2006 18:13:00 -0000      1.8
+++ dlls/twain/ds_image.c       9 Apr 2006 19:13:29 -0000
@@ -80,76 +80,81 @@
TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
                              TW_MEMREF pData)
{
-#ifndef HAVE_SANE
-    return TWRC_FAILURE;
-#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)
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_BADDEST;
-    }
-    else if (pSource->currentState != 6 && pSource->currentState != 7)
-    {
-        twRC = TWRC_FAILURE;
-        pSource->twCC = TWCC_SEQERROR;
-    }
-    else
-    {
-        if (pSource->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;
-            TRACE("Getting parameters\n");
-        }
+       pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
+       activeDS *pSource = TWAIN_LookupSource (pDest);

-        pImageInfo->XResolution.Whole = -1;
-        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;
+       TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");

-        TRACE("Bits per Sample %i\n",pSource->sane_param.depth);
-        TRACE("Frame Format %i\n",pSource->sane_param.format);
-
-        if (pSource->sane_param.format == SANE_FRAME_RGB )
-        {
-            pImageInfo->BitsPerPixel = pSource->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->PixelType = TWPT_RGB;
-        }
-        else if (pSource->sane_param.format == SANE_FRAME_GRAY)
-        {
-            pImageInfo->BitsPerPixel = pSource->sane_param.depth;
-            pImageInfo->Compression = TWCP_NONE;
-            pImageInfo->Planar = TRUE;
-            pImageInfo->SamplesPerPixel = 1;
-            pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
-            pImageInfo->PixelType = TWPT_GRAY;
-        }
-        else
-        {
-            ERR("Unhandled source frame type %i\n",pSource->sane_param.format);
-            twRC = TWRC_FAILURE;
-            pSource->twCC = TWCC_SEQERROR;
-        }
-    }
-
-    return twRC;
+       if (!pSource) {
+               FIXME("no source\n");
+               DSM_twCC = TWCC_BADDEST;
+               return TWRC_FAILURE;
+       }
+       if (pSource->currentState != 6 && pSource->currentState != 7) {
+               FIXME("bad state %d\n", pSource->currentState);
+               pSource->twCC = TWCC_SEQERROR;
+               return TWRC_FAILURE;
+       }
+
+       switch (devices[pSource->deviceIndex].type) {
+#ifdef HAVE_SANE
+       case DEVTYPE_SANE: {
+               SANE_Status status;
+               if (pSource->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;
+                   TRACE("Getting parameters\n");
+               }
+
+               pImageInfo->XResolution.Whole = -1;
+               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;
+
+               TRACE("Bits per Sample %i\n",pSource->sane_param.depth);
+               TRACE("Frame Format %i\n",pSource->sane_param.format);
+
+               if (pSource->sane_param.format == SANE_FRAME_RGB )
+               {
+                   pImageInfo->BitsPerPixel = pSource->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->PixelType = TWPT_RGB;
+               }
+               else if (pSource->sane_param.format == SANE_FRAME_GRAY)
+               {
+                   pImageInfo->BitsPerPixel = pSource->sane_param.depth;
+                   pImageInfo->Compression = TWCP_NONE;
+                   pImageInfo->Planar = TRUE;
+                   pImageInfo->SamplesPerPixel = 1;
+                   pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
+                   pImageInfo->PixelType = TWPT_GRAY;
+               }
+               else
+               {
+                   ERR("Unhandled source frame type 
%i\n",pSource->sane_param.format);
+                   pSource->twCC = TWCC_SEQERROR;
+                   return TWRC_FAILURE;
+               }
+               break;
+       }
#endif
+       case DEVTYPE_GPHOTO:
+               FIXME("gphoto case\n");
+               break;
+       default:
+               FIXME("Unknown devtype %d\n", 
devices[pSource->deviceIndex].type);
+               break;
+       }
+       return TWRC_SUCCESS;
}

/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
Index: dlls/twain/dsm_ctrl.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/dsm_ctrl.c,v
retrieving revision 1.13
diff -u -r1.13 dsm_ctrl.c
--- dlls/twain/dsm_ctrl.c       28 Mar 2006 18:13:00 -0000      1.13
+++ dlls/twain/dsm_ctrl.c       9 Apr 2006 19:13:29 -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,54 +35,149 @@

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;
+int nrdevices = 0;
+struct all_devices *devices = NULL;

-    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;
+static void
+detect_sane_devices() {
+#ifdef HAVE_SANE
+       const SANE_Device **sane_devlist;
+       int i;
+
+       FIXME("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]));
+               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;
-    }
+        gp_list_free (list);
+#endif
+}

-    return twRC;
+static void
+twain_autodetect() {
+       if (detectionrun) return;
+       detectionrun = 1;
+       
+       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) {
+               /* Only valid to close a data source if it is in state 4 */
+               if (currentDS->currentState == 4) {
+                       switch (devices[currentDS->deviceIndex].type) {
+#ifdef HAVE_SANE
+                       case DEVTYPE_SANE:
+                               sane_close (currentDS->deviceHandle);
+                               break;
+#endif
+#ifdef HAVE_GPHOTO2
+                       case DEVTYPE_GPHOTO:
+                               gp_camera_exit (currentDS->camera, NULL);
+                               currentDS->camera = NULL;
+                               break;
#endif
+                       default:
+                               FIXME("Unknown devtype %d\n", 
devices[currentDS->deviceIndex].type);
+                               break;
+                       }
+                       /* 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;
+       }
+       return twRC;
}

/* Sane returns device names that are longer than the 32 bytes allowed
@@ -118,229 +214,221 @@
}
#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;
+       }
+       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;
-
-    }
-    else
-    {
-        twRC = TWRC_FAILURE;
-        DSM_twCC = TWCC_NODS;
-    }
+       pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;

-    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;
+       TW_UINT16 i = 0;
+       pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+       TW_STR32 shortname;
+       activeDS *newSource;
+
+       TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
+
+       if (DSM_currentState != 3) {
+               DSM_twCC = TWCC_SEQERROR;
+               FIXME("sequence error\n");
+               return TWRC_FAILURE;
+       }
+       twain_autodetect();
+       if (!nrdevices) {
+               DSM_twCC = TWCC_NODS;
+               FIXME("No devices.\n");
+               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;
+                       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;
+       }
+       newSource->deviceIndex = i;
+       switch (devices[i].type) {
+#ifdef HAVE_SANE
+       case DEVTYPE_SANE: {
+               SANE_Status status;
+               status = 
sane_open(devices[i].u.sane.dev->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;
+                       DSM_twCC = TWCC_SUCCESS;
+                       return TWRC_SUCCESS;
+               } else {
+                       DSM_twCC = TWCC_OPERATIONERROR;
+                       return TWRC_FAILURE;
+               }
+               break;
+       }
+#endif
+       case DEVTYPE_GPHOTO: {
+#ifdef HAVE_GPHOTO2
+               int ret, m;
+               CameraAbilities a;
+               CameraAbilitiesList *al = NULL;
+
+
+               DSM_twCC = TWCC_OPERATIONERROR;
+               ret = gp_camera_new (&newSource->camera);
+               if (ret < GP_OK) {
+                       FIXME("failed to gp_camera_new\n");
+                       return TWRC_FAILURE;
+               }
+
+               gp_abilities_list_new (&al);
+               gp_abilities_list_load (al, NULL);
+               m = gp_abilities_list_lookup_model (al, 
devices[i].u.gphoto.name);
+               if (m < GP_OK) {
+                       FIXME("failed to gp_camera_list_lookup_model\n");
+                       return TWRC_FAILURE;
+               }
+               ret = gp_abilities_list_get_abilities (al, m, &a);
+               if (ret < GP_OK) {
+                       FIXME("failed to gp_camera_list_get_abilities\n");
+                       return TWRC_FAILURE;
+               }
+               ret = gp_camera_set_abilities (newSource->camera, a);
+               if (ret < GP_OK) {
+                       FIXME("failed to gp_camera_set_abilities\n");
+                       return TWRC_FAILURE;
+               }
+               gp_abilities_list_free (al);
+               /* 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;
+               DSM_twCC = TWCC_SUCCESS;
+               TRACE("succeeded opening gphoto camera.\n");
+               return TWRC_SUCCESS;
#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;
+               ERR("No gphoto support?\n");
#endif
+       }
+       default:
+               FIXME("default case, device type %d?\n", devices[i].type);
+               DSM_twCC = TWCC_OPERATIONERROR;
+               return TWRC_FAILURE;
+       }
}

/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
@@ -351,7 +439,7 @@
#else
    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");
@@ -404,50 +492,40 @@
/* 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;
+       TW_UINT16 twRC = TWRC_SUCCESS;

-    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;
-    }
+       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_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;
}

/* DG_CONTROL/DAT_STATUS/MSG_GET */
TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-    pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
+       pTW_STATUS pSourceStatus = (pTW_STATUS) pData;

-    TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
+       TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");

-    pSourceStatus->ConditionCode = DSM_twCC;
-    DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
-
-    return TWRC_SUCCESS;
+       pSourceStatus->ConditionCode = DSM_twCC;
+       DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
+       return TWRC_SUCCESS;
}
Index: dlls/twain/twain_i.h
===================================================================
RCS file: /home/wine/wine/dlls/twain/twain_i.h,v
retrieving revision 1.8
diff -u -r1.8 twain_i.h
--- dlls/twain/twain_i.h        28 Mar 2006 18:13:00 -0000      1.8
+++ dlls/twain/twain_i.h        9 Apr 2006 19:13:29 -0000
@@ -28,6 +28,13 @@
#endif
#include <stdarg.h>

+#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"
@@ -43,12 +50,15 @@
    TW_UINT16           twCC;                   /* condition code */
    HWND                hwndOwner;              /* window handle of the app */
    HWND                progressWnd;            /* window handle of the 
scanning window */
+    INT                 deviceIndex;           /* index of the current device 
*/
#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 */
+    BOOL                sane_param_valid;      /* true if valid sane_param*/
+#endif
+#ifdef HAVE_GPHOTO2
+    Camera             *camera;
#endif
    /* Capabiblities */
    TW_UINT16           capXferMech;            /* ICAP_XFERMECH */
@@ -62,9 +72,33 @@
TW_UINT16 DSM_currentDevice;    /* keep track of device during enumeration */
HINSTANCE DSM_instance;

+enum twain_devtype {
+       DEVTYPE_SANE,
+       DEVTYPE_GPHOTO
+};
+
+struct sane_device {
#ifdef HAVE_SANE
-const SANE_Device **device_list;/* a list of all sane devices */
+       const SANE_Device       *dev;
#endif
+};
+
+struct gphoto_device {
+       const char *name;
+       const char *port;
+};
+
+struct all_devices {
+       enum    twain_devtype   type;
+       union {
+               struct sane_device      sane;
+               struct gphoto_device    gphoto;
+       } u;
+};
+
+extern int nrdevices;
+extern struct all_devices *devices;
+
activeDS *activeSources;        /* list of active data sources */

/* Helper functions */
Index: dlls/twain/ui.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ui.c,v
retrieving revision 1.1
diff -u -r1.1 ui.c
--- dlls/twain/ui.c     28 Mar 2006 18:13:00 -0000      1.1
+++ dlls/twain/ui.c     9 Apr 2006 19:13:30 -0000
@@ -574,15 +574,15 @@
        index ++;
    }
- len = lstrlenA(device_list[pSource->deviceIndex]->vendor)
-         + lstrlenA(device_list[pSource->deviceIndex]->model) + 2;
+    len = lstrlenA(devices[pSource->deviceIndex].u.sane.dev->vendor)
+         + lstrlenA(devices[pSource->deviceIndex].u.sane.dev->model) + 2;

    szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
-    MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->vendor,-1,
+    
MultiByteToWideChar(CP_ACP,0,devices[pSource->deviceIndex].u.sane.dev->vendor,-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(devices[pSource->deviceIndex].u.sane.dev->vendor)] = ' 
';
+    
MultiByteToWideChar(CP_ACP,0,devices[pSource->deviceIndex].u.sane.dev->model,-1,
+            
&szCaption[lstrlenA(devices[pSource->deviceIndex].u.sane.dev->vendor)+1],len);
psh.dwSize = sizeof(PROPSHEETHEADERW);
    psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;





Reply via email to