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;elseactiveSources = 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));elsedevices = 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));elsedevices = 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;elseactiveSources = 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;