mirror of
https://github.com/reactos/wine.git
synced 2024-12-04 17:56:51 +00:00
452 lines
13 KiB
C
452 lines
13 KiB
C
/*
|
|
* TWAIN32 Source Manager
|
|
*
|
|
* Copyright 2000 Corel Corporation
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "twain.h"
|
|
#include "twain_i.h"
|
|
#include "wine/debug.h"
|
|
|
|
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;
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
twRC = TWRC_FAILURE;
|
|
DSM_twCC = TWCC_SEQERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
twRC = TWRC_FAILURE;
|
|
DSM_twCC = TWCC_NODS;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* Sane returns device names that are longer than the 32 bytes allowed
|
|
by TWAIN. However, it colon separates them, and the last bit is
|
|
the most interesting. So we use the last bit, and add a signature
|
|
to ensure uniqueness */
|
|
#ifdef HAVE_SANE
|
|
static void copy_sane_short_name(const char *in, char *out, size_t outsize)
|
|
{
|
|
const char *p;
|
|
int signature = 0;
|
|
|
|
if (strlen(in) <= outsize - 1)
|
|
{
|
|
strcpy(out, in);
|
|
return;
|
|
}
|
|
|
|
for (p = in; *p; p++)
|
|
signature += *p;
|
|
|
|
p = strrchr(in, ':');
|
|
if (!p)
|
|
p = in;
|
|
else
|
|
p++;
|
|
|
|
if (strlen(p) > outsize - 7 - 1)
|
|
p += strlen(p) - (outsize - 7 - 1);
|
|
|
|
strcpy(out, p);
|
|
sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
|
|
|
|
}
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* 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");
|
|
|
|
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;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
|
|
TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
|
|
{
|
|
#ifndef HAVE_SANE
|
|
DSM_twCC = TWCC_NODS;
|
|
return TWRC_FAILURE;
|
|
#else
|
|
TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
|
|
pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
|
|
TW_STR32 shortname;
|
|
activeDS *newSource;
|
|
SANE_Status status;
|
|
|
|
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
|
|
|
|
if (DSM_currentState != 3)
|
|
{
|
|
DSM_twCC = TWCC_SEQERROR;
|
|
return TWRC_FAILURE;
|
|
}
|
|
|
|
if (!device_list &&
|
|
(sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
|
|
{
|
|
DSM_twCC = TWCC_NODS;
|
|
return TWRC_FAILURE;
|
|
}
|
|
|
|
if (pIdentity->ProductName[0] != '\0')
|
|
{
|
|
/* Make sure the source to be opened exists in the device list */
|
|
for (i = 0; device_list[i]; i ++)
|
|
{
|
|
copy_sane_short_name(device_list[i]->name, shortname, sizeof(shortname) - 1);
|
|
if (strcmp (shortname, pIdentity->ProductName) == 0)
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (device_list[i])
|
|
{
|
|
/* the source is found in the device list */
|
|
newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
|
|
if (newSource)
|
|
{
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
|
|
TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
|
|
{
|
|
#ifndef HAVE_SANE
|
|
return TWRC_SUCCESS;
|
|
#else
|
|
TW_UINT16 twRC = TWRC_SUCCESS;
|
|
|
|
TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
|
|
|
|
/* FIXME: we should replace xscanimage with our own User Select UI */
|
|
system("xscanimage");
|
|
|
|
DSM_twCC = TWCC_SUCCESS;
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
|
|
TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
|
|
{
|
|
#ifndef HAVE_SANE
|
|
return TWRC_FAILURE;
|
|
#else
|
|
TW_UINT16 twRC = TWRC_SUCCESS;
|
|
activeDS *currentDS = activeSources, *nextDS;
|
|
|
|
TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
|
|
|
|
if (DSM_currentState == 3)
|
|
{
|
|
sane_exit ();
|
|
DSM_initialized = FALSE;
|
|
DSM_parentHWND = 0;
|
|
DSM_currentState = 2;
|
|
|
|
/* If there are data sources still open, close them now. */
|
|
while (currentDS != NULL)
|
|
{
|
|
nextDS = currentDS->next;
|
|
sane_close (currentDS->deviceHandle);
|
|
HeapFree (GetProcessHeap(), 0, currentDS);
|
|
currentDS = nextDS;
|
|
}
|
|
activeSources = NULL;
|
|
DSM_twCC = TWCC_SUCCESS;
|
|
twRC = TWRC_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DSM_twCC = TWCC_SEQERROR;
|
|
twRC = TWRC_FAILURE;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
|
|
TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
|
|
{
|
|
#ifndef HAVE_SANE
|
|
return TWRC_FAILURE;
|
|
#else
|
|
TW_UINT16 twRC = TWRC_SUCCESS;
|
|
SANE_Status status;
|
|
SANE_Int version_code;
|
|
|
|
TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
|
|
|
|
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;
|
|
}
|
|
|
|
return twRC;
|
|
#endif
|
|
}
|
|
|
|
/* DG_CONTROL/DAT_STATUS/MSG_GET */
|
|
TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
|
|
{
|
|
pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
|
|
|
|
TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
|
|
|
|
pSourceStatus->ConditionCode = DSM_twCC;
|
|
DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
|
|
|
|
return TWRC_SUCCESS;
|
|
}
|