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;
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;
Am Sonntag, den 09.04.2006, 21:16 +0200 schrieb Marcus Meissner:
+EXTRALIBS = @SANELIBS@ @GPHOTO2LIBS@
It was ok for twain to fail, when sane was not installed. IMHO, when get more alternatives, then all backends must be usable independent (linked dynamic).
We do not want to force libsane and libgphoto2 installed on a System, when the user want to use twain.
On Tue, Apr 18, 2006 at 10:48:30PM +0200, Detlef Riekenberg wrote:
Am Sonntag, den 09.04.2006, 21:16 +0200 schrieb Marcus Meissner:
+EXTRALIBS = @SANELIBS@ @GPHOTO2LIBS@
It was ok for twain to fail, when sane was not installed. IMHO, when get more alternatives, then all backends must be usable independent (linked dynamic).
We do not want to force libsane and libgphoto2 installed on a System, when the user want to use twain.
Dynamic loading can be added. TWAIN itself pretty useless, until you add windows native twain source driver support ;)
But yes.
I now approaching this from another angle.
- Split off the SANE datasource handler from the twain_32 into a seperate dlls/sane.ds
- gphoto will get dlls/gphoto2.ds or similar.
- native drivers will be possible.
- twain_32 keeps the Data Source Managers parts and manages the Data Sources.
=> sane.ds and gphoto.ds can be installed seperately.
twain_32 will however keep some sane & gphoto autodetection logic in this approach, basically because twain_32 (in my understanding) is a bit dumb and has a 1 driver - 1 device assumption, which is not useful for gphoto and sane.
Ciao, Marcus