RFC/PATCH: Twain + Gphoto
Aric Stewart
aric at codeweavers.com
Mon Apr 17 08:20:31 CDT 2006
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;
>
>
>
>
More information about the wine-devel
mailing list